Skip to content

Commit b1b1eaa

Browse files
tmpolaczykaesedepece
authored andcommitted
test(data_structures): test transaction malleability in mempool
1 parent b029a44 commit b1b1eaa

File tree

1 file changed

+152
-0
lines changed
  • data_structures/src/chain

1 file changed

+152
-0
lines changed

data_structures/src/chain/mod.rs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4801,6 +4801,158 @@ mod tests {
48014801
assert!(transactions_pool.output_pointer_map.is_empty());
48024802
}
48034803

4804+
#[test]
4805+
fn transactions_pool_malleability_vt() {
4806+
let input = Input::default();
4807+
let mut vt_1 = VTTransaction::new(
4808+
VTTransactionBody::new(vec![input], vec![]),
4809+
vec![KeyedSignature::default()],
4810+
);
4811+
// Add dummy signature, but pretend it is valid
4812+
match &mut vt_1.signatures[0].signature {
4813+
Signature::Secp256k1(sig) => sig.der = vec![0; 32],
4814+
}
4815+
4816+
let mut vt_2 = vt_1.clone();
4817+
// Flip one bit in the signature, but pretend that the signature is still valid (malleability).
4818+
match &mut vt_2.signatures[0].signature {
4819+
Signature::Secp256k1(secp_sig) => {
4820+
// Flip 1 bit
4821+
secp_sig.der[10] ^= 0x01;
4822+
}
4823+
}
4824+
4825+
let vt1 = Transaction::ValueTransfer(vt_1.clone());
4826+
let vt2 = Transaction::ValueTransfer(vt_2.clone());
4827+
assert_eq!(vt1.hash(), vt2.hash());
4828+
assert_ne!(vt1, vt2);
4829+
4830+
let mut transactions_pool = TransactionsPool::default();
4831+
transactions_pool.insert(vt1.clone(), 1);
4832+
transactions_pool.insert(vt2.clone(), 1);
4833+
// Removing vt_1 actually returns vt_2, because they have the same hash, but this is fine
4834+
// because they both have a valid signature
4835+
let t = transactions_pool.vt_remove(&vt_1).unwrap();
4836+
assert_eq!(Transaction::ValueTransfer(t), vt2);
4837+
assert!(!transactions_pool.contains(&vt1).unwrap());
4838+
assert!(!transactions_pool.contains(&vt2).unwrap());
4839+
}
4840+
4841+
#[test]
4842+
fn transactions_pool_malleability_dr() {
4843+
let input = Input::default();
4844+
let mut dr_1 = DRTransaction::new(
4845+
DRTransactionBody::new(vec![input], vec![], DataRequestOutput::default()),
4846+
vec![KeyedSignature::default()],
4847+
);
4848+
// Add dummy signature, but pretend it is valid
4849+
match &mut dr_1.signatures[0].signature {
4850+
Signature::Secp256k1(sig) => sig.der = vec![0; 32],
4851+
}
4852+
4853+
let mut dr_2 = dr_1.clone();
4854+
// Flip one bit in the signature, but pretend that the signature is still valid (malleability).
4855+
match &mut dr_2.signatures[0].signature {
4856+
Signature::Secp256k1(secp_sig) => {
4857+
// Flip 1 bit
4858+
secp_sig.der[10] ^= 0x01;
4859+
}
4860+
}
4861+
4862+
let dr1 = Transaction::DataRequest(dr_1.clone());
4863+
let dr2 = Transaction::DataRequest(dr_2.clone());
4864+
assert_eq!(dr1.hash(), dr2.hash());
4865+
assert_ne!(dr1, dr2);
4866+
4867+
let mut transactions_pool = TransactionsPool::default();
4868+
transactions_pool.insert(dr1.clone(), 1);
4869+
transactions_pool.insert(dr2.clone(), 1);
4870+
// Removing dr_1 actually returns dr_2, because they have the same hash, but this is fine
4871+
// because they both have a valid signature
4872+
let t = transactions_pool.dr_remove(&dr_1).unwrap();
4873+
assert_eq!(Transaction::DataRequest(t), dr2);
4874+
assert!(!transactions_pool.contains(&dr1).unwrap());
4875+
assert!(!transactions_pool.contains(&dr2).unwrap());
4876+
}
4877+
4878+
#[test]
4879+
fn transactions_pool_malleability_co() {
4880+
let c1 = Hash::SHA256([1; 32]);
4881+
let mut t1 = Transaction::Commit(CommitTransaction {
4882+
body: CommitTransactionBody::without_collateral(
4883+
Default::default(),
4884+
c1,
4885+
Default::default(),
4886+
),
4887+
signatures: vec![KeyedSignature::default()],
4888+
});
4889+
// Add dummy signature, but pretend it is valid
4890+
match &mut t1 {
4891+
Transaction::Commit(co1) => match &mut co1.signatures[0].signature {
4892+
Signature::Secp256k1(sig) => sig.der = vec![0; 32],
4893+
},
4894+
_ => unreachable!(),
4895+
}
4896+
4897+
let mut t2 = t1.clone();
4898+
// Flip one bit in the signature, but pretend that the signature is still valid (malleability).
4899+
match &mut t2 {
4900+
Transaction::Commit(co2) => {
4901+
match &mut co2.signatures[0].signature {
4902+
Signature::Secp256k1(secp_sig) => {
4903+
// Flip 1 bit
4904+
secp_sig.der[10] ^= 0x01;
4905+
}
4906+
}
4907+
}
4908+
_ => unreachable!(),
4909+
}
4910+
4911+
let mut transactions_pool = TransactionsPool::default();
4912+
transactions_pool.insert(t1, 0);
4913+
transactions_pool.insert(t2.clone(), 0);
4914+
let mut expected = TransactionsPool::default();
4915+
expected.insert(t2, 0);
4916+
assert_eq!(transactions_pool.co_transactions, expected.co_transactions);
4917+
}
4918+
4919+
#[test]
4920+
fn transactions_pool_malleability_re() {
4921+
let r1 = vec![1];
4922+
let mut t1 = Transaction::Reveal(RevealTransaction {
4923+
body: RevealTransactionBody::new(Default::default(), r1, Default::default()),
4924+
signatures: vec![KeyedSignature::default()],
4925+
});
4926+
// Add dummy signature, but pretend it is valid
4927+
match &mut t1 {
4928+
Transaction::Reveal(re1) => match &mut re1.signatures[0].signature {
4929+
Signature::Secp256k1(sig) => sig.der = vec![0; 32],
4930+
},
4931+
_ => unreachable!(),
4932+
}
4933+
4934+
let mut t2 = t1.clone();
4935+
// Flip one bit in the signature, but pretend that the signature is still valid (malleability).
4936+
match &mut t2 {
4937+
Transaction::Reveal(re2) => {
4938+
match &mut re2.signatures[0].signature {
4939+
Signature::Secp256k1(secp_sig) => {
4940+
// Flip 1 bit
4941+
secp_sig.der[10] ^= 0x01;
4942+
}
4943+
}
4944+
}
4945+
_ => unreachable!(),
4946+
}
4947+
4948+
let mut transactions_pool = TransactionsPool::default();
4949+
transactions_pool.insert(t1, 0);
4950+
transactions_pool.insert(t2.clone(), 0);
4951+
let mut expected = TransactionsPool::default();
4952+
expected.insert(t2, 0);
4953+
assert_eq!(transactions_pool.re_transactions, expected.re_transactions);
4954+
}
4955+
48044956
#[test]
48054957
fn transactions_pool_size_limit() {
48064958
let input = Input::default();

0 commit comments

Comments
 (0)