Skip to content

Commit

Permalink
Merge branch 'grarco/unmerkle-replay-protection' (#1863)
Browse files Browse the repository at this point in the history
  • Loading branch information
grarco committed Sep 4, 2023
2 parents 97ee4ce + fdfcfd9 commit 1513c7f
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 66 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Removed replay protection storage keys from the merkle tree.
([\#1863](https://github.com/anoma/namada/pull/1863))
82 changes: 76 additions & 6 deletions apps/src/lib/node/ledger/shell/finalize_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ where
.update_header(TxType::Raw)
.header_hash();
let tx_hash_key =
replay_protection::get_tx_hash_key(&tx_hash);
replay_protection::get_replay_protection_key(&tx_hash);
self.wl_storage
.delete(&tx_hash_key)
.expect("Error while deleting tx hash from storage");
Expand Down Expand Up @@ -544,7 +544,9 @@ where
msg
{
let tx_hash_key =
replay_protection::get_tx_hash_key(&hash);
replay_protection::get_replay_protection_key(
&hash,
);
self.wl_storage.delete(&tx_hash_key).expect(
"Error while deleting tx hash key from storage",
);
Expand Down Expand Up @@ -2311,6 +2313,73 @@ mod test_finalize_block {
}
}

/// Test that replay protection keys are not added to the merkle tree
#[test]
fn test_replay_keys_not_merkelized() {
let (mut shell, _, _, _) = setup();
let keypair = gen_keypair();

let (wrapper_tx, processed_tx) = mk_wrapper_tx(&shell, &keypair);
let wrapper_hash_key = replay_protection::get_replay_protection_key(
&wrapper_tx.header_hash(),
);
let mut decrypted_tx = wrapper_tx;

decrypted_tx.update_header(TxType::Raw);
let decrypted_hash_key = replay_protection::get_replay_protection_key(
&decrypted_tx.header_hash(),
);

// merkle tree root before finalize_block
let root_pre = shell.shell.wl_storage.storage.block.tree.root();

let event = &shell
.finalize_block(FinalizeBlock {
txs: vec![processed_tx],
..Default::default()
})
.expect("Test failed")[0];
assert_eq!(event.event_type.to_string(), String::from("accepted"));
let code = event
.attributes
.get("code")
.expect(
"Test
failed",
)
.as_str();
assert_eq!(code, String::from(ErrorCodes::Ok).as_str());

// the merkle tree root should not change after finalize_block
let root_post = shell.shell.wl_storage.storage.block.tree.root();
assert_eq!(root_pre.0, root_post.0);

// Check transactions' hashes in storage
assert!(shell.shell.wl_storage.has_key(&wrapper_hash_key).unwrap());
assert!(shell.shell.wl_storage.has_key(&decrypted_hash_key).unwrap());
// Check that non of the hashes is present in the merkle tree
assert!(
!shell
.shell
.wl_storage
.storage
.block
.tree
.has_key(&wrapper_hash_key)
.unwrap()
);
assert!(
!shell
.shell
.wl_storage
.storage
.block
.tree
.has_key(&decrypted_hash_key)
.unwrap()
);
}

/// Test that if a decrypted transaction fails because of out-of-gas, its
/// hash is removed from storage to allow rewrapping it
#[test]
Expand Down Expand Up @@ -2348,7 +2417,7 @@ mod test_finalize_block {
}));

// Write inner hash in storage
let inner_hash_key = replay_protection::get_tx_hash_key(
let inner_hash_key = replay_protection::get_replay_protection_key(
&wrapper_tx.clone().update_header(TxType::Raw).header_hash(),
);
shell
Expand Down Expand Up @@ -2423,9 +2492,10 @@ mod test_finalize_block {
&keypair,
)));

let wrapper_hash_key =
replay_protection::get_tx_hash_key(&wrapper.header_hash());
let inner_hash_key = replay_protection::get_tx_hash_key(
let wrapper_hash_key = replay_protection::get_replay_protection_key(
&wrapper.header_hash(),
);
let inner_hash_key = replay_protection::get_replay_protection_key(
&wrapper.clone().update_header(TxType::Raw).header_hash(),
);

Expand Down
14 changes: 8 additions & 6 deletions apps/src/lib/node/ledger/shell/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -888,7 +888,8 @@ where
) -> Result<()> {
let inner_tx_hash =
wrapper.clone().update_header(TxType::Raw).header_hash();
let inner_hash_key = replay_protection::get_tx_hash_key(&inner_tx_hash);
let inner_hash_key =
replay_protection::get_replay_protection_key(&inner_tx_hash);
if temp_wl_storage
.has_key(&inner_hash_key)
.expect("Error while checking inner tx hash key in storage")
Expand All @@ -909,7 +910,7 @@ where
Tx::try_from(tx_bytes).expect("Deserialization shouldn't fail");
let wrapper_hash = tx.header_hash();
let wrapper_hash_key =
replay_protection::get_tx_hash_key(&wrapper_hash);
replay_protection::get_replay_protection_key(&wrapper_hash);
if temp_wl_storage
.has_key(&wrapper_hash_key)
.expect("Error while checking wrapper tx hash key in storage")
Expand Down Expand Up @@ -1221,7 +1222,7 @@ where
inner_tx.update_header(TxType::Raw);
let inner_tx_hash = &inner_tx.header_hash();
let inner_hash_key =
replay_protection::get_tx_hash_key(inner_tx_hash);
replay_protection::get_replay_protection_key(inner_tx_hash);
if self
.wl_storage
.storage
Expand All @@ -1242,7 +1243,7 @@ where
.expect("Deserialization shouldn't fail");
let wrapper_hash = hash::Hash(tx.header_hash().0);
let wrapper_hash_key =
replay_protection::get_tx_hash_key(&wrapper_hash);
replay_protection::get_replay_protection_key(&wrapper_hash);
if self
.wl_storage
.storage
Expand Down Expand Up @@ -2457,7 +2458,7 @@ mod test_mempool_validate {
// Write wrapper hash to storage
let wrapper_hash = wrapper.header_hash();
let wrapper_hash_key =
replay_protection::get_tx_hash_key(&wrapper_hash);
replay_protection::get_replay_protection_key(&wrapper_hash);
shell
.wl_storage
.storage
Expand Down Expand Up @@ -2496,7 +2497,8 @@ mod test_mempool_validate {
let inner_tx_hash =
wrapper.clone().update_header(TxType::Raw).header_hash();
// Write inner hash in storage
let inner_hash_key = replay_protection::get_tx_hash_key(&inner_tx_hash);
let inner_hash_key =
replay_protection::get_replay_protection_key(&inner_tx_hash);
shell
.wl_storage
.storage
Expand Down
8 changes: 5 additions & 3 deletions apps/src/lib/node/ledger/shell/prepare_proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1213,8 +1213,9 @@ mod test_prepare_proposal {

// Write wrapper hash to storage
let wrapper_unsigned_hash = wrapper.header_hash();
let hash_key =
replay_protection::get_tx_hash_key(&wrapper_unsigned_hash);
let hash_key = replay_protection::get_replay_protection_key(
&wrapper_unsigned_hash,
);
shell
.wl_storage
.storage
Expand Down Expand Up @@ -1309,7 +1310,8 @@ mod test_prepare_proposal {
wrapper.clone().update_header(TxType::Raw).header_hash();

// Write inner hash to storage
let hash_key = replay_protection::get_tx_hash_key(&inner_unsigned_hash);
let hash_key =
replay_protection::get_replay_protection_key(&inner_unsigned_hash);
shell
.wl_storage
.storage
Expand Down
8 changes: 5 additions & 3 deletions apps/src/lib/node/ledger/shell/process_proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2169,8 +2169,9 @@ mod test_process_proposal {

// Write wrapper hash to storage
let wrapper_unsigned_hash = wrapper.header_hash();
let hash_key =
replay_protection::get_tx_hash_key(&wrapper_unsigned_hash);
let hash_key = replay_protection::get_replay_protection_key(
&wrapper_unsigned_hash,
);
shell
.wl_storage
.storage
Expand Down Expand Up @@ -2305,7 +2306,8 @@ mod test_process_proposal {
wrapper.clone().update_header(TxType::Raw).header_hash();

// Write inner hash to storage
let hash_key = replay_protection::get_tx_hash_key(&inner_unsigned_hash);
let hash_key =
replay_protection::get_replay_protection_key(&inner_unsigned_hash);
shell
.wl_storage
.storage
Expand Down
4 changes: 2 additions & 2 deletions core/src/ledger/replay_protection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ pub const ADDRESS: Address =
Address::Internal(InternalAddress::ReplayProtection);

/// Check if a key is a replay protection key
pub fn is_tx_hash_key(key: &Key) -> bool {
pub fn is_replay_protection_key(key: &Key) -> bool {
matches!(&key.segments[0], DbKeySeg::AddressSeg(addr) if addr == &ADDRESS)
}

/// Get the transaction hash key
pub fn get_tx_hash_key(hash: &Hash) -> Key {
pub fn get_replay_protection_key(hash: &Hash) -> Key {
Key::from(ADDRESS.to_db_key())
.push(&hash.to_string())
.expect("Cannot obtain a valid db key")
Expand Down
Loading

0 comments on commit 1513c7f

Please sign in to comment.