diff --git a/.changelog/unreleased/improvements/2222-masp-cross-epoch-proof-fix.md b/.changelog/unreleased/improvements/2222-masp-cross-epoch-proof-fix.md new file mode 100644 index 0000000000..bd8f0ac7b3 --- /dev/null +++ b/.changelog/unreleased/improvements/2222-masp-cross-epoch-proof-fix.md @@ -0,0 +1,2 @@ +- Allowed the unshielding of previous epochs assets from the masp. + ([\#2222](https://github.com/anoma/namada/pull/2222)) \ No newline at end of file diff --git a/shared/src/ledger/native_vp/masp.rs b/shared/src/ledger/native_vp/masp.rs index 54048f6759..dcdba8f901 100644 --- a/shared/src/ledger/native_vp/masp.rs +++ b/shared/src/ledger/native_vp/masp.rs @@ -45,7 +45,7 @@ where pub ctx: Ctx<'a, DB, H, CA>, } -/// Generates the current asset type given the current epoch and an +/// Generates the current asset type given the provided epoch and an /// unique token address fn asset_type_from_epoched_address( epoch: Epoch, @@ -58,23 +58,6 @@ fn asset_type_from_epoched_address( AssetType::new(token_bytes.as_ref()).expect("unable to create asset type") } -/// Checks if the asset type matches the expected asset type, Adds a -/// debug log if the values do not match. -fn valid_asset_type( - asset_type: &AssetType, - asset_type_to_test: &AssetType, -) -> bool { - let res = - asset_type.get_identifier() == asset_type_to_test.get_identifier(); - if !res { - tracing::debug!( - "The asset type must be derived from the token address and \ - current epoch" - ); - } - res -} - /// Checks if the reported transparent amount and the unshielded /// values agree, if not adds to the debug log fn valid_transfer_amount( @@ -99,13 +82,12 @@ fn convert_amount( token: &Address, val: token::Amount, denom: token::MaspDenom, -) -> (AssetType, I128Sum) { +) -> I128Sum { let asset_type = asset_type_from_epoched_address(epoch, token, denom); // Combine the value and unit into one amount - let amount = - I128Sum::from_nonnegative(asset_type, denom.denominate(&val) as i128) - .expect("invalid value or asset type for amount"); - (asset_type, amount) + + I128Sum::from_nonnegative(asset_type, denom.denominate(&val) as i128) + .expect("invalid value or asset type for amount") } impl<'a, DB, H, CA> NativeVp for MaspVp<'a, DB, H, CA> @@ -134,7 +116,7 @@ where // where the shielded value has an incorrect timestamp // are automatically rejected for denom in token::MaspDenom::iter() { - let (_transp_asset, transp_amt) = convert_amount( + let transp_amt = convert_amount( epoch, &transfer.token, transfer.amount.into(), @@ -196,20 +178,23 @@ where None => continue, }; - let expected_asset_type: AssetType = - asset_type_from_epoched_address( - epoch, - &transfer.token, - denom, - ); - // Satisfies 2. and 3. - if !valid_asset_type(&expected_asset_type, &out.asset_type) { - // we don't know which masp denoms are necessary - // apriori. This is encoded via - // the asset types. - continue; - } + let conversion_state = self.ctx.storage.get_conversion_state(); + let asset_epoch = + match conversion_state.assets.get(&out.asset_type) { + Some(((address, _), asset_epoch, _, _)) + if address == &transfer.token => + { + asset_epoch + } + _ => { + // we don't know which masp denoms are necessary + // apriori. This is encoded via + // the asset types. + continue; + } + }; + if !valid_transfer_amount( out.value, denom.denominate(&transfer.amount.amount), @@ -217,8 +202,8 @@ where return Ok(false); } - let (_transp_asset, transp_amt) = convert_amount( - epoch, + let transp_amt = convert_amount( + *asset_epoch, &transfer.token, transfer.amount.amount, denom, @@ -285,6 +270,7 @@ where } _ => {} } + // Verify the proofs and charge the gas for the expensive execution self.ctx .charge_gas(MASP_VERIFY_SHIELDED_TX_GAS) diff --git a/test_fixtures/masp_proofs/51EF94B13138B91DB3081F95193F779253B53A9A0BD62FD3DF8F6FCF4AF1E145.bin b/test_fixtures/masp_proofs/51EF94B13138B91DB3081F95193F779253B53A9A0BD62FD3DF8F6FCF4AF1E145.bin index 8b21aac70d..b142e6796d 100644 Binary files a/test_fixtures/masp_proofs/51EF94B13138B91DB3081F95193F779253B53A9A0BD62FD3DF8F6FCF4AF1E145.bin and b/test_fixtures/masp_proofs/51EF94B13138B91DB3081F95193F779253B53A9A0BD62FD3DF8F6FCF4AF1E145.bin differ diff --git a/test_fixtures/masp_proofs/544F7432B95E26E312105FB804BF9BC175A70082068C8785BDDBF49DCCA4BE66.bin b/test_fixtures/masp_proofs/544F7432B95E26E312105FB804BF9BC175A70082068C8785BDDBF49DCCA4BE66.bin index 1636c1394f..3952963e0e 100644 Binary files a/test_fixtures/masp_proofs/544F7432B95E26E312105FB804BF9BC175A70082068C8785BDDBF49DCCA4BE66.bin and b/test_fixtures/masp_proofs/544F7432B95E26E312105FB804BF9BC175A70082068C8785BDDBF49DCCA4BE66.bin differ diff --git a/test_fixtures/masp_proofs/6DD5A788D36258E9D5FEF454DBC89879834677F926130D56EB5E4067728EB5CF.bin b/test_fixtures/masp_proofs/6DD5A788D36258E9D5FEF454DBC89879834677F926130D56EB5E4067728EB5CF.bin index 94f997688b..d6777132a3 100644 Binary files a/test_fixtures/masp_proofs/6DD5A788D36258E9D5FEF454DBC89879834677F926130D56EB5E4067728EB5CF.bin and b/test_fixtures/masp_proofs/6DD5A788D36258E9D5FEF454DBC89879834677F926130D56EB5E4067728EB5CF.bin differ diff --git a/test_fixtures/masp_proofs/6E92D0B97A65FB5ADFA6371A6CBE50202AF004DFD895A721EDA284D96B253ACC.bin b/test_fixtures/masp_proofs/6E92D0B97A65FB5ADFA6371A6CBE50202AF004DFD895A721EDA284D96B253ACC.bin index 60b6f86069..ffea35c6f0 100644 Binary files a/test_fixtures/masp_proofs/6E92D0B97A65FB5ADFA6371A6CBE50202AF004DFD895A721EDA284D96B253ACC.bin and b/test_fixtures/masp_proofs/6E92D0B97A65FB5ADFA6371A6CBE50202AF004DFD895A721EDA284D96B253ACC.bin differ diff --git a/test_fixtures/masp_proofs/8032CA7B951C625E43F48AEBD53CEA99A9BC66B2BAB03D4ABA1AE57B12596061.bin b/test_fixtures/masp_proofs/8032CA7B951C625E43F48AEBD53CEA99A9BC66B2BAB03D4ABA1AE57B12596061.bin index b983254f6b..cce1836fd8 100644 Binary files a/test_fixtures/masp_proofs/8032CA7B951C625E43F48AEBD53CEA99A9BC66B2BAB03D4ABA1AE57B12596061.bin and b/test_fixtures/masp_proofs/8032CA7B951C625E43F48AEBD53CEA99A9BC66B2BAB03D4ABA1AE57B12596061.bin differ diff --git a/test_fixtures/masp_proofs/8A79BF5E0292339E70287DB626F136D4522BAFC99E0E81FD54A28A38E8419CFC.bin b/test_fixtures/masp_proofs/8A79BF5E0292339E70287DB626F136D4522BAFC99E0E81FD54A28A38E8419CFC.bin index 5aedea90bf..c74348c48c 100644 Binary files a/test_fixtures/masp_proofs/8A79BF5E0292339E70287DB626F136D4522BAFC99E0E81FD54A28A38E8419CFC.bin and b/test_fixtures/masp_proofs/8A79BF5E0292339E70287DB626F136D4522BAFC99E0E81FD54A28A38E8419CFC.bin differ diff --git a/test_fixtures/masp_proofs/90502CEAE917AE038FDA2337AFB0464F2130123149D5691B85C35AABC49FA2BD.bin b/test_fixtures/masp_proofs/90502CEAE917AE038FDA2337AFB0464F2130123149D5691B85C35AABC49FA2BD.bin index 44754a7a46..f2279877dc 100644 Binary files a/test_fixtures/masp_proofs/90502CEAE917AE038FDA2337AFB0464F2130123149D5691B85C35AABC49FA2BD.bin and b/test_fixtures/masp_proofs/90502CEAE917AE038FDA2337AFB0464F2130123149D5691B85C35AABC49FA2BD.bin differ diff --git a/test_fixtures/masp_proofs/A312CDD49C05B7C768F5DAF708C010E6D95775165E4FC619A11DCFDB59E21D30.bin b/test_fixtures/masp_proofs/A312CDD49C05B7C768F5DAF708C010E6D95775165E4FC619A11DCFDB59E21D30.bin new file mode 100644 index 0000000000..67decdde40 Binary files /dev/null and b/test_fixtures/masp_proofs/A312CDD49C05B7C768F5DAF708C010E6D95775165E4FC619A11DCFDB59E21D30.bin differ diff --git a/test_fixtures/masp_proofs/A8A9963AC2983B576BAE4DE9BA6D2CF14C7F9E90A8588BA75DA0D2860F36E2CB.bin b/test_fixtures/masp_proofs/A8A9963AC2983B576BAE4DE9BA6D2CF14C7F9E90A8588BA75DA0D2860F36E2CB.bin index e475b08f8b..9e942f81f5 100644 Binary files a/test_fixtures/masp_proofs/A8A9963AC2983B576BAE4DE9BA6D2CF14C7F9E90A8588BA75DA0D2860F36E2CB.bin and b/test_fixtures/masp_proofs/A8A9963AC2983B576BAE4DE9BA6D2CF14C7F9E90A8588BA75DA0D2860F36E2CB.bin differ diff --git a/test_fixtures/masp_proofs/AEA19C9B07742FF5F6D759B171396732D2EBF77728D2772EB251123DF2CEF6A1.bin b/test_fixtures/masp_proofs/AEA19C9B07742FF5F6D759B171396732D2EBF77728D2772EB251123DF2CEF6A1.bin index 4b7967cf85..6cba86af9a 100644 Binary files a/test_fixtures/masp_proofs/AEA19C9B07742FF5F6D759B171396732D2EBF77728D2772EB251123DF2CEF6A1.bin and b/test_fixtures/masp_proofs/AEA19C9B07742FF5F6D759B171396732D2EBF77728D2772EB251123DF2CEF6A1.bin differ diff --git a/test_fixtures/masp_proofs/B947FEFC6EC94A041657FF3A9420D5BB3FDEB1199EF712C059C80C4DBF6F3ED8.bin b/test_fixtures/masp_proofs/B947FEFC6EC94A041657FF3A9420D5BB3FDEB1199EF712C059C80C4DBF6F3ED8.bin index 9627a1ce5c..017ffcd74e 100644 Binary files a/test_fixtures/masp_proofs/B947FEFC6EC94A041657FF3A9420D5BB3FDEB1199EF712C059C80C4DBF6F3ED8.bin and b/test_fixtures/masp_proofs/B947FEFC6EC94A041657FF3A9420D5BB3FDEB1199EF712C059C80C4DBF6F3ED8.bin differ diff --git a/test_fixtures/masp_proofs/C788F9057C615CCE7B260BB8BF5CF776D5DE7C9153D67B7FDF22ED6F35558738.bin b/test_fixtures/masp_proofs/C788F9057C615CCE7B260BB8BF5CF776D5DE7C9153D67B7FDF22ED6F35558738.bin index d3c3a5c241..a22c9f2199 100644 Binary files a/test_fixtures/masp_proofs/C788F9057C615CCE7B260BB8BF5CF776D5DE7C9153D67B7FDF22ED6F35558738.bin and b/test_fixtures/masp_proofs/C788F9057C615CCE7B260BB8BF5CF776D5DE7C9153D67B7FDF22ED6F35558738.bin differ diff --git a/test_fixtures/masp_proofs/CBF4087F2AB578C83A736E4598DBA1FDB2515DF33D43611F2860B8D3C178B474.bin b/test_fixtures/masp_proofs/CBF4087F2AB578C83A736E4598DBA1FDB2515DF33D43611F2860B8D3C178B474.bin index 06393963b3..d446d16439 100644 Binary files a/test_fixtures/masp_proofs/CBF4087F2AB578C83A736E4598DBA1FDB2515DF33D43611F2860B8D3C178B474.bin and b/test_fixtures/masp_proofs/CBF4087F2AB578C83A736E4598DBA1FDB2515DF33D43611F2860B8D3C178B474.bin differ diff --git a/test_fixtures/masp_proofs/E7F3B43D776427F6570F4EF1600F74AF27826AB075ECA82AE64F488CC7D7B99D.bin b/test_fixtures/masp_proofs/E7F3B43D776427F6570F4EF1600F74AF27826AB075ECA82AE64F488CC7D7B99D.bin new file mode 100644 index 0000000000..00154939a1 Binary files /dev/null and b/test_fixtures/masp_proofs/E7F3B43D776427F6570F4EF1600F74AF27826AB075ECA82AE64F488CC7D7B99D.bin differ diff --git a/test_fixtures/masp_proofs/EDE8DC791D02098C5C199CAF2F6C8B75587507CA52981F48FD1FC9C5BE0BEE43.bin b/test_fixtures/masp_proofs/EDE8DC791D02098C5C199CAF2F6C8B75587507CA52981F48FD1FC9C5BE0BEE43.bin index 90da4e0f00..c26a5a7cc6 100644 Binary files a/test_fixtures/masp_proofs/EDE8DC791D02098C5C199CAF2F6C8B75587507CA52981F48FD1FC9C5BE0BEE43.bin and b/test_fixtures/masp_proofs/EDE8DC791D02098C5C199CAF2F6C8B75587507CA52981F48FD1FC9C5BE0BEE43.bin differ diff --git a/tests/src/integration/masp.rs b/tests/src/integration/masp.rs index c5b51a6eac..6f644d219f 100644 --- a/tests/src/integration/masp.rs +++ b/tests/src/integration/masp.rs @@ -1163,9 +1163,6 @@ fn wrapper_fee_unshielding() -> Result<()> { let validator_one_rpc = "127.0.0.1:26567"; // Download the shielded pool parameters before starting node let _ = FsShieldedUtils::new(PathBuf::new()); - // Lengthen epoch to ensure that a transaction can be constructed and - // submitted within the same block. Necessary to ensure that conversion is - // not invalidated. let (mut node, _services) = setup::setup()?; _ = node.next_epoch(); @@ -1248,3 +1245,90 @@ fn wrapper_fee_unshielding() -> Result<()> { assert!(tx_run); Ok(()) } + +// Test that a masp unshield transaction can be succesfully executed even across +// an epoch boundary. +#[test] +fn cross_epoch_tx() -> Result<()> { + // This address doesn't matter for tests. But an argument is required. + let validator_one_rpc = "127.0.0.1:26567"; + // Download the shielded pool parameters before starting node + let _ = FsShieldedUtils::new(PathBuf::new()); + let (mut node, _services) = setup::setup()?; + _ = node.next_epoch(); + + // 1. Shield some tokens + run( + &node, + Bin::Client, + vec![ + "transfer", + "--source", + ALBERT, + "--target", + AA_PAYMENT_ADDRESS, + "--token", + NAM, + "--amount", + "1000", + "--ledger-address", + validator_one_rpc, + ], + )?; + node.assert_success(); + + // 2. Generate the tx in the current epoch + let tempdir = tempfile::tempdir().unwrap(); + run( + &node, + Bin::Client, + vec![ + "transfer", + "--source", + A_SPENDING_KEY, + "--target", + BERTHA, + "--token", + NAM, + "--amount", + "100", + "--gas-payer", + ALBERT_KEY, + "--output-folder-path", + tempdir.path().to_str().unwrap(), + "--dump-tx", + "--ledger-address", + validator_one_rpc, + ], + )?; + node.assert_success(); + + // Look for the only file in the temp dir + let tx_path = tempdir + .path() + .read_dir() + .unwrap() + .next() + .unwrap() + .unwrap() + .path(); + + // 3. Submit the unshielding in the following epoch + _ = node.next_epoch(); + run( + &node, + Bin::Client, + vec![ + "tx", + "--owner", + ALBERT_KEY, + "--tx-path", + tx_path.to_str().unwrap(), + "--ledger-address", + validator_one_rpc, + ], + )?; + node.assert_success(); + + Ok(()) +}