From 15bf1b7153cd9b1aff6db17f66218f3c6744cbb4 Mon Sep 17 00:00:00 2001 From: DaPorkchop_ Date: Wed, 26 Jun 2024 10:25:45 +0200 Subject: [PATCH 1/3] add traits for generating placeholder values for use in tests --- src/utils/mod.rs | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/utils/mod.rs b/src/utils/mod.rs index adb6987..5c0840b 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -51,3 +51,68 @@ pub fn add_btreemap( }); m1 } + +/// A trait which indicates that it is possible to acquire a "placeholder" value +/// of a type, which can be used for test purposes. +#[cfg(test)] +pub trait Placeholder : Sized { + /// Gets a placeholder value of this type which can be used for test purposes. + fn placeholder() -> Self; + + /// Gets an array of placeholder values of this type which can be used for test purposes. + fn placeholder_array() -> [Self; N] { + core::array::from_fn(|_| Self::placeholder()) + } +} + +/// A trait which indicates that it is possible to acquire a "placeholder" value +/// of a type, which can be used for test purposes. These placeholder values are consistent +/// across program runs. +#[cfg(test)] +pub trait PlaceholderIndexed : Sized { + /// Gets a dummy valid of this type which can be used for test purposes. + /// + /// This allows acquiring multiple distinct placeholder values which are still consistent + /// between runs. + /// + /// ### Arguments + /// + /// * `index` - the index of the placeholder value to obtain. Two placeholder values generated + /// from the same index are guaranteed to be equal (even across multiple test runs, + /// so long as the value format doesn't change). + fn placeholder_indexed(index: u64) -> Self; + + /// Gets an array of placeholder values of this type which can be used for test purposes. + fn placeholder_array_indexed(base_index: u64) -> [Self; N] { + core::array::from_fn(|n| Self::placeholder_indexed(base_index.wrapping_add(n as u64))) + } +} + +#[cfg(test)] +impl Placeholder for T { + fn placeholder() -> Self { + Self::placeholder_indexed(0) + } +} + +/// Generates the given number of pseudorandom bytes based on the given seed. +/// +/// This is intended to be used in tests, where random but reproducible placeholder values are often +/// required. +/// +/// ### Arguments +/// +/// * `seed_parts` - the parts of the seed, which will be concatenated to form the RNG seed +#[cfg(test)] +pub fn placeholder_bytes(seed_parts: &[&[u8]]) -> [u8; N] { + // Use Shake-256 to generate an arbitrarily large number of random bytes based on the given seed. + let mut shake256 = sha3::Shake256::default(); + for slice in seed_parts { + sha3::digest::Update::update(&mut shake256, slice); + } + let mut reader = sha3::digest::ExtendableOutput::finalize_xof(shake256); + + let mut res = [0u8; N]; + sha3::digest::XofReader::read(&mut reader, &mut res); + res +} From 0e148be1945cb8427cf61a947d1efcf9ae14bfce Mon Sep 17 00:00:00 2001 From: DaPorkchop_ Date: Thu, 11 Jul 2024 16:41:31 +0200 Subject: [PATCH 2/3] PlaceholderIndexed -> PlaceholderSeed --- src/utils/mod.rs | 49 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 5c0840b..aa17b53 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -69,7 +69,33 @@ pub trait Placeholder : Sized { /// of a type, which can be used for test purposes. These placeholder values are consistent /// across program runs. #[cfg(test)] -pub trait PlaceholderIndexed : Sized { +pub trait PlaceholderSeed: Sized + PartialEq { + /// Gets a dummy valid of this type which can be used for test purposes. + /// + /// This allows acquiring multiple distinct placeholder values which are still consistent + /// between runs. + /// + /// ### Arguments + /// + /// * `seed_parts` - the parts of the seed for the placeholder value to obtain. Two placeholder + /// values generated from the same seed are guaranteed to be equal (even + /// across multiple test runs, so long as the value format doesn't change). + fn placeholder_seed_parts<'a>(seed_parts: impl IntoIterator) -> Self; + + /// Gets a dummy valid of this type which can be used for test purposes. + /// + /// This allows acquiring multiple distinct placeholder values which are still consistent + /// between runs. + /// + /// ### Arguments + /// + /// * `seed` - the seed for the placeholder value to obtain. Two placeholder + /// values generated from the same seed are guaranteed to be equal (even + /// across multiple test runs, so long as the value format doesn't change). + fn placeholder_seed(seed: impl AsRef<[u8]>) -> Self { + Self::placeholder_seed_parts([ seed.as_ref() ]) + } + /// Gets a dummy valid of this type which can be used for test purposes. /// /// This allows acquiring multiple distinct placeholder values which are still consistent @@ -80,18 +106,27 @@ pub trait PlaceholderIndexed : Sized { /// * `index` - the index of the placeholder value to obtain. Two placeholder values generated /// from the same index are guaranteed to be equal (even across multiple test runs, /// so long as the value format doesn't change). - fn placeholder_indexed(index: u64) -> Self; + fn placeholder_indexed(index: u64) -> Self { + Self::placeholder_seed_parts([ index.to_le_bytes().as_slice() ]) + } + + /// Gets an array of placeholder values of this type which can be used for test purposes. + fn placeholder_array_seed(seed: impl AsRef<[u8]>) -> [Self; N] { + core::array::from_fn(|n| Self::placeholder_seed_parts( + [ seed.as_ref(), &(n as u64).to_le_bytes() ] + )) + } /// Gets an array of placeholder values of this type which can be used for test purposes. fn placeholder_array_indexed(base_index: u64) -> [Self; N] { - core::array::from_fn(|n| Self::placeholder_indexed(base_index.wrapping_add(n as u64))) + Self::placeholder_array_seed(base_index.to_le_bytes()) } } #[cfg(test)] -impl Placeholder for T { +impl Placeholder for T { fn placeholder() -> Self { - Self::placeholder_indexed(0) + ::placeholder_seed_parts([]) } } @@ -104,7 +139,9 @@ impl Placeholder for T { /// /// * `seed_parts` - the parts of the seed, which will be concatenated to form the RNG seed #[cfg(test)] -pub fn placeholder_bytes(seed_parts: &[&[u8]]) -> [u8; N] { +pub fn placeholder_bytes<'a, const N: usize>( + seed_parts: impl IntoIterator +) -> [u8; N] { // Use Shake-256 to generate an arbitrarily large number of random bytes based on the given seed. let mut shake256 = sha3::Shake256::default(); for slice in seed_parts { From b98c036ed0134c4344749928d3b9fb40c77878b8 Mon Sep 17 00:00:00 2001 From: DaPorkchop_ Date: Fri, 12 Jul 2024 13:44:56 +0200 Subject: [PATCH 3/3] transaction: remove unused signatures and pub_keys from TxConstructor --- src/primitives/transaction.rs | 2 - src/utils/script_utils.rs | 120 +++++++++++---------------------- src/utils/transaction_utils.rs | 25 ------- 3 files changed, 39 insertions(+), 108 deletions(-) diff --git a/src/primitives/transaction.rs b/src/primitives/transaction.rs index 08435fd..eca00de 100644 --- a/src/primitives/transaction.rs +++ b/src/primitives/transaction.rs @@ -33,8 +33,6 @@ impl GenesisTxHashSpec { #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct TxConstructor { pub previous_out: OutPoint, - pub signatures: Vec, - pub pub_keys: Vec, pub address_version: Option, } diff --git a/src/utils/script_utils.rs b/src/utils/script_utils.rs index a2cd085..aadb774 100644 --- a/src/utils/script_utils.rs +++ b/src/utils/script_utils.rs @@ -2634,43 +2634,37 @@ mod tests { } /// Util function to create p2pkh TxIns - fn create_multisig_tx_ins(tx_values: Vec, m: usize) -> Vec { - let mut tx_ins = Vec::new(); - - for entry in tx_values { - let mut new_tx_in = TxIn::new(); - new_tx_in.script_signature = Script::multisig_validation( - m, - entry.pub_keys.len(), - entry.previous_out.t_hash.clone(), - entry.signatures, - entry.pub_keys, - ); - new_tx_in.previous_out = Some(entry.previous_out); - - tx_ins.push(new_tx_in); - } - - tx_ins + fn create_multisig_tx_ins(tx_values: &[(OutPoint, &[Signature], &[PublicKey])], m: usize) -> Vec { + tx_values.iter() + .map(|(previous_out, signatures, pub_keys)| { + let mut new_tx_in = TxIn::new(); + new_tx_in.script_signature = Script::multisig_validation( + m, + pub_keys.len(), + previous_out.t_hash.clone(), + signatures.to_vec(), + pub_keys.to_vec(), + ); + new_tx_in.previous_out = Some(previous_out.clone()); + new_tx_in + }) + .collect() } /// Util function to create multisig member TxIns - fn create_multisig_member_tx_ins(tx_values: Vec) -> Vec { - let mut tx_ins = Vec::new(); - - for entry in tx_values { - let mut new_tx_in = TxIn::new(); - new_tx_in.script_signature = Script::member_multisig( - entry.previous_out.t_hash.clone(), - entry.pub_keys[0], - entry.signatures[0], - ); - new_tx_in.previous_out = Some(entry.previous_out); - - tx_ins.push(new_tx_in); - } - - tx_ins + fn create_multisig_member_tx_ins(tx_values: &[(OutPoint, Signature, PublicKey)]) -> Vec { + tx_values.iter() + .map(|(previous_out, signature, pub_key)| { + let mut new_tx_in = TxIn::new(); + new_tx_in.script_signature = Script::member_multisig( + previous_out.t_hash.clone(), + pub_key.clone(), + signature.clone(), + ); + new_tx_in.previous_out = Some(previous_out.clone()); + new_tx_in + }) + .collect() } #[test] @@ -2732,14 +2726,9 @@ mod tests { let t_hash = hex::encode(vec![0, 0, 0]); let signature = sign::sign_detached(t_hash.as_bytes(), &sk); - let tx_const = TxConstructor { - previous_out: OutPoint::new(t_hash, 0), - signatures: vec![signature], - pub_keys: vec![pk], - address_version, - }; + let tx_const = (OutPoint::new(t_hash, 0), signature, pk); - let tx_ins = create_multisig_member_tx_ins(vec![tx_const]); + let tx_ins = create_multisig_member_tx_ins(&[tx_const]); assert!(&tx_ins[0].clone().script_signature.interpret()); } @@ -2768,14 +2757,9 @@ mod tests { let t_hash = hex::encode(vec![0, 0, 0]); let signature = sign::sign_detached(t_hash.as_bytes(), &sk); - let tx_const = TxConstructor { - previous_out: OutPoint::new(t_hash, 0), - signatures: vec![signature], - pub_keys: vec![pk], - address_version, - }; + let tx_const = (OutPoint::new(t_hash, 0), signature, pk); - let tx_ins = create_multisig_member_tx_ins(vec![tx_const]); + let tx_ins = create_multisig_member_tx_ins(&[tx_const]); assert!(!&tx_ins[0].clone().script_signature.interpret()); } @@ -2797,8 +2781,6 @@ mod tests { let tx_const = TxConstructor { previous_out: outpoint, - signatures: vec![], - pub_keys: vec![pk], address_version, }; @@ -2837,12 +2819,9 @@ mod tests { }; let hash_to_sign = construct_tx_in_signable_hash(&outpoint); - let signature = sign::sign_detached(hash_to_sign.as_bytes(), &sk); let tx_const = TxConstructor { previous_out: outpoint, - signatures: vec![signature], - pub_keys: vec![second_pk], address_version, }; @@ -2882,12 +2861,9 @@ mod tests { }; let hash_to_sign = construct_tx_in_signable_hash(&outpoint); - let signature = sign::sign_detached(hash_to_sign.as_bytes(), &sk); let tx_const = TxConstructor { previous_out: outpoint, - signatures: vec![signature], - pub_keys: vec![pk], address_version, }; @@ -2936,12 +2912,9 @@ mod tests { }; let hash_to_sign = construct_tx_in_signable_hash(&outpoint); - let signature = sign::sign_detached(hash_to_sign.as_bytes(), &sk); let tx_const = TxConstructor { previous_out: outpoint, - signatures: vec![signature], - pub_keys: vec![pk], address_version, }; @@ -2996,14 +2969,9 @@ mod tests { let first_sig = sign::sign_detached(check_data.as_bytes(), &first_sk); let second_sig = sign::sign_detached(check_data.as_bytes(), &second_sk); - let tx_const = TxConstructor { - previous_out: OutPoint::new(check_data, 0), - signatures: vec![first_sig, second_sig], - pub_keys: vec![first_pk, second_pk, third_pk], - address_version, - }; - - let tx_ins = create_multisig_tx_ins(vec![tx_const], m); + let tx_ins = create_multisig_tx_ins(&[ + (OutPoint::new(check_data, 0), &[first_sig, second_sig], &[first_pk, second_pk, third_pk]), + ], m); assert!(&tx_ins[0].script_signature.interpret()); } @@ -3305,14 +3273,9 @@ mod tests { let t_hash = hex::encode(vec![0, 0, 0]); let signature = sign::sign_detached(t_hash.as_bytes(), &sk); - let tx_const = TxConstructor { - previous_out: OutPoint::new(t_hash, 0), - signatures: vec![signature], - pub_keys: vec![pk], - address_version, - }; + let tx_const = (OutPoint::new(t_hash, 0), signature, pk); - let tx_ins = create_multisig_member_tx_ins(vec![tx_const]); + let tx_ins = create_multisig_member_tx_ins(&[tx_const]); assert!(!&tx_ins[0].clone().script_signature.interpret()); } @@ -3340,14 +3303,9 @@ mod tests { let t_hash = hex::encode(vec![0, 0, 0]); let signature = sign::sign_detached(t_hash.as_bytes(), &sk); - let tx_const = TxConstructor { - previous_out: OutPoint::new(t_hash, 0), - signatures: vec![signature], - pub_keys: vec![pk], - address_version, - }; + let tx_const = (OutPoint::new(t_hash, 0), signature, pk); - let tx_ins = create_multisig_member_tx_ins(vec![tx_const]); + let tx_ins = create_multisig_member_tx_ins(&[tx_const]); assert!(&tx_ins[0].clone().script_signature.interpret()); } diff --git a/src/utils/transaction_utils.rs b/src/utils/transaction_utils.rs index 8e9fd99..b9d0406 100644 --- a/src/utils/transaction_utils.rs +++ b/src/utils/transaction_utils.rs @@ -762,7 +762,6 @@ mod tests { let (_pk, sk) = sign::gen_keypair(); let (pk, _sk) = sign::gen_keypair(); let t_hash = vec![0, 0, 0]; - let signature = sign::sign_detached(&t_hash, &sk); let drs_block_hash = hex::encode(vec![1, 2, 3, 4, 5, 6]); let mut key_material = BTreeMap::new(); let prev_out = OutPoint::new(hex::encode(t_hash), 0); @@ -771,8 +770,6 @@ mod tests { let tx_const = TxConstructor { previous_out: prev_out, - signatures: vec![signature], - pub_keys: vec![pk], address_version, }; @@ -794,8 +791,6 @@ mod tests { let tx_const = TxConstructor { previous_out: OutPoint::new(spending_tx_hash, 0), - signatures: vec![], - pub_keys: vec![], address_version: Some(NETWORK_VERSION_V0), }; @@ -834,8 +829,6 @@ mod tests { let tx_const = TxConstructor { previous_out: OutPoint::new(spending_tx_hash, 0), - signatures: vec![], - pub_keys: vec![], address_version: Some(NETWORK_VERSION_V0), }; @@ -918,7 +911,6 @@ mod tests { let (_pk, sk) = sign::gen_keypair(); let (pk, _sk) = sign::gen_keypair(); let t_hash = vec![0, 0, 0]; - let signature = sign::sign_detached(&t_hash, &sk); let tokens = TokenAmount(400000); let fees = TokenAmount(1000); let prev_out = OutPoint::new(hex::encode(t_hash), 0); @@ -927,8 +919,6 @@ mod tests { let tx_const = TxConstructor { previous_out: prev_out.clone(), - signatures: vec![signature], - pub_keys: vec![pk], address_version: Some(2), }; @@ -962,7 +952,6 @@ mod tests { let (_pk, sk) = sign::gen_keypair(); let (pk, _sk) = sign::gen_keypair(); let t_hash = vec![0, 0, 0]; - let signature = sign::sign_detached(&t_hash, &sk); let fees = TokenAmount(1000); let prev_out = OutPoint::new(hex::encode(t_hash), 0); let mut key_material = BTreeMap::new(); @@ -970,8 +959,6 @@ mod tests { let tx_const = TxConstructor { previous_out: prev_out.clone(), - signatures: vec![signature], - pub_keys: vec![pk], address_version: Some(2), }; @@ -1010,16 +997,12 @@ mod tests { let (_pk, sk) = sign::gen_keypair(); let (pk, _sk) = sign::gen_keypair(); let t_hash = vec![0, 0, 0]; - let signature = sign::sign_detached(&t_hash, &sk); let prev_out = OutPoint::new(hex::encode(t_hash), 0); let mut key_material = BTreeMap::new(); key_material.insert(prev_out.clone(), (pk, sk)); - let tx_const = TxConstructor { previous_out: prev_out.clone(), - signatures: vec![signature], - pub_keys: vec![pk], address_version: Some(2), }; @@ -1071,7 +1054,6 @@ mod tests { let (pk, sk) = sign::gen_keypair(); let t_hash_1 = hex::encode(vec![0, 0, 0]); - let signed = sign::sign_detached(t_hash_1.as_bytes(), &sk); let prev_out = OutPoint::new(hex::encode(t_hash_1), 0); let mut key_material = BTreeMap::new(); @@ -1080,8 +1062,6 @@ mod tests { let tx_1 = TxConstructor { previous_out: OutPoint::new("".to_string(), 0), - signatures: vec![signed], - pub_keys: vec![pk], address_version, }; @@ -1104,8 +1084,6 @@ mod tests { // Second tx referencing first let tx_2 = TxConstructor { previous_out: tx_1_out_p.clone(), - signatures: vec![signed], - pub_keys: vec![pk], address_version, }; let tx_ins_2 = construct_payment_tx_ins(vec![tx_2]); @@ -1153,7 +1131,6 @@ mod tests { let (_pk, sk) = sign::gen_keypair(); let (pk, _sk) = sign::gen_keypair(); let t_hash = hex::encode(vec![0, 0, 0]); - let signature = sign::sign_detached(t_hash.as_bytes(), &sk); let prev_out = OutPoint::new(hex::encode(&t_hash), 0); let mut key_material = BTreeMap::new(); key_material.insert(prev_out.clone(), (pk, sk)); @@ -1167,8 +1144,6 @@ mod tests { let tx_const = TxConstructor { previous_out: prev_out.clone(), - signatures: vec![signature], - pub_keys: vec![pk], address_version, };