Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add NonceGenerator trait and implement RollingNonce #500

Merged
merged 3 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 8 additions & 23 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,19 @@ jobs:
with:
toolchain: ${{ matrix.rust }}

- name: Run cargo check Windows
if: matrix.os == 'windows-latest'
run: cargo check --no-default-features --features num

- name: Run cargo check
if: matrix.os != 'windows-latest'
run: cargo check

test:
name: Test Suite
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2

- name: Install stable toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
strategy:
fail-fast: false
matrix:
os: [ windows-latest, ubuntu-latest, macOS-latest ]
rust: [ stable ]

- name: Run cargo test
run: cargo test
runs-on: ${{ matrix.os }}

test-windows:
name: Test Suite Windows
runs-on: windows-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2
Expand All @@ -61,7 +48,7 @@ jobs:
toolchain: stable

- name: Run cargo test
run: cargo test --no-default-features --features num
run: cargo test --release

lints:
name: Lints
Expand All @@ -80,6 +67,4 @@ jobs:
run: cargo fmt --all -- --check

- name: Run cargo clippy
run: |
cargo clippy -- -D warnings
cargo clippy --no-default-features --features num -- -D warnings
run: cargo clippy -- -D warnings
10 changes: 2 additions & 8 deletions pallas-applying/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,7 @@ pub fn validate_txs(
) -> ValidationResult {
let mut delta_state: CertState = cert_state.clone();
for (txix, metx) in metxs.iter().enumerate() {
validate_tx(
&metx,
txix.try_into().unwrap(),
env,
utxos,
&mut delta_state,
)?;
validate_tx(metx, txix.try_into().unwrap(), env, utxos, &mut delta_state)?;
}
*cert_state = delta_state;
Ok(())
Expand Down Expand Up @@ -67,7 +61,7 @@ pub fn validate_tx(
utxos,
cert_state,
spp,
&acnt,
acnt,
env.block_slot(),
env.network_id(),
&metx.era(),
Expand Down
46 changes: 22 additions & 24 deletions pallas-applying/src/shelley_ma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ use pallas_traverse::{
time::Slot, wellknown::GenesisValues, ComputeHash, Era, MultiEraInput, MultiEraOutput,
};

use std::{cmp::max, collections::HashMap, ops::Deref}; // TODO: remove when fixed missing args
use std::{cmp::max, collections::HashMap, ops::Deref};
// TODO: remove when fixed missing args

#[allow(clippy::too_many_arguments)]
pub fn validate_shelley_ma_tx(
mtx: &MintedTx,
txix: TransactionIndex,
Expand Down Expand Up @@ -63,7 +65,7 @@ pub fn validate_shelley_ma_tx(
stk_dep_count,
stk_refund_count,
pool_count,
&acnt,
acnt,
block_slot,
&stab_win,
prot_pps,
Expand Down Expand Up @@ -229,8 +231,8 @@ fn get_produced(
// Adding fees
res = add_values(&res, &Value::Coin(tx_body.fee), &neg_val_err)?;
// Pool reg deposits and staking key registrations
let total_deposits = prot_pps.pool_deposit * *pool_count +
prot_pps.key_deposit * *stk_dep_count;
let total_deposits =
prot_pps.pool_deposit * *pool_count + prot_pps.key_deposit * *stk_dep_count;
res = add_values(&res, &Value::Coin(total_deposits), &neg_val_err)?;
Ok(res)
}
Expand Down Expand Up @@ -407,6 +409,7 @@ fn compute_script_hash(script: &NativeScript) -> PolicyId {
}

// Checks all certificates in order, and counts the relevant ones for computing deposits.
#[allow(clippy::too_many_arguments)]
fn check_certificates(
cert_opt: &Option<Vec<Certificate>>,
tx_ix: TransactionIndex,
Expand Down Expand Up @@ -452,7 +455,7 @@ fn check_certificates(
relays,
pool_metadata,
} => {
if !cert_state.pstate.pool_params.contains_key(&operator) {
if !cert_state.pstate.pool_params.contains_key(operator) {
*pool_count += 1;
}
let pool_param = PoolParam {
Expand Down Expand Up @@ -551,7 +554,7 @@ where
V: Clone,
{
if map.contains_key(key) {
return Err(error);
Err(error)
} else {
map.insert(key.clone(), value.clone());
Ok(())
Expand All @@ -568,14 +571,12 @@ fn check_pool_reg_or_update(
Err(ShelleyMA(PoolCostBelowMin))
} else if ps.pool_params.contains_key(pool_hash) {
// Updating
ps.fut_pool_params
.insert(pool_hash.clone(), (*pool_param).clone());
ps.retiring.remove(&pool_hash);
ps.fut_pool_params.insert(*pool_hash, (*pool_param).clone());
ps.retiring.remove(pool_hash);
Ok(())
} else {
// Registering
ps.pool_params
.insert(pool_hash.clone(), (*pool_param).clone());
ps.pool_params.insert(*pool_hash, (*pool_param).clone());
Ok(())
}
}
Expand All @@ -587,11 +588,11 @@ fn check_pool_retirement(
emax: &u32,
ps: &mut PState,
) -> ValidationResult {
if !ps.pool_params.contains_key(&pool_hash) {
if !ps.pool_params.contains_key(pool_hash) {
return Err(ShelleyMA(PoolNotRegistered));
}
if (*cepoch < *repoch) & (*repoch <= *cepoch + *emax as u64) {
ps.retiring.insert(pool_hash.clone(), *repoch);
ps.retiring.insert(*pool_hash, *repoch);
Ok(())
} else {
Err(ShelleyMA(PoolNotRegistered))
Expand Down Expand Up @@ -633,7 +634,7 @@ fn check_genesis_key_delegation(
} else {
let gen_slot: Slot = *slot + *stab_win;
ds.fut_gen_delegs
.insert((gen_slot, gkh.clone()), (dkh.clone(), vrf.clone()));
.insert((gen_slot, gkh.clone()), (dkh.clone(), *vrf));
Ok(())
}
}
Expand All @@ -646,7 +647,7 @@ fn check_mir(
acnt: &AccountState,
) -> ValidationResult {
let genesis = &GenesisValues::mainnet();
if !(*slot < first_slot(genesis, &(to_epoch(genesis, slot) + 1)) - *stab_win) {
if *slot >= first_slot(genesis, &(to_epoch(genesis, slot) + 1)) - *stab_win {
Err(ShelleyMA(MIRCertificateTooLateinEpoch))
} else {
let (ir_reserves, ir_treasury) = ds.inst_rewards.clone();
Expand All @@ -655,16 +656,13 @@ fn check_mir(
Treasury => (acnt.treasury, ir_treasury.clone()),
};
let mut combined: HashMap<StakeCredential, Coin> = HashMap::new();
match &mir.target {
StakeCredentials(kvp) => {
let mut kvv: Vec<(StakeCredential, u64)> = // TODO: Err if the value is negative
kvp.iter().map(|kv| (kv.clone().0, kv.clone().1 as u64)).collect();
kvv.extend(ir_pot);
for (key, value) in kvv {
combined.insert(key, value);
}
if let StakeCredentials(kvp) = &mir.target {
let mut kvv: Vec<(StakeCredential, u64)> = // TODO: Err if the value is negative
kvp.iter().map(|kv| (kv.clone().0, kv.clone().1 as u64)).collect();
kvv.extend(ir_pot);
for (key, value) in kvv {
combined.insert(key, value);
}
_ => (),
}
if combined.iter().map(|kv| kv.1).sum::<u64>() > pot {
return Err(ShelleyMA(InsufficientForInstantaneousRewards));
Expand Down
80 changes: 46 additions & 34 deletions pallas-applying/tests/shelley_ma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod common;

use common::*;
use pallas_addresses::{Address, Network, ShelleyAddress};
use pallas_applying::utils::PoolParam;
use pallas_applying::{
utils::{
AccountState, Environment, MultiEraProtocolParameters, ShelleyMAError, ShelleyProtParams,
Expand All @@ -18,18 +19,16 @@ use pallas_codec::{
};
use pallas_crypto::hash::Hash;
use pallas_primitives::alonzo::{
MintedTx, MintedWitnessSet, Nonce, NonceVariant, RationalNumber, StakeCredential,
TransactionBody, TransactionOutput, VKeyWitness, Value, PoolMetadata, Relay,
PoolKeyhash, Certificate,
Certificate, MintedTx, MintedWitnessSet, Nonce, NonceVariant, PoolKeyhash, PoolMetadata,
RationalNumber, Relay, StakeCredential, TransactionBody, TransactionOutput, VKeyWitness, Value,
};
use pallas_traverse::{Era, MultiEraTx};
use std::str::FromStr;
use pallas_applying::utils::PoolParam;

#[cfg(test)]
mod shelley_ma_tests {
use super::*;

#[test]
// Transaction hash:
// 50eba65e73c8c5f7b09f4ea28cf15dce169f3d1c322ca3deff03725f51518bb2
Expand Down Expand Up @@ -468,7 +467,11 @@ mod shelley_ma_tests {
Err(err) => panic!("Unexpected error ({:?})", err),
};

if !cert_state.pstate.pool_params.contains_key(&mary2_pool_operator()) {
if !cert_state
.pstate
.pool_params
.contains_key(&mary2_pool_operator())
{
panic!("Pool not registered or keyhash mismatch");
}
}
Expand All @@ -484,15 +487,13 @@ mod shelley_ma_tests {
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Mary);
let utxos: UTxOs = mk_utxo_for_alonzo_compatible_tx(
&mtx.transaction_body,
&[(
String::from(MARY3_UTXO),
Value::Coin(627_760_000),
None,
)],
&[(String::from(MARY3_UTXO), Value::Coin(627_760_000), None)],
);

let mut cert_state: CertState = CertState::default();
cert_state.pstate.pool_params
cert_state
.pstate
.pool_params
.insert(mary2_pool_operator(), mary2_pool_param());
match validate_txs(&[metx], &mary3_env(), &utxos, &mut cert_state) {
Ok(()) => (),
Expand All @@ -503,24 +504,41 @@ mod shelley_ma_tests {
fn mary2_pool_operator() -> PoolKeyhash {
Hash::from_str("59EBE72AE96462018FBE04633100F90B3066688D85F00F3BD254707F").unwrap()
}

// Params for the pool registered in `successful_mainnet_mary_tx_with_pool_reg`
fn mary2_pool_param() -> PoolParam {
PoolParam {
vrf_keyhash: Hash::from_str("1EFB798F239B9B02DEB4636A3AB1962AF43512595FCB82276E11971E684E49B7").unwrap(),
vrf_keyhash: Hash::from_str(
"1EFB798F239B9B02DEB4636A3AB1962AF43512595FCB82276E11971E684E49B7",
)
.unwrap(),
pledge: 1000000000,
cost: 340000000,
margin: RationalNumber { numerator: 3, denominator: 100 },
reward_account: hex::decode("E1FB2B631DB76384F64DD94B47F97FC8C2A206764C17A1DE7DA2F70E83").unwrap().into(),
pool_owners: Vec::from([Hash::from_str("FB2B631DB76384F64DD94B47F97FC8C2A206764C17A1DE7DA2F70E83").unwrap()]),
relays: [
Relay::SingleHostAddr(Nullable::Some(3001),
Nullable::Some(hex::decode("C22614BB").unwrap().into()),
Nullable::Null,)
].to_vec(),
margin: RationalNumber {
numerator: 3,
denominator: 100,
},
reward_account: hex::decode(
"E1FB2B631DB76384F64DD94B47F97FC8C2A206764C17A1DE7DA2F70E83",
)
.unwrap()
.into(),
pool_owners: Vec::from([Hash::from_str(
"FB2B631DB76384F64DD94B47F97FC8C2A206764C17A1DE7DA2F70E83",
)
.unwrap()]),
relays: [Relay::SingleHostAddr(
Nullable::Some(3001),
Nullable::Some(hex::decode("C22614BB").unwrap().into()),
Nullable::Null,
)]
.to_vec(),
pool_metadata: Nullable::Some(PoolMetadata {
url: "https://cardapool.com/a.json".to_string(),
hash: Hash::from_str("01F708549816C9A075FF96E9682C11A5F5C7F4E147862A663BDEECE0716AB76E").unwrap(),
hash: Hash::from_str(
"01F708549816C9A075FF96E9682C11A5F5C7F4E147862A663BDEECE0716AB76E",
)
.unwrap(),
}),
}
}
Expand Down Expand Up @@ -1785,11 +1803,7 @@ mod shelley_ma_tests {
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Mary);
let utxos: UTxOs = mk_utxo_for_alonzo_compatible_tx(
&mtx.transaction_body,
&[(
String::from(MARY3_UTXO),
Value::Coin(627_760_000),
None,
)],
&[(String::from(MARY3_UTXO), Value::Coin(627_760_000), None)],
);

let mut cert_state: CertState = CertState::default();
Expand Down Expand Up @@ -1827,15 +1841,13 @@ mod shelley_ma_tests {

let utxos: UTxOs = mk_utxo_for_alonzo_compatible_tx(
&mtx.transaction_body,
&[(
String::from(MARY3_UTXO),
Value::Coin(627_760_000),
None,
)],
&[(String::from(MARY3_UTXO), Value::Coin(627_760_000), None)],
);

let mut cert_state: CertState = CertState::default();
cert_state.pstate.pool_params
cert_state
.pstate
.pool_params
.insert(mary2_pool_operator(), mary2_pool_param());
match validate_txs(&[metx], &mary3_env(), &utxos, &mut cert_state) {
Ok(()) => panic!("Staking key is not registered"),
Expand Down
10 changes: 9 additions & 1 deletion pallas-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ homepage = "https://github.com/txpipe/pallas"
documentation = "https://docs.rs/pallas-crypto"
license = "Apache-2.0"
readme = "README.md"
authors = ["Nicolas Di Prima <[email protected]>"]
authors = [
"Nicolas Di Prima <[email protected]>",
"Andrew Westberg <[email protected]>",
]

[dependencies]
hex = "0.4"
Expand All @@ -18,7 +21,12 @@ rand_core = "0.6"
pallas-codec = { version = "=0.30.2", path = "../pallas-codec" }
serde = "1.0.143"

# The vrf crate has not been fully tested in production environments and still has several upstream issues that
# are open PRs but not merged yet.
vrf_dalek = { git = "https://github.com/txpipe/vrf", rev = "044b45a1a919ba9d9c2471fc5c4d441f13086676" }

[dev-dependencies]
itertools = "0.13"
quickcheck = "1.0"
quickcheck_macros = "1.0"
rand = "0.8"
Expand Down
4 changes: 2 additions & 2 deletions pallas-crypto/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Crate with all the cryptographic material to support Cardano protocol:
- [x] Ed25519 Extended asymmetric key pair
- [ ] Bip32-Ed25519 key derivation
- [ ] BIP39 mnemonics
- [ ] VRF
- [x] VRF
- [ ] KES
- [ ] SECP256k1

- [x] Nonce calculations
Loading
Loading