diff --git a/.changelog/v0.38.0/bug-fixes/3075-force-fee-payment.md b/.changelog/v0.38.0/bug-fixes/3075-force-fee-payment.md new file mode 100644 index 0000000000..7b15a59a63 --- /dev/null +++ b/.changelog/v0.38.0/bug-fixes/3075-force-fee-payment.md @@ -0,0 +1,2 @@ +- Fixed the fee collection logic in `finalize_block` to match that of + `process_proposal`. ([\#3075](https://github.com/anoma/namada/issues/3075)) \ No newline at end of file diff --git a/.changelog/v0.38.0/improvements/2972-masp-parallel-verification.md b/.changelog/v0.38.0/improvements/2972-masp-parallel-verification.md new file mode 100644 index 0000000000..4aa10651bb --- /dev/null +++ b/.changelog/v0.38.0/improvements/2972-masp-parallel-verification.md @@ -0,0 +1,2 @@ +- Improved masp vp verification to run in parallel. + ([\#2972](https://github.com/anoma/namada/pull/2972)) \ No newline at end of file diff --git a/.changelog/v0.38.0/improvements/3232-masp-no-transfer-dep.md b/.changelog/v0.38.0/improvements/3232-masp-no-transfer-dep.md new file mode 100644 index 0000000000..359a4d4651 --- /dev/null +++ b/.changelog/v0.38.0/improvements/3232-masp-no-transfer-dep.md @@ -0,0 +1,2 @@ +- Removed any dependency on the specific transaction data from the masp vp. + ([\#3232](https://github.com/anoma/namada/pull/3232)) \ No newline at end of file diff --git a/.changelog/v0.38.0/improvements/3268-track-caller-events.md b/.changelog/v0.38.0/improvements/3268-track-caller-events.md new file mode 100644 index 0000000000..a195bc6cf8 --- /dev/null +++ b/.changelog/v0.38.0/improvements/3268-track-caller-events.md @@ -0,0 +1,3 @@ +- Add a new event attribute facility to track events to their origin + in Namada's source code. This is useful for debugging purposes. + ([\#3268](https://github.com/anoma/namada/pull/3268)) \ No newline at end of file diff --git a/.changelog/v0.38.0/improvements/3296-test-vectors-with-randomness2.md b/.changelog/v0.38.0/improvements/3296-test-vectors-with-randomness2.md new file mode 100644 index 0000000000..48ae627d24 --- /dev/null +++ b/.changelog/v0.38.0/improvements/3296-test-vectors-with-randomness2.md @@ -0,0 +1,2 @@ +- Include the used MASP randomness parameters in the test vectors. + ([\#3296](https://github.com/anoma/namada/pull/3296)) \ No newline at end of file diff --git a/.changelog/v0.38.0/improvements/3305-update-config-rs.md b/.changelog/v0.38.0/improvements/3305-update-config-rs.md new file mode 100644 index 0000000000..f5eaa5dd32 --- /dev/null +++ b/.changelog/v0.38.0/improvements/3305-update-config-rs.md @@ -0,0 +1,3 @@ +- Replaced unmaintained config-rs to an unreleased version + that replaces its also unmaintained yaml dependency. + ([\#3305](https://github.com/anoma/namada/pull/3305)) \ No newline at end of file diff --git a/.changelog/v0.38.0/improvements/3308-wasmer-upgrade.md b/.changelog/v0.38.0/improvements/3308-wasmer-upgrade.md new file mode 100644 index 0000000000..b7f43144a2 --- /dev/null +++ b/.changelog/v0.38.0/improvements/3308-wasmer-upgrade.md @@ -0,0 +1,4 @@ +- Upgrade `wasmer` vm to upstream version `4.3.1`, + moving away from the [forked code based on version + `2.3.0`](https://github.com/heliaxdev/wasmer/tree/255054f7f58b7b4a525f2fee6b9b86422d1ca15b). + ([\#3308](https://github.com/anoma/namada/pull/3308)) \ No newline at end of file diff --git a/.changelog/v0.38.0/improvements/3310-scheduled-migrations.md b/.changelog/v0.38.0/improvements/3310-scheduled-migrations.md new file mode 100644 index 0000000000..20c5dbb41d --- /dev/null +++ b/.changelog/v0.38.0/improvements/3310-scheduled-migrations.md @@ -0,0 +1,3 @@ +- Allow nodes to schedule a migrations json to be read and run to facilitate hard-forking. This is done by + taking a migrations json and passing the path, a hash of the contents, and a block height to the node when + starting the ledger. ([\#3310](https://github.com/anoma/namada/pull/3310)) \ No newline at end of file diff --git a/.changelog/v0.38.0/improvements/3317-store-ibc-trace-when-minting.md b/.changelog/v0.38.0/improvements/3317-store-ibc-trace-when-minting.md new file mode 100644 index 0000000000..7622b65086 --- /dev/null +++ b/.changelog/v0.38.0/improvements/3317-store-ibc-trace-when-minting.md @@ -0,0 +1,2 @@ +- Store IBC denom when minting the IBC token + ([\#3317](https://github.com/anoma/namada/issues/3317)) \ No newline at end of file diff --git a/.changelog/v0.38.0/improvements/3331-replace-wee-alloc.md b/.changelog/v0.38.0/improvements/3331-replace-wee-alloc.md new file mode 100644 index 0000000000..bb5c7fb986 --- /dev/null +++ b/.changelog/v0.38.0/improvements/3331-replace-wee-alloc.md @@ -0,0 +1,2 @@ +- Switched from wee allocator to rlsf for WASM. + ([\#3331](https://github.com/anoma/namada/pull/3331)) \ No newline at end of file diff --git a/.changelog/v0.38.0/summary.md b/.changelog/v0.38.0/summary.md new file mode 100644 index 0000000000..bc3404ff76 --- /dev/null +++ b/.changelog/v0.38.0/summary.md @@ -0,0 +1 @@ +Namada 0.38.0 is a minor release that upgrades the MASP and events and also cleans up dependencies. diff --git a/.changelog/v0.38.1/summary.md b/.changelog/v0.38.1/summary.md new file mode 100644 index 0000000000..c11de24a66 --- /dev/null +++ b/.changelog/v0.38.1/summary.md @@ -0,0 +1,2 @@ +Namada 0.38.1 is a patch release that fixes a license issue with the last minor release needed to build binaries in CI. + diff --git a/.changelog/v0.39.0/bug-fixes/3340-validator--by-tm-addr.md b/.changelog/v0.39.0/bug-fixes/3340-validator--by-tm-addr.md new file mode 100644 index 0000000000..e5459cb091 --- /dev/null +++ b/.changelog/v0.39.0/bug-fixes/3340-validator--by-tm-addr.md @@ -0,0 +1,3 @@ +- Fixes an issue with unsanitized input to a PoS query to find + a validator by TM address which may cause a node to panic. + ([\#3340](https://github.com/anoma/namada/pull/3340)) \ No newline at end of file diff --git a/.changelog/v0.39.0/bug-fixes/3358-fix-dry-run-writelog.md b/.changelog/v0.39.0/bug-fixes/3358-fix-dry-run-writelog.md new file mode 100644 index 0000000000..0c43f3bea7 --- /dev/null +++ b/.changelog/v0.39.0/bug-fixes/3358-fix-dry-run-writelog.md @@ -0,0 +1,2 @@ +- Fix to clear the write log when dry-run batched transaction + ([\#3358](https://github.com/anoma/namada/issues/3358)) \ No newline at end of file diff --git a/.changelog/v0.39.0/improvements/3297-split-transfer-tx.md b/.changelog/v0.39.0/improvements/3297-split-transfer-tx.md new file mode 100644 index 0000000000..a4a8b2fa4c --- /dev/null +++ b/.changelog/v0.39.0/improvements/3297-split-transfer-tx.md @@ -0,0 +1,6 @@ +- The transfer command has been split into: + - `transfer` (shielded transfer) + - `transparent-transfer` + - `shield` (from transparent to shielded) + - `unshield` (from shielded to transparent) + ([\#3297](https://github.com/anoma/namada/pull/3297)) \ No newline at end of file diff --git a/.changelog/v0.39.0/improvements/3315-wasmer-read-only-mem.md b/.changelog/v0.39.0/improvements/3315-wasmer-read-only-mem.md new file mode 100644 index 0000000000..317c36dcc7 --- /dev/null +++ b/.changelog/v0.39.0/improvements/3315-wasmer-read-only-mem.md @@ -0,0 +1,2 @@ +- Avoid growing wasm memory when performing read-only accesses. + ([\#3315](https://github.com/anoma/namada/pull/3315)) \ No newline at end of file diff --git a/.changelog/v0.39.0/improvements/3318-masp-custom-epoch.md b/.changelog/v0.39.0/improvements/3318-masp-custom-epoch.md new file mode 100644 index 0000000000..7b1d0ea050 --- /dev/null +++ b/.changelog/v0.39.0/improvements/3318-masp-custom-epoch.md @@ -0,0 +1,2 @@ +- Added a separate epoch tracker for masp to decouple its logic from the rest of + the protocol. ([\#3318](https://github.com/anoma/namada/pull/3318)) \ No newline at end of file diff --git a/.changelog/v0.39.0/improvements/3333-sync-default-node-addr.md b/.changelog/v0.39.0/improvements/3333-sync-default-node-addr.md new file mode 100644 index 0000000000..e16e88ce97 --- /dev/null +++ b/.changelog/v0.39.0/improvements/3333-sync-default-node-addr.md @@ -0,0 +1,3 @@ +- Default to the address from local config when the `--node` + argument is not specified for `shielded-sync` command + ([\#3333](https://github.com/anoma/namada/pull/3333)) \ No newline at end of file diff --git a/.changelog/v0.39.0/improvements/3348-allow-protocol-nam-transf.md b/.changelog/v0.39.0/improvements/3348-allow-protocol-nam-transf.md new file mode 100644 index 0000000000..5846c7af11 --- /dev/null +++ b/.changelog/v0.39.0/improvements/3348-allow-protocol-nam-transf.md @@ -0,0 +1,2 @@ +- Allow NAM transfers for protocol actions. + ([\#3348](https://github.com/anoma/namada/pull/3348)) \ No newline at end of file diff --git a/.changelog/v0.39.0/improvements/3349-gas-payer-from-implicit-addr.md b/.changelog/v0.39.0/improvements/3349-gas-payer-from-implicit-addr.md new file mode 100644 index 0000000000..ef93a86287 --- /dev/null +++ b/.changelog/v0.39.0/improvements/3349-gas-payer-from-implicit-addr.md @@ -0,0 +1,2 @@ +- Select gas payer from implicit address in the Namada CLI. + ([\#3349](https://github.com/anoma/namada/pull/3349)) \ No newline at end of file diff --git a/.changelog/v0.39.0/improvements/3350-diposable-keys-cleanup.md b/.changelog/v0.39.0/improvements/3350-diposable-keys-cleanup.md new file mode 100644 index 0000000000..df6b443e30 --- /dev/null +++ b/.changelog/v0.39.0/improvements/3350-diposable-keys-cleanup.md @@ -0,0 +1,2 @@ +- Remove old disposable keys from the wallet. + ([\#3350](https://github.com/anoma/namada/pull/3350)) \ No newline at end of file diff --git a/.changelog/v0.39.0/improvements/3351-masp-adjustments.md b/.changelog/v0.39.0/improvements/3351-masp-adjustments.md new file mode 100644 index 0000000000..640f99d80e --- /dev/null +++ b/.changelog/v0.39.0/improvements/3351-masp-adjustments.md @@ -0,0 +1,2 @@ +- Addressed some minor issues in the shielded token code. + ([\#3351](https://github.com/anoma/namada/pull/3351)) \ No newline at end of file diff --git a/.changelog/v0.39.0/summary.md b/.changelog/v0.39.0/summary.md new file mode 100644 index 0000000000..8da8641d4d --- /dev/null +++ b/.changelog/v0.39.0/summary.md @@ -0,0 +1 @@ +Namada 0.39.0 is a minor release that primarily abstracts the different kinds of transfer transactions and makes upgrades to the MASP and VPs. diff --git a/.github/workflows/scripts/e2e.json b/.github/workflows/scripts/e2e.json index 5825e4dadc..361141270f 100644 --- a/.github/workflows/scripts/e2e.json +++ b/.github/workflows/scripts/e2e.json @@ -19,7 +19,6 @@ "e2e::ledger_tests::test_genesis_validators": 14, "e2e::ledger_tests::test_node_connectivity_and_consensus": 28, "e2e::ledger_tests::test_epoch_sleep": 12, - "e2e::ledger_tests::wrapper_disposable_signer": 28, "e2e::ledger_tests::deactivate_and_reactivate_validator": 67, "e2e::ledger_tests::test_invalid_validator_txs": 73, "e2e::ledger_tests::suspend_ledger": 30, diff --git a/.github/workflows/scripts/hermes.txt b/.github/workflows/scripts/hermes.txt index 7588db229e..b86c49b38e 100644 --- a/.github/workflows/scripts/hermes.txt +++ b/.github/workflows/scripts/hermes.txt @@ -1 +1 @@ -1.8.2-namada-beta10-rc +1.8.2-namada-beta11-rc2 diff --git a/.github/workflows/scripts/integration.py b/.github/workflows/scripts/integration.py index 9dc8e591bd..1f756b0067 100644 --- a/.github/workflows/scripts/integration.py +++ b/.github/workflows/scripts/integration.py @@ -8,16 +8,16 @@ "integration::masp::cross_epoch_unshield", "integration::masp::dynamic_assets", "integration::masp::masp_incentives", - "integration::masp::masp_pinned_txs", "integration::masp::masp_txs_and_queries", "integration::masp::multiple_unfetched_txs_same_block", "integration::masp::spend_unconverted_asset_type", - "integration::masp::wrapper_fee_unshielding", - "integration::masp::wrapper_fee_unshielding_out_of_gas", ] NIGHTLY_VERSION = open("rust-nightly-version", "r").read().strip() -CARGO_TEST_COMMAND = "RUST_BACKTRACE=1 cargo +{} test --lib {} --features integration -Z unstable-options -- --test-threads=1 --exact -Z unstable-options --report-time" +CARGO_TEST_COMMAND = ( + "RUST_BACKTRACE=1 cargo +{} test --lib {} --features integration -Z" + " unstable-options -- --test-threads=1 --exact -Z unstable-options --report-time" +) test_results = {} has_failures = False @@ -27,28 +27,26 @@ start = time.time() command = CARGO_TEST_COMMAND.format(NIGHTLY_VERSION, task) end = time.time() - subprocess.check_call(command, shell=True, stdout=sys.stdout, stderr=subprocess.STDOUT) + subprocess.check_call( + command, shell=True, stdout=sys.stdout, stderr=subprocess.STDOUT + ) test_results[task] = { - 'status': 'ok', - 'time': round(end - start), - 'command': command + "status": "ok", + "time": round(end - start), + "command": command, } except: - test_results[task] = { - 'status': 'fail', - 'time': -1, - 'command': command - } + test_results[task] = {"status": "fail", "time": -1, "command": command} has_failures = True continue for test_name in test_results.keys(): - test_status = test_results[test_name]['status'] - time = test_results[test_name]['time'] + test_status = test_results[test_name]["status"] + time = test_results[test_name]["time"] print("- Test {} ({}s) -> status: {}".format(test_name, time, test_status)) - if test_results[test_name]['status'] != 'ok': - test_command = test_results[test_name]['command'] + if test_results[test_name]["status"] != "ok": + test_command = test_results[test_name]["command"] print(" Run locally with: {}".format(test_command)) if has_failures: - exit(1) \ No newline at end of file + exit(1) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce0413d07b..4e079a09ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,80 @@ # CHANGELOG +## v0.39.0 + +Namada 0.39.0 is a minor release that primarily abstracts the different kinds of transfer transactions and makes upgrades to the MASP and VPs. + +### BUG FIXES + +- Fixes an issue with unsanitized input to a PoS query to find + a validator by TM address which may cause a node to panic. + ([\#3340](https://github.com/anoma/namada/pull/3340)) +- Fix to clear the write log when dry-run batched transaction + ([\#3358](https://github.com/anoma/namada/issues/3358)) + +### IMPROVEMENTS + +- The transfer command has been split into: + - `transfer` (shielded transfer) + - `transparent-transfer` + - `shield` (from transparent to shielded) + - `unshield` (from shielded to transparent) + ([\#3297](https://github.com/anoma/namada/pull/3297)) +- Avoid growing wasm memory when performing read-only accesses. + ([\#3315](https://github.com/anoma/namada/pull/3315)) +- Added a separate epoch tracker for masp to decouple its logic from the rest of + the protocol. ([\#3318](https://github.com/anoma/namada/pull/3318)) +- Default to the address from local config when the `--node` + argument is not specified for `shielded-sync` command + ([\#3333](https://github.com/anoma/namada/pull/3333)) +- Allow NAM transfers for protocol actions. + ([\#3348](https://github.com/anoma/namada/pull/3348)) +- Select gas payer from implicit address in the Namada CLI. + ([\#3349](https://github.com/anoma/namada/pull/3349)) +- Remove old disposable keys from the wallet. + ([\#3350](https://github.com/anoma/namada/pull/3350)) +- Addressed some minor issues in the shielded token code. + ([\#3351](https://github.com/anoma/namada/pull/3351)) + +## v0.38.1 + +Namada 0.38.1 is a patch release that fixes a license issue with the last minor release needed to build binaries in CI. + +## v0.38.0 + +Namada 0.38.0 is a minor release that upgrades the MASP and events and also cleans up dependencies. + +### BUG FIXES + +- Fixed the fee collection logic in `finalize_block` to match that of + `process_proposal`. ([\#3075](https://github.com/anoma/namada/issues/3075)) + +### IMPROVEMENTS + +- Improved masp vp verification to run in parallel. + ([\#2972](https://github.com/anoma/namada/pull/2972)) +- Removed any dependency on the specific transaction data from the masp vp. + ([\#3232](https://github.com/anoma/namada/pull/3232)) +- Add a new event attribute facility to track events to their origin + in Namada's source code. This is useful for debugging purposes. + ([\#3268](https://github.com/anoma/namada/pull/3268)) +- Include the used MASP randomness parameters in the test vectors. + ([\#3296](https://github.com/anoma/namada/pull/3296)) +- Replaced unmaintained config-rs to an unreleased version + that replaces its also unmaintained yaml dependency. + ([\#3305](https://github.com/anoma/namada/pull/3305)) +- Upgrade `wasmer` vm to upstream version `4.3.1`, + moving away from the [forked code based on version + `2.3.0`](https://github.com/heliaxdev/wasmer/tree/255054f7f58b7b4a525f2fee6b9b86422d1ca15b). + ([\#3308](https://github.com/anoma/namada/pull/3308)) +- Allow nodes to schedule a migrations json to be read and run to facilitate hard-forking. This is done by + taking a migrations json and passing the path, a hash of the contents, and a block height to the node when + starting the ledger. ([\#3310](https://github.com/anoma/namada/pull/3310)) +- Store IBC denom when minting the IBC token + ([\#3317](https://github.com/anoma/namada/issues/3317)) +- Switched from wee allocator to rlsf for WASM. + ([\#3331](https://github.com/anoma/namada/pull/3331)) + ## v0.37.0 Namada 0.37.0 is a minor release that adds replay protection entries to consensus and enables merklizing data without diffs. diff --git a/Cargo.lock b/Cargo.lock index 3dd5b9b05b..5266d7563f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,11 +54,23 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "once_cell", "version_check", ] +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.2" @@ -68,6 +80,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -229,16 +247,16 @@ dependencies = [ ] [[package]] -name = "arrayref" -version = "0.3.7" +name = "arraydeque" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236" [[package]] -name = "arrayvec" -version = "0.5.2" +name = "arrayref" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" @@ -310,6 +328,15 @@ dependencies = [ "rustc_version 0.4.0", ] +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + [[package]] name = "auto_impl" version = "1.1.0" @@ -349,7 +376,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustversion", - "serde 1.0.193", + "serde", "sync_wrapper", "tower", "tower-layer", @@ -384,7 +411,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object 0.32.1", + "object", "rustc-demangle", ] @@ -433,7 +460,7 @@ dependencies = [ "displaydoc", "ics23", "prost 0.12.3", - "serde 1.0.193", + "serde", "serde_json", "sha2 0.10.8", "tendermint 0.35.0", @@ -479,7 +506,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" dependencies = [ - "serde 1.0.193", + "serde", ] [[package]] @@ -488,7 +515,7 @@ version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "serde 1.0.193", + "serde", ] [[package]] @@ -552,7 +579,7 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" dependencies = [ - "serde 1.0.193", + "serde", ] [[package]] @@ -584,7 +611,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec", "constant_time_eq", ] @@ -595,7 +622,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94230421e395b9920d23df13ea5d77a20e1725331f90fbbf6df6040b33f756ae" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec", "constant_time_eq", ] @@ -606,7 +633,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec", "cc", "cfg-if", "constant_time_eq", @@ -765,7 +792,7 @@ version = "4.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da78b32057b8fdfc352504708feeba7216dcd65a2c9ab02978cbd288d1279b6c" dependencies = [ - "serde 1.0.193", + "serde", "utf8-width", ] @@ -803,7 +830,16 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" dependencies = [ - "serde 1.0.193", + "serde", +] + +[[package]] +name = "bytesize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" +dependencies = [ + "serde", ] [[package]] @@ -823,7 +859,7 @@ version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" dependencies = [ - "serde 1.0.193", + "serde", ] [[package]] @@ -832,7 +868,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e34637b3140142bdf929fb439e8aa4ebad7651ebf7b1080b3930aa16ac1459ff" dependencies = [ - "serde 1.0.193", + "serde", ] [[package]] @@ -844,7 +880,7 @@ dependencies = [ "camino", "cargo-platform", "semver 1.0.20", - "serde 1.0.193", + "serde", "serde_json", "thiserror", ] @@ -880,7 +916,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "nom 7.1.3", + "nom", ] [[package]] @@ -941,7 +977,7 @@ checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" dependencies = [ "ciborium-io", "ciborium-ll", - "serde 1.0.193", + "serde", ] [[package]] @@ -1023,6 +1059,12 @@ name = "clru" version = "0.5.0" source = "git+https://github.com/marmeladema/clru-rs.git?rev=71ca566#71ca566915f21f3c308091ca7756a91b0f8b5afc" +[[package]] +name = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + [[package]] name = "coins-bip32" version = "0.8.7" @@ -1034,7 +1076,7 @@ dependencies = [ "digest 0.10.7", "hmac 0.12.1", "k256", - "serde 1.0.193", + "serde", "sha2 0.10.8", "thiserror", ] @@ -1068,7 +1110,7 @@ dependencies = [ "generic-array", "hex", "ripemd", - "serde 1.0.193", + "serde", "serde_derive", "sha2 0.10.8", "sha3", @@ -1120,18 +1162,21 @@ dependencies = [ [[package]] name = "config" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1b9d958c2b1368a663f05538fc1b5975adce1e19f435acceae987aceeeb369" +version = "0.14.0" +source = "git+https://github.com/mehcode/config-rs.git?rev=e3c1d0b452639478662a44f15ef6d5b6d969bf9b#e3c1d0b452639478662a44f15ef6d5b6d969bf9b" dependencies = [ + "async-trait", + "convert_case", + "json5", "lazy_static", - "nom 5.1.3", + "nom", + "pathdiff", + "ron", "rust-ini", - "serde 1.0.193", - "serde-hjson", + "serde", "serde_json", - "toml 0.5.11", - "yaml-rust", + "toml 0.8.2", + "yaml-rust2", ] [[package]] @@ -1143,6 +1188,12 @@ dependencies = [ "windows", ] +[[package]] +name = "const-crc32" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68d13f542d70e5b339bf46f6f74704ac052cfd526c58cd87996bd1ef4615b9a0" + [[package]] name = "const-hex" version = "1.10.0" @@ -1153,7 +1204,7 @@ dependencies = [ "cpufeatures", "hex", "proptest", - "serde 1.0.193", + "serde", ] [[package]] @@ -1162,6 +1213,26 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.15", + "once_cell", + "tiny-keccak", +] + [[package]] name = "const_panic" version = "0.2.8" @@ -1185,6 +1256,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -1245,7 +1325,7 @@ checksum = "7879036156092ad1c22fe0d7316efc5a5eceec2bc3906462a2560215f2a2f929" dependencies = [ "cosmwasm-schema-derive", "schemars", - "serde 1.0.193", + "serde", "serde_json", "thiserror", ] @@ -1276,7 +1356,7 @@ dependencies = [ "forward_ref", "hex", "schemars", - "serde 1.0.193", + "serde", "serde-json-wasm 0.5.2", "sha2 0.10.8", "static_assertions", @@ -1294,56 +1374,74 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.82.3" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38faa2a16616c8e78a18d37b4726b98bfd2de192f2fdc8a39ddf568a408a0f75" +checksum = "2a2ab4512dfd3a6f4be184403a195f76e81a8a9f9e6c898e19d2dc3ce20e0115" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.82.3" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26f192472a3ba23860afd07d2b0217dc628f21fcc72617aa1336d98e1671f33b" +checksum = "98b022ed2a5913a38839dfbafe6cf135342661293b08049843362df4301261dc" dependencies = [ + "arrayvec", + "bumpalo", "cranelift-bforest", "cranelift-codegen-meta", "cranelift-codegen-shared", + "cranelift-egraph", "cranelift-entity", + "cranelift-isle", "gimli 0.26.2", "log", - "regalloc", + "regalloc2", "smallvec", "target-lexicon", ] [[package]] name = "cranelift-codegen-meta" -version = "0.82.3" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32ddb89e9b89d3d9b36a5b7d7ea3261c98235a76ac95ba46826b8ec40b1a24" +checksum = "639307b45434ad112a98f8300c0f0ab085cbefcd767efcdef9ef19d4c0756e74" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.82.3" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "278e52e29c53fcf32431ef08406c295699a70306d05a0715c5b1bf50e33a9ab7" + +[[package]] +name = "cranelift-egraph" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01fd0d9f288cc1b42d9333b7a776b17e278fc888c28e6a0f09b5573d45a150bc" +checksum = "624b54323b06e675293939311943ba82d323bb340468ce1889be5da7932c8d73" +dependencies = [ + "cranelift-entity", + "fxhash", + "hashbrown 0.12.3", + "indexmap 1.9.3", + "log", + "smallvec", +] [[package]] name = "cranelift-entity" -version = "0.82.3" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3bfe172b83167604601faf9dc60453e0d0a93415b57a9c4d1a7ae6849185cf" +checksum = "9a59bcbca89c3f1b70b93ab3cbba5e5e0cbf3e63dadb23c7525cb142e21a9d4c" [[package]] name = "cranelift-frontend" -version = "0.82.3" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a006e3e32d80ce0e4ba7f1f9ddf66066d052a8c884a110b91d05404d6ce26dce" +checksum = "0d70abacb8cfef3dc8ff7e8836e9c1d70f7967dfdac824a4cd5e30223415aca6" dependencies = [ "cranelift-codegen", "log", @@ -1351,6 +1449,12 @@ dependencies = [ "target-lexicon", ] +[[package]] +name = "cranelift-isle" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "393bc73c451830ff8dbb3a07f61843d6cb41a084f9996319917c0b291ed785bb" + [[package]] name = "crc32fast" version = "1.3.2" @@ -1379,7 +1483,7 @@ dependencies = [ "plotters", "rayon", "regex", - "serde 1.0.193", + "serde", "serde_derive", "serde_json", "tinytemplate", @@ -1396,6 +1500,12 @@ dependencies = [ "itertools 0.10.5", ] +[[package]] +name = "critical-section" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" + [[package]] name = "crossbeam-channel" version = "0.5.12" @@ -1429,6 +1539,15 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.19" @@ -1556,7 +1675,17 @@ checksum = "d5ff29294ee99373e2cd5fd21786a3c0ced99a52fec2ca347d565489c61b723c" dependencies = [ "cosmwasm-std", "schemars", - "serde 1.0.193", + "serde", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", ] [[package]] @@ -1565,8 +1694,22 @@ version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.3", + "darling_macro 0.20.3", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", ] [[package]] @@ -1582,23 +1725,53 @@ dependencies = [ "syn 2.0.52", ] +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", +] + [[package]] name = "darling_macro" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ - "darling_core", + "darling_core 0.20.3", "quote", "syn 2.0.52", ] +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.3", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "data-encoding" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +[[package]] +name = "debugless-unwrap" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f400d0750c0c069e8493f2256cb4da6f604b6d2eeb69a0ca8863acde352f8400" + [[package]] name = "der" version = "0.7.8" @@ -1635,6 +1808,48 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive-getters" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2c35ab6e03642397cdda1dd58abbc05d418aef8e36297f336d5aba060fe8df" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling 0.14.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -1710,12 +1925,30 @@ dependencies = [ "syn 2.0.52", ] +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + [[package]] name = "doc-comment" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "document-features" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95" +dependencies = [ + "litrs", +] + [[package]] name = "drain_filter_polyfill" version = "0.1.3" @@ -1742,7 +1975,7 @@ checksum = "7c1a2e028bbf7921549873b291ddc0cfe08b673d9489da81ac28898cd5a0e6e0" dependencies = [ "chrono", "rust_decimal", - "serde 1.0.193", + "serde", "thiserror", "time", "winnow 0.6.8", @@ -1777,7 +2010,7 @@ checksum = "64fba5a42bd76a17cad4bfa00de168ee1cbfa06a5e8ce992ae880218c05641a9" dependencies = [ "byteorder", "dynasm", - "memmap2", + "memmap2 0.5.10", ] [[package]] @@ -1814,7 +2047,7 @@ dependencies = [ "curve25519-dalek-ng", "hex", "rand_core 0.6.4", - "serde 1.0.193", + "serde", "sha2 0.9.9", "thiserror", "zeroize", @@ -1828,7 +2061,7 @@ checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" dependencies = [ "curve25519-dalek 4.1.2", "ed25519", - "serde 1.0.193", + "serde", "sha2 0.10.8", "subtle", "zeroize", @@ -1844,7 +2077,7 @@ dependencies = [ "hashbrown 0.12.3", "hex", "rand_core 0.6.4", - "serde 1.0.193", + "serde", "sha2 0.9.9", "zeroize", ] @@ -1875,6 +2108,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + [[package]] name = "encoding_rs" version = "0.8.33" @@ -1897,7 +2136,7 @@ dependencies = [ "log", "rand 0.8.5", "rlp", - "serde 1.0.193", + "serde", "sha3", "zeroize", ] @@ -1937,7 +2176,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" dependencies = [ - "darling", + "darling 0.20.3", "proc-macro2", "quote", "syn 2.0.52", @@ -1967,7 +2206,7 @@ checksum = "768064bd3a0e2bedcba91dc87ace90beea91acc41b6a01a3ca8e9aa8827461bf" dependencies = [ "log", "once_cell", - "serde 1.0.193", + "serde", "serde_json", ] @@ -1985,7 +2224,7 @@ dependencies = [ "pbkdf2 0.11.0", "rand 0.8.5", "scrypt", - "serde 1.0.193", + "serde", "serde_json", "sha2 0.10.8", "sha3", @@ -2003,7 +2242,7 @@ dependencies = [ "hex", "once_cell", "regex", - "serde 1.0.193", + "serde", "serde_json", "sha3", "thiserror", @@ -2105,7 +2344,7 @@ checksum = "8c405f24ea3a517899ba7985385c43dc4a7eb1209af3b1e0a1a32d7dcc7f8d09" dependencies = [ "ethers-core", "once_cell", - "serde 1.0.193", + "serde", "serde_json", ] @@ -2123,7 +2362,7 @@ dependencies = [ "futures-util", "once_cell", "pin-project", - "serde 1.0.193", + "serde", "serde_json", "thiserror", ] @@ -2143,7 +2382,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "serde 1.0.193", + "serde", "serde_json", "syn 2.0.52", "toml 0.8.2", @@ -2172,7 +2411,7 @@ version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f03e0bdc216eeb9e355b90cf610ef6c5bb8aca631f97b5ae9980ce34ea7878d" dependencies = [ - "arrayvec 0.7.4", + "arrayvec", "bytes", "cargo_metadata", "chrono", @@ -2186,7 +2425,7 @@ dependencies = [ "open-fastrlp", "rand 0.8.5", "rlp", - "serde 1.0.193", + "serde", "serde_json", "strum 0.25.0", "syn 2.0.52", @@ -2206,7 +2445,7 @@ dependencies = [ "ethers-core", "reqwest", "semver 1.0.20", - "serde 1.0.193", + "serde", "serde_json", "thiserror", "tracing", @@ -2229,7 +2468,7 @@ dependencies = [ "futures-util", "instant", "reqwest", - "serde 1.0.193", + "serde", "serde_json", "thiserror", "tokio", @@ -2261,7 +2500,7 @@ dependencies = [ "once_cell", "pin-project", "reqwest", - "serde 1.0.193", + "serde", "serde_json", "thiserror", "tokio", @@ -2454,6 +2693,40 @@ dependencies = [ "num-traits 0.2.17", ] +[[package]] +name = "frost-core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45d6280625f1603d160df24b23e4984a6a7286f41455ae606823d0104c32e834" +dependencies = [ + "byteorder", + "const-crc32", + "debugless-unwrap", + "derive-getters", + "document-features", + "hex", + "itertools 0.12.1", + "postcard", + "rand_core 0.6.4", + "serde", + "serdect", + "thiserror", + "visibility", + "zeroize", +] + +[[package]] +name = "frost-rerandomized" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c58f58ea009000db490efd9a3936d0035647a2b00c7ba8f3868c2ed0306b0b" +dependencies = [ + "derive-getters", + "document-features", + "frost-core", + "rand_core 0.6.4", +] + [[package]] name = "fs_extra" version = "1.3.0" @@ -2610,9 +2883,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", @@ -2713,7 +2986,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.11", - "indexmap 2.1.0", + "indexmap 2.2.6", "slab", "tokio", "tokio-util 0.7.10", @@ -2727,12 +3000,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] -name = "hashbrown" -version = "0.11.2" +name = "hash32" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" dependencies = [ - "ahash", + "byteorder", ] [[package]] @@ -2741,7 +3014,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.8", ] [[package]] @@ -2749,6 +3022,10 @@ name = "hashbrown" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash 0.8.11", + "allocator-api2", +] [[package]] name = "hashers" @@ -2759,6 +3036,15 @@ dependencies = [ "fxhash", ] +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.3", +] + [[package]] name = "hdrhistogram" version = "7.5.4" @@ -2793,6 +3079,20 @@ dependencies = [ "http 0.2.11", ] +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version 0.4.0", + "serde", + "spin 0.9.8", + "stable_deref_trait", +] + [[package]] name = "heck" version = "0.4.1" @@ -3031,7 +3331,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "schemars", - "serde 1.0.193", + "serde", "serde-json-wasm 1.0.1", ] @@ -3061,7 +3361,7 @@ dependencies = [ "primitive-types", "scale-info", "schemars", - "serde 1.0.193", + "serde", "uint", ] @@ -3088,7 +3388,7 @@ dependencies = [ "ibc-client-wasm-types", "ibc-core", "prost 0.12.3", - "serde 1.0.193", + "serde", ] [[package]] @@ -3104,7 +3404,7 @@ dependencies = [ "ibc-core-handler-types", "ibc-core-host", "ibc-primitives", - "serde 1.0.193", + "serde", "tendermint 0.36.0", "tendermint-light-client-verifier", ] @@ -3133,7 +3433,7 @@ dependencies = [ "ibc-core-host-types", "ibc-primitives", "ibc-proto", - "serde 1.0.193", + "serde", "tendermint 0.36.0", "tendermint-light-client-verifier", "tendermint-proto 0.36.0", @@ -3152,7 +3452,7 @@ dependencies = [ "ibc-core-host-types", "ibc-primitives", "ibc-proto", - "serde 1.0.193", + "serde", ] [[package]] @@ -3216,7 +3516,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "schemars", - "serde 1.0.193", + "serde", "sha2 0.10.8", "subtle-encoding", "tendermint 0.36.0", @@ -3269,7 +3569,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "schemars", - "serde 1.0.193", + "serde", "subtle-encoding", "tendermint 0.36.0", ] @@ -3289,7 +3589,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "schemars", - "serde 1.0.193", + "serde", "subtle-encoding", ] @@ -3323,7 +3623,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "schemars", - "serde 1.0.193", + "serde", "subtle-encoding", "tendermint 0.36.0", ] @@ -3364,7 +3664,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "schemars", - "serde 1.0.193", + "serde", "subtle-encoding", "tendermint 0.36.0", ] @@ -3406,7 +3706,7 @@ dependencies = [ "ibc-core-host-types", "ibc-primitives", "ibc-proto", - "serde 1.0.193", + "serde", "sha2 0.10.8", "subtle-encoding", "tendermint 0.36.0", @@ -3425,7 +3725,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "schemars", - "serde 1.0.193", + "serde", ] [[package]] @@ -3458,7 +3758,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "schemars", - "serde 1.0.193", + "serde", "subtle-encoding", "tendermint 0.36.0", ] @@ -3488,7 +3788,7 @@ dependencies = [ "prost 0.12.3", "scale-info", "schemars", - "serde 1.0.193", + "serde", "tendermint 0.36.0", "time", ] @@ -3509,7 +3809,7 @@ dependencies = [ "prost 0.12.3", "scale-info", "schemars", - "serde 1.0.193", + "serde", "subtle-encoding", "tendermint-proto 0.36.0", "tonic", @@ -3561,7 +3861,7 @@ dependencies = [ "informalsystems-pbjson 0.6.0", "prost 0.12.3", "ripemd", - "serde 1.0.193", + "serde", "sha2 0.10.8", "sha3", ] @@ -3617,7 +3917,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" dependencies = [ - "serde 1.0.193", + "serde", ] [[package]] @@ -3637,7 +3937,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5ad43a3f5795945459d577f6589cf62a476e92c79b75e70cd954364e14ce17b" dependencies = [ - "serde 1.0.193", + "serde", ] [[package]] @@ -3652,7 +3952,7 @@ version = "0.8.0" source = "git+https://github.com/heliaxdev/index-set?tag=v0.8.1#b0d928f83cf0d465ccda299d131e8df2859b5184" dependencies = [ "borsh 1.2.1", - "serde 1.0.193", + "serde", ] [[package]] @@ -3663,28 +3963,29 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", - "serde 1.0.193", + "serde", ] [[package]] name = "indexmap" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +version = "2.2.4" +source = "git+https://github.com/heliaxdev/indexmap?tag=2.2.4-heliax-1#b5b5b547bd6ab04bbb16e060326a50ddaeb6c909" dependencies = [ + "borsh 1.2.1", "equivalent", "hashbrown 0.14.3", + "serde", ] [[package]] name = "indexmap" -version = "2.2.4" -source = "git+https://github.com/heliaxdev/indexmap?tag=2.2.4-heliax-1#b5b5b547bd6ab04bbb16e060326a50ddaeb6c909" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ - "borsh 1.2.1", "equivalent", "hashbrown 0.14.3", - "serde 1.0.193", + "serde", ] [[package]] @@ -3694,7 +3995,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4eecd90f87bea412eac91c6ef94f6b1e390128290898cbe14f2b926787ae1fb" dependencies = [ "base64 0.13.1", - "serde 1.0.193", + "serde", ] [[package]] @@ -3704,7 +4005,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aa4a0980c8379295100d70854354e78df2ee1c6ca0f96ffe89afeb3140e3a3d" dependencies = [ "base64 0.21.7", - "serde 1.0.193", + "serde", ] [[package]] @@ -3802,6 +4103,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + [[package]] name = "jsonwebtoken" version = "8.3.0" @@ -3811,7 +4123,7 @@ dependencies = [ "base64 0.21.7", "pem", "ring 0.16.20", - "serde 1.0.193", + "serde", "serde_json", "simple_asn1", ] @@ -3954,28 +4266,15 @@ checksum = "02036c84eab9c48e85bc568d269221ba4f5e1cfbc785c3c2c2f6bb8c131f9287" dependencies = [ "async-trait", "ledger-transport", - "serde 1.0.193", + "serde", "thiserror", ] -[[package]] -name = "lexical-core" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" -dependencies = [ - "arrayvec 0.5.2", - "bitflags 1.3.2", - "cfg-if", - "ryu", - "static_assertions", -] - [[package]] name = "libc" -version = "0.2.150" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libgit2-sys" @@ -4049,7 +4348,7 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" dependencies = [ - "serde 1.0.193", + "serde", ] [[package]] @@ -4078,6 +4377,12 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + [[package]] name = "lock_api" version = "0.4.11" @@ -4095,31 +4400,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] -name = "loupe" -version = "0.1.3" +name = "mach" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6a72dfa44fe15b5e76b94307eeb2ff995a8c5b283b55008940c02e0c5b634d" -dependencies = [ - "indexmap 1.9.3", - "loupe-derive", - "rustversion", -] - -[[package]] -name = "loupe-derive" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fbfc88337168279f2e9ae06e157cfed4efd3316e14dc96ed074d4f2e6c5952" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "mach" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" dependencies = [ "libc", ] @@ -4133,15 +4417,15 @@ dependencies = [ "indexmap 1.9.3", "linked-hash-map", "regex", - "serde 1.0.193", + "serde", "serde_derive", - "serde_yaml", + "serde_yaml 0.7.5", ] [[package]] name = "masp_note_encryption" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=3aacc707c5948e7423589ac617305448bead9842#3aacc707c5948e7423589ac617305448bead9842" +source = "git+https://github.com/anoma/masp?rev=4ede1c42d76d6348af8224bc8bfac4404321fe82#4ede1c42d76d6348af8224bc8bfac4404321fe82" dependencies = [ "borsh 1.2.1", "chacha20", @@ -4154,7 +4438,7 @@ dependencies = [ [[package]] name = "masp_primitives" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=3aacc707c5948e7423589ac617305448bead9842#3aacc707c5948e7423589ac617305448bead9842" +source = "git+https://github.com/anoma/masp?rev=4ede1c42d76d6348af8224bc8bfac4404321fe82#4ede1c42d76d6348af8224bc8bfac4404321fe82" dependencies = [ "aes", "bip0039", @@ -4186,13 +4470,13 @@ dependencies = [ [[package]] name = "masp_proofs" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=3aacc707c5948e7423589ac617305448bead9842#3aacc707c5948e7423589ac617305448bead9842" +source = "git+https://github.com/anoma/masp?rev=4ede1c42d76d6348af8224bc8bfac4404321fe82#4ede1c42d76d6348af8224bc8bfac4404321fe82" dependencies = [ "bellman", "blake2b_simd", "bls12_381", "directories", - "getrandom 0.2.11", + "getrandom 0.2.15", "group", "itertools 0.11.0", "jubjub", @@ -4235,12 +4519,12 @@ dependencies = [ ] [[package]] -name = "memoffset" -version = "0.6.5" +name = "memmap2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +checksum = "6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872" dependencies = [ - "autocfg", + "libc", ] [[package]] @@ -4360,30 +4644,21 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "namada" -version = "0.37.0" +version = "0.39.0" dependencies = [ "assert_matches", "async-trait", "base58", - "bimap", "borsh 1.2.1", "borsh-ext", "byte-unit", - "circular-queue", "clru", - "data-encoding", - "derivation-path", - "derivative", - "ethbridge-bridge-contract", "ethers", "eyre", - "futures", "ibc-testkit", "itertools 0.12.1", "k256", - "konst", "linkme", - "loupe", "masp_primitives", "masp_proofs", "namada_account", @@ -4393,7 +4668,6 @@ dependencies = [ "namada_gas", "namada_governance", "namada_ibc", - "namada_macros", "namada_migrations", "namada_parameters", "namada_proof_of_stake", @@ -4406,33 +4680,22 @@ dependencies = [ "namada_tx_env", "namada_vote_ext", "namada_vp_env", - "num-traits 0.2.17", - "num256", - "orion", - "owo-colors", "parity-wasm", - "paste", "pretty_assertions", "proptest", "prost 0.12.3", "rand 0.8.5", - "rand_core 0.6.4", "rayon", - "regex", "ripemd", - "serde 1.0.193", "serde_json", "sha2 0.9.9", - "slip10_ed25519", "smooth-operator", "tempfile", "tendermint-rpc", "test-log", "thiserror", "tiny-bip39", - "tiny-hderive", "tokio", - "toml 0.5.11", "tracing", "tracing-subscriber", "uint", @@ -4440,18 +4703,14 @@ dependencies = [ "wasmer", "wasmer-cache", "wasmer-compiler-singlepass", - "wasmer-engine-dylib", - "wasmer-engine-universal", "wasmer-vm", "wasmparser 0.107.0", "wasmtimer", - "wat", - "zeroize", ] [[package]] name = "namada_account" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "linkme", @@ -4460,16 +4719,15 @@ dependencies = [ "namada_migrations", "namada_storage", "proptest", - "serde 1.0.193", + "serde", ] [[package]] name = "namada_apps" -version = "0.37.0" +version = "0.39.0" dependencies = [ "assert_matches", "bit-set", - "bytes", "color-eyre", "eyre", "git2", @@ -4484,14 +4742,12 @@ dependencies = [ "toml 0.5.11", "tracing", "tracing-subscriber", - "warp", "winapi", - "zeroize", ] [[package]] name = "namada_apps_lib" -version = "0.37.0" +version = "0.39.0" dependencies = [ "assert_matches", "async-trait", @@ -4528,7 +4784,7 @@ dependencies = [ "rand_core 0.6.4", "reqwest", "rpassword", - "serde 1.0.193", + "serde", "serde_json", "sha2 0.9.9", "tar", @@ -4550,13 +4806,14 @@ dependencies = [ [[package]] name = "namada_benchmarks" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "borsh-ext", "criterion", "lazy_static", "masp_primitives", + "masp_proofs", "namada", "namada_apps_lib", "namada_node", @@ -4568,12 +4825,11 @@ dependencies = [ "wasm-instrument", "wasmer", "wasmer-compiler-singlepass", - "wasmer-engine-universal", ] [[package]] name = "namada_controller" -version = "0.37.0" +version = "0.39.0" dependencies = [ "namada_core", "smooth-operator", @@ -4582,7 +4838,7 @@ dependencies = [ [[package]] name = "namada_core" -version = "0.37.0" +version = "0.39.0" dependencies = [ "assert_matches", "bech32 0.8.1", @@ -4616,7 +4872,7 @@ dependencies = [ "rand 0.8.5", "rand_core 0.6.4", "ripemd", - "serde 1.0.193", + "serde", "serde_json", "sha2 0.9.9", "smooth-operator", @@ -4635,7 +4891,7 @@ dependencies = [ [[package]] name = "namada_encoding_spec" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "itertools 0.12.1", @@ -4646,7 +4902,7 @@ dependencies = [ [[package]] name = "namada_ethereum_bridge" -version = "0.37.0" +version = "0.39.0" dependencies = [ "assert_matches", "borsh 1.2.1", @@ -4669,11 +4925,7 @@ dependencies = [ "namada_trans_token", "namada_tx", "namada_vote_ext", - "rand 0.8.5", - "serde 1.0.193", - "serde_json", - "tendermint 0.36.0", - "tendermint-proto 0.36.0", + "serde", "thiserror", "toml 0.5.11", "tracing", @@ -4681,14 +4933,14 @@ dependencies = [ [[package]] name = "namada_events" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "linkme", "namada_core", "namada_macros", "namada_migrations", - "serde 1.0.193", + "serde", "serde_json", "thiserror", "tracing", @@ -4696,10 +4948,11 @@ dependencies = [ [[package]] name = "namada_examples" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "data-encoding", + "masp_primitives", "masp_proofs", "namada_apps_lib", "namada_macros", @@ -4709,14 +4962,13 @@ dependencies = [ "namada_shielded_token", "namada_trans_token", "proptest", - "regex", "serde_json", "tokio", ] [[package]] name = "namada_gas" -version = "0.37.0" +version = "0.39.0" dependencies = [ "assert_matches", "borsh 1.2.1", @@ -4726,13 +4978,13 @@ dependencies = [ "namada_macros", "namada_migrations", "proptest", - "serde 1.0.193", + "serde", "thiserror", ] [[package]] name = "namada_governance" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "itertools 0.12.1", @@ -4746,7 +4998,7 @@ dependencies = [ "namada_storage", "namada_trans_token", "proptest", - "serde 1.0.193", + "serde", "serde_json", "smooth-operator", "thiserror", @@ -4755,7 +5007,7 @@ dependencies = [ [[package]] name = "namada_ibc" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "ibc", @@ -4767,7 +5019,6 @@ dependencies = [ "masp_primitives", "namada_core", "namada_events", - "namada_gas", "namada_governance", "namada_macros", "namada_migrations", @@ -4775,11 +5026,10 @@ dependencies = [ "namada_state", "namada_storage", "namada_token", - "namada_tx", "primitive-types", "proptest", "prost 0.12.3", - "serde 1.0.193", + "serde", "serde_json", "sha2 0.9.9", "thiserror", @@ -4788,7 +5038,7 @@ dependencies = [ [[package]] name = "namada_light_sdk" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "borsh-ext", @@ -4802,7 +5052,7 @@ dependencies = [ [[package]] name = "namada_macros" -version = "0.37.0" +version = "0.39.0" dependencies = [ "data-encoding", "pretty_assertions", @@ -4814,7 +5064,7 @@ dependencies = [ [[package]] name = "namada_merkle_tree" -version = "0.37.0" +version = "0.39.0" dependencies = [ "assert_matches", "borsh 1.2.1", @@ -4833,7 +5083,7 @@ dependencies = [ [[package]] name = "namada_migrations" -version = "0.37.0" +version = "0.39.0" dependencies = [ "lazy_static", "linkme", @@ -4842,7 +5092,7 @@ dependencies = [ [[package]] name = "namada_node" -version = "0.37.0" +version = "0.39.0" dependencies = [ "assert_matches", "async-trait", @@ -4903,9 +5153,8 @@ dependencies = [ [[package]] name = "namada_parameters" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "borsh 1.2.1", "namada_core", "namada_macros", "namada_storage", @@ -4914,11 +5163,10 @@ dependencies = [ [[package]] name = "namada_proof_of_stake" -version = "0.37.0" +version = "0.39.0" dependencies = [ "assert_matches", "borsh 1.2.1", - "data-encoding", "derivative", "itertools 0.12.1", "konst", @@ -4934,12 +5182,11 @@ dependencies = [ "namada_state", "namada_storage", "namada_trans_token", - "num-traits 0.2.17", "once_cell", "pretty_assertions", "proptest", "proptest-state-machine", - "serde 1.0.193", + "serde", "smooth-operator", "test-log", "thiserror", @@ -4950,14 +5197,14 @@ dependencies = [ [[package]] name = "namada_replay_protection" -version = "0.37.0" +version = "0.39.0" dependencies = [ "namada_core", ] [[package]] name = "namada_sdk" -version = "0.37.0" +version = "0.39.0" dependencies = [ "assert_matches", "async-trait", @@ -5009,13 +5256,12 @@ dependencies = [ "rand 0.8.5", "rand_core 0.6.4", "regex", - "serde 1.0.193", + "serde", "serde_json", "sha2 0.9.9", "slip10_ed25519", "smooth-operator", "tempfile", - "tendermint-config", "tendermint-rpc", "thiserror", "tiny-bip39", @@ -5029,7 +5275,7 @@ dependencies = [ [[package]] name = "namada_shielded_token" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "masp_primitives", @@ -5038,10 +5284,9 @@ dependencies = [ "namada_parameters", "namada_storage", "namada_trans_token", - "namada_tx", "proptest", "rayon", - "serde 1.0.193", + "serde", "smooth-operator", "test-log", "tracing", @@ -5049,12 +5294,11 @@ dependencies = [ [[package]] name = "namada_state" -version = "0.37.0" +version = "0.39.0" dependencies = [ "assert_matches", "borsh 1.2.1", "chrono", - "ics23", "itertools 0.12.1", "linkme", "namada_core", @@ -5070,18 +5314,15 @@ dependencies = [ "patricia_tree", "pretty_assertions", "proptest", - "sha2 0.9.9", "smooth-operator", - "sparse-merkle-tree", "test-log", "thiserror", - "tiny-keccak", "tracing", ] [[package]] name = "namada_storage" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "itertools 0.12.1", @@ -5092,7 +5333,7 @@ dependencies = [ "namada_migrations", "namada_replay_protection", "regex", - "serde 1.0.193", + "serde", "smooth-operator", "thiserror", "tracing", @@ -5100,7 +5341,7 @@ dependencies = [ [[package]] name = "namada_test_utils" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "namada_core", @@ -5109,14 +5350,12 @@ dependencies = [ [[package]] name = "namada_tests" -version = "0.37.0" +version = "0.39.0" dependencies = [ "assert_cmd", "assert_matches", - "async-trait", "borsh 1.2.1", "borsh-ext", - "chrono", "color-eyre", "concat-idents", "data-encoding", @@ -5130,7 +5369,6 @@ dependencies = [ "ibc-testkit", "ics23", "itertools 0.12.1", - "lazy_static", "namada", "namada_apps_lib", "namada_core", @@ -5140,7 +5378,6 @@ dependencies = [ "namada_tx_prelude", "namada_vm_env", "namada_vp_prelude", - "num-traits 0.2.17", "once_cell", "pretty_assertions", "proptest", @@ -5148,7 +5385,7 @@ dependencies = [ "prost 0.12.3", "rand 0.8.5", "regex", - "serde 1.0.193", + "serde", "serde_json", "sha2 0.9.9", "tar", @@ -5157,24 +5394,26 @@ dependencies = [ "test-log", "tokio", "toml 0.5.11", - "tracing", - "tracing-subscriber", ] [[package]] name = "namada_token" -version = "0.37.0" +version = "0.39.0" dependencies = [ + "borsh 1.2.1", "namada_core", "namada_events", + "namada_macros", "namada_shielded_token", "namada_storage", "namada_trans_token", + "proptest", + "serde", ] [[package]] name = "namada_trans_token" -version = "0.37.0" +version = "0.39.0" dependencies = [ "konst", "linkme", @@ -5185,7 +5424,7 @@ dependencies = [ [[package]] name = "namada_tx" -version = "0.37.0" +version = "0.39.0" dependencies = [ "ark-bls12-381", "assert_matches", @@ -5206,7 +5445,7 @@ dependencies = [ "prost 0.12.3", "prost-types 0.12.3", "rand 0.8.5", - "serde 1.0.193", + "serde", "serde_json", "sha2 0.9.9", "thiserror", @@ -5215,7 +5454,7 @@ dependencies = [ [[package]] name = "namada_tx_env" -version = "0.37.0" +version = "0.39.0" dependencies = [ "namada_core", "namada_events", @@ -5224,7 +5463,7 @@ dependencies = [ [[package]] name = "namada_tx_prelude" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "masp_primitives", @@ -5241,13 +5480,11 @@ dependencies = [ "namada_tx", "namada_tx_env", "namada_vm_env", - "sha2 0.9.9", - "thiserror", ] [[package]] name = "namada_vm_env" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "masp_primitives", @@ -5256,7 +5493,7 @@ dependencies = [ [[package]] name = "namada_vote_ext" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "data-encoding", @@ -5265,12 +5502,12 @@ dependencies = [ "namada_macros", "namada_migrations", "namada_tx", - "serde 1.0.193", + "serde", ] [[package]] name = "namada_vp_env" -version = "0.37.0" +version = "0.39.0" dependencies = [ "derivative", "masp_primitives", @@ -5280,12 +5517,11 @@ dependencies = [ "namada_storage", "namada_tx", "smooth-operator", - "thiserror", ] [[package]] name = "namada_vp_prelude" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "namada_account", @@ -5302,7 +5538,6 @@ dependencies = [ "namada_vm_env", "namada_vp_env", "sha2 0.9.9", - "thiserror", ] [[package]] @@ -5342,17 +5577,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" -[[package]] -name = "nom" -version = "5.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b" -dependencies = [ - "lexical-core", - "memchr", - "version_check", -] - [[package]] name = "nom" version = "7.1.3" @@ -5477,15 +5701,6 @@ dependencies = [ "num-traits 0.2.17", ] -[[package]] -name = "num-traits" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -dependencies = [ - "num-traits 0.2.17", -] - [[package]] name = "num-traits" version = "0.2.17" @@ -5514,7 +5729,7 @@ dependencies = [ "num", "num-derive 0.3.3", "num-traits 0.2.17", - "serde 1.0.193", + "serde", "serde_derive", ] @@ -5549,18 +5764,6 @@ dependencies = [ "syn 2.0.52", ] -[[package]] -name = "object" -version = "0.28.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" -dependencies = [ - "crc32fast", - "hashbrown 0.11.2", - "indexmap 1.9.3", - "memchr", -] - [[package]] name = "object" version = "0.32.1" @@ -5594,7 +5797,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" dependencies = [ - "arrayvec 0.7.4", + "arrayvec", "auto_impl", "bytes", "ethereum-types", @@ -5657,6 +5860,16 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "ordered-multimap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" +dependencies = [ + "dlv-list", + "hashbrown 0.14.3", +] + [[package]] name = "orion" version = "0.16.1" @@ -5664,7 +5877,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6624905ddd92e460ff0685567539ed1ac985b2dee4c92c7edcd64fce905b00c" dependencies = [ "ct-codecs", - "getrandom 0.2.11", + "getrandom 0.2.15", "subtle", "zeroize", ] @@ -5696,12 +5909,12 @@ version = "3.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" dependencies = [ - "arrayvec 0.7.4", + "arrayvec", "bitvec", "byte-slice-cast", "impl-trait-for-tuples", "parity-scale-codec-derive", - "serde 1.0.193", + "serde", ] [[package]] @@ -5775,6 +5988,12 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "patricia_tree" version = "0.8.0" @@ -5857,15 +6076,49 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.5" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" dependencies = [ "memchr", "thiserror", "ucd-trie", ] +[[package]] +name = "pest_derive" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "pest_meta" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +dependencies = [ + "once_cell", + "pest", + "sha2 0.10.8", +] + [[package]] name = "petgraph" version = "0.6.4" @@ -5873,7 +6126,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.1.0", + "indexmap 2.2.6", ] [[package]] @@ -5979,6 +6232,18 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "postcard" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" +dependencies = [ + "cobs", + "embedded-io", + "heapless", + "serde", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -6344,7 +6609,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", ] [[package]] @@ -6390,17 +6655,17 @@ dependencies = [ [[package]] name = "reddsa" version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78a5191930e84973293aa5f532b513404460cd2216c1cfb76d08748c15b40b02" +source = "git+https://github.com/heliaxdev/reddsa?rev=46d363b929e1b940688fa0c53d637e304a755185#46d363b929e1b940688fa0c53d637e304a755185" dependencies = [ "blake2b_simd", "byteorder", + "frost-rerandomized", "group", "hex", "jubjub", "pasta_curves", "rand_core 0.6.4", - "serde 1.0.193", + "serde", "thiserror", "zeroize", ] @@ -6413,7 +6678,7 @@ checksum = "7a60db2c3bc9c6fd1e8631fee75abc008841d27144be744951d6b9b75f9b569c" dependencies = [ "rand_core 0.6.4", "reddsa", - "serde 1.0.193", + "serde", "thiserror", "zeroize", ] @@ -6433,19 +6698,20 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "libredox", "thiserror", ] [[package]] -name = "regalloc" -version = "0.0.34" +name = "regalloc2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62446b1d3ebf980bdc68837700af1d77b37bc430e524bf95319c6eada2a4cc02" +checksum = "300d4fbfb40c1c66a78ba3ddd41c1110247cf52f97b87d0f2fc9209bd49b030c" dependencies = [ + "fxhash", "log", - "rustc-hash", + "slice-group-by", "smallvec", ] @@ -6542,7 +6808,7 @@ dependencies = [ "rustls", "rustls-native-certs", "rustls-pemfile", - "serde 1.0.193", + "serde", "serde_json", "serde_urlencoded", "system-configuration", @@ -6589,7 +6855,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", - "getrandom 0.2.11", + "getrandom 0.2.15", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -6614,6 +6880,7 @@ dependencies = [ "bitvec", "bytecheck", "hashbrown 0.12.3", + "indexmap 1.9.3", "ptr_meta", "rend", "rkyv_derive", @@ -6673,6 +6940,18 @@ dependencies = [ "librocksdb-sys", ] +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64 0.21.7", + "bitflags 2.5.0", + "serde", + "serde_derive", +] + [[package]] name = "rpassword" version = "5.0.1" @@ -6685,9 +6964,13 @@ dependencies = [ [[package]] name = "rust-ini" -version = "0.13.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" +checksum = "3e0698206bcb8882bf2a9ecb4c1e7785db57ff052297085a6efd4fe42302068a" +dependencies = [ + "cfg-if", + "ordered-multimap", +] [[package]] name = "rust_decimal" @@ -6695,7 +6978,7 @@ version = "1.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a" dependencies = [ - "arrayvec 0.7.4", + "arrayvec", "num-traits 0.2.17", ] @@ -6874,8 +7157,9 @@ checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" dependencies = [ "dyn-clone", "schemars_derive", - "serde 1.0.193", + "serde", "serde_json", + "url", ] [[package]] @@ -6968,6 +7252,12 @@ dependencies = [ "libc", ] +[[package]] +name = "self_cell" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" + [[package]] name = "semver" version = "0.11.0" @@ -6983,7 +7273,7 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" dependencies = [ - "serde 1.0.193", + "serde", ] [[package]] @@ -7009,38 +7299,20 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" - -[[package]] -name = "serde" -version = "1.0.193" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] -[[package]] -name = "serde-hjson" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a3a4e0ea8a88553209f6cc6cfe8724ecad22e1acf372793c27d995290fe74f8" -dependencies = [ - "lazy_static", - "num-traits 0.1.43", - "regex", - "serde 0.8.23", -] - [[package]] name = "serde-json-wasm" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e9213a07d53faa0b8dd81e767a54a8188a242fdb9be99ab75ec576a774bfdd7" dependencies = [ - "serde 1.0.193", + "serde", ] [[package]] @@ -7049,7 +7321,18 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f05da0d153dd4595bdffd5099dc0e9ce425b205ee648eb93437ff7302af8c9a5" dependencies = [ - "serde 1.0.193", + "serde", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", ] [[package]] @@ -7058,7 +7341,7 @@ version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" dependencies = [ - "serde 1.0.193", + "serde", ] [[package]] @@ -7068,14 +7351,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" dependencies = [ "half", - "serde 1.0.193", + "serde", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", @@ -7101,7 +7384,7 @@ checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", - "serde 1.0.193", + "serde", ] [[package]] @@ -7121,7 +7404,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" dependencies = [ - "serde 1.0.193", + "serde", ] [[package]] @@ -7133,7 +7416,7 @@ dependencies = [ "form_urlencoded", "itoa", "ryu", - "serde 1.0.193", + "serde", ] [[package]] @@ -7144,10 +7427,23 @@ checksum = "ef8099d3df28273c99a1728190c7a9f19d444c941044f64adf986bee7ec53051" dependencies = [ "dtoa", "linked-hash-map", - "serde 1.0.193", + "serde", "yaml-rust", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.2.6", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "serdect" version = "0.2.0" @@ -7155,7 +7451,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" dependencies = [ "base16ct", - "serde 1.0.193", + "serde", ] [[package]] @@ -7212,6 +7508,16 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shared-buffer" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16" +dependencies = [ + "bytes", + "memmap2 0.6.2", +] + [[package]] name = "shlex" version = "1.3.0" @@ -7270,6 +7576,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "slice-group-by" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" + [[package]] name = "slip10_ed25519" version = "0.1.3" @@ -7293,16 +7605,16 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "smooth-operator" -version = "0.6.0" -source = "git+https://github.com/heliaxdev/smooth-operator?tag=v0.6.0#1e9e2382dd6c053f54418db836f7f03143fcd2f3" +version = "0.7.0" +source = "git+https://github.com/heliaxdev/smooth-operator?tag=v0.7.0#0e182707f5e5bb9c6e0efa2d235dc9efd715d0a1" dependencies = [ "smooth-operator-impl", ] [[package]] name = "smooth-operator-impl" -version = "0.6.0" -source = "git+https://github.com/heliaxdev/smooth-operator?tag=v0.6.0#1e9e2382dd6c053f54418db836f7f03143fcd2f3" +version = "0.7.0" +source = "git+https://github.com/heliaxdev/smooth-operator?tag=v0.7.0#0e182707f5e5bb9c6e0efa2d235dc9efd715d0a1" dependencies = [ "proc-macro2", "quote", @@ -7375,6 +7687,9 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] [[package]] name = "spki" @@ -7595,7 +7910,7 @@ dependencies = [ "once_cell", "prost 0.12.3", "prost-types 0.12.3", - "serde 1.0.193", + "serde", "serde_bytes", "serde_json", "serde_repr", @@ -7625,7 +7940,7 @@ dependencies = [ "prost 0.12.3", "prost-types 0.12.3", "ripemd", - "serde 1.0.193", + "serde", "serde_bytes", "serde_json", "serde_repr", @@ -7645,7 +7960,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e07b383dc8780ebbec04cfb603f3fdaba6ea6663d8dd861425b1ffa7761fe90d" dependencies = [ "flex-error", - "serde 1.0.193", + "serde", "serde_json", "tendermint 0.36.0", "toml 0.8.2", @@ -7664,7 +7979,7 @@ dependencies = [ "flex-error", "futures", "regex", - "serde 1.0.193", + "serde", "serde_cbor", "serde_derive", "serde_json", @@ -7685,7 +8000,7 @@ checksum = "4216e487165e5dbd7af79952eaa0d5f06c5bde861eb76c690acd7f2d2a19395c" dependencies = [ "derive_more", "flex-error", - "serde 1.0.193", + "serde", "tendermint 0.36.0", "time", ] @@ -7702,7 +8017,7 @@ dependencies = [ "num-traits 0.2.17", "prost 0.12.3", "prost-types 0.12.3", - "serde 1.0.193", + "serde", "serde_bytes", "subtle-encoding", "time", @@ -7718,7 +8033,7 @@ dependencies = [ "flex-error", "prost 0.12.3", "prost-types 0.12.3", - "serde 1.0.193", + "serde", "serde_bytes", "subtle-encoding", "time", @@ -7734,13 +8049,13 @@ dependencies = [ "bytes", "flex-error", "futures", - "getrandom 0.2.11", + "getrandom 0.2.15", "peg", "pin-project", "rand 0.8.5", "reqwest", "semver 1.0.20", - "serde 1.0.193", + "serde", "serde_bytes", "serde_json", "subtle", @@ -7765,7 +8080,7 @@ checksum = "b233cec83c56c413ccc346af866cb9206a14d468fcecf0255080107bc9b103c0" dependencies = [ "ed25519-consensus", "gumdrop", - "serde 1.0.193", + "serde", "serde_json", "simple-error", "tempfile", @@ -7882,7 +8197,7 @@ dependencies = [ "deranged", "itoa", "powerfmt", - "serde 1.0.193", + "serde", "time-core", "time-macros", ] @@ -7947,7 +8262,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ - "serde 1.0.193", + "serde", "serde_json", ] @@ -8096,7 +8411,19 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "serde 1.0.193", + "serde", +] + +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.19.15", ] [[package]] @@ -8105,7 +8432,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" dependencies = [ - "serde 1.0.193", + "serde", "serde_spanned", "toml_datetime", "toml_edit 0.20.2", @@ -8117,7 +8444,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ - "serde 1.0.193", + "serde", ] [[package]] @@ -8126,7 +8453,9 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.6", + "serde", + "serde_spanned", "toml_datetime", "winnow 0.5.25", ] @@ -8137,8 +8466,8 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.1.0", - "serde 1.0.193", + "indexmap 2.2.6", + "serde", "serde_spanned", "toml_datetime", "winnow 0.5.25", @@ -8318,7 +8647,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" dependencies = [ - "serde 1.0.193", + "serde", "tracing-core", ] @@ -8332,7 +8661,7 @@ dependencies = [ "nu-ansi-term", "once_cell", "regex", - "serde 1.0.193", + "serde", "serde_json", "sharded-slab", "thread_local", @@ -8468,6 +8797,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + [[package]] name = "unicode-width" version = "0.1.11" @@ -8490,6 +8825,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.7.1" @@ -8511,6 +8852,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -8537,8 +8879,8 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom 0.2.11", - "serde 1.0.193", + "getrandom 0.2.15", + "serde", ] [[package]] @@ -8565,6 +8907,17 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "visibility" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3fd98999db9227cf28e59d83e1f120f42bc233d4b152e8fab9bc87d5bb1e0f8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + [[package]] name = "wait-timeout" version = "0.2.0" @@ -8613,7 +8966,7 @@ dependencies = [ "pin-project", "rustls-pemfile", "scoped-tls", - "serde 1.0.193", + "serde", "serde_json", "serde_urlencoded", "tokio", @@ -8722,46 +9075,38 @@ dependencies = [ [[package]] name = "wasmer" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1852ee143a2d8143265bfee017c43bf690702d6c2b45a763a2f13e669f5b7ec" dependencies = [ + "bytes", "cfg-if", + "derivative", "indexmap 1.9.3", "js-sys", - "loupe", "more-asserts", + "rustc-demangle", + "serde", + "serde-wasm-bindgen", + "shared-buffer", "target-lexicon", "thiserror", + "tracing", "wasm-bindgen", - "wasmer-artifact", "wasmer-compiler", "wasmer-compiler-cranelift", "wasmer-derive", - "wasmer-engine", - "wasmer-engine-dylib", - "wasmer-engine-universal", "wasmer-types", "wasmer-vm", "wat", "winapi", ] -[[package]] -name = "wasmer-artifact" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" -dependencies = [ - "enumset", - "loupe", - "thiserror", - "wasmer-compiler", - "wasmer-types", -] - [[package]] name = "wasmer-cache" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092ca4da29a7320b99c9b6660dfbde055f4db0a71c1273860272c213b2f7e019" dependencies = [ "blake3", "hex", @@ -8771,31 +9116,42 @@ dependencies = [ [[package]] name = "wasmer-compiler" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4f157d715f3bb60c2c9d7b9e48299a30e9209f87f4484f79f9cd586b40b6ee" dependencies = [ + "backtrace", + "bytes", + "cfg-if", + "enum-iterator", "enumset", - "loupe", + "lazy_static", + "leb128", + "memmap2 0.5.10", + "more-asserts", + "region", "rkyv", - "serde 1.0.193", - "serde_bytes", + "self_cell", + "shared-buffer", "smallvec", - "target-lexicon", "thiserror", "wasmer-types", - "wasmparser 0.83.0", + "wasmer-vm", + "wasmparser 0.121.2", + "winapi", + "xxhash-rust", ] [[package]] name = "wasmer-compiler-cranelift" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb457e66b77ca2188fbbd6c2056ec6e8ccb4bddee73e60ba9d39733d7b2e8068" dependencies = [ "cranelift-codegen", "cranelift-entity", "cranelift-frontend", "gimli 0.26.2", - "loupe", "more-asserts", "rayon", "smallvec", @@ -8803,185 +9159,128 @@ dependencies = [ "tracing", "wasmer-compiler", "wasmer-types", - "wasmer-vm", ] [[package]] name = "wasmer-compiler-singlepass" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a3196b2a87d5c6692021ece7ad1cf7fe43b7f1669c3aba1b8ccfcebe660070c" dependencies = [ "byteorder", "dynasm", "dynasmrt", + "enumset", "gimli 0.26.2", "lazy_static", - "loupe", "more-asserts", "rayon", "smallvec", "wasmer-compiler", "wasmer-types", - "wasmer-vm", -] - -[[package]] -name = "wasmer-derive" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "wasmer-engine" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" -dependencies = [ - "backtrace", - "enumset", - "lazy_static", - "loupe", - "memmap2", - "more-asserts", - "rustc-demangle", - "serde 1.0.193", - "serde_bytes", - "target-lexicon", - "thiserror", - "wasmer-artifact", - "wasmer-compiler", - "wasmer-types", - "wasmer-vm", -] - -[[package]] -name = "wasmer-engine-dylib" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" -dependencies = [ - "cfg-if", - "enum-iterator", - "enumset", - "leb128", - "libloading", - "loupe", - "object 0.28.4", - "rkyv", - "serde 1.0.193", - "tempfile", - "tracing", - "wasmer-artifact", - "wasmer-compiler", - "wasmer-engine", - "wasmer-object", - "wasmer-types", - "wasmer-vm", - "which", ] [[package]] -name = "wasmer-engine-universal" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" -dependencies = [ - "cfg-if", - "enumset", - "leb128", - "loupe", - "region", - "rkyv", - "wasmer-compiler", - "wasmer-engine", - "wasmer-engine-universal-artifact", - "wasmer-types", - "wasmer-vm", - "winapi", -] - -[[package]] -name = "wasmer-engine-universal-artifact" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +name = "wasmer-config" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a0f70c177b1c5062cfe0f5308c3317751796fef9403c22a0cd7b4cacd4ccd8" dependencies = [ - "enum-iterator", - "enumset", - "loupe", - "rkyv", + "anyhow", + "bytesize", + "derive_builder", + "hex", + "indexmap 2.2.6", + "schemars", + "semver 1.0.20", + "serde", + "serde_cbor", + "serde_json", + "serde_yaml 0.9.34+deprecated", "thiserror", - "wasmer-artifact", - "wasmer-compiler", - "wasmer-types", + "toml 0.8.2", + "url", ] [[package]] -name = "wasmer-object" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +name = "wasmer-derive" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cd5732ff64370e98986f9753cce13b91cc9d3c4b649e31b0d08d5db69164ea" dependencies = [ - "object 0.28.4", - "thiserror", - "wasmer-compiler", - "wasmer-types", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] name = "wasmer-types" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c890fd0dbda40df03977b899d1ad7113deba3c225f2cc7b88deb7633044d3e07" dependencies = [ - "backtrace", + "bytecheck", "enum-iterator", + "enumset", + "getrandom 0.2.15", + "hex", "indexmap 1.9.3", - "loupe", + "more-asserts", "rkyv", - "serde 1.0.193", + "sha2 0.10.8", + "target-lexicon", "thiserror", + "webc", + "xxhash-rust", ] [[package]] name = "wasmer-vm" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e0dc60ab800cf0bd44e2d35d88422d256d2470b00c72778f91bfb826c42dbd0" dependencies = [ "backtrace", "cc", "cfg-if", "corosensei", + "crossbeam-queue", + "dashmap", + "derivative", "enum-iterator", + "fnv", "indexmap 1.9.3", "lazy_static", "libc", - "loupe", "mach", - "memoffset 0.6.5", + "memoffset 0.9.0", "more-asserts", "region", - "rkyv", "scopeguard", - "serde 1.0.193", "thiserror", - "wasmer-artifact", "wasmer-types", "winapi", ] [[package]] name = "wasmparser" -version = "0.83.0" +version = "0.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a" +checksum = "29e3ac9b780c7dda0cac7a52a5d6d2d6707cc6e3451c9db209b6c758f40d7acb" +dependencies = [ + "indexmap 1.9.3", + "semver 1.0.20", +] [[package]] name = "wasmparser" -version = "0.107.0" +version = "0.121.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29e3ac9b780c7dda0cac7a52a5d6d2d6707cc6e3451c9db209b6c758f40d7acb" +checksum = "9dbe55c8f9d0dbd25d9447a5a889ff90c0cc3feaa7395310d3d826b2c703eaab" dependencies = [ - "indexmap 1.9.3", + "bitflags 2.5.0", + "indexmap 2.2.6", "semver 1.0.20", ] @@ -9030,6 +9329,35 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webc" +version = "6.0.0-rc1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fc686c7b43c9bc630a499f6ae1f0a4c4bd656576a53ae8a147b0cc9bc983ad" +dependencies = [ + "anyhow", + "base64 0.21.7", + "bytes", + "cfg-if", + "document-features", + "flate2", + "indexmap 1.9.3", + "libc", + "once_cell", + "semver 1.0.20", + "serde", + "serde_cbor", + "serde_json", + "sha2 0.10.8", + "shared-buffer", + "tar", + "tempfile", + "thiserror", + "toml 0.7.8", + "url", + "wasmer-config", +] + [[package]] name = "webpki-roots" version = "0.25.3" @@ -9394,6 +9722,12 @@ dependencies = [ "libc", ] +[[package]] +name = "xxhash-rust" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927da81e25be1e1a2901d59b81b37dd2efd1fc9c9345a55007f09bf5a2d3ee03" + [[package]] name = "yaml-rust" version = "0.4.5" @@ -9403,6 +9737,17 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "yaml-rust2" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8902160c4e6f2fb145dbe9d6760a75e3c9522d8bf796ed7047c85919ac7115f8" +dependencies = [ + "arraydeque", + "encoding_rs", + "hashlink", +] + [[package]] name = "yansi" version = "0.5.1" @@ -9418,6 +9763,26 @@ dependencies = [ "nonempty", ] +[[package]] +name = "zerocopy" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + [[package]] name = "zeroize" version = "1.7.0" diff --git a/Cargo.toml b/Cargo.toml index 0d1f58a577..6821a58e31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,7 @@ keywords = ["blockchain", "privacy", "crypto", "protocol", "network"] license = "GPL-3.0" readme = "README.md" repository = "https://github.com/anoma/namada" -version = "0.37.0" +version = "0.39.0" [workspace.dependencies] ark-bls12-381 = {version = "0.3"} @@ -86,7 +86,7 @@ clap = "4.3.4" clru = {git = "https://github.com/marmeladema/clru-rs.git", rev = "71ca566"} color-eyre = "0.6.2" concat-idents = "1.1.2" -config = "0.11.0" +config = { git = "https://github.com/mehcode/config-rs.git", rev = "e3c1d0b452639478662a44f15ef6d5b6d969bf9b" } data-encoding = "2.3.2" derivation-path = "0.2.0" derivative = "2.2.0" @@ -125,8 +125,8 @@ libc = "0.2.97" libloading = "0.7.2" linkme = "0.3.24" # branch = "main" -masp_primitives = { git = "https://github.com/anoma/masp", rev = "3aacc707c5948e7423589ac617305448bead9842" } -masp_proofs = { git = "https://github.com/anoma/masp", rev = "3aacc707c5948e7423589ac617305448bead9842", default-features = false, features = ["local-prover"] } +masp_primitives = { git = "https://github.com/anoma/masp", rev = "4ede1c42d76d6348af8224bc8bfac4404321fe82" } +masp_proofs = { git = "https://github.com/anoma/masp", rev = "4ede1c42d76d6348af8224bc8bfac4404321fe82", default-features = false, features = ["local-prover"] } num256 = "0.3.5" num_cpus = "1.13.0" num-derive = "0.4" @@ -161,7 +161,7 @@ sha2 = "0.9.3" sha2-const = "0.1.2" signal-hook = "0.3.9" slip10_ed25519 = "0.1.3" -smooth-operator = {git = "https://github.com/heliaxdev/smooth-operator", tag = "v0.6.0"} +smooth-operator = {git = "https://github.com/heliaxdev/smooth-operator", tag = "v0.7.0"} # sysinfo with disabled multithread feature sysinfo = {version = "0.27.8", default-features = false} tar = "0.4.37" @@ -189,13 +189,18 @@ tracing-log = "0.2.0" tracing-subscriber = {version = "0.3.7", default-features = false, features = ["env-filter", "fmt"]} wasmparser = "0.107.0" wasm-instrument = {version = "0.4.0", features = ["sign_ext"]} -wasmer = {git = "https://github.com/heliaxdev/wasmer", rev = "255054f7f58b7b4a525f2fee6b9b86422d1ca15b"} -wasmer-compiler-singlepass = { git = "https://github.com/heliaxdev/wasmer", rev = "255054f7f58b7b4a525f2fee6b9b86422d1ca15b" } -wasmer-engine-universal = { git = "https://github.com/heliaxdev/wasmer", rev = "255054f7f58b7b4a525f2fee6b9b86422d1ca15b" } +wasmer = "4.3.1" +wasmer-cache = "4.3.1" +wasmer-compiler-singlepass = "4.3.1" +wasmer-vm = "4.3.1" winapi = "0.3.9" yansi = "0.5.1" zeroize = { version = "1.5.5", features = ["zeroize_derive"] } +[patch.crates-io] +# Patch to the fork containing the correct personalization and basepoints for masp +reddsa = { git = "https://github.com/heliaxdev/reddsa", rev = "46d363b929e1b940688fa0c53d637e304a755185" } + [profile.release] lto = true opt-level = 3 diff --git a/about.toml b/about.toml index 87e4e8f4bf..0aa3e55d87 100644 --- a/about.toml +++ b/about.toml @@ -15,4 +15,5 @@ accepted = [ "Apache-2.0", "NOASSERTION", "Zlib", + "BSL-1.0", ] diff --git a/crates/apps/Cargo.toml b/crates/apps/Cargo.toml index 9faffd9963..d53b817861 100644 --- a/crates/apps/Cargo.toml +++ b/crates/apps/Cargo.toml @@ -61,9 +61,6 @@ tokio = {workspace = true, features = ["full"]} toml.workspace = true tracing-subscriber = { workspace = true, features = ["std", "json", "ansi", "tracing-log"]} tracing.workspace = true -zeroize.workspace = true -warp = "0.3.2" -bytes = "1.1.0" [target.'cfg(windows)'.dependencies] winapi.workspace = true diff --git a/crates/apps/src/bin/namada-node/cli.rs b/crates/apps/src/bin/namada-node/cli.rs index eb941e0d62..bca121ac6b 100644 --- a/crates/apps/src/bin/namada-node/cli.rs +++ b/crates/apps/src/bin/namada-node/cli.rs @@ -2,6 +2,7 @@ use eyre::{Context, Result}; use namada::core::time::{DateTimeUtc, Utc}; +use namada::sdk::migrations::ScheduledMigration; use namada_apps_lib::cli::cmds::TestGenesis; use namada_apps_lib::cli::{self, cmds}; use namada_apps_lib::config::{Action, ActionAtHeight, ValidatorLocalConfig}; @@ -17,7 +18,21 @@ pub fn main() -> Result<()> { let chain_ctx = ctx.take_chain_or_exit(); let wasm_dir = chain_ctx.wasm_dir(); sleep_until(args.start_time); - node::run(chain_ctx.config.ledger, wasm_dir); + let scheduled_migration = args.migration_path.map(|p| { + let hash = args.migration_hash.expect( + "Expected a hash to be provided along with the \ + migrations file.", + ); + let height = args.migration_height.expect( + "Expected a block height for the scheduled migration.", + ); + ScheduledMigration::from_path(p, hash, height).unwrap() + }); + node::run( + chain_ctx.config.ledger, + wasm_dir, + scheduled_migration, + ); } cmds::Ledger::RunUntil(cmds::LedgerRunUntil(args)) => { let mut chain_ctx = ctx.take_chain_or_exit(); @@ -25,7 +40,7 @@ pub fn main() -> Result<()> { sleep_until(args.time); chain_ctx.config.ledger.shell.action_at_height = Some(args.action_at_height); - node::run(chain_ctx.config.ledger, wasm_dir); + node::run(chain_ctx.config.ledger, wasm_dir, None); } cmds::Ledger::Reset(_) => { let chain_ctx = ctx.take_chain_or_exit(); @@ -69,7 +84,7 @@ pub fn main() -> Result<()> { ); // don't stop on panics let handle = std::thread::spawn(|| { - node::run(chain_ctx.config.ledger, wasm_dir) + node::run(chain_ctx.config.ledger, wasm_dir, None) }); _ = handle.join(); std::env::remove_var("NAMADA_INITIAL_HEIGHT"); diff --git a/crates/apps/src/bin/namada/cli.rs b/crates/apps/src/bin/namada/cli.rs index 9b97f2e761..ac56cd02d3 100644 --- a/crates/apps/src/bin/namada/cli.rs +++ b/crates/apps/src/bin/namada/cli.rs @@ -45,7 +45,10 @@ fn handle_command(cmd: cli::cmds::Namada, raw_sub_cmd: String) -> Result<()> { } cli::cmds::Namada::Client(_) | cli::cmds::Namada::TxCustom(_) - | cli::cmds::Namada::TxTransfer(_) + | cli::cmds::Namada::TxTransparentTransfer(_) + | cli::cmds::Namada::TxShieldedTransfer(_) + | cli::cmds::Namada::TxShieldingTransfer(_) + | cli::cmds::Namada::TxUnshieldingTransfer(_) | cli::cmds::Namada::TxIbcTransfer(_) | cli::cmds::Namada::TxUpdateAccount(_) | cli::cmds::Namada::TxRevealPk(_) diff --git a/crates/apps_lib/src/cli.rs b/crates/apps_lib/src/cli.rs index bef722d042..eadf78063a 100644 --- a/crates/apps_lib/src/cli.rs +++ b/crates/apps_lib/src/cli.rs @@ -57,7 +57,10 @@ pub mod cmds { // Inlined commands from the client. TxCustom(TxCustom), - TxTransfer(TxTransfer), + TxTransparentTransfer(TxTransparentTransfer), + TxShieldedTransfer(TxShieldedTransfer), + TxShieldingTransfer(TxShieldingTransfer), + TxUnshieldingTransfer(TxUnshieldingTransfer), TxIbcTransfer(TxIbcTransfer), TxUpdateAccount(TxUpdateAccount), TxInitProposal(TxInitProposal), @@ -74,7 +77,10 @@ pub mod cmds { .subcommand(EthBridgePool::def()) .subcommand(Ledger::def()) .subcommand(TxCustom::def()) - .subcommand(TxTransfer::def()) + .subcommand(TxTransparentTransfer::def()) + .subcommand(TxShieldedTransfer::def()) + .subcommand(TxShieldingTransfer::def()) + .subcommand(TxUnshieldingTransfer::def()) .subcommand(TxIbcTransfer::def()) .subcommand(TxUpdateAccount::def()) .subcommand(TxInitProposal::def()) @@ -91,7 +97,14 @@ pub mod cmds { let wallet = SubCmd::parse(matches).map(Self::Wallet); let ledger = SubCmd::parse(matches).map(Self::Ledger); let tx_custom = SubCmd::parse(matches).map(Self::TxCustom); - let tx_transfer = SubCmd::parse(matches).map(Self::TxTransfer); + let tx_transparent_transfer = + SubCmd::parse(matches).map(Self::TxTransparentTransfer); + let tx_shielded_transfer = + SubCmd::parse(matches).map(Self::TxShieldedTransfer); + let tx_shielding_transfer = + SubCmd::parse(matches).map(Self::TxShieldingTransfer); + let tx_unshielding_transfer = + SubCmd::parse(matches).map(Self::TxUnshieldingTransfer); let tx_ibc_transfer = SubCmd::parse(matches).map(Self::TxIbcTransfer); let tx_update_account = @@ -107,7 +120,10 @@ pub mod cmds { .or(wallet) .or(ledger) .or(tx_custom) - .or(tx_transfer) + .or(tx_transparent_transfer) + .or(tx_shielded_transfer) + .or(tx_shielding_transfer) + .or(tx_unshielding_transfer) .or(tx_ibc_transfer) .or(tx_update_account) .or(tx_init_proposal) @@ -218,7 +234,10 @@ pub mod cmds { app // Simple transactions .subcommand(TxCustom::def().display_order(1)) - .subcommand(TxTransfer::def().display_order(1)) + .subcommand(TxTransparentTransfer::def().display_order(1)) + .subcommand(TxShieldedTransfer::def().display_order(1)) + .subcommand(TxShieldingTransfer::def().display_order(1)) + .subcommand(TxUnshieldingTransfer::def().display_order(1)) .subcommand(TxIbcTransfer::def().display_order(1)) .subcommand(TxUpdateAccount::def().display_order(1)) .subcommand(TxInitAccount::def().display_order(1)) @@ -280,7 +299,14 @@ pub mod cmds { fn parse(matches: &ArgMatches) -> Option { use NamadaClientWithContext::*; let tx_custom = Self::parse_with_ctx(matches, TxCustom); - let tx_transfer = Self::parse_with_ctx(matches, TxTransfer); + let tx_transparent_transfer = + Self::parse_with_ctx(matches, TxTransparentTransfer); + let tx_shielded_transfer = + Self::parse_with_ctx(matches, TxShieldedTransfer); + let tx_shielding_transfer = + Self::parse_with_ctx(matches, TxShieldingTransfer); + let tx_unshielding_transfer = + Self::parse_with_ctx(matches, TxUnshieldingTransfer); let tx_ibc_transfer = Self::parse_with_ctx(matches, TxIbcTransfer); let tx_update_account = Self::parse_with_ctx(matches, TxUpdateAccount); @@ -356,7 +382,10 @@ pub mod cmds { let shielded_sync = Self::parse_with_ctx(matches, ShieldedSync); let utils = SubCmd::parse(matches).map(Self::WithoutContext); tx_custom - .or(tx_transfer) + .or(tx_transparent_transfer) + .or(tx_shielded_transfer) + .or(tx_shielding_transfer) + .or(tx_unshielding_transfer) .or(tx_ibc_transfer) .or(tx_update_account) .or(tx_init_account) @@ -443,7 +472,10 @@ pub mod cmds { pub enum NamadaClientWithContext { // Ledger cmds TxCustom(TxCustom), - TxTransfer(TxTransfer), + TxTransparentTransfer(TxTransparentTransfer), + TxShieldedTransfer(TxShieldedTransfer), + TxShieldingTransfer(TxShieldingTransfer), + TxUnshieldingTransfer(TxUnshieldingTransfer), TxIbcTransfer(TxIbcTransfer), QueryResult(QueryResult), TxUpdateAccount(TxUpdateAccount), @@ -862,6 +894,9 @@ pub mod cmds { // The `run` command is the default if no sub-command given .or(Some(Self::Run(LedgerRun(args::LedgerRun { start_time: None, + migration_path: None, + migration_hash: None, + migration_height: None, })))) }) } @@ -1246,21 +1281,90 @@ pub mod cmds { } #[derive(Clone, Debug)] - pub struct TxTransfer(pub args::TxTransfer); + pub struct TxTransparentTransfer( + pub args::TxTransparentTransfer, + ); + + impl SubCmd for TxTransparentTransfer { + const CMD: &'static str = "transparent-transfer"; - impl SubCmd for TxTransfer { + fn parse(matches: &ArgMatches) -> Option { + matches.subcommand_matches(Self::CMD).map(|matches| { + TxTransparentTransfer(args::TxTransparentTransfer::parse( + matches, + )) + }) + } + + fn def() -> App { + App::new(Self::CMD) + .about(wrap!("Send a transparent transfer transaction.")) + .add_args::>() + } + } + + #[derive(Clone, Debug)] + pub struct TxShieldedTransfer( + pub args::TxShieldedTransfer, + ); + + impl SubCmd for TxShieldedTransfer { const CMD: &'static str = "transfer"; fn parse(matches: &ArgMatches) -> Option { - matches - .subcommand_matches(Self::CMD) - .map(|matches| TxTransfer(args::TxTransfer::parse(matches))) + matches.subcommand_matches(Self::CMD).map(|matches| { + TxShieldedTransfer(args::TxShieldedTransfer::parse(matches)) + }) } fn def() -> App { App::new(Self::CMD) - .about(wrap!("Send a signed transfer transaction.")) - .add_args::>() + .about(wrap!("Send a shielded transfer transaction (from a shielded address to a shielded address).")) + .add_args::>() + } + } + + #[derive(Clone, Debug)] + pub struct TxShieldingTransfer( + pub args::TxShieldingTransfer, + ); + + impl SubCmd for TxShieldingTransfer { + const CMD: &'static str = "shield"; + + fn parse(matches: &ArgMatches) -> Option { + matches.subcommand_matches(Self::CMD).map(|matches| { + TxShieldingTransfer(args::TxShieldingTransfer::parse(matches)) + }) + } + + fn def() -> App { + App::new(Self::CMD) + .about(wrap!("Send a shielding transfer transaction (from a transparent address to a shielded address).")) + .add_args::>() + } + } + + #[derive(Clone, Debug)] + pub struct TxUnshieldingTransfer( + pub args::TxUnshieldingTransfer, + ); + + impl SubCmd for TxUnshieldingTransfer { + const CMD: &'static str = "unshield"; + + fn parse(matches: &ArgMatches) -> Option { + matches.subcommand_matches(Self::CMD).map(|matches| { + TxUnshieldingTransfer(args::TxUnshieldingTransfer::parse( + matches, + )) + }) + } + + fn def() -> App { + App::new(Self::CMD) + .about(wrap!("Send an unshielding transfer transaction (from a shielded address to a transparent address).")) + .add_args::>() } } @@ -2984,7 +3088,9 @@ pub mod args { use namada::core::time::DateTimeUtc; use namada::core::token; use namada::core::token::NATIVE_MAX_DECIMAL_PLACES; + use namada::hash::Hash; use namada::ibc::core::host::types::identifiers::{ChannelId, PortId}; + use namada::masp::MaspEpoch; use namada::tx::data::GasLimit; pub use namada_sdk::args::*; pub use namada_sdk::tx::{ @@ -2993,10 +3099,11 @@ pub mod args { TX_CHANGE_METADATA_WASM, TX_CLAIM_REWARDS_WASM, TX_DEACTIVATE_VALIDATOR_WASM, TX_IBC_WASM, TX_INIT_ACCOUNT_WASM, TX_INIT_PROPOSAL, TX_REACTIVATE_VALIDATOR_WASM, TX_REDELEGATE_WASM, - TX_RESIGN_STEWARD, TX_REVEAL_PK, TX_TRANSFER_WASM, TX_UNBOND_WASM, - TX_UNJAIL_VALIDATOR_WASM, TX_UPDATE_ACCOUNT_WASM, - TX_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL, TX_WITHDRAW_WASM, - VP_USER_WASM, + TX_RESIGN_STEWARD, TX_REVEAL_PK, TX_SHIELDED_TRANSFER_WASM, + TX_SHIELDING_TRANSFER_WASM, TX_TRANSPARENT_TRANSFER_WASM, + TX_UNBOND_WASM, TX_UNJAIL_VALIDATOR_WASM, TX_UNSHIELDING_TRANSFER_WASM, + TX_UPDATE_ACCOUNT_WASM, TX_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL, + TX_WITHDRAW_WASM, VP_USER_WASM, }; use namada_sdk::DEFAULT_GAS_LIMIT; @@ -3135,6 +3242,7 @@ pub mod args { arg("validator"); pub const HALT_ACTION: ArgFlag = flag("halt"); pub const HASH: Arg = arg("hash"); + pub const HASH_OPT: ArgOpt = arg_opt("hash"); pub const HASH_LIST: Arg = arg("hash-list"); pub const HD_DERIVATION_PATH: ArgDefault = arg_default("hd-path", DefaultFn(|| "default".to_string())); @@ -3160,10 +3268,12 @@ pub mod args { pub const LIST_FIND_ADDRESSES_ONLY: ArgFlag = flag("addr"); pub const LIST_FIND_KEYS_ONLY: ArgFlag = flag("keys"); pub const LOCALHOST: ArgFlag = flag("localhost"); + pub const MASP_EPOCH: ArgOpt = arg_opt("masp-epoch"); pub const MAX_COMMISSION_RATE_CHANGE: Arg = arg("max-commission-rate-change"); pub const MAX_ETH_GAS: ArgOpt = arg_opt("max_eth-gas"); pub const MEMO_OPT: ArgOpt = arg_opt("memo"); + pub const MIGRATION_PATH: ArgOpt = arg_opt("migration-path"); pub const MODE: ArgOpt = arg_opt("mode"); pub const NET_ADDRESS: Arg = arg("net-address"); pub const NAMADA_START_TIME: ArgOpt = arg_opt("time"); @@ -3177,6 +3287,8 @@ pub mod args { pub const OWNER: Arg = arg("owner"); pub const OWNER_OPT: ArgOpt = OWNER.opt(); pub const PATH: Arg = arg("path"); + pub const PATH_OPT: ArgOpt = arg_opt("path"); + pub const PAYMENT_ADDRESS_TARGET: Arg = arg("target"); pub const PORT_ID: ArgDefault = arg_default( "port-id", DefaultFn(|| PortId::from_str("transfer").unwrap()), @@ -3227,12 +3339,14 @@ pub mod args { pub const SIGNATURES: ArgMulti = arg_multi("signatures"); pub const SOURCE: Arg = arg("source"); pub const SOURCE_OPT: ArgOpt = SOURCE.opt(); + pub const SOURCE_VALIDATOR: Arg = arg("source-validator"); + pub const SPENDING_KEY_SOURCE: Arg = arg("source"); pub const SPENDING_KEYS: ArgMulti = arg_multi("spending-keys"); pub const STEWARD: Arg = arg("steward"); - pub const SOURCE_VALIDATOR: Arg = arg("source-validator"); pub const STORAGE_KEY: Arg = arg("storage-key"); pub const SUSPEND_ACTION: ArgFlag = flag("suspend"); + pub const TARGET: Arg = arg("target"); pub const TEMPLATES_PATH: Arg = arg("templates-path"); pub const TIMEOUT_HEIGHT: ArgOpt = arg_opt("timeout-height"); pub const TIMEOUT_SEC_OFFSET: ArgOpt = arg_opt("timeout-sec-offset"); @@ -3339,12 +3453,24 @@ pub mod args { #[derive(Clone, Debug)] pub struct LedgerRun { pub start_time: Option, + pub migration_path: Option, + pub migration_hash: Option, + pub migration_height: Option, } impl Args for LedgerRun { fn parse(matches: &ArgMatches) -> Self { let start_time = NAMADA_START_TIME.parse(matches); - Self { start_time } + let migration_path = PATH_OPT.parse(matches); + let migration_hash = HASH_OPT.parse(matches); + let migration_height = BLOCK_HEIGHT_OPT.parse(matches); + Self { + start_time, + migration_path, + migration_hash: migration_hash + .map(|h| Hash::try_from(h).unwrap()), + migration_height, + } } fn def(app: App) -> App { @@ -3356,6 +3482,33 @@ pub mod args { equivalent:\n2023-01-20T12:12:12Z\n2023-01-20 \ 12:12:12Z\n2023- 01-20T12: 12:12Z" ))) + .arg( + PATH_OPT + .def() + .requires(HASH_OPT.name) + .requires(BLOCK_HEIGHT_OPT.name) + .help(wrap!("Optional path to a migrations JSON file.")), + ) + .arg( + HASH_OPT + .def() + .requires(PATH_OPT.name) + .requires(BLOCK_HEIGHT_OPT.name) + .help(wrap!( + "Hash to verify contents of optionally provided \ + migrations file." + )), + ) + .arg( + BLOCK_HEIGHT_OPT + .def() + .requires(PATH_OPT.name) + .requires(HASH_OPT.name) + .help(wrap!( + "Height for which the optionally provided migration \ + should be executed." + )), + ) } } @@ -4175,19 +4328,21 @@ pub mod args { } } - impl CliToSdk> for TxTransfer { + impl CliToSdk> + for TxTransparentTransfer + { type Error = std::io::Error; fn to_sdk( self, ctx: &mut Context, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { let tx = self.tx.to_sdk(ctx)?; let chain_ctx = ctx.borrow_mut_chain_or_exit(); - Ok(TxTransfer:: { + Ok(TxTransparentTransfer:: { tx, - source: chain_ctx.get_cached(&self.source), + source: chain_ctx.get(&self.source), target: chain_ctx.get(&self.target), token: chain_ctx.get(&self.token), amount: self.amount, @@ -4196,14 +4351,14 @@ pub mod args { } } - impl Args for TxTransfer { + impl Args for TxTransparentTransfer { fn parse(matches: &ArgMatches) -> Self { let tx = Tx::parse(matches); - let source = TRANSFER_SOURCE.parse(matches); - let target = TRANSFER_TARGET.parse(matches); + let source = SOURCE.parse(matches); + let target = TARGET.parse(matches); let token = TOKEN.parse(matches); let amount = InputAmount::Unvalidated(AMOUNT.parse(matches)); - let tx_code_path = PathBuf::from(TX_TRANSFER_WASM); + let tx_code_path = PathBuf::from(TX_TRANSPARENT_TRANSFER_WASM); Self { tx, source, @@ -4216,15 +4371,193 @@ pub mod args { fn def(app: App) -> App { app.add_args::>() - .arg(TRANSFER_SOURCE.def().help(wrap!( + .arg(SOURCE.def().help(wrap!( "The source account address. The source's key may be used \ to produce the signature." ))) - .arg(TRANSFER_TARGET.def().help(wrap!( - "The target account address. The target's key may be used \ - to produce the signature." + .arg(TARGET.def().help(wrap!("The target account address."))) + .arg(TOKEN.def().help(wrap!("The token address."))) + .arg( + AMOUNT + .def() + .help(wrap!("The amount to transfer in decimal.")), + ) + } + } + + impl CliToSdk> for TxShieldedTransfer { + type Error = std::io::Error; + + fn to_sdk( + self, + ctx: &mut Context, + ) -> Result, Self::Error> { + let tx = self.tx.to_sdk(ctx)?; + let chain_ctx = ctx.borrow_mut_chain_or_exit(); + + Ok(TxShieldedTransfer:: { + tx, + source: chain_ctx.get_cached(&self.source), + target: chain_ctx.get(&self.target), + token: chain_ctx.get(&self.token), + amount: self.amount, + tx_code_path: self.tx_code_path.to_path_buf(), + }) + } + } + + impl Args for TxShieldedTransfer { + fn parse(matches: &ArgMatches) -> Self { + let tx = Tx::parse(matches); + let source = SPENDING_KEY_SOURCE.parse(matches); + let target = PAYMENT_ADDRESS_TARGET.parse(matches); + let token = TOKEN.parse(matches); + let amount = InputAmount::Unvalidated(AMOUNT.parse(matches)); + let tx_code_path = PathBuf::from(TX_SHIELDED_TRANSFER_WASM); + Self { + tx, + source, + target, + token, + amount, + tx_code_path, + } + } + + fn def(app: App) -> App { + app.add_args::>() + .arg( + SPENDING_KEY_SOURCE + .def() + .help(wrap!("The source shielded spending key.")), + ) + .arg( + PAYMENT_ADDRESS_TARGET + .def() + .help(wrap!("The shielded target account address.")), + ) + .arg(TOKEN.def().help(wrap!("The token address."))) + .arg( + AMOUNT + .def() + .help(wrap!("The amount to transfer in decimal.")), + ) + } + } + + impl CliToSdk> for TxShieldingTransfer { + type Error = std::io::Error; + + fn to_sdk( + self, + ctx: &mut Context, + ) -> Result, Self::Error> { + let tx = self.tx.to_sdk(ctx)?; + let chain_ctx = ctx.borrow_mut_chain_or_exit(); + + Ok(TxShieldingTransfer:: { + tx, + source: chain_ctx.get(&self.source), + target: chain_ctx.get(&self.target), + token: chain_ctx.get(&self.token), + amount: self.amount, + tx_code_path: self.tx_code_path.to_path_buf(), + }) + } + } + + impl Args for TxShieldingTransfer { + fn parse(matches: &ArgMatches) -> Self { + let tx = Tx::parse(matches); + let source = SOURCE.parse(matches); + let target = PAYMENT_ADDRESS_TARGET.parse(matches); + let token = TOKEN.parse(matches); + let amount = InputAmount::Unvalidated(AMOUNT.parse(matches)); + let tx_code_path = PathBuf::from(TX_SHIELDING_TRANSFER_WASM); + Self { + tx, + source, + target, + token, + amount, + tx_code_path, + } + } + + fn def(app: App) -> App { + app.add_args::>() + .arg(SOURCE.def().help(wrap!( + "The transparent source account address. The source's key \ + will be used to produce the signature." ))) - .arg(TOKEN.def().help(wrap!("The transfer token."))) + .arg( + PAYMENT_ADDRESS_TARGET + .def() + .help(wrap!("The target shielded account address.")), + ) + .arg(TOKEN.def().help(wrap!("The token address."))) + .arg( + AMOUNT + .def() + .help(wrap!("The amount to transfer in decimal.")), + ) + } + } + + impl CliToSdk> + for TxUnshieldingTransfer + { + type Error = std::io::Error; + + fn to_sdk( + self, + ctx: &mut Context, + ) -> Result, Self::Error> { + let tx = self.tx.to_sdk(ctx)?; + let chain_ctx = ctx.borrow_mut_chain_or_exit(); + + Ok(TxUnshieldingTransfer:: { + tx, + source: chain_ctx.get_cached(&self.source), + target: chain_ctx.get(&self.target), + token: chain_ctx.get(&self.token), + amount: self.amount, + tx_code_path: self.tx_code_path.to_path_buf(), + }) + } + } + + impl Args for TxUnshieldingTransfer { + fn parse(matches: &ArgMatches) -> Self { + let tx = Tx::parse(matches); + let source = SPENDING_KEY_SOURCE.parse(matches); + let target = TARGET.parse(matches); + let token = TOKEN.parse(matches); + let amount = InputAmount::Unvalidated(AMOUNT.parse(matches)); + let tx_code_path = PathBuf::from(TX_UNSHIELDING_TRANSFER_WASM); + Self { + tx, + source, + target, + token, + amount, + tx_code_path, + } + } + + fn def(app: App) -> App { + app.add_args::>() + .arg( + SPENDING_KEY_SOURCE + .def() + .help(wrap!("The source shielded spending key.")), + ) + .arg( + TARGET + .def() + .help(wrap!("The transparent target account address.")), + ) + .arg(TOKEN.def().help(wrap!("The token address."))) .arg( AMOUNT .def() @@ -5458,7 +5791,7 @@ pub mod args { fn parse(matches: &ArgMatches) -> Self { let query = Query::parse(matches); let token = TOKEN_OPT.parse(matches); - let epoch = EPOCH.parse(matches); + let epoch = MASP_EPOCH.parse(matches); Self { query, epoch, @@ -5468,11 +5801,9 @@ pub mod args { fn def(app: App) -> App { app.add_args::>() - .arg( - EPOCH.def().help(wrap!( - "The epoch for which to query conversions." - )), - ) + .arg(MASP_EPOCH.def().help(wrap!( + "The masp epoch for which to query conversions." + ))) .arg(TOKEN_OPT.def().help(wrap!( "The token address for which to query conversions." ))) @@ -6032,7 +6363,7 @@ pub mod args { impl Args for ShieldedSync { fn parse(matches: &ArgMatches) -> Self { - let ledger_address = LEDGER_ADDRESS.parse(matches); + let ledger_address = CONFIG_RPC_LEDGER_ADDRESS.parse(matches); let batch_size = BATCH_SIZE_OPT.parse(matches); let start_query_height = BLOCK_HEIGHT_FROM_OPT.parse(matches); let last_query_height = BLOCK_HEIGHT_TO_OPT.parse(matches); @@ -6049,7 +6380,7 @@ pub mod args { } fn def(app: App) -> App { - app.arg(LEDGER_ADDRESS.def().help(LEDGER_ADDRESS_ABOUT)) + app.arg(CONFIG_RPC_LEDGER_ADDRESS.def().help(LEDGER_ADDRESS_ABOUT)) .arg(BATCH_SIZE_OPT.def().help(wrap!( "Optional batch size which determines how many txs to \ fetch before caching locally. Default is 1." @@ -6083,7 +6414,7 @@ pub mod args { let chain_ctx = ctx.borrow_mut_chain_or_exit(); Ok(ShieldedSync { - ledger_address: self.ledger_address, + ledger_address: chain_ctx.get(&self.ledger_address), batch_size: self.batch_size, start_query_height: self.start_query_height, last_query_height: self.last_query_height, @@ -6426,6 +6757,7 @@ pub mod args { type Data = PathBuf; type EthereumAddress = String; type Keypair = WalletKeypair; + type PaymentAddress = WalletPaymentAddr; type PublicKey = WalletPublicKey; type SpendingKey = WalletSpendingKey; type TendermintAddress = tendermint_rpc::Url; diff --git a/crates/apps_lib/src/cli/client.rs b/crates/apps_lib/src/cli/client.rs index 03f69c3f3e..79103a9f3d 100644 --- a/crates/apps_lib/src/cli/client.rs +++ b/crates/apps_lib/src/cli/client.rs @@ -52,7 +52,7 @@ impl CliApi { ) } } - Sub::TxTransfer(TxTransfer(args)) => { + Sub::TxTransparentTransfer(TxTransparentTransfer(args)) => { let chain_ctx = ctx.borrow_mut_chain_or_exit(); let ledger_address = chain_ctx.get(&args.tx.ledger_address); @@ -62,7 +62,43 @@ impl CliApi { client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx)?; let namada = ctx.to_sdk(client, io); - tx::submit_transfer(&namada, args).await?; + tx::submit_transparent_transfer(&namada, args).await?; + } + Sub::TxShieldedTransfer(TxShieldedTransfer(args)) => { + let chain_ctx = ctx.borrow_mut_chain_or_exit(); + let ledger_address = + chain_ctx.get(&args.tx.ledger_address); + let client = client.unwrap_or_else(|| { + C::from_tendermint_address(&ledger_address) + }); + client.wait_until_node_is_synced(&io).await?; + let args = args.to_sdk(&mut ctx)?; + let namada = ctx.to_sdk(client, io); + tx::submit_shielded_transfer(&namada, args).await?; + } + Sub::TxShieldingTransfer(TxShieldingTransfer(args)) => { + let chain_ctx = ctx.borrow_mut_chain_or_exit(); + let ledger_address = + chain_ctx.get(&args.tx.ledger_address); + let client = client.unwrap_or_else(|| { + C::from_tendermint_address(&ledger_address) + }); + client.wait_until_node_is_synced(&io).await?; + let args = args.to_sdk(&mut ctx)?; + let namada = ctx.to_sdk(client, io); + tx::submit_shielding_transfer(&namada, args).await?; + } + Sub::TxUnshieldingTransfer(TxUnshieldingTransfer(args)) => { + let chain_ctx = ctx.borrow_mut_chain_or_exit(); + let ledger_address = + chain_ctx.get(&args.tx.ledger_address); + let client = client.unwrap_or_else(|| { + C::from_tendermint_address(&ledger_address) + }); + client.wait_until_node_is_synced(&io).await?; + let args = args.to_sdk(&mut ctx)?; + let namada = ctx.to_sdk(client, io); + tx::submit_unshielding_transfer(&namada, args).await?; } Sub::TxIbcTransfer(TxIbcTransfer(args)) => { let chain_ctx = ctx.borrow_mut_chain_or_exit(); @@ -301,12 +337,12 @@ impl CliApi { .await?; } Sub::ShieldedSync(ShieldedSync(args)) => { + let args = args.to_sdk(&mut ctx)?; + let chain_ctx = ctx.take_chain_or_exit(); let client = client.unwrap_or_else(|| { C::from_tendermint_address(&args.ledger_address) }); client.wait_until_node_is_synced(&io).await?; - let args = args.to_sdk(&mut ctx)?; - let chain_ctx = ctx.take_chain_or_exit(); let vks = chain_ctx .wallet .get_viewing_keys() diff --git a/crates/apps_lib/src/cli/context.rs b/crates/apps_lib/src/cli/context.rs index 2fad9721c5..db94b7ad9a 100644 --- a/crates/apps_lib/src/cli/context.rs +++ b/crates/apps_lib/src/cli/context.rs @@ -9,9 +9,9 @@ use color_eyre::eyre::Result; use namada::core::address::{Address, InternalAddress}; use namada::core::chain::ChainId; use namada::core::ethereum_events::EthAddress; -use namada::core::ibc::{is_ibc_denom, is_nft_trace}; use namada::core::key::*; use namada::core::masp::*; +use namada::ibc::{is_ibc_denom, is_nft_trace}; use namada::io::Io; use namada::ledger::ibc::storage::ibc_token; use namada_sdk::masp::fs::FsShieldedUtils; @@ -26,6 +26,9 @@ use crate::config::{genesis, Config}; use crate::wallet::CliWalletUtils; use crate::{wallet, wasm_loader}; +/// Skip errors encountered while parsing raw string values. +struct SkipErr; + /// Env. var to set wasm directory pub const ENV_VAR_WASM_DIR: &str = "NAMADA_WASM_DIR"; @@ -423,7 +426,6 @@ impl ArgFromContext for Address { ctx: &ChainContext, raw: impl AsRef, ) -> Result { - struct Skip; let raw = raw.as_ref(); // An address can be either raw (bech32m encoding) FromStr::from_str(raw) @@ -435,9 +437,9 @@ impl ArgFromContext for Address { .map(|addr| { Address::Internal(InternalAddress::Erc20(addr)) }) - .map_err(|_| Skip) + .map_err(|_| SkipErr) }) - .unwrap_or(Err(Skip)) + .unwrap_or(Err(SkipErr)) }) // An IBC token .or_else(|_| { @@ -451,19 +453,19 @@ impl ArgFromContext for Address { let ibc_denom = format!("{trace_path}/{base_token}"); ibc_token(ibc_denom) }) - .ok_or(Skip) + .ok_or(SkipErr) }) .or_else(|_| { is_nft_trace(raw) .map(|(_, _, _)| ibc_token(raw)) - .ok_or(Skip) + .ok_or(SkipErr) }) // Or it can be an alias that may be found in the wallet .or_else(|_| { ctx.wallet .find_address(raw) .map(|x| x.into_owned()) - .ok_or(Skip) + .ok_or(SkipErr) }) .map_err(|_| format!("Unknown address {raw}")) } @@ -526,18 +528,37 @@ impl ArgFromContext for common::PublicKey { raw: impl AsRef, ) -> Result { let raw = raw.as_ref(); - // A public key can be either a raw public key in hex string - FromStr::from_str(raw).or_else(|_parse_err| { - // Or it can be a public key hash in hex string - FromStr::from_str(raw) - .map(|pkh: PublicKeyHash| { - ctx.wallet.find_public_key_by_pkh(&pkh).unwrap() - }) - // Or it can be an alias that may be found in the wallet - .or_else(|_parse_err| { - ctx.wallet.find_public_key(raw).map_err(|x| x.to_string()) - }) - }) + // A public key can either be a bech32 encoded (tpknam1...) string + FromStr::from_str(raw) + .map_err(|_| SkipErr) + // Or it can be a hex encoded public key hash + .or_else(|SkipErr| { + FromStr::from_str(raw).map_err(|_| SkipErr).and_then( + |pkh: PublicKeyHash| { + ctx.wallet + .find_public_key_by_pkh(&pkh) + .map_err(|_| SkipErr) + }, + ) + }) + // Or it can be an alias that may be found in the wallet + .or_else(|SkipErr| { + ctx.wallet.find_public_key(raw).map_err(|_| SkipErr) + }) + // Or it can be an implicit address + .or_else(|SkipErr| { + let Address::Implicit(implicit_addr) = + Address::decode(raw).map_err(|_| SkipErr)? + else { + return Err(SkipErr); + }; + ctx.wallet + .find_public_key_from_implicit_addr(&implicit_addr) + .map_err(|_| SkipErr) + }) + .map_err(|SkipErr| { + format!("Couldn't look-up public key associated with {raw:?}") + }) } } diff --git a/crates/apps_lib/src/client/rpc.rs b/crates/apps_lib/src/client/rpc.rs index ac8f98d3b2..941fa83444 100644 --- a/crates/apps_lib/src/client/rpc.rs +++ b/crates/apps_lib/src/client/rpc.rs @@ -32,6 +32,7 @@ use namada::ledger::parameters::{storage as param_storage, EpochDuration}; use namada::ledger::pos::types::{CommissionPair, Slash}; use namada::ledger::pos::PosParams; use namada::ledger::queries::RPC; +use namada::masp::MaspEpoch; use namada::proof_of_stake::types::{ ValidatorState, ValidatorStateInfo, WeightedValidator, }; @@ -72,6 +73,13 @@ pub async fn query_and_print_epoch(context: &impl Namada) -> Epoch { epoch } +/// Query and print the masp epoch of the last committed block +pub async fn query_and_print_masp_epoch(context: &impl Namada) -> MaspEpoch { + let epoch = rpc::query_masp_epoch(context.client()).await.unwrap(); + display_line!(context.io(), "Last committed masp epoch: {}", epoch); + epoch +} + /// Query and print some information to help discern when the next epoch will /// begin. pub async fn query_and_print_next_epoch_info(context: &impl Namada) { @@ -372,7 +380,7 @@ async fn query_shielded_balance( } // The epoch is required to identify timestamped tokens - let epoch = query_and_print_epoch(context).await; + let masp_epoch = query_and_print_masp_epoch(context).await; // Query the token alias in the wallet for pretty printing token balances let token_alias = lookup_token_alias(context, &token, &MASP).await; @@ -400,7 +408,7 @@ async fn query_shielded_balance( context.client(), context.io(), &viewing_key, - epoch, + masp_epoch, ) .await .unwrap() @@ -412,7 +420,7 @@ async fn query_shielded_balance( }; let total_balance = shielded - .decode_combine_sum_to_epoch(context.client(), balance, epoch) + .decode_combine_sum_to_epoch(context.client(), balance, masp_epoch) .await .0 .get(&token); @@ -1765,7 +1773,7 @@ pub async fn query_conversion( Address, token::Denomination, MaspDigitPos, - Epoch, + MaspEpoch, I128Sum, MerklePath, )> { diff --git a/crates/apps_lib/src/client/tx.rs b/crates/apps_lib/src/client/tx.rs index f7a2a182c6..80e6e52e09 100644 --- a/crates/apps_lib/src/client/tx.rs +++ b/crates/apps_lib/src/client/tx.rs @@ -739,18 +739,45 @@ pub async fn submit_init_validator( .await } -pub async fn submit_transfer( +pub async fn submit_transparent_transfer( namada: &impl Namada, - args: args::TxTransfer, + args: args::TxTransparentTransfer, ) -> Result<(), error::Error> { - for _ in 0..2 { - submit_reveal_aux( - namada, - args.tx.clone(), - &args.source.effective_address(), - ) - .await?; + submit_reveal_aux(namada, args.tx.clone(), &args.source).await?; + + let (mut tx, signing_data) = args.clone().build(namada).await?; + + if args.tx.dump_tx { + tx::dump_tx(namada.io(), &args.tx, tx); + } else { + sign(namada, &mut tx, &args.tx, signing_data).await?; + namada.submit(tx, &args.tx).await?; + } + + Ok(()) +} + +pub async fn submit_shielded_transfer( + namada: &impl Namada, + args: args::TxShieldedTransfer, +) -> Result<(), error::Error> { + let (mut tx, signing_data) = args.clone().build(namada).await?; + + if args.tx.dump_tx { + tx::dump_tx(namada.io(), &args.tx, tx); + } else { + sign(namada, &mut tx, &args.tx, signing_data).await?; + namada.submit(tx, &args.tx).await?; + } + Ok(()) +} +pub async fn submit_shielding_transfer( + namada: &impl Namada, + args: args::TxShieldingTransfer, +) -> Result<(), error::Error> { + // Repeat once if the tx fails on a crossover of an epoch + for _ in 0..2 { let (mut tx, signing_data, tx_epoch) = args.clone().build(namada).await?; @@ -760,22 +787,18 @@ pub async fn submit_transfer( } else { sign(namada, &mut tx, &args.tx, signing_data).await?; let cmt_hash = tx.first_commitments().unwrap().get_hash(); - let result = namada.submit(tx, &args.tx).await?; - match result { ProcessTxResponse::Applied(resp) if - // If a transaction is shielded - tx_epoch.is_some() && - // And it is rejected by a VP + // If a transaction is rejected by a VP matches!(resp.batch_result().get(&cmt_hash), Some(InnerTxResult::VpsRejected(_))) => { - let submission_epoch = rpc::query_and_print_epoch(namada).await; + let submission_masp_epoch = rpc::query_and_print_masp_epoch(namada).await; // And its submission epoch doesn't match construction epoch - if tx_epoch.unwrap() != submission_epoch { + if tx_epoch != submission_masp_epoch { // Then we probably straddled an epoch boundary. Let's retry... edisplay_line!(namada.io(), - "MASP transaction rejected and this may be due to the \ + "Shielding transaction rejected and this may be due to the \ epoch changing. Attempting to resubmit transaction.", ); continue; @@ -787,7 +810,21 @@ pub async fn submit_transfer( } } } + Ok(()) +} + +pub async fn submit_unshielding_transfer( + namada: &impl Namada, + args: args::TxUnshieldingTransfer, +) -> Result<(), error::Error> { + let (mut tx, signing_data) = args.clone().build(namada).await?; + if args.tx.dump_tx { + tx::dump_tx(namada.io(), &args.tx, tx); + } else { + sign(namada, &mut tx, &args.tx, signing_data).await?; + namada.submit(tx, &args.tx).await?; + } Ok(()) } diff --git a/crates/apps_lib/src/config/genesis.rs b/crates/apps_lib/src/config/genesis.rs index ae439e784a..d6e5d97046 100644 --- a/crates/apps_lib/src/config/genesis.rs +++ b/crates/apps_lib/src/config/genesis.rs @@ -309,6 +309,8 @@ pub struct Parameters { pub implicit_vp_sha256: [u8; 32], /// Expected number of epochs per year (read only) pub epochs_per_year: u64, + /// How many epochs it takes to transition to the next masp epoch + pub masp_epoch_multiplier: u64, /// Maximum amount of signatures per transaction pub max_signatures_per_transaction: u8, /// Fee unshielding gas limit diff --git a/crates/apps_lib/src/config/genesis/chain.rs b/crates/apps_lib/src/config/genesis/chain.rs index a47c37d9de..690d67909f 100644 --- a/crates/apps_lib/src/config/genesis/chain.rs +++ b/crates/apps_lib/src/config/genesis/chain.rs @@ -302,6 +302,7 @@ impl Finalized { tx_allowlist, implicit_vp, epochs_per_year, + masp_epoch_multiplier, max_signatures_per_transaction, fee_unshielding_gas_limit, max_block_gas, @@ -346,6 +347,7 @@ impl Finalized { tx_allowlist, implicit_vp_code_hash, epochs_per_year, + masp_epoch_multiplier, max_proposal_bytes, max_signatures_per_transaction, fee_unshielding_gas_limit, diff --git a/crates/apps_lib/src/config/genesis/templates.rs b/crates/apps_lib/src/config/genesis/templates.rs index 7a3ae4764c..db5ac13772 100644 --- a/crates/apps_lib/src/config/genesis/templates.rs +++ b/crates/apps_lib/src/config/genesis/templates.rs @@ -293,6 +293,8 @@ pub struct ChainParams { pub implicit_vp: String, /// Expected number of epochs per year pub epochs_per_year: u64, + /// How many epochs it takes to transition to the next masp epoch + pub masp_epoch_multiplier: u64, /// Maximum number of signature per transaction pub max_signatures_per_transaction: u8, /// Max gas for block @@ -319,6 +321,7 @@ impl ChainParams { tx_allowlist, implicit_vp, epochs_per_year, + masp_epoch_multiplier, max_signatures_per_transaction, max_block_gas, fee_unshielding_gas_limit, @@ -364,6 +367,7 @@ impl ChainParams { tx_allowlist, implicit_vp, epochs_per_year, + masp_epoch_multiplier, max_signatures_per_transaction, max_block_gas, fee_unshielding_gas_limit, diff --git a/crates/apps_lib/src/config/global.rs b/crates/apps_lib/src/config/global.rs index f6d917c770..ef1d5ecf5d 100644 --- a/crates/apps_lib/src/config/global.rs +++ b/crates/apps_lib/src/config/global.rs @@ -43,13 +43,16 @@ impl GlobalConfig { pub fn read(base_dir: impl AsRef) -> Result { let file_path = Self::file_path(base_dir.as_ref()); let file_name = file_path.to_str().expect("Expected UTF-8 file path"); - let mut config = config::Config::new(); + let mut config = config::Config::default(); if file_path.exists() { - config - .merge(config::File::with_name(file_name)) + config = config::Config::builder() + .add_source(config::File::with_name(file_name)) + .build() .map_err(Error::ReadError)?; } - config.try_into().map_err(Error::DeserializationError) + config + .try_deserialize() + .map_err(|e: config::ConfigError| Error::DeserializationError(e)) } /// Write configuration to a file. diff --git a/crates/apps_lib/src/config/mod.rs b/crates/apps_lib/src/config/mod.rs index d5041b184b..c6484d10b0 100644 --- a/crates/apps_lib/src/config/mod.rs +++ b/crates/apps_lib/src/config/mod.rs @@ -273,17 +273,17 @@ impl Config { mode, )) .map_err(Error::ReadError)?; - let mut config = config::Config::new(); + let builder = config::Config::builder() + .add_source(defaults) + .add_source(config::File::with_name(file_name)) + .add_source( + config::Environment::with_prefix("NAMADA").separator("__"), + ); + + let config = builder.build().map_err(Error::ReadError)?; config - .merge(defaults) - .and_then(|c| c.merge(config::File::with_name(file_name))) - .and_then(|c| { - c.merge( - config::Environment::with_prefix("NAMADA").separator("__"), - ) - }) - .map_err(Error::ReadError)?; - config.try_into().map_err(Error::DeserializationError) + .try_deserialize() + .map_err(Error::DeserializationError) } /// Generate configuration and write it to a file. diff --git a/crates/benches/Cargo.toml b/crates/benches/Cargo.toml index ca308f9100..7a4add83c8 100644 --- a/crates/benches/Cargo.toml +++ b/crates/benches/Cargo.toml @@ -46,6 +46,7 @@ namada = { path = "../namada", features = ["rand", "benches"] } namada_apps_lib = { path = "../apps_lib" } namada_node = { path = "../node", features = ["benches"] } masp_primitives.workspace = true +masp_proofs = { workspace = true, features = ["benchmarks"] } borsh.workspace = true borsh-ext.workspace = true criterion = { version = "0.5", features = ["html_reports"] } @@ -57,5 +58,4 @@ tempfile.workspace = true sha2.workspace = true wasm-instrument.workspace = true wasmer-compiler-singlepass.workspace = true -wasmer-engine-universal.workspace = true wasmer.workspace = true diff --git a/crates/benches/host_env.rs b/crates/benches/host_env.rs index 8b13760964..1eee561163 100644 --- a/crates/benches/host_env.rs +++ b/crates/benches/host_env.rs @@ -3,29 +3,29 @@ use namada::core::account::AccountPublicKeysMap; use namada::core::address; use namada::core::collections::{HashMap, HashSet}; use namada::ledger::storage::DB; -use namada::token::{Amount, Transfer}; +use namada::token::{Amount, TransparentTransfer}; use namada::tx::Authorization; use namada::vm::wasm::TxCache; use namada_apps_lib::wallet::defaults; use namada_apps_lib::wasm_loader; use namada_node::bench_utils::{ - BenchShell, TX_INIT_PROPOSAL_WASM, TX_REVEAL_PK_WASM, TX_TRANSFER_WASM, - TX_UPDATE_ACCOUNT_WASM, VP_USER_WASM, WASM_DIR, + BenchShell, TX_INIT_PROPOSAL_WASM, TX_REVEAL_PK_WASM, + TX_TRANSPARENT_TRANSFER_WASM, TX_UPDATE_ACCOUNT_WASM, VP_USER_WASM, + WASM_DIR, }; // Benchmarks the validation of a single signature on a single `Section` of a // transaction fn tx_section_signature_validation(c: &mut Criterion) { let shell = BenchShell::default(); - let transfer_data = Transfer { + let transfer_data = TransparentTransfer { source: defaults::albert_address(), target: defaults::bertha_address(), token: address::testing::nam(), amount: Amount::native_whole(500).native_denominated(), - shielded: None, }; let tx = shell.generate_tx( - TX_TRANSFER_WASM, + TX_TRANSPARENT_TRANSFER_WASM, transfer_data, None, None, @@ -62,7 +62,7 @@ fn compile_wasm(c: &mut Criterion) { let mut txs: HashMap<&str, Vec> = HashMap::default(); for tx in [ - TX_TRANSFER_WASM, + TX_TRANSPARENT_TRANSFER_WASM, TX_INIT_PROPOSAL_WASM, TX_REVEAL_PK_WASM, TX_UPDATE_ACCOUNT_WASM, @@ -111,7 +111,7 @@ fn untrusted_wasm_validation(c: &mut Criterion) { let mut txs: HashMap<&str, Vec> = HashMap::default(); for tx in [ - TX_TRANSFER_WASM, + TX_TRANSPARENT_TRANSFER_WASM, TX_INIT_PROPOSAL_WASM, TX_REVEAL_PK_WASM, TX_UPDATE_ACCOUNT_WASM, diff --git a/crates/benches/native_vps.rs b/crates/benches/native_vps.rs index b538c21b19..2ee9986fb1 100644 --- a/crates/benches/native_vps.rs +++ b/crates/benches/native_vps.rs @@ -5,9 +5,13 @@ use std::rc::Rc; use std::str::FromStr; use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; +use masp_primitives::sapling::redjubjub::PublicKey; use masp_primitives::sapling::Node; use masp_primitives::transaction::sighash::{signature_hash, SignableInput}; use masp_primitives::transaction::txid::TxIdDigester; +use masp_primitives::transaction::TransactionData; +use masp_proofs::group::GroupEncoding; +use masp_proofs::sapling::BatchValidator; use namada::core::address::{self, Address, InternalAddress}; use namada::core::collections::HashMap; use namada::core::eth_bridge_pool::{GasFee, PendingTransfer}; @@ -46,23 +50,22 @@ use namada::ledger::pgf::PgfVp; use namada::ledger::pos::PosVP; use namada::proof_of_stake; use namada::proof_of_stake::KeySeg; -use namada::sdk::masp::{ - check_convert, check_output, check_spend, partial_deauthorize, - preload_verifying_keys, PVKs, -}; +use namada::sdk::masp::{partial_deauthorize, preload_verifying_keys, PVKs}; use namada::sdk::masp_primitives::merkle_tree::CommitmentTree; use namada::sdk::masp_primitives::transaction::Transaction; -use namada::sdk::masp_proofs::sapling::SaplingVerificationContext; +use namada::sdk::masp_proofs::sapling::SaplingVerificationContextInner; use namada::state::{Epoch, StorageRead, StorageWrite, TxIndex}; -use namada::token::{Amount, Transfer}; +use namada::token::{Amount, TransparentTransfer}; use namada::tx::{BatchedTx, Code, Section, Tx}; use namada_apps_lib::wallet::defaults; use namada_node::bench_utils::{ generate_foreign_key_tx, BenchShell, BenchShieldedCtx, ALBERT_PAYMENT_ADDRESS, ALBERT_SPENDING_KEY, BERTHA_PAYMENT_ADDRESS, TX_BRIDGE_POOL_WASM, TX_IBC_WASM, TX_INIT_PROPOSAL_WASM, TX_RESIGN_STEWARD, - TX_TRANSFER_WASM, TX_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL_WASM, + TX_TRANSPARENT_TRANSFER_WASM, TX_UPDATE_STEWARD_COMMISSION, + TX_VOTE_PROPOSAL_WASM, }; +use rand_core::OsRng; fn governance(c: &mut Criterion) { let mut group = c.benchmark_group("vp_governance"); @@ -472,13 +475,12 @@ fn vp_multitoken(c: &mut Criterion) { generate_foreign_key_tx(&defaults::albert_keypair()); let transfer = shell.generate_tx( - TX_TRANSFER_WASM, - Transfer { + TX_TRANSPARENT_TRANSFER_WASM, + TransparentTransfer { source: defaults::albert_address(), target: defaults::bertha_address(), token: address::testing::nam(), amount: Amount::native_whole(1000).native_denominated(), - shielded: None, }, None, None, @@ -642,11 +644,11 @@ fn masp(c: &mut Criterion) { group.finish(); } +// Instead of benchmarking BatchValidator::check_bundle we benchmark the 4 +// functions that are called internally for better resolution fn masp_check_spend(c: &mut Criterion) { - let spend_vk = &preload_verifying_keys().spend_vk; - c.bench_function("vp_masp_check_spend", |b| { - b.iter_batched_ref( + b.iter_batched( || { let (_, _verifiers_from_tx, signed_tx) = setup_storage_for_masp_verification("shielded"); @@ -670,7 +672,7 @@ fn masp_check_spend(c: &mut Criterion) { .first() .unwrap() .to_owned(); - let ctx = SaplingVerificationContext::new(true); + let ctx = SaplingVerificationContextInner::new(); let tx_data = transaction.deref(); // Partially deauthorize the transparent bundle let unauth_tx_data = partial_deauthorize(tx_data).unwrap(); @@ -680,11 +682,28 @@ fn masp_check_spend(c: &mut Criterion) { &SignableInput::Shielded, &txid_parts, ); + let zkproof = masp_proofs::bellman::groth16::Proof::read( + spend.zkproof.as_slice(), + ) + .unwrap(); - (ctx, spend, sighash) + (ctx, spend, sighash, zkproof) }, - |(ctx, spend, sighash)| { - assert!(check_spend(spend, sighash.as_ref(), ctx, spend_vk)); + |(mut ctx, spend, sighash, zkproof)| { + assert!(ctx.check_spend( + spend.cv, + spend.anchor, + &spend.nullifier.0, + PublicKey(spend.rk.0), + sighash.as_ref(), + spend.spend_auth_sig, + zkproof, + &mut (), + // We do sig and proofs verification in parallel, so just + // use dummy verifiers here + |_, _, _, _| true, + |_, _, _| true + )); }, BatchSize::SmallInput, ) @@ -692,10 +711,8 @@ fn masp_check_spend(c: &mut Criterion) { } fn masp_check_convert(c: &mut Criterion) { - let convert_vk = &preload_verifying_keys().convert_vk; - c.bench_function("vp_masp_check_convert", |b| { - b.iter_batched_ref( + b.iter_batched( || { let (_, _verifiers_from_tx, signed_tx) = setup_storage_for_masp_verification("shielded"); @@ -719,12 +736,24 @@ fn masp_check_convert(c: &mut Criterion) { .first() .unwrap() .to_owned(); - let ctx = SaplingVerificationContext::new(true); + let ctx = SaplingVerificationContextInner::new(); + let zkproof = masp_proofs::bellman::groth16::Proof::read( + convert.zkproof.as_slice(), + ) + .unwrap(); - (ctx, convert) + (ctx, convert, zkproof) }, - |(ctx, convert)| { - assert!(check_convert(convert, ctx, convert_vk)); + |(mut ctx, convert, zkproof)| { + assert!(ctx.check_convert( + convert.cv, + convert.anchor, + zkproof, + &mut (), + // We do proofs verification in parallel, so just use dummy + // verifier here + |_, _, _| true, + )); }, BatchSize::SmallInput, ) @@ -732,10 +761,8 @@ fn masp_check_convert(c: &mut Criterion) { } fn masp_check_output(c: &mut Criterion) { - let output_vk = &preload_verifying_keys().output_vk; - c.bench_function("masp_vp_check_output", |b| { - b.iter_batched_ref( + b.iter_batched( || { let (_, _verifiers_from_tx, signed_tx) = setup_storage_for_masp_verification("shielded"); @@ -759,12 +786,28 @@ fn masp_check_output(c: &mut Criterion) { .first() .unwrap() .to_owned(); - let ctx = SaplingVerificationContext::new(true); + let ctx = SaplingVerificationContextInner::new(); + let zkproof = masp_proofs::bellman::groth16::Proof::read( + output.zkproof.as_slice(), + ) + .unwrap(); + let epk = masp_proofs::jubjub::ExtendedPoint::from_bytes( + &output.ephemeral_key.0, + ) + .unwrap(); - (ctx, output) + (ctx, output, epk, zkproof) }, - |(ctx, output)| { - assert!(check_output(output, ctx, output_vk)); + |(mut ctx, output, epk, zkproof)| { + assert!(ctx.check_output( + output.cv, + output.cmu, + epk, + zkproof, + // We do proofs verification in parallel, so just use dummy + // verifier here + |_, _| true + )); }, BatchSize::SmallInput, ) @@ -772,12 +815,6 @@ fn masp_check_output(c: &mut Criterion) { } fn masp_final_check(c: &mut Criterion) { - let PVKs { - spend_vk, - convert_vk, - output_vk, - } = preload_verifying_keys(); - let (_, _verifiers_from_tx, signed_tx) = setup_storage_for_masp_verification("shielded"); @@ -794,41 +831,344 @@ fn masp_final_check(c: &mut Criterion) { .unwrap() .to_owned(); let sapling_bundle = transaction.sapling_bundle().unwrap(); - let mut ctx = SaplingVerificationContext::new(true); // Partially deauthorize the transparent bundle let unauth_tx_data = partial_deauthorize(transaction.deref()).unwrap(); let txid_parts = unauth_tx_data.digest(TxIdDigester); let sighash = signature_hash(&unauth_tx_data, &SignableInput::Shielded, &txid_parts); + let mut ctx = SaplingVerificationContextInner::new(); // Check spends, converts and outputs before the final check assert!(sapling_bundle.shielded_spends.iter().all(|spend| { - check_spend(spend, sighash.as_ref(), &mut ctx, spend_vk) + let zkproof = masp_proofs::bellman::groth16::Proof::read( + spend.zkproof.as_slice(), + ) + .unwrap(); + + ctx.check_spend( + spend.cv, + spend.anchor, + &spend.nullifier.0, + PublicKey(spend.rk.0), + sighash.as_ref(), + spend.spend_auth_sig, + zkproof, + &mut (), + |_, _, _, _| true, + |_, _, _| true, + ) + })); + assert!(sapling_bundle.shielded_converts.iter().all(|convert| { + let zkproof = masp_proofs::bellman::groth16::Proof::read( + convert.zkproof.as_slice(), + ) + .unwrap(); + ctx.check_convert( + convert.cv, + convert.anchor, + zkproof, + &mut (), + |_, _, _| true, + ) + })); + assert!(sapling_bundle.shielded_outputs.iter().all(|output| { + let zkproof = masp_proofs::bellman::groth16::Proof::read( + output.zkproof.as_slice(), + ) + .unwrap(); + let epk = masp_proofs::jubjub::ExtendedPoint::from_bytes( + &output.ephemeral_key.0, + ) + .unwrap(); + ctx.check_output( + output.cv, + output.cmu, + epk.to_owned(), + zkproof, + |_, _| true, + ) })); - assert!( - sapling_bundle - .shielded_converts - .iter() - .all(|convert| check_convert(convert, &mut ctx, convert_vk)) - ); - assert!( - sapling_bundle - .shielded_outputs - .iter() - .all(|output| check_output(output, &mut ctx, output_vk)) - ); c.bench_function("vp_masp_final_check", |b| { b.iter(|| { assert!(ctx.final_check( sapling_bundle.value_balance.clone(), sighash.as_ref(), - sapling_bundle.authorization.binding_sig + sapling_bundle.authorization.binding_sig, + // We do sig verification in parallel, so just use dummy + // verifier here + |_, _, _| true )) }) }); } +#[derive(Debug)] +enum BenchNote { + Spend, + Convert, + Output, +} + +// Tweaks the transaction to match the desired benchmark +fn customize_masp_tx_data( + multi: bool, + request: &BenchNote, +) -> ( + TransactionData, + Transaction, +) { + let (_, _, tx) = setup_storage_for_masp_verification("unshielding"); + let transaction = tx + .tx + .sections + .into_iter() + .filter_map(|section| match section { + Section::MaspTx(transaction) => Some(transaction), + _ => None, + }) + .collect::>() + .first() + .unwrap() + .to_owned(); + let mut sapling_bundle = transaction.sapling_bundle().unwrap().to_owned(); + + match request { + BenchNote::Spend => { + if multi { + // ensure we have two spend proofs + sapling_bundle.shielded_spends = [ + sapling_bundle.shielded_spends.clone(), + sapling_bundle.shielded_spends, + ] + .concat(); + assert_eq!(sapling_bundle.shielded_spends.len(), 2); + } else { + // ensure we have one spend proof + assert_eq!(sapling_bundle.shielded_spends.len(), 1); + } + } + BenchNote::Convert => { + if multi { + // ensure we have two convert proofs + sapling_bundle.shielded_converts = [ + sapling_bundle.shielded_converts.clone(), + sapling_bundle.shielded_converts, + ] + .concat(); + assert_eq!(sapling_bundle.shielded_converts.len(), 2); + } else { + // ensure we have one convert proof + assert_eq!(sapling_bundle.shielded_converts.len(), 1); + } + } + BenchNote::Output => { + if multi { + // ensure we have two output proofs + assert_eq!(sapling_bundle.shielded_outputs.len(), 2); + } else { + // ensure we have one output proof + sapling_bundle.shielded_outputs.truncate(1); + assert_eq!(sapling_bundle.shielded_outputs.len(), 1); + } + } + }; + + ( + TransactionData::from_parts( + transaction.version(), + transaction.consensus_branch_id(), + transaction.lock_time(), + transaction.expiry_height(), + transaction.transparent_bundle().cloned(), + Some(sapling_bundle), + ), + transaction, + ) +} + +// benchmark the cost of validating two signatures in a batch. +fn masp_batch_signature_verification(c: &mut Criterion) { + let (_, _, tx) = setup_storage_for_masp_verification("unshielding"); + let transaction = tx + .tx + .sections + .into_iter() + .filter_map(|section| match section { + Section::MaspTx(transaction) => Some(transaction), + _ => None, + }) + .collect::>() + .first() + .unwrap() + .to_owned(); + let sapling_bundle = transaction.sapling_bundle().unwrap(); + // ensure we have two signatures to verify (the binding and one spending) + assert_eq!(sapling_bundle.shielded_spends.len(), 1); + + // Partially deauthorize the transparent bundle + let unauth_tx_data = partial_deauthorize(transaction.deref()).unwrap(); + let txid_parts = unauth_tx_data.digest(TxIdDigester); + let sighash = + signature_hash(&unauth_tx_data, &SignableInput::Shielded, &txid_parts) + .as_ref() + .to_owned(); + + c.bench_function("masp_batch_signature_verification", |b| { + b.iter_batched( + || { + let mut ctx = BatchValidator::new(); + // Check bundle first + if !ctx.check_bundle(sapling_bundle.to_owned(), sighash) { + panic!("Failed check bundle"); + } + + ctx + }, + |ctx| assert!(ctx.verify_signatures(OsRng).is_ok()), + BatchSize::SmallInput, + ) + }); +} + +// Benchmark both one and two proofs and take the difference as the variable +// cost for every proofs. Charge the full cost for the first note and then +// charge the variable cost multiplied by the number of remaining notes and +// divided by the number of cores +fn masp_batch_spend_proofs_validate(c: &mut Criterion) { + let mut group = c.benchmark_group("masp_batch_spend_proofs_validate"); + let PVKs { spend_vk, .. } = preload_verifying_keys(); + + for double in [true, false] { + let (tx_data, transaction) = + customize_masp_tx_data(double, &BenchNote::Spend); + + // Partially deauthorize the transparent bundle + let unauth_tx_data = partial_deauthorize(transaction.deref()).unwrap(); + let txid_parts = unauth_tx_data.digest(TxIdDigester); + // Compute the sighash from the original, unmodified transaction + let sighash = signature_hash( + &unauth_tx_data, + &SignableInput::Shielded, + &txid_parts, + ) + .as_ref() + .to_owned(); + let sapling_bundle = tx_data.sapling_bundle().unwrap(); + + let bench_name = if double { "double" } else { "single" }; + group.bench_function(bench_name, |b| { + b.iter_batched( + || { + let mut ctx = BatchValidator::new(); + // Check bundle first + if !ctx.check_bundle(sapling_bundle.to_owned(), sighash) { + panic!("Failed check bundle"); + } + + ctx + }, + |ctx| assert!(ctx.verify_spend_proofs(spend_vk).is_ok()), + BatchSize::SmallInput, + ) + }); + } + + group.finish(); +} + +// Benchmark both one and two proofs and take the difference as the variable +// cost for every proofs. Charge the full cost for the first note and then +// charge the variable cost multiplied by the number of remaining notes and +// divided by the number of cores +fn masp_batch_convert_proofs_validate(c: &mut Criterion) { + let mut group = c.benchmark_group("masp_batch_convert_proofs_validate"); + let PVKs { convert_vk, .. } = preload_verifying_keys(); + + for double in [true, false] { + let (tx_data, transaction) = + customize_masp_tx_data(double, &BenchNote::Convert); + + // Partially deauthorize the transparent bundle + let unauth_tx_data = partial_deauthorize(transaction.deref()).unwrap(); + let txid_parts = unauth_tx_data.digest(TxIdDigester); + // Compute the sighash from the original, unmodified transaction + let sighash = signature_hash( + &unauth_tx_data, + &SignableInput::Shielded, + &txid_parts, + ) + .as_ref() + .to_owned(); + let sapling_bundle = tx_data.sapling_bundle().unwrap(); + + let bench_name = if double { "double" } else { "single" }; + group.bench_function(bench_name, |b| { + b.iter_batched( + || { + let mut ctx = BatchValidator::new(); + // Check bundle first + if !ctx.check_bundle(sapling_bundle.to_owned(), sighash) { + panic!("Failed check bundle"); + } + + ctx + }, + |ctx| assert!(ctx.verify_convert_proofs(convert_vk).is_ok()), + BatchSize::SmallInput, + ) + }); + } + + group.finish(); +} + +// Benchmark both one and two proofs and take the difference as the variable +// cost for every proofs. Charge the full cost for the first note and then +// charge the variable cost multiplied by the number of remaining notes and +// divided by the number of cores +fn masp_batch_output_proofs_validate(c: &mut Criterion) { + let mut group = c.benchmark_group("masp_batch_output_proofs_validate"); + let PVKs { output_vk, .. } = preload_verifying_keys(); + + for double in [true, false] { + let (tx_data, transaction) = + customize_masp_tx_data(double, &BenchNote::Output); + + // Partially deauthorize the transparent bundle + let unauth_tx_data = partial_deauthorize(transaction.deref()).unwrap(); + let txid_parts = unauth_tx_data.digest(TxIdDigester); + // Compute the sighash from the original, unmodified transaction + let sighash = signature_hash( + &unauth_tx_data, + &SignableInput::Shielded, + &txid_parts, + ) + .as_ref() + .to_owned(); + let sapling_bundle = tx_data.sapling_bundle().unwrap(); + + let bench_name = if double { "double" } else { "single" }; + group.bench_function(bench_name, |b| { + b.iter_batched( + || { + let mut ctx = BatchValidator::new(); + // Check bundle first + if !ctx.check_bundle(sapling_bundle.to_owned(), sighash) { + panic!("Failed check bundle"); + } + + ctx + }, + |ctx| assert!(ctx.verify_output_proofs(output_vk).is_ok()), + BatchSize::SmallInput, + ) + }); + } + + group.finish(); +} + fn pgf(c: &mut Criterion) { let mut group = c.benchmark_group("vp_pgf"); @@ -1439,6 +1779,10 @@ criterion_group!( masp_check_convert, masp_check_output, masp_final_check, + masp_batch_signature_verification, + masp_batch_spend_proofs_validate, + masp_batch_convert_proofs_validate, + masp_batch_output_proofs_validate, vp_multitoken, pgf, eth_bridge_nut, diff --git a/crates/benches/process_wrapper.rs b/crates/benches/process_wrapper.rs index 26ad6d2e74..9510ee3125 100644 --- a/crates/benches/process_wrapper.rs +++ b/crates/benches/process_wrapper.rs @@ -3,11 +3,11 @@ use namada::core::address; use namada::core::key::RefTo; use namada::core::storage::BlockHeight; use namada::core::time::DateTimeUtc; -use namada::token::{Amount, DenominatedAmount, Transfer}; +use namada::token::{Amount, DenominatedAmount, TransparentTransfer}; use namada::tx::data::{Fee, WrapperTx}; use namada::tx::Authorization; use namada_apps_lib::wallet::defaults; -use namada_node::bench_utils::{BenchShell, TX_TRANSFER_WASM}; +use namada_node::bench_utils::{BenchShell, TX_TRANSPARENT_TRANSFER_WASM}; use namada_node::shell::process_proposal::ValidationMeta; fn process_tx(c: &mut Criterion) { @@ -18,13 +18,12 @@ fn process_tx(c: &mut Criterion) { BlockHeight(2); let mut batched_tx = shell.generate_tx( - TX_TRANSFER_WASM, - Transfer { + TX_TRANSPARENT_TRANSFER_WASM, + TransparentTransfer { source: defaults::albert_address(), target: defaults::bertha_address(), token: address::testing::nam(), amount: Amount::native_whole(1).native_denominated(), - shielded: None, }, None, None, @@ -56,7 +55,7 @@ fn process_tx(c: &mut Criterion) { let datetime = DateTimeUtc::now(); c.bench_function("wrapper_tx_validation", |b| { - b.iter_batched( + b.iter_batched_ref( || { ( // Prevent block out of gas and replay protection @@ -68,10 +67,10 @@ fn process_tx(c: &mut Criterion) { ) }, |( - mut temp_state, - mut validation_meta, - mut vp_wasm_cache, - mut tx_wasm_cache, + temp_state, + validation_meta, + vp_wasm_cache, + tx_wasm_cache, block_proposer, )| { assert_eq!( @@ -79,12 +78,12 @@ fn process_tx(c: &mut Criterion) { shell .check_proposal_tx( &wrapper, - &mut validation_meta, - &mut temp_state, + validation_meta, + temp_state, datetime, - &mut vp_wasm_cache, - &mut tx_wasm_cache, - &block_proposer + vp_wasm_cache, + tx_wasm_cache, + block_proposer ) .code, 0 diff --git a/crates/benches/wasm_opcodes.rs b/crates/benches/wasm_opcodes.rs index b9ce3bfdb2..ceae69bc51 100644 --- a/crates/benches/wasm_opcodes.rs +++ b/crates/benches/wasm_opcodes.rs @@ -410,12 +410,11 @@ impl Display for WatBuilder { // optimizations that would compile out the benchmarks since most of them are // trivial operations fn get_wasm_store() -> Store { - wasmer::Store::new( - &wasmer_engine_universal::Universal::new( - wasmer_compiler_singlepass::Singlepass::default(), - ) - .engine(), - ) + Store::new(::new( + Box::new(wasmer_compiler_singlepass::Singlepass::default()), + wasmer::Target::default(), + wasmer::sys::Features::default(), + )) } // An empty wasm module to serve as the base reference for all the other @@ -428,12 +427,13 @@ fn empty_module(c: &mut Criterion) { ) "#, ); - let module = Module::new(&get_wasm_store(), module_wat).unwrap(); - let instance = Instance::new(&module, &imports! {}).unwrap(); + let mut store = get_wasm_store(); + let module = Module::new(&store, module_wat).unwrap(); + let instance = Instance::new(&mut store, &module, &imports! {}).unwrap(); let function = instance.exports.get_function(ENTRY_POINT).unwrap(); c.bench_function("empty_module", |b| { - b.iter(|| function.call(&[Value::I32(0)]).unwrap()); + b.iter(|| function.call(&mut store, &[Value::I32(0)]).unwrap()); }); } @@ -441,16 +441,19 @@ fn ops(c: &mut Criterion) { let mut group = c.benchmark_group("wasm_opts"); for builder in bench_functions() { - let module = - Module::new(&get_wasm_store(), builder.to_string()).unwrap(); - let instance = Instance::new(&module, &imports! {}).unwrap(); + let mut store = get_wasm_store(); + let module = Module::new(&store, builder.to_string()).unwrap(); + let instance = + Instance::new(&mut store, &module, &imports! {}).unwrap(); let function = instance.exports.get_function(ENTRY_POINT).unwrap(); group.bench_function(format!("{}", builder.instruction), |b| { if let Unreachable = builder.instruction { - b.iter(|| function.call(&[Value::I32(0)]).unwrap_err()); + b.iter(|| { + function.call(&mut store, &[Value::I32(0)]).unwrap_err() + }); } else { - b.iter(|| function.call(&[Value::I32(0)]).unwrap()); + b.iter(|| function.call(&mut store, &[Value::I32(0)]).unwrap()); } }); } diff --git a/crates/core/src/address.rs b/crates/core/src/address.rs index bdda98c56e..409622d747 100644 --- a/crates/core/src/address.rs +++ b/crates/core/src/address.rs @@ -9,6 +9,7 @@ use std::str::FromStr; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use data_encoding::HEXUPPER; +use ibc::primitives::Signer; use namada_macros::BorshDeserializer; #[cfg(feature = "migrations")] use namada_migrations::*; @@ -16,7 +17,6 @@ use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use crate::ethereum_events::EthAddress; -use crate::ibc::primitives::Signer; use crate::ibc::IbcTokenHash; use crate::key::PublicKeyHash; use crate::{impl_display_and_from_str_via_format, key, string_encoding}; diff --git a/crates/core/src/ibc.rs b/crates/core/src/ibc.rs index f63805f16a..fe29f61fe7 100644 --- a/crates/core/src/ibc.rs +++ b/crates/core/src/ibc.rs @@ -9,32 +9,8 @@ use namada_macros::BorshDeserializer; #[cfg(feature = "migrations")] use namada_migrations::*; use serde::{Deserialize, Serialize}; -use thiserror::Error; -use super::address::{Address, InternalAddress, HASH_LEN}; -use crate::ibc::apps::nft_transfer::context::{NftClassContext, NftContext}; -use crate::ibc::apps::nft_transfer::types::error::NftTransferError; -use crate::ibc::apps::nft_transfer::types::msgs::transfer::MsgTransfer as IbcMsgNftTransfer; -use crate::ibc::apps::nft_transfer::types::{ - ClassData, ClassId, ClassUri, PrefixedClassId, TokenData, TokenId, - TokenUri, TracePath as NftTracePath, -}; -use crate::ibc::apps::transfer::types::msgs::transfer::MsgTransfer as IbcMsgTransfer; -use crate::ibc::apps::transfer::types::{PrefixedDenom, TracePath}; -use crate::ibc::core::channel::types::msgs::{ - MsgAcknowledgement as IbcMsgAcknowledgement, - MsgRecvPacket as IbcMsgRecvPacket, MsgTimeout as IbcMsgTimeout, -}; -use crate::ibc::core::handler::types::msgs::MsgEnvelope; -use crate::ibc::primitives::proto::Protobuf; -use crate::token::Transfer; - -/// The event type defined in ibc-rs for receiving a token -pub const EVENT_TYPE_PACKET: &str = "fungible_token_packet"; -/// The event type defined in ibc-rs for receiving an NFT -pub const EVENT_TYPE_NFT_PACKET: &str = "non_fungible_token_packet"; -/// The escrow address for IBC transfer -pub const IBC_ESCROW_ADDRESS: Address = Address::Internal(InternalAddress::Ibc); +use super::address::HASH_LEN; /// IBC token hash derived from a denomination. #[derive( @@ -71,423 +47,3 @@ impl FromStr for IbcTokenHash { Ok(IbcTokenHash(output)) } } - -/// The different variants of an Ibc message -#[derive(Debug, Clone)] -pub enum IbcMessage { - /// Ibc Envelop - Envelope(Box), - /// Ibc transaprent transfer - Transfer(MsgTransfer), - /// NFT transfer - NftTransfer(MsgNftTransfer), - /// Receiving a packet - RecvPacket(MsgRecvPacket), - /// Acknowledgement - AckPacket(MsgAcknowledgement), - /// Timeout - Timeout(MsgTimeout), -} - -/// IBC transfer message with `Transfer` -#[derive(Debug, Clone)] -pub struct MsgTransfer { - /// IBC transfer message - pub message: IbcMsgTransfer, - /// Shieleded transfer for MASP transaction - pub transfer: Option, -} - -impl BorshSerialize for MsgTransfer { - fn serialize( - &self, - writer: &mut W, - ) -> std::io::Result<()> { - let encoded_msg = self.message.clone().encode_vec(); - let members = (encoded_msg, self.transfer.clone()); - BorshSerialize::serialize(&members, writer) - } -} - -impl BorshDeserialize for MsgTransfer { - fn deserialize_reader( - reader: &mut R, - ) -> std::io::Result { - use std::io::{Error, ErrorKind}; - let (msg, transfer): (Vec, Option) = - BorshDeserialize::deserialize_reader(reader)?; - let message = IbcMsgTransfer::decode_vec(&msg) - .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; - Ok(Self { message, transfer }) - } -} - -/// IBC NFT transfer message with `Transfer` -#[derive(Debug, Clone)] -pub struct MsgNftTransfer { - /// IBC NFT transfer message - pub message: IbcMsgNftTransfer, - /// Shieleded transfer for MASP transaction - pub transfer: Option, -} - -impl BorshSerialize for MsgNftTransfer { - fn serialize( - &self, - writer: &mut W, - ) -> std::io::Result<()> { - let encoded_msg = self.message.clone().encode_vec(); - let members = (encoded_msg, self.transfer.clone()); - BorshSerialize::serialize(&members, writer) - } -} - -impl BorshDeserialize for MsgNftTransfer { - fn deserialize_reader( - reader: &mut R, - ) -> std::io::Result { - use std::io::{Error, ErrorKind}; - let (msg, transfer): (Vec, Option) = - BorshDeserialize::deserialize_reader(reader)?; - let message = IbcMsgNftTransfer::decode_vec(&msg) - .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; - Ok(Self { message, transfer }) - } -} - -/// IBC shielded transfer -#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, BorshDeserializer)] -pub struct IbcShieldedTransfer { - /// The IBC event type - pub transfer: Transfer, - /// The attributes of the IBC event - pub masp_tx: masp_primitives::transaction::Transaction, -} - -/// IBC receiving packet message with `Transfer` -#[derive(Debug, Clone)] -pub struct MsgRecvPacket { - /// IBC receiving packet message - pub message: IbcMsgRecvPacket, - /// Shieleded transfer for MASP transaction - pub transfer: Option, -} - -impl BorshSerialize for MsgRecvPacket { - fn serialize( - &self, - writer: &mut W, - ) -> std::io::Result<()> { - let encoded_msg = self.message.clone().encode_vec(); - let members = (encoded_msg, self.transfer.clone()); - BorshSerialize::serialize(&members, writer) - } -} - -impl BorshDeserialize for MsgRecvPacket { - fn deserialize_reader( - reader: &mut R, - ) -> std::io::Result { - use std::io::{Error, ErrorKind}; - let (msg, transfer): (Vec, Option) = - BorshDeserialize::deserialize_reader(reader)?; - let message = IbcMsgRecvPacket::decode_vec(&msg) - .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; - Ok(Self { message, transfer }) - } -} - -/// IBC acknowledgement message with `Transfer` for refunding to a shielded -/// address -#[derive(Debug, Clone)] -pub struct MsgAcknowledgement { - /// IBC acknowledgement message - pub message: IbcMsgAcknowledgement, - /// Shieleded transfer for MASP transaction - pub transfer: Option, -} - -impl BorshSerialize for MsgAcknowledgement { - fn serialize( - &self, - writer: &mut W, - ) -> std::io::Result<()> { - let encoded_msg = self.message.clone().encode_vec(); - let members = (encoded_msg, self.transfer.clone()); - BorshSerialize::serialize(&members, writer) - } -} - -impl BorshDeserialize for MsgAcknowledgement { - fn deserialize_reader( - reader: &mut R, - ) -> std::io::Result { - use std::io::{Error, ErrorKind}; - let (msg, transfer): (Vec, Option) = - BorshDeserialize::deserialize_reader(reader)?; - let message = IbcMsgAcknowledgement::decode_vec(&msg) - .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; - Ok(Self { message, transfer }) - } -} - -/// IBC timeout packet message with `Transfer` for refunding to a shielded -/// address -#[derive(Debug, Clone)] -pub struct MsgTimeout { - /// IBC timeout message - pub message: IbcMsgTimeout, - /// Shieleded transfer for MASP transaction - pub transfer: Option, -} - -impl BorshSerialize for MsgTimeout { - fn serialize( - &self, - writer: &mut W, - ) -> std::io::Result<()> { - let encoded_msg = self.message.clone().encode_vec(); - let members = (encoded_msg, self.transfer.clone()); - BorshSerialize::serialize(&members, writer) - } -} - -impl BorshDeserialize for MsgTimeout { - fn deserialize_reader( - reader: &mut R, - ) -> std::io::Result { - use std::io::{Error, ErrorKind}; - let (msg, transfer): (Vec, Option) = - BorshDeserialize::deserialize_reader(reader)?; - let message = IbcMsgTimeout::decode_vec(&msg) - .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; - Ok(Self { message, transfer }) - } -} - -#[allow(missing_docs)] -#[derive(Error, Debug)] -pub enum Error { - #[error("IBC transfer memo HEX decoding error: {0}")] - DecodingHex(data_encoding::DecodeError), - #[error("IBC transfer memo decoding error: {0}")] - DecodingShieldedTransfer(std::io::Error), -} - -/// Returns the trace path and the token string if the denom is an IBC -/// denom. -pub fn is_ibc_denom(denom: impl AsRef) -> Option<(TracePath, String)> { - let prefixed_denom = PrefixedDenom::from_str(denom.as_ref()).ok()?; - let base_denom = prefixed_denom.base_denom.to_string(); - if prefixed_denom.trace_path.is_empty() || base_denom.contains('/') { - // The denom is just a token or an NFT trace - return None; - } - // The base token isn't decoded because it could be non Namada token - Some((prefixed_denom.trace_path, base_denom)) -} - -/// Returns the trace path and the token string if the trace is an NFT one -pub fn is_nft_trace( - trace: impl AsRef, -) -> Option<(NftTracePath, String, String)> { - // The trace should be {port}/{channel}/.../{class_id}/{token_id} - if let Some((class_id, token_id)) = trace.as_ref().rsplit_once('/') { - let prefixed_class_id = PrefixedClassId::from_str(class_id).ok()?; - // The base token isn't decoded because it could be non Namada token - Some(( - prefixed_class_id.trace_path, - prefixed_class_id.base_class_id.to_string(), - token_id.to_string(), - )) - } else { - None - } -} - -/// NFT class -#[derive(Clone, Debug)] -pub struct NftClass { - /// NFT class ID - pub class_id: PrefixedClassId, - /// NFT class URI - pub class_uri: Option, - /// NFT class data - pub class_data: Option, -} - -impl BorshSerialize for NftClass { - fn serialize( - &self, - writer: &mut W, - ) -> std::io::Result<()> { - BorshSerialize::serialize(&self.class_id.to_string(), writer)?; - match &self.class_uri { - Some(uri) => { - BorshSerialize::serialize(&true, writer)?; - BorshSerialize::serialize(&uri.to_string(), writer)?; - } - None => BorshSerialize::serialize(&false, writer)?, - } - match &self.class_data { - Some(data) => { - BorshSerialize::serialize(&true, writer)?; - BorshSerialize::serialize(&data.to_string(), writer) - } - None => BorshSerialize::serialize(&false, writer), - } - } -} - -impl BorshDeserialize for NftClass { - fn deserialize_reader( - reader: &mut R, - ) -> std::io::Result { - use std::io::{Error, ErrorKind}; - let class_id: String = BorshDeserialize::deserialize_reader(reader)?; - let class_id = class_id.parse().map_err(|e: NftTransferError| { - Error::new(ErrorKind::InvalidData, e.to_string()) - })?; - - let is_uri: bool = BorshDeserialize::deserialize_reader(reader)?; - let class_uri = if is_uri { - let uri_str: String = BorshDeserialize::deserialize_reader(reader)?; - Some(uri_str.parse().map_err(|e: NftTransferError| { - Error::new(ErrorKind::InvalidData, e.to_string()) - })?) - } else { - None - }; - - let is_data: bool = BorshDeserialize::deserialize_reader(reader)?; - let class_data = if is_data { - let data_str: String = - BorshDeserialize::deserialize_reader(reader)?; - Some(data_str.parse().map_err(|e: NftTransferError| { - Error::new(ErrorKind::InvalidData, e.to_string()) - })?) - } else { - None - }; - - Ok(Self { - class_id, - class_uri, - class_data, - }) - } -} - -impl NftClassContext for NftClass { - fn get_id(&self) -> &ClassId { - &self.class_id.base_class_id - } - - fn get_uri(&self) -> Option<&ClassUri> { - self.class_uri.as_ref() - } - - fn get_data(&self) -> Option<&ClassData> { - self.class_data.as_ref() - } -} - -/// NFT metadata -#[derive(Clone, Debug)] -pub struct NftMetadata { - /// NFT class ID - pub class_id: PrefixedClassId, - /// NFT ID - pub token_id: TokenId, - /// NFT URI - pub token_uri: Option, - /// NFT data - pub token_data: Option, -} - -impl BorshSerialize for NftMetadata { - fn serialize( - &self, - writer: &mut W, - ) -> std::io::Result<()> { - BorshSerialize::serialize(&self.class_id.to_string(), writer)?; - BorshSerialize::serialize(&self.token_id.to_string(), writer)?; - match &self.token_uri { - Some(uri) => { - BorshSerialize::serialize(&true, writer)?; - BorshSerialize::serialize(&uri.to_string(), writer)?; - } - None => BorshSerialize::serialize(&false, writer)?, - } - match &self.token_data { - Some(data) => { - BorshSerialize::serialize(&true, writer)?; - BorshSerialize::serialize(&data.to_string(), writer) - } - None => BorshSerialize::serialize(&false, writer), - } - } -} - -impl BorshDeserialize for NftMetadata { - fn deserialize_reader( - reader: &mut R, - ) -> std::io::Result { - use std::io::{Error, ErrorKind}; - let class_id: String = BorshDeserialize::deserialize_reader(reader)?; - let class_id = class_id.parse().map_err(|e: NftTransferError| { - Error::new(ErrorKind::InvalidData, e.to_string()) - })?; - - let token_id: String = BorshDeserialize::deserialize_reader(reader)?; - let token_id = token_id.parse().map_err(|e: NftTransferError| { - Error::new(ErrorKind::InvalidData, e.to_string()) - })?; - - let is_uri: bool = BorshDeserialize::deserialize_reader(reader)?; - let token_uri = if is_uri { - let uri_str: String = BorshDeserialize::deserialize_reader(reader)?; - Some(uri_str.parse().map_err(|e: NftTransferError| { - Error::new(ErrorKind::InvalidData, e.to_string()) - })?) - } else { - None - }; - - let is_data: bool = BorshDeserialize::deserialize_reader(reader)?; - let token_data = if is_data { - let data_str: String = - BorshDeserialize::deserialize_reader(reader)?; - Some(data_str.parse().map_err(|e: NftTransferError| { - Error::new(ErrorKind::InvalidData, e.to_string()) - })?) - } else { - None - }; - - Ok(Self { - class_id, - token_id, - token_uri, - token_data, - }) - } -} - -impl NftContext for NftMetadata { - fn get_class_id(&self) -> &ClassId { - &self.class_id.base_class_id - } - - fn get_id(&self) -> &TokenId { - &self.token_id - } - - fn get_uri(&self) -> Option<&TokenUri> { - self.token_uri.as_ref() - } - - fn get_data(&self) -> Option<&TokenData> { - self.token_data.as_ref() - } -} diff --git a/crates/core/src/masp.rs b/crates/core/src/masp.rs index fde643d214..4255983854 100644 --- a/crates/core/src/masp.rs +++ b/crates/core/src/masp.rs @@ -2,6 +2,7 @@ use std::collections::BTreeMap; use std::fmt::Display; +use std::num::ParseIntError; use std::str::FromStr; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; @@ -16,6 +17,7 @@ use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use crate::address::{Address, DecodeError, HASH_HEX_LEN, IBC, MASP}; +use crate::hash::Hash; use crate::impl_display_and_from_str_via_format; use crate::storage::Epoch; use crate::string_encoding::{ @@ -24,6 +26,72 @@ use crate::string_encoding::{ }; use crate::token::{Denomination, MaspDigitPos}; +/// Wrapper type around `Epoch` for type safe operations involving the masp +/// epoch +#[derive( + BorshSerialize, + BorshDeserialize, + BorshDeserializer, + BorshSchema, + Clone, + Copy, + Debug, + PartialOrd, + Ord, + PartialEq, + Eq, + Hash, + Serialize, + Deserialize, +)] +pub struct MaspEpoch(Epoch); + +impl Display for MaspEpoch { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl FromStr for MaspEpoch { + type Err = ParseIntError; + + fn from_str(s: &str) -> std::result::Result { + let raw: u64 = u64::from_str(s)?; + Ok(Self(Epoch(raw))) + } +} + +impl MaspEpoch { + /// Converts and `Epoch` into a `MaspEpoch` based on the provided conversion + /// rate + pub fn try_from_epoch( + epoch: Epoch, + masp_epoch_multiplier: u64, + ) -> Result { + Ok(Self( + epoch + .checked_div(masp_epoch_multiplier) + .ok_or("Masp epoch multiplier cannot be 0")?, + )) + } + + /// Returns a 0 masp epoch + pub const fn zero() -> Self { + Self(Epoch(0)) + } + + /// Change to the previous masp epoch. + pub fn prev(&self) -> Option { + Some(Self(self.0.checked_sub(1)?)) + } + + /// Initialize a new masp epoch from the provided one + #[cfg(any(test, feature = "testing"))] + pub const fn new(epoch: u64) -> Self { + Self(Epoch(epoch)) + } +} + /// The plain representation of a MASP aaset #[derive( BorshSerialize, @@ -48,7 +116,7 @@ pub struct AssetData { /// The digit position covered by this asset type pub position: MaspDigitPos, /// The epoch of the asset type, if any - pub epoch: Option, + pub epoch: Option, } impl AssetData { @@ -67,7 +135,7 @@ impl AssetData { /// Give this pre-asset type the given epoch if already has an epoch. Return /// the replaced value. - pub fn redate(&mut self, to: Epoch) -> Option { + pub fn redate(&mut self, to: MaspEpoch) -> Option { if self.epoch.is_some() { self.epoch.replace(to) } else { @@ -86,7 +154,7 @@ pub fn encode_asset_type( token: Address, denom: Denomination, position: MaspDigitPos, - epoch: Option, + epoch: Option, ) -> Result { AssetData { token, @@ -611,3 +679,21 @@ impl FromStr for MaspValue { }) } } + +/// The masp transactions' references of a given batch +#[derive(Default, Clone, Serialize, Deserialize)] +pub struct MaspTxRefs(pub Vec); + +impl Display for MaspTxRefs { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", serde_json::to_string(self).unwrap()) + } +} + +impl FromStr for MaspTxRefs { + type Err = serde_json::Error; + + fn from_str(s: &str) -> Result { + serde_json::from_str(s) + } +} diff --git a/crates/core/src/parameters.rs b/crates/core/src/parameters.rs index 2f047ce670..aaf2c294f8 100644 --- a/crates/core/src/parameters.rs +++ b/crates/core/src/parameters.rs @@ -46,6 +46,9 @@ pub struct Parameters { pub implicit_vp_code_hash: Option, /// Expected number of epochs per year (read only) pub epochs_per_year: u64, + /// The multiplier for masp epochs (it requires this amount of epochs to + /// transition to the next masp epoch) + pub masp_epoch_multiplier: u64, /// Maximum number of signature per transaction pub max_signatures_per_transaction: u8, /// Fee unshielding gas limit diff --git a/crates/core/src/time.rs b/crates/core/src/time.rs index b4ed29e6b6..ed1815efca 100644 --- a/crates/core/src/time.rs +++ b/crates/core/src/time.rs @@ -162,6 +162,12 @@ impl DateTimeUtc { ) } + /// Returns the unix timestamp associated with this [`DateTimeUtc`]. + #[inline] + pub fn to_unix_timestamp(&self) -> i64 { + self.0.timestamp() + } + /// Returns a [`DateTimeUtc`] corresponding to the provided Unix timestamp. #[inline] pub fn from_unix_timestamp(timestamp: i64) -> Option { diff --git a/crates/core/src/token.rs b/crates/core/src/token.rs index 7a713a1355..aead0e1b37 100644 --- a/crates/core/src/token.rs +++ b/crates/core/src/token.rs @@ -7,17 +7,15 @@ use std::str::FromStr; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use data_encoding::BASE32HEX_NOPAD; use ethabi::ethereum_types::U256; +use ibc::apps::transfer::types::Amount as IbcAmount; use namada_macros::BorshDeserializer; #[cfg(feature = "migrations")] use namada_migrations::*; use serde::{Deserialize, Serialize}; use thiserror::Error; -use crate::address::Address; use crate::arith::{self, checked, CheckedAdd, CheckedSub}; use crate::dec::{Dec, POS_DECIMAL_PRECISION}; -use crate::hash::Hash; -use crate::ibc::apps::transfer::types::Amount as IbcAmount; use crate::storage; use crate::storage::{DbKeySeg, KeySeg}; use crate::uint::{self, Uint, I256}; @@ -950,34 +948,6 @@ impl From for IbcAmount { } } -/// A simple bilateral token transfer -#[derive( - Debug, - Clone, - PartialEq, - BorshSerialize, - BorshDeserialize, - BorshDeserializer, - BorshSchema, - Hash, - Eq, - PartialOrd, - Serialize, - Deserialize, -)] -pub struct Transfer { - /// Source address will spend the tokens - pub source: Address, - /// Target address will receive the tokens - pub target: Address, - /// Token's address - pub token: Address, - /// The amount of tokens - pub amount: DenominatedAmount, - /// Shielded transaction part - pub shielded: Option, -} - #[allow(missing_docs)] #[derive(Error, Debug)] pub enum AmountError { @@ -994,9 +964,6 @@ pub mod testing { use proptest::prelude::*; use super::*; - use crate::address::testing::{ - arb_established_address, arb_non_internal_address, - }; impl std::ops::Add for Amount { type Output = Self; @@ -1078,24 +1045,6 @@ pub mod testing { } } - prop_compose! { - /// Generate a transfer - pub fn arb_transfer()( - source in arb_non_internal_address(), - target in arb_non_internal_address(), - token in arb_established_address().prop_map(Address::Established), - amount in arb_denominated_amount(), - ) -> Transfer { - Transfer { - source, - target, - token, - amount, - shielded: None, - } - } - } - /// Generate an arbitrary token amount pub fn arb_amount() -> impl Strategy { any::().prop_map(|val| Amount::from_uint(val, 0).unwrap()) diff --git a/crates/encoding_spec/src/main.rs b/crates/encoding_spec/src/main.rs index ea5858ae3f..efb5c0c79c 100644 --- a/crates/encoding_spec/src/main.rs +++ b/crates/encoding_spec/src/main.rs @@ -23,14 +23,13 @@ use borsh::{schema, schema_container_of}; use itertools::Itertools; use lazy_static::lazy_static; use madato::types::TableRow; -use namada::account; use namada::core::address::Address; use namada::core::collections::HashSet; use namada::core::key::ed25519::{PublicKey, Signature}; use namada::core::storage::{self, Epoch}; -use namada::core::token; use namada::ledger::parameters::Parameters; use namada::tx::data::{pos, TxType, WrapperTx}; +use namada::{account, token}; /// This generator will write output into this `docs` file. const OUTPUT_PATH: &str = @@ -82,7 +81,14 @@ fn main() -> Result<(), Box> { let signature_schema = schema_container_of::(); let init_account_schema = schema_container_of::(); let init_validator_schema = schema_container_of::(); - let token_transfer_schema = schema_container_of::(); + let transparent_transfer_schema = + schema_container_of::(); + let shielded_transfer_schema = + schema_container_of::(); + let shielding_transfer_schema = + schema_container_of::(); + let unshielding_transfer_schema = + schema_container_of::(); let update_account = schema_container_of::(); let pos_bond_schema = schema_container_of::(); let pos_withdraw_schema = schema_container_of::(); @@ -109,7 +115,10 @@ fn main() -> Result<(), Box> { definitions.extend(btree(&signature_schema)); definitions.extend(btree(&init_account_schema)); definitions.extend(btree(&init_validator_schema)); - definitions.extend(btree(&token_transfer_schema)); + definitions.extend(btree(&transparent_transfer_schema)); + definitions.extend(btree(&shielded_transfer_schema)); + definitions.extend(btree(&shielding_transfer_schema)); + definitions.extend(btree(&unshielding_transfer_schema)); definitions.extend(btree(&update_account)); definitions.extend(btree(&pos_bond_schema)); definitions.extend(btree(&pos_withdraw_schema)); @@ -183,10 +192,10 @@ fn main() -> Result<(), Box> { tables.push(init_validator_table); let token_transfer_definition = definitions - .remove(token_transfer_schema.declaration()) + .remove(transparent_transfer_schema.declaration()) .unwrap(); let token_transfer_table = definition_to_table( - token_transfer_schema.declaration(), + transparent_transfer_schema.declaration(), token_transfer_definition, ).with_rust_doc_link("https://dev.namada.net/master/rustdoc/namada/types/token/struct.Transfer.html"); tables.push(token_transfer_table); diff --git a/crates/ethereum_bridge/Cargo.toml b/crates/ethereum_bridge/Cargo.toml index 89c558ecd9..0250028605 100644 --- a/crates/ethereum_bridge/Cargo.toml +++ b/crates/ethereum_bridge/Cargo.toml @@ -40,17 +40,12 @@ namada_tx = {path = "../tx"} namada_vote_ext = {path = "../vote_ext"} borsh.workspace = true -ethabi.workspace = true ethers.workspace = true eyre.workspace = true itertools.workspace = true konst.workspace = true linkme = {workspace = true, optional = true} serde.workspace = true -serde_json.workspace = true -rand.workspace = true -tendermint = {workspace = true} -tendermint-proto = {workspace = true} thiserror.workspace = true tracing = "0.1.30" diff --git a/crates/events/Cargo.toml b/crates/events/Cargo.toml index 961b40f7ef..573b82e25f 100644 --- a/crates/events/Cargo.toml +++ b/crates/events/Cargo.toml @@ -14,12 +14,13 @@ version.workspace = true [features] default = [] +debug = [] mainnet = [] migrations = [ "namada_migrations", "linkme", ] -testing = [] +testing = ["debug"] [dependencies] namada_core = {path = "../core"} diff --git a/crates/events/src/extend.rs b/crates/events/src/extend.rs index fdd098b401..f51052a0f5 100644 --- a/crates/events/src/extend.rs +++ b/crates/events/src/extend.rs @@ -7,6 +7,7 @@ use std::str::FromStr; use namada_core::collections::HashMap; use namada_core::hash::Hash; +use namada_core::masp::MaspTxRefs; use namada_core::storage::{BlockHeight, TxIndex}; use super::*; @@ -498,28 +499,13 @@ impl EventAttributeEntry<'static> for MaspTxBlockIndex { } } -/// A displyable collection of hashes. -#[derive(Serialize, Deserialize)] -pub struct DisplayableHashVec(Vec); - -impl Display for DisplayableHashVec { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", serde_json::to_string(self).unwrap()) - } -} - -impl From> for DisplayableHashVec { - fn from(value: Vec) -> Self { - Self(value) - } -} - /// Extend an [`Event`] with `masp_tx_batch_refs` data, indicating the specific -/// inner transactions inside the batch that are valid masp txs. -pub struct MaspTxBatchRefs(pub DisplayableHashVec); +/// inner transactions inside the batch that are valid masp txs and the +/// references to the relative masp sections. +pub struct MaspTxBatchRefs(pub MaspTxRefs); impl EventAttributeEntry<'static> for MaspTxBatchRefs { - type Value = DisplayableHashVec; + type Value = MaspTxRefs; type ValueOwned = Self::Value; const KEY: &'static str = "masp_tx_batch_refs"; diff --git a/crates/events/src/lib.rs b/crates/events/src/lib.rs index 78999b0a99..71e0df8ff5 100644 --- a/crates/events/src/lib.rs +++ b/crates/events/src/lib.rs @@ -20,6 +20,8 @@ pub mod extend; #[cfg(any(test, feature = "testing"))] pub mod testing; +#[cfg(any(test, feature = "debug"))] +pub mod tracer; use std::borrow::Cow; use std::collections::BTreeMap; diff --git a/crates/events/src/tracer.rs b/crates/events/src/tracer.rs new file mode 100644 index 0000000000..91ca8d147b --- /dev/null +++ b/crates/events/src/tracer.rs @@ -0,0 +1,302 @@ +//! Trace the origin of emitted events. +//! +//! ## Example +//! +//! ``` +//! #[track_caller] +//! fn emit_event(event: crate::Event, events: &mut impl EmitEvents) { +//! let mut tracer = EventTracer::trace(events); +//! tracer.emit(event); +//! } +//! ``` + +use std::borrow::Cow; +use std::fmt; +use std::mem::{self, MaybeUninit}; +use std::ops::DerefMut; +use std::panic::Location; +use std::str::FromStr; + +use namada_core::booleans::BoolResultUnitExt; + +use super::{EmitEvents, EventToEmit}; +use crate::extend::{ComposeEvent, EventAttributeEntry}; + +/// The origin of an event in source code. +#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct EventTrace<'a> { + pkg_name: Cow<'a, str>, + pkg_version: Cow<'a, str>, + file: Cow<'a, str>, + line: u32, + column: u32, +} + +impl<'a> FromStr for EventTrace<'a> { + type Err = String; + + fn from_str(s: &str) -> Result { + let bindings = s.split(',').map(|binding| { + binding.split_once('=').ok_or_else(|| { + format!("Invalid event trace binding: {binding}") + }) + }); + + mod bits { + pub const DONE: i32 = PKG_NAME | PKG_VERSION | FILE | LINE | COLUMN; + + pub const PKG_NAME: i32 = 0b1; + pub const PKG_VERSION: i32 = 0b10; + pub const FILE: i32 = 0b100; + pub const LINE: i32 = 0b1000; + pub const COLUMN: i32 = 0b10000; + } + + macro_rules! init_trace_field { + ($trace:expr => $field:ident : $type:ty = $value:expr) => { + $trace + .as_mut_ptr() + .cast::() + .wrapping_add(mem::offset_of!(Self, $field)) + .cast::<$type>() + .write($value); + }; + } + + let mut init_state = 0i32; + let mut trace: MaybeUninit> = MaybeUninit::uninit(); + + for maybe_binding in bindings { + let (field, value) = maybe_binding?; + + match field { + "pkg_name" => { + unsafe { + init_trace_field!(trace => pkg_name: Cow<'static, str> = Cow::Owned(value.to_owned())); + } + + init_state |= bits::PKG_NAME; + } + "pkg_version" => { + unsafe { + init_trace_field!(trace => pkg_version: Cow<'static, str> = Cow::Owned(value.to_owned())); + } + + init_state |= bits::PKG_VERSION; + } + "file" => { + unsafe { + init_trace_field!(trace => file: Cow<'static, str> = Cow::Owned(value.to_owned())); + } + + init_state |= bits::FILE; + } + "line" => { + let line = value.parse().map_err(|err| { + format!( + "Failed to parse event trace file line: {value}: \ + {err}" + ) + })?; + unsafe { + init_trace_field!(trace => line: u32 = line); + } + + init_state |= bits::LINE; + } + "column" => { + let column = value.parse().map_err(|err| { + format!( + "Failed to parse event trace file column: \ + {value}: {err}" + ) + })?; + unsafe { + init_trace_field!(trace => column: u32 = column); + } + + init_state |= bits::COLUMN; + } + _ => return Err(format!("Unknown event trace field: {field}")), + } + } + + (init_state == bits::DONE).ok_or_else(|| { + "Some fields were not initialized in the event trace".to_owned() + })?; + + Ok(unsafe { trace.assume_init() }) + } +} + +impl fmt::Display for EventTrace<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { + pkg_name, + pkg_version, + file, + line, + column, + } = self; + write!( + f, + "pkg_name={pkg_name},pkg_version={pkg_version},file={file},\ + line={line},column={column}" + ) + } +} + +/// Tracer of emitted events. +pub struct EventTracer { + wrapped: W, + pkg_name: &'static str, + pkg_version: &'static str, +} + +impl EventTracer { + /// Build a new [`EventTracer`]. + pub const fn trace(wrapped: W) -> Self { + Self { + wrapped, + pkg_name: env!("CARGO_PKG_NAME"), + pkg_version: env!("CARGO_PKG_VERSION"), + } + } +} + +impl EmitEvents for EventTracer +where + EE: EmitEvents, + W: DerefMut, +{ + #[track_caller] + fn emit(&mut self, event: E) + where + E: EventToEmit, + { + let caller = Location::caller(); + + self.wrapped.emit(event.with(EventOrigin(EventTrace { + pkg_name: Cow::Borrowed(self.pkg_name), + pkg_version: Cow::Borrowed(self.pkg_version), + file: Cow::Borrowed(caller.file()), + line: caller.line(), + column: caller.column(), + }))); + } + + #[track_caller] + fn emit_many(&mut self, event_batch: B) + where + B: IntoIterator, + E: EventToEmit, + { + let caller = Location::caller(); + + self.wrapped.emit_many(event_batch.into_iter().map(|event| { + event.with(EventOrigin(EventTrace { + pkg_name: Cow::Borrowed(self.pkg_name), + pkg_version: Cow::Borrowed(self.pkg_version), + file: Cow::Borrowed(caller.file()), + line: caller.line(), + column: caller.column(), + })) + })); + } +} + +/// Extend an [`Event`](super::Event) with data pertaining to its origin in +/// source code. +pub struct EventOrigin<'a>(pub EventTrace<'a>); + +impl<'a> EventAttributeEntry<'a> for EventOrigin<'a> { + type Value = EventTrace<'a>; + type ValueOwned = EventTrace<'static>; + + const KEY: &'static str = "event-origin"; + + fn into_value(self) -> Self::Value { + self.0 + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{Event, EventLevel, EventTypeBuilder}; + + const fn dummy_trace() -> EventTrace<'static> { + EventTrace { + pkg_name: Cow::Borrowed("pkg"), + pkg_version: Cow::Borrowed("ver"), + file: Cow::Borrowed("src/file.rs"), + line: 1, + column: 2, + } + } + + #[test] + fn test_event_trace_emit_event() { + let (event, start_line, end_line) = { + let ev = Event::new( + EventTypeBuilder::new_with_type("test").build(), + EventLevel::Tx, + ); + let mut events = Vec::with_capacity(1); + + const START_LINE: u32 = line!(); + emit_event(ev, &mut events); + const END_LINE: u32 = line!(); + + (events.pop().unwrap(), START_LINE, END_LINE) + }; + + let trace = event.read_attribute::>().unwrap(); + + assert!(trace.line > start_line && trace.line < end_line); + assert_eq!(trace.file, file!()); + assert_eq!(trace.pkg_name, env!("CARGO_PKG_NAME")); + assert_eq!(trace.pkg_version, env!("CARGO_PKG_VERSION")); + } + + #[test] + fn test_event_trace_roundtrip() { + let serialized = dummy_trace().to_string(); + let deserialized: EventTrace<'static> = serialized.parse().unwrap(); + + assert_eq!(deserialized, dummy_trace()); + } + + #[test] + fn test_event_trace_fields_missing() { + let serialized = "pkg_name=pkg,pkg_version=ver"; + let result: Result, _> = serialized.parse(); + + assert_eq!( + result, + Err("Some fields were not initialized in the event trace" + .to_owned()) + ); + } + + #[test] + fn test_event_trace_invalid_line() { + let serialized = "pkg_name=pkg,line=bruv"; + let result: Result, _> = serialized.parse(); + + assert_eq!( + result, + Err( + "Failed to parse event trace file line: bruv: invalid digit \ + found in string" + .to_owned() + ) + ); + } + + #[track_caller] + fn emit_event(event: Event, events: &mut impl EmitEvents) { + let mut tracer = EventTracer::trace(events); + tracer.emit(event); + } +} diff --git a/crates/gas/src/lib.rs b/crates/gas/src/lib.rs index c015542008..89e24209ff 100644 --- a/crates/gas/src/lib.rs +++ b/crates/gas/src/lib.rs @@ -84,14 +84,31 @@ pub const WASM_MEMORY_PAGE_GAS: u32 = pub const IBC_ACTION_VALIDATE_GAS: u64 = 1_472_023; /// The cost to execute an Ibc action pub const IBC_ACTION_EXECUTE_GAS: u64 = 3_678_745; -/// The cost to verify a masp spend note -pub const MASP_VERIFY_SPEND_GAS: u64 = 66_822_000; -/// The cost to verify a masp convert note -pub const MASP_VERIFY_CONVERT_GAS: u64 = 45_240_000; -/// The cost to verify a masp output note -pub const MASP_VERIFY_OUTPUT_GAS: u64 = 55_023_000; -/// The cost to run the final masp verification -pub const MASP_VERIFY_FINAL_GAS: u64 = 3_475_200; +/// The cost of masp sig verification +pub const MASP_VERIFY_SIG_GAS: u64 = 5_443_000; +/// The fixed cost of spend note verification +pub const MASP_FIXED_SPEND_GAS: u64 = 87_866_000; +/// The variable cost of spend note verification +pub const MASP_VARIABLE_SPEND_GAS: u64 = 14_384_000; +/// The fixed cost of convert note verification +pub const MASP_FIXED_CONVERT_GAS: u64 = 70_308_000; +/// The variable cost of convert note verification +pub const MASP_VARIABLE_CONVERT_GAS: u64 = 12_664_000; +/// The fixed cost of output note verification +pub const MASP_FIXED_OUTPUT_GAS: u64 = 78_203_000; +/// The variable cost of output note verification +pub const MASP_VARIABLE_OUTPUT_GAS: u64 = 14_586_000; +/// The cost to process a masp spend note in the bundle +pub const MASP_SPEND_CHECK_GAS: u64 = 479_730; +/// The cost to process a masp convert note in the bundle +pub const MASP_CONVERT_CHECK_GAS: u64 = 173_570; +/// The cost to process a masp output note in the bundle +pub const MASP_OUTPUT_CHECK_GAS: u64 = 310_260; +/// The cost to run the final masp check in the bundle +pub const MASP_FINAL_CHECK_GAS: u64 = 44; +/// Gas divider specific for the masp vp. Only allocates half of the cores to +/// the masp vp since we can expect the other half to be busy with other vps +pub const MASP_PARALLEL_GAS_DIVIDER: u64 = PARALLEL_GAS_DIVIDER / 2; /// Gas module result for functions that may fail pub type Result = std::result::Result; diff --git a/crates/ibc/Cargo.toml b/crates/ibc/Cargo.toml index d523b9f793..6822e0b40f 100644 --- a/crates/ibc/Cargo.toml +++ b/crates/ibc/Cargo.toml @@ -23,7 +23,6 @@ testing = ["namada_core/testing", "ibc-testkit", "proptest"] [dependencies] namada_core = { path = "../core" } namada_events = { path = "../events", default-features = false } -namada_gas = { path = "../gas" } namada_governance = { path = "../governance" } namada_macros = {path = "../macros"} namada_migrations = {path = "../migrations", optional = true} @@ -31,7 +30,6 @@ namada_parameters = { path = "../parameters" } namada_state = { path = "../state" } namada_storage = { path = "../storage" } namada_token = { path = "../token" } -namada_tx = { path = "../tx"} borsh.workspace = true konst.workspace = true diff --git a/crates/ibc/src/actions.rs b/crates/ibc/src/actions.rs index 65ebd59b80..8acc41623c 100644 --- a/crates/ibc/src/actions.rs +++ b/crates/ibc/src/actions.rs @@ -4,16 +4,15 @@ use std::cell::RefCell; use std::collections::BTreeSet; use std::rc::Rc; +use ibc::apps::transfer::types::msgs::transfer::MsgTransfer as IbcMsgTransfer; +use ibc::apps::transfer::types::packet::PacketData; +use ibc::apps::transfer::types::PrefixedCoin; +use ibc::core::channel::types::timeout::TimeoutHeight; use namada_core::address::Address; use namada_core::borsh::BorshSerializeExt; -use namada_core::ibc::apps::transfer::types::msgs::transfer::MsgTransfer as IbcMsgTransfer; -use namada_core::ibc::apps::transfer::types::packet::PacketData; -use namada_core::ibc::apps::transfer::types::PrefixedCoin; -use namada_core::ibc::core::channel::types::timeout::TimeoutHeight; -use namada_core::ibc::MsgTransfer; use namada_core::tendermint::Time as TmTime; use namada_core::token::Amount; -use namada_events::{EmitEvents, EventTypeBuilder}; +use namada_events::EmitEvents; use namada_governance::storage::proposal::PGFIbcTarget; use namada_parameters::read_epoch_duration_parameter; use namada_state::{ @@ -25,6 +24,7 @@ use namada_token as token; use crate::event::IbcEvent; use crate::{ storage as ibc_storage, IbcActions, IbcCommonContext, IbcStorageContext, + MsgTransfer, }; /// IBC protocol context @@ -123,23 +123,6 @@ where Ok(()) } - /// Get IBC events - fn get_ibc_events( - &self, - event_type: impl AsRef, - ) -> Result, StorageError> { - let event_type = EventTypeBuilder::new_of::() - .with_segment(event_type) - .build(); - - Ok(self - .state - .write_log() - .lookup_events_with_prefix(&event_type) - .filter_map(|event| IbcEvent::try_from(event).ok()) - .collect()) - } - /// Transfer token fn transfer_token( &mut self, diff --git a/crates/ibc/src/context/client.rs b/crates/ibc/src/context/client.rs index 702a1b5e4b..ab34d71832 100644 --- a/crates/ibc/src/context/client.rs +++ b/crates/ibc/src/context/client.rs @@ -1,17 +1,17 @@ //! AnyClientState and AnyConsensusState for IBC context +use ibc::clients::tendermint::client_state::ClientState as TmClientState; +use ibc::clients::tendermint::consensus_state::ConsensusState as TmConsensusState; +use ibc::clients::tendermint::types::{ + ClientState as TmClientStateType, ConsensusState as TmConsensusStateType, +}; +use ibc::core::client::types::error::ClientError; +use ibc::primitives::proto::Any; use ibc_derive::{IbcClientState, IbcConsensusState}; #[cfg(feature = "testing")] use ibc_testkit::testapp::ibc::clients::mock::client_state::MockClientState; #[cfg(feature = "testing")] use ibc_testkit::testapp::ibc::clients::mock::consensus_state::MockConsensusState; -use namada_core::ibc::clients::tendermint::client_state::ClientState as TmClientState; -use namada_core::ibc::clients::tendermint::consensus_state::ConsensusState as TmConsensusState; -use namada_core::ibc::clients::tendermint::types::{ - ClientState as TmClientStateType, ConsensusState as TmConsensusStateType, -}; -use namada_core::ibc::core::client::types::error::ClientError; -use namada_core::ibc::primitives::proto::Any; use prost::Message; use super::common::IbcCommonContext; diff --git a/crates/ibc/src/context/common.rs b/crates/ibc/src/context/common.rs index 562ac257c1..dcc14b7049 100644 --- a/crates/ibc/src/context/common.rs +++ b/crates/ibc/src/context/common.rs @@ -2,30 +2,27 @@ use core::time::Duration; -use namada_core::address::Address; -use namada_core::ibc::apps::nft_transfer::types::{PrefixedClassId, TokenId}; -use namada_core::ibc::clients::tendermint::consensus_state::ConsensusState as TmConsensusState; -use namada_core::ibc::clients::tendermint::types::ConsensusState as TmConsensusStateType; -use namada_core::ibc::core::channel::types::channel::ChannelEnd; -use namada_core::ibc::core::channel::types::commitment::{ +use ibc::apps::nft_transfer::types::{PrefixedClassId, TokenId}; +use ibc::clients::tendermint::consensus_state::ConsensusState as TmConsensusState; +use ibc::clients::tendermint::types::ConsensusState as TmConsensusStateType; +use ibc::core::channel::types::channel::ChannelEnd; +use ibc::core::channel::types::commitment::{ AcknowledgementCommitment, PacketCommitment, }; -use namada_core::ibc::core::channel::types::error::{ - ChannelError, PacketError, -}; -use namada_core::ibc::core::channel::types::packet::Receipt; -use namada_core::ibc::core::channel::types::timeout::TimeoutHeight; -use namada_core::ibc::core::client::types::error::ClientError; -use namada_core::ibc::core::client::types::Height; -use namada_core::ibc::core::connection::types::error::ConnectionError; -use namada_core::ibc::core::connection::types::ConnectionEnd; -use namada_core::ibc::core::handler::types::error::ContextError; -use namada_core::ibc::core::host::types::identifiers::{ +use ibc::core::channel::types::error::{ChannelError, PacketError}; +use ibc::core::channel::types::packet::Receipt; +use ibc::core::channel::types::timeout::TimeoutHeight; +use ibc::core::client::types::error::ClientError; +use ibc::core::client::types::Height; +use ibc::core::connection::types::error::ConnectionError; +use ibc::core::connection::types::ConnectionEnd; +use ibc::core::handler::types::error::ContextError; +use ibc::core::host::types::identifiers::{ ChannelId, ClientId, ConnectionId, PortId, Sequence, }; -use namada_core::ibc::primitives::proto::{Any, Protobuf}; -use namada_core::ibc::primitives::Timestamp; -use namada_core::ibc::{NftClass, NftMetadata}; +use ibc::primitives::proto::{Any, Protobuf}; +use ibc::primitives::Timestamp; +use namada_core::address::Address; use namada_core::storage::{BlockHeight, Key}; use namada_core::tendermint::Time as TmTime; use namada_core::time::DurationSecs; @@ -37,7 +34,7 @@ use sha2::Digest; use super::client::{AnyClientState, AnyConsensusState}; use super::storage::IbcStorageContext; -use crate::storage; +use crate::{storage, NftClass, NftMetadata}; /// Result of IBC common function call pub type Result = std::result::Result; diff --git a/crates/ibc/src/context/execution.rs b/crates/ibc/src/context/execution.rs index 955228edfe..c081d519f7 100644 --- a/crates/ibc/src/context/execution.rs +++ b/crates/ibc/src/context/execution.rs @@ -1,25 +1,23 @@ //! ExecutionContext implementation for IBC -use namada_core::ibc::core::channel::types::channel::ChannelEnd; -use namada_core::ibc::core::channel::types::commitment::{ +use ibc::core::channel::types::channel::ChannelEnd; +use ibc::core::channel::types::commitment::{ AcknowledgementCommitment, PacketCommitment, }; -use namada_core::ibc::core::channel::types::packet::Receipt; -use namada_core::ibc::core::client::context::ClientExecutionContext; -use namada_core::ibc::core::client::types::Height; -use namada_core::ibc::core::connection::types::ConnectionEnd; -use namada_core::ibc::core::handler::types::error::ContextError; -use namada_core::ibc::core::handler::types::events::IbcEvent; -use namada_core::ibc::core::host::types::identifiers::{ - ClientId, ConnectionId, Sequence, -}; -use namada_core::ibc::core::host::types::path::{ +use ibc::core::channel::types::packet::Receipt; +use ibc::core::client::context::ClientExecutionContext; +use ibc::core::client::types::Height; +use ibc::core::connection::types::ConnectionEnd; +use ibc::core::handler::types::error::ContextError; +use ibc::core::handler::types::events::IbcEvent; +use ibc::core::host::types::identifiers::{ClientId, ConnectionId, Sequence}; +use ibc::core::host::types::path::{ AckPath, ChannelEndPath, ClientConnectionPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath, ConnectionPath, ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; -use namada_core::ibc::core::host::ExecutionContext; -use namada_core::ibc::primitives::Timestamp; +use ibc::core::host::ExecutionContext; +use ibc::primitives::Timestamp; use super::client::AnyClientState; use super::common::IbcCommonContext; diff --git a/crates/ibc/src/context/mod.rs b/crates/ibc/src/context/mod.rs index be3190813e..7bba1137b9 100644 --- a/crates/ibc/src/context/mod.rs +++ b/crates/ibc/src/context/mod.rs @@ -16,9 +16,9 @@ use std::fmt::Debug; use std::rc::Rc; use std::time::Duration; +use ibc::core::commitment_types::specs::ProofSpecs; +use ibc::core::host::types::identifiers::ChainId as IbcChainId; use namada_core::hash::Sha256Hasher; -use namada_core::ibc::core::commitment_types::specs::ProofSpecs; -use namada_core::ibc::core::host::types::identifiers::ChainId as IbcChainId; use namada_state::merkle_tree::ics23_specs::proof_specs; /// IBC context to handle IBC-related data diff --git a/crates/ibc/src/context/nft_transfer.rs b/crates/ibc/src/context/nft_transfer.rs index ef06b05ed7..85d9aad44e 100644 --- a/crates/ibc/src/context/nft_transfer.rs +++ b/crates/ibc/src/context/nft_transfer.rs @@ -3,22 +3,21 @@ use std::cell::RefCell; use std::rc::Rc; -use namada_core::address::Address; -use namada_core::ibc::apps::nft_transfer::context::{ +use ibc::apps::nft_transfer::context::{ NftTransferExecutionContext, NftTransferValidationContext, }; -use namada_core::ibc::apps::nft_transfer::types::error::NftTransferError; -use namada_core::ibc::apps::nft_transfer::types::{ +use ibc::apps::nft_transfer::types::error::NftTransferError; +use ibc::apps::nft_transfer::types::{ ClassData, ClassUri, Memo, PrefixedClassId, TokenData, TokenId, TokenUri, PORT_ID_STR, }; -use namada_core::ibc::core::handler::types::error::ContextError; -use namada_core::ibc::core::host::types::identifiers::{ChannelId, PortId}; -use namada_core::ibc::{NftClass, NftMetadata, IBC_ESCROW_ADDRESS}; +use ibc::core::handler::types::error::ContextError; +use ibc::core::host::types::identifiers::{ChannelId, PortId}; +use namada_core::address::Address; use namada_core::token::Amount; use super::common::IbcCommonContext; -use crate::storage; +use crate::{storage, NftClass, NftMetadata, IBC_ESCROW_ADDRESS}; /// NFT transfer context to handle tokens #[derive(Debug)] @@ -89,6 +88,26 @@ where .store_withdraw(token, added_withdraw) .map_err(NftTransferError::from) } + + fn store_ibc_trace( + &self, + owner: &Address, + class_id: &PrefixedClassId, + token_id: &TokenId, + ) -> Result<(), NftTransferError> { + let ibc_trace = format!("{class_id}/{token_id}"); + let trace_hash = storage::calc_hash(&ibc_trace); + + self.inner + .borrow_mut() + .store_ibc_trace(owner.to_string(), &trace_hash, &ibc_trace) + .map_err(NftTransferError::from)?; + + self.inner + .borrow_mut() + .store_ibc_trace(token_id, &trace_hash, &ibc_trace) + .map_err(NftTransferError::from) + } } impl NftTransferValidationContext for NftTransferContext @@ -342,6 +361,10 @@ where self.update_mint_amount(&ibc_token, true)?; self.add_deposit(&ibc_token)?; + // Store the IBC trace with the token hash to be able to retrieve it + // later + self.store_ibc_trace(account, class_id, token_id)?; + self.inner .borrow_mut() .mint_token(account, &ibc_token, Amount::from_u64(1)) diff --git a/crates/ibc/src/context/nft_transfer_mod.rs b/crates/ibc/src/context/nft_transfer_mod.rs index e8af60b523..1d94056425 100644 --- a/crates/ibc/src/context/nft_transfer_mod.rs +++ b/crates/ibc/src/context/nft_transfer_mod.rs @@ -4,8 +4,8 @@ use std::cell::RefCell; use std::fmt::Debug; use std::rc::Rc; -use namada_core::ibc::apps::nft_transfer::context::NftTransferValidationContext; -use namada_core::ibc::apps::nft_transfer::module::{ +use ibc::apps::nft_transfer::context::NftTransferValidationContext; +use ibc::apps::nft_transfer::module::{ on_acknowledgement_packet_execute, on_acknowledgement_packet_validate, on_chan_close_confirm_execute, on_chan_close_confirm_validate, on_chan_close_init_execute, on_chan_close_init_validate, @@ -16,21 +16,17 @@ use namada_core::ibc::apps::nft_transfer::module::{ on_recv_packet_execute, on_timeout_packet_execute, on_timeout_packet_validate, }; -use namada_core::ibc::apps::nft_transfer::types::error::NftTransferError; -use namada_core::ibc::apps::nft_transfer::types::MODULE_ID_STR; -use namada_core::ibc::core::channel::types::acknowledgement::Acknowledgement; -use namada_core::ibc::core::channel::types::channel::{Counterparty, Order}; -use namada_core::ibc::core::channel::types::error::{ - ChannelError, PacketError, -}; -use namada_core::ibc::core::channel::types::packet::Packet; -use namada_core::ibc::core::channel::types::Version; -use namada_core::ibc::core::host::types::identifiers::{ - ChannelId, ConnectionId, PortId, -}; -use namada_core::ibc::core::router::module::Module; -use namada_core::ibc::core::router::types::module::{ModuleExtras, ModuleId}; -use namada_core::ibc::primitives::Signer; +use ibc::apps::nft_transfer::types::error::NftTransferError; +use ibc::apps::nft_transfer::types::MODULE_ID_STR; +use ibc::core::channel::types::acknowledgement::Acknowledgement; +use ibc::core::channel::types::channel::{Counterparty, Order}; +use ibc::core::channel::types::error::{ChannelError, PacketError}; +use ibc::core::channel::types::packet::Packet; +use ibc::core::channel::types::Version; +use ibc::core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; +use ibc::core::router::module::Module; +use ibc::core::router::types::module::{ModuleExtras, ModuleId}; +use ibc::primitives::Signer; use super::common::IbcCommonContext; use super::nft_transfer::NftTransferContext; @@ -332,10 +328,8 @@ fn into_packet_error(error: NftTransferError) -> PacketError { pub mod testing { use std::str::FromStr; - use namada_core::ibc::apps::nft_transfer::types::{ - ack_success_b64, PORT_ID_STR, - }; - use namada_core::ibc::core::channel::types::acknowledgement::AcknowledgementStatus; + use ibc::apps::nft_transfer::types::{ack_success_b64, PORT_ID_STR}; + use ibc::core::channel::types::acknowledgement::AcknowledgementStatus; use super::*; diff --git a/crates/ibc/src/context/router.rs b/crates/ibc/src/context/router.rs index 0833a6282a..61fc6e24d9 100644 --- a/crates/ibc/src/context/router.rs +++ b/crates/ibc/src/context/router.rs @@ -2,11 +2,11 @@ use std::rc::Rc; +use ibc::core::host::types::identifiers::PortId; +use ibc::core::router::module::Module; +use ibc::core::router::router::Router; +use ibc::core::router::types::module::ModuleId; use namada_core::collections::HashMap; -use namada_core::ibc::core::host::types::identifiers::PortId; -use namada_core::ibc::core::router::module::Module; -use namada_core::ibc::core::router::router::Router; -use namada_core::ibc::core::router::types::module::ModuleId; use super::super::ModuleWrapper; diff --git a/crates/ibc/src/context/storage.rs b/crates/ibc/src/context/storage.rs index 4db283e567..a33b2621fd 100644 --- a/crates/ibc/src/context/storage.rs +++ b/crates/ibc/src/context/storage.rs @@ -12,12 +12,6 @@ pub trait IbcStorageContext: StorageRead + StorageWrite { /// Emit an IBC event fn emit_ibc_event(&mut self, event: IbcEvent) -> Result<(), Error>; - /// Get IBC events - fn get_ibc_events( - &self, - event_type: impl AsRef, - ) -> Result, Error>; - /// Transfer token fn transfer_token( &mut self, diff --git a/crates/ibc/src/context/token_transfer.rs b/crates/ibc/src/context/token_transfer.rs index fa4b71aafe..ca1128ea68 100644 --- a/crates/ibc/src/context/token_transfer.rs +++ b/crates/ibc/src/context/token_transfer.rs @@ -4,23 +4,20 @@ use std::cell::RefCell; use std::collections::BTreeSet; use std::rc::Rc; -use namada_core::address::{Address, InternalAddress}; -use namada_core::ibc::apps::transfer::context::{ +use ibc::apps::transfer::context::{ TokenTransferExecutionContext, TokenTransferValidationContext, }; -use namada_core::ibc::apps::transfer::types::error::TokenTransferError; -use namada_core::ibc::apps::transfer::types::{ - Memo, PrefixedCoin, PrefixedDenom, -}; -use namada_core::ibc::core::channel::types::error::ChannelError; -use namada_core::ibc::core::handler::types::error::ContextError; -use namada_core::ibc::core::host::types::identifiers::{ChannelId, PortId}; -use namada_core::ibc::IBC_ESCROW_ADDRESS; +use ibc::apps::transfer::types::error::TokenTransferError; +use ibc::apps::transfer::types::{Memo, PrefixedCoin, PrefixedDenom}; +use ibc::core::channel::types::error::ChannelError; +use ibc::core::handler::types::error::ContextError; +use ibc::core::host::types::identifiers::{ChannelId, PortId}; +use namada_core::address::{Address, InternalAddress}; use namada_core::uint::Uint; use namada_token::Amount; use super::common::IbcCommonContext; -use crate::storage; +use crate::{storage, IBC_ESCROW_ADDRESS}; /// Token transfer context to handle tokens #[derive(Debug)] @@ -138,6 +135,32 @@ where .store_withdraw(token, added_withdraw) .map_err(TokenTransferError::from) } + + fn maybe_store_ibc_denom( + &self, + owner: &Address, + coin: &PrefixedCoin, + ) -> Result<(), TokenTransferError> { + if coin.denom.trace_path.is_empty() { + // It isn't an IBC denom + return Ok(()); + } + let ibc_denom = coin.denom.to_string(); + let trace_hash = storage::calc_hash(&ibc_denom); + + self.inner + .borrow_mut() + .store_ibc_trace(owner.to_string(), &trace_hash, &ibc_denom) + .map_err(TokenTransferError::from)?; + + let base_token = Address::decode(coin.denom.base_denom.as_str()) + .map(|a| a.to_string()) + .unwrap_or(coin.denom.base_denom.to_string()); + self.inner + .borrow_mut() + .store_ibc_trace(base_token, &trace_hash, &ibc_denom) + .map_err(TokenTransferError::from) + } } impl TokenTransferValidationContext for TokenTransferContext @@ -274,6 +297,10 @@ where self.insert_verifier(&ibc_token); } + // Store the IBC denom with the token hash to be able to retrieve it + // later + self.maybe_store_ibc_denom(account, coin)?; + self.inner .borrow_mut() .mint_token(account, &ibc_token, amount) diff --git a/crates/ibc/src/context/transfer_mod.rs b/crates/ibc/src/context/transfer_mod.rs index 4b88220213..9a1075e280 100644 --- a/crates/ibc/src/context/transfer_mod.rs +++ b/crates/ibc/src/context/transfer_mod.rs @@ -5,9 +5,8 @@ use std::collections::BTreeSet; use std::fmt::Debug; use std::rc::Rc; -use namada_core::address::Address; -use namada_core::ibc::apps::transfer::context::TokenTransferValidationContext; -use namada_core::ibc::apps::transfer::module::{ +use ibc::apps::transfer::context::TokenTransferValidationContext; +use ibc::apps::transfer::module::{ on_acknowledgement_packet_execute, on_acknowledgement_packet_validate, on_chan_close_confirm_execute, on_chan_close_confirm_validate, on_chan_close_init_execute, on_chan_close_init_validate, @@ -18,21 +17,18 @@ use namada_core::ibc::apps::transfer::module::{ on_recv_packet_execute, on_timeout_packet_execute, on_timeout_packet_validate, }; -use namada_core::ibc::apps::transfer::types::error::TokenTransferError; -use namada_core::ibc::apps::transfer::types::MODULE_ID_STR; -use namada_core::ibc::core::channel::types::acknowledgement::Acknowledgement; -use namada_core::ibc::core::channel::types::channel::{Counterparty, Order}; -use namada_core::ibc::core::channel::types::error::{ - ChannelError, PacketError, -}; -use namada_core::ibc::core::channel::types::packet::Packet; -use namada_core::ibc::core::channel::types::Version; -use namada_core::ibc::core::host::types::identifiers::{ - ChannelId, ConnectionId, PortId, -}; -use namada_core::ibc::core::router::module::Module; -use namada_core::ibc::core::router::types::module::{ModuleExtras, ModuleId}; -use namada_core::ibc::primitives::Signer; +use ibc::apps::transfer::types::error::TokenTransferError; +use ibc::apps::transfer::types::MODULE_ID_STR; +use ibc::core::channel::types::acknowledgement::Acknowledgement; +use ibc::core::channel::types::channel::{Counterparty, Order}; +use ibc::core::channel::types::error::{ChannelError, PacketError}; +use ibc::core::channel::types::packet::Packet; +use ibc::core::channel::types::Version; +use ibc::core::host::types::identifiers::{ChannelId, ConnectionId, PortId}; +use ibc::core::router::module::Module; +use ibc::core::router::types::module::{ModuleExtras, ModuleId}; +use ibc::primitives::Signer; +use namada_core::address::Address; use super::common::IbcCommonContext; use super::token_transfer::TokenTransferContext; @@ -351,10 +347,8 @@ fn into_packet_error(error: TokenTransferError) -> PacketError { pub mod testing { use std::str::FromStr; - use namada_core::ibc::apps::transfer::types::{ - ack_success_b64, PORT_ID_STR, - }; - use namada_core::ibc::core::channel::types::acknowledgement::AcknowledgementStatus; + use ibc::apps::transfer::types::{ack_success_b64, PORT_ID_STR}; + use ibc::core::channel::types::acknowledgement::AcknowledgementStatus; use super::*; diff --git a/crates/ibc/src/context/validation.rs b/crates/ibc/src/context/validation.rs index e063ccc772..5cb60fcd12 100644 --- a/crates/ibc/src/context/validation.rs +++ b/crates/ibc/src/context/validation.rs @@ -1,31 +1,31 @@ //! ValidationContext implementation for IBC -#[cfg(feature = "testing")] -use ibc_testkit::testapp::ibc::clients::mock::client_state::MockClientState; -use namada_core::ibc::clients::tendermint::client_state::ClientState as TmClientState; -use namada_core::ibc::core::channel::types::channel::ChannelEnd; -use namada_core::ibc::core::channel::types::commitment::{ +use ibc::clients::tendermint::client_state::ClientState as TmClientState; +use ibc::core::channel::types::channel::ChannelEnd; +use ibc::core::channel::types::commitment::{ AcknowledgementCommitment, PacketCommitment, }; -use namada_core::ibc::core::channel::types::packet::Receipt; -use namada_core::ibc::core::client::context::{ +use ibc::core::channel::types::packet::Receipt; +use ibc::core::client::context::{ ClientValidationContext, ExtClientValidationContext, }; -use namada_core::ibc::core::client::types::Height; -use namada_core::ibc::core::commitment_types::commitment::CommitmentPrefix; -use namada_core::ibc::core::commitment_types::specs::ProofSpecs; -use namada_core::ibc::core::connection::types::ConnectionEnd; -use namada_core::ibc::core::handler::types::error::ContextError; -use namada_core::ibc::core::host::types::identifiers::{ +use ibc::core::client::types::Height; +use ibc::core::commitment_types::commitment::CommitmentPrefix; +use ibc::core::commitment_types::specs::ProofSpecs; +use ibc::core::connection::types::ConnectionEnd; +use ibc::core::handler::types::error::ContextError; +use ibc::core::host::types::identifiers::{ ChainId, ClientId, ConnectionId, Sequence, }; -use namada_core::ibc::core::host::types::path::{ +use ibc::core::host::types::path::{ AckPath, ChannelEndPath, ClientConsensusStatePath, CommitmentPath, ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; -use namada_core::ibc::core::host::ValidationContext; -use namada_core::ibc::cosmos_host::ValidateSelfClientContext; -use namada_core::ibc::primitives::{Signer, Timestamp}; +use ibc::core::host::ValidationContext; +use ibc::cosmos_host::ValidateSelfClientContext; +use ibc::primitives::{Signer, Timestamp}; +#[cfg(feature = "testing")] +use ibc_testkit::testapp::ibc::clients::mock::client_state::MockClientState; use super::client::{AnyClientState, AnyConsensusState}; use super::common::IbcCommonContext; diff --git a/crates/ibc/src/event.rs b/crates/ibc/src/event.rs index 7bd613e881..5d340aee25 100644 --- a/crates/ibc/src/event.rs +++ b/crates/ibc/src/event.rs @@ -3,23 +3,23 @@ use std::cmp::Ordering; use std::str::FromStr; -use namada_core::borsh::*; -use namada_core::collections::HashMap; -use namada_core::ibc::core::channel::types::packet::Packet; -use namada_core::ibc::core::channel::types::timeout::TimeoutHeight as IbcTimeoutHeight; -use namada_core::ibc::core::client::types::events::{ +use ibc::core::channel::types::packet::Packet; +use ibc::core::channel::types::timeout::TimeoutHeight as IbcTimeoutHeight; +use ibc::core::client::types::events::{ CLIENT_ID_ATTRIBUTE_KEY, CONSENSUS_HEIGHTS_ATTRIBUTE_KEY, }; -use namada_core::ibc::core::client::types::{Height as IbcHeight, HeightError}; -use namada_core::ibc::core::handler::types::events::IbcEvent as RawIbcEvent; -use namada_core::ibc::core::host::types::identifiers::{ +use ibc::core::client::types::{Height as IbcHeight, HeightError}; +use ibc::core::handler::types::events::IbcEvent as RawIbcEvent; +use ibc::core::host::types::identifiers::{ ChannelId as IbcChannelId, ClientId as IbcClientId, ConnectionId as IbcConnectionId, PortId, Sequence, }; -use namada_core::ibc::primitives::Timestamp; +use ibc::primitives::Timestamp; +use namada_core::borsh::*; +use namada_core::collections::HashMap; use namada_core::tendermint::abci::Event as AbciEvent; use namada_events::extend::{ - event_domain_of, AttributesMap, EventAttributeEntry, ExtendAttributesMap, + event_domain_of, AttributesMap, EventAttributeEntry, ReadFromEventAttributes as _, }; use namada_events::{ @@ -36,7 +36,7 @@ pub const TOKEN_EVENT_DESCRIPTOR: &str = IbcEvent::DOMAIN; pub mod types { //! IBC event types. - use namada_core::ibc::core::client::types::events::UPDATE_CLIENT_EVENT; + use ibc::core::client::types::events::UPDATE_CLIENT_EVENT; use namada_events::{event_type, EventType}; use super::IbcEvent; @@ -140,63 +140,6 @@ pub struct IbcEvent { pub attributes: HashMap, } -fn validate_ibc_event_type( - namada_event: &Event, -) -> Result { - if namada_event.kind().domain() != IbcEvent::DOMAIN { - return Err(EventError::InvalidEventType); - } - - let event_type = namada_event.kind().sub_domain(); - - // TODO(namada#3229): validate IBC event types. eg: - // - // ```ignore - // if !matches!( - // event_type, - // "update_client" | "send_packet" | "write_acknowledgement" - // ) { - // return Err(EventError::InvalidEventType); - // } - // ``` - - Ok(IbcEventType(event_type.to_owned())) -} - -impl TryFrom<&Event> for IbcEvent { - type Error = EventError; - - fn try_from( - namada_event: &Event, - ) -> std::result::Result { - Ok(Self { - event_type: validate_ibc_event_type(namada_event)?, - #[allow(deprecated)] - attributes: namada_event - .attributes() - .iter() - .map(|(k, v)| (k.clone(), v.clone())) - .collect(), - }) - } -} - -impl TryFrom for IbcEvent { - type Error = EventError; - - fn try_from(namada_event: Event) -> std::result::Result { - Ok(Self { - event_type: validate_ibc_event_type(&namada_event)?, - attributes: { - let mut attrs: HashMap<_, _> = - namada_event.into_attributes().into_iter().collect(); - attrs.with_attribute(event_domain_of::()); - attrs - }, - }) - } -} - impl std::cmp::PartialOrd for IbcEvent { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) @@ -388,7 +331,7 @@ impl FromStr for TimeoutHeight { type Err = HeightError; fn from_str(s: &str) -> Result { - namada_core::ibc::core::client::types::Height::from_str(s).map_or_else( + ibc::core::client::types::Height::from_str(s).map_or_else( |err| match err { HeightError::ZeroHeight => { Ok(TimeoutHeight(IbcTimeoutHeight::Never)) diff --git a/crates/ibc/src/lib.rs b/crates/ibc/src/lib.rs index fc79cfd566..15a673c9c6 100644 --- a/crates/ibc/src/lib.rs +++ b/crates/ibc/src/lib.rs @@ -20,6 +20,8 @@ mod actions; pub mod context; pub mod event; +mod msg; +mod nft; pub mod parameters; pub mod storage; @@ -27,6 +29,7 @@ use std::cell::RefCell; use std::collections::BTreeSet; use std::fmt::Debug; use std::rc::Rc; +use std::str::FromStr; pub use actions::transfer_over_ibc; use borsh::BorshDeserialize; @@ -39,45 +42,52 @@ pub use context::token_transfer::TokenTransferContext; pub use context::transfer_mod::{ModuleWrapper, TransferModule}; use context::IbcContext; pub use context::ValidationParams; -use namada_core::address::{Address, MASP}; -use namada_core::ibc::apps::nft_transfer::handler::{ +use ibc::apps::nft_transfer::handler::{ send_nft_transfer_execute, send_nft_transfer_validate, }; -use namada_core::ibc::apps::nft_transfer::types::error::NftTransferError; -use namada_core::ibc::apps::nft_transfer::types::packet::PacketData as NftPacketData; -use namada_core::ibc::apps::nft_transfer::types::{ - is_receiver_chain_source as is_nft_receiver_chain_source, PrefixedClassId, - TokenId, TracePrefix as NftTracePrefix, +use ibc::apps::nft_transfer::types::error::NftTransferError; +use ibc::apps::nft_transfer::types::{ + ack_success_b64, is_receiver_chain_source as is_nft_receiver_chain_source, + PrefixedClassId, TokenId, TracePath as NftTracePath, + TracePrefix as NftTracePrefix, }; -use namada_core::ibc::apps::transfer::handler::{ +use ibc::apps::transfer::handler::{ send_transfer_execute, send_transfer_validate, }; -use namada_core::ibc::apps::transfer::types::error::TokenTransferError; -use namada_core::ibc::apps::transfer::types::packet::PacketData; -use namada_core::ibc::apps::transfer::types::{ - is_receiver_chain_source, TracePrefix, +use ibc::apps::transfer::types::error::TokenTransferError; +use ibc::apps::transfer::types::{ + is_receiver_chain_source, PrefixedDenom, TracePath, TracePrefix, }; -use namada_core::ibc::core::channel::types::acknowledgement::{ +use ibc::core::channel::types::acknowledgement::{ Acknowledgement, AcknowledgementStatus, }; -use namada_core::ibc::core::channel::types::msgs::{ +use ibc::core::channel::types::commitment::compute_ack_commitment; +use ibc::core::channel::types::msgs::{ MsgRecvPacket as IbcMsgRecvPacket, PacketMsg, }; -use namada_core::ibc::core::entrypoint::{execute, validate}; -use namada_core::ibc::core::handler::types::error::ContextError; -use namada_core::ibc::core::handler::types::events::Error as RawIbcEventError; -use namada_core::ibc::core::handler::types::msgs::MsgEnvelope; -use namada_core::ibc::core::host::types::error::IdentifierError; -use namada_core::ibc::core::host::types::identifiers::{ChannelId, PortId}; -use namada_core::ibc::core::router::types::error::RouterError; -use namada_core::ibc::primitives::proto::Any; -pub use namada_core::ibc::*; -use namada_core::masp::PaymentAddress; -use namada_events::extend::{ReadFromEventAttributes, Success as SuccessAttr}; -use namada_token::Transfer; +use ibc::core::entrypoint::{execute, validate}; +use ibc::core::handler::types::error::ContextError; +use ibc::core::handler::types::events::Error as RawIbcEventError; +use ibc::core::handler::types::msgs::MsgEnvelope; +use ibc::core::host::types::error::IdentifierError; +use ibc::core::host::types::identifiers::{ChannelId, PortId}; +use ibc::core::router::types::error::RouterError; +use ibc::primitives::proto::Any; +pub use ibc::*; +pub use msg::*; +use namada_core::address::{self, Address}; +use namada_token::ShieldingTransfer; +pub use nft::*; use prost::Message; use thiserror::Error; +/// The event type defined in ibc-rs for receiving a token +pub const EVENT_TYPE_PACKET: &str = "fungible_token_packet"; +/// The event type defined in ibc-rs for receiving an NFT +pub const EVENT_TYPE_NFT_PACKET: &str = "non_fungible_token_packet"; +/// The escrow address for IBC transfer +pub const IBC_ESCROW_ADDRESS: Address = address::IBC; + #[allow(missing_docs)] #[derive(Error, Debug)] pub enum Error { @@ -142,7 +152,7 @@ where pub fn execute( &mut self, tx_data: &[u8], - ) -> Result, Error> { + ) -> Result, Error> { let message = decode_message(tx_data)?; match &message { IbcMessage::Transfer(msg) => { @@ -175,10 +185,7 @@ where MsgEnvelope::Packet(PacketMsg::Recv(msg.message.clone())); execute(&mut self.ctx, &mut self.router, envelope) .map_err(|e| Error::Context(Box::new(e)))?; - let transfer = if self.is_receiving_success()? { - // the current ibc-rs execution doesn't store the denom - // for the token hash when transfer with MsgRecvPacket - self.store_trace(&msg.message)?; + let transfer = if self.is_receiving_success(&msg.message)? { // For receiving the token to a shielded address msg.transfer.clone() } else { @@ -211,147 +218,31 @@ where IbcMessage::Envelope(envelope) => { execute(&mut self.ctx, &mut self.router, *envelope.clone()) .map_err(|e| Error::Context(Box::new(e)))?; - if let MsgEnvelope::Packet(PacketMsg::Recv(msg)) = &**envelope { - if self.is_receiving_success()? { - // the current ibc-rs execution doesn't store the denom - // for the token hash when transfer with MsgRecvPacket - self.store_trace(msg)?; - } - } Ok(None) } } } - /// Store the trace path when transfer with MsgRecvPacket - fn store_trace(&mut self, msg: &IbcMsgRecvPacket) -> Result<(), Error> { - // Get the IBC trace, and the receiver from the packet data - let minted_token_info = if let Ok(data) = - serde_json::from_slice::(&msg.packet.data) - { - let ibc_denom = received_ibc_trace( - data.token.denom.to_string(), - &msg.packet.port_id_on_a, - &msg.packet.chan_id_on_a, - &msg.packet.port_id_on_b, - &msg.packet.chan_id_on_b, - )?; - if !ibc_denom.contains('/') { - // Skip to store it because the token has been redeemed - return Ok(()); - } - let receiver = - if data.receiver.as_ref().parse::().is_ok() { - MASP.to_string() - } else { - data.receiver.to_string() - }; - Some((vec![ibc_denom], receiver)) - } else if let Ok(data) = - serde_json::from_slice::(&msg.packet.data) - { - let ibc_traces: Result, _> = data - .token_ids - .0 - .iter() - .map(|id| { - let trace = format!("{}/{id}", data.class_id); - received_ibc_trace( - trace, - &msg.packet.port_id_on_a, - &msg.packet.chan_id_on_a, - &msg.packet.port_id_on_b, - &msg.packet.chan_id_on_b, - ) - }) - .collect(); - let receiver = - if data.receiver.as_ref().parse::().is_ok() { - MASP.to_string() - } else { - data.receiver.to_string() - }; - Some((ibc_traces?, receiver)) - } else { - None - }; - - if let Some((ibc_traces, receiver)) = minted_token_info { - // If the trace event has the trace hash and the IBC denom or NFT - // IDs, a token has been minted. The raw IBC trace including the - // port ID, the channel ID and the base token is stored to be - // restored from the trace hash. - for ibc_trace in ibc_traces { - let trace_hash = storage::calc_hash(&ibc_trace); - self.ctx - .inner - .borrow_mut() - .store_ibc_trace(&receiver, &trace_hash, &ibc_trace) - .map_err(|e| { - Error::Trace(format!( - "Writing the IBC trace failed: {}", - e - )) - })?; - let base_token = if let Some((_, base_token)) = - is_ibc_denom(&ibc_trace) - { - base_token - } else if let Some((_, _, token_id)) = is_nft_trace(&ibc_trace) - { - token_id - } else { - // non-prefixed denom - continue; - }; - self.ctx - .inner - .borrow_mut() - .store_ibc_trace(base_token, trace_hash, &ibc_trace) - .map_err(|e| { - Error::Trace(format!( - "Writing the IBC trace failed: {}", - e - )) - })?; - } - } - Ok(()) - } - - /// Check the result of receiving the packet from IBC events - fn is_receiving_success(&self) -> Result { - let mut receive_event = self + /// Check the result of receiving the packet by checking the packet + /// acknowledgement + fn is_receiving_success( + &self, + msg: &IbcMsgRecvPacket, + ) -> Result { + let packet_ack = self .ctx .inner .borrow() - .get_ibc_events(EVENT_TYPE_PACKET) - .map_err(|_| { - Error::Trace("Reading the IBC event failed".to_string()) - })?; - if receive_event.is_empty() { - // check the packet is for an NFT - receive_event = self - .ctx - .inner - .borrow() - .get_ibc_events(EVENT_TYPE_NFT_PACKET) - .map_err(|_| { - Error::Trace("Reading the IBC event failed".to_string()) - })?; - } - receive_event.first().as_ref().map_or_else( - || Ok(false), - |event| { - let success = SuccessAttr::read_opt_from_event_attributes( - &event.attributes, - ) - .map_err(|err| { - Error::Trace(format!("Reading the IBC event failed: {err}")) - })?; - Ok(success.unwrap_or(false)) - }, - ) + .packet_ack( + &msg.packet.port_id_on_b, + &msg.packet.chan_id_on_b, + msg.packet.seq_on_a, + ) + .map_err(|e| Error::Context(Box::new(e)))?; + let success_ack_commitment = compute_ack_commitment( + &AcknowledgementStatus::success(ack_success_b64()).into(), + ); + Ok(packet_ack == success_ack_commitment) } /// Validate according to the message in IBC VP @@ -550,6 +441,37 @@ pub fn received_ibc_token( } } +/// Returns the trace path and the token string if the denom is an IBC +/// denom. +pub fn is_ibc_denom(denom: impl AsRef) -> Option<(TracePath, String)> { + let prefixed_denom = PrefixedDenom::from_str(denom.as_ref()).ok()?; + let base_denom = prefixed_denom.base_denom.to_string(); + if prefixed_denom.trace_path.is_empty() || base_denom.contains('/') { + // The denom is just a token or an NFT trace + return None; + } + // The base token isn't decoded because it could be non Namada token + Some((prefixed_denom.trace_path, base_denom)) +} + +/// Returns the trace path and the token string if the trace is an NFT one +pub fn is_nft_trace( + trace: impl AsRef, +) -> Option<(NftTracePath, String, String)> { + // The trace should be {port}/{channel}/.../{class_id}/{token_id} + if let Some((class_id, token_id)) = trace.as_ref().rsplit_once('/') { + let prefixed_class_id = PrefixedClassId::from_str(class_id).ok()?; + // The base token isn't decoded because it could be non Namada token + Some(( + prefixed_class_id.trace_path, + prefixed_class_id.base_class_id.to_string(), + token_id.to_string(), + )) + } else { + None + } +} + #[cfg(any(test, feature = "testing"))] /// Testing helpers ans strategies for IBC pub mod testing { diff --git a/crates/ibc/src/msg.rs b/crates/ibc/src/msg.rs new file mode 100644 index 0000000000..4d382cf2d4 --- /dev/null +++ b/crates/ibc/src/msg.rs @@ -0,0 +1,194 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use ibc::apps::nft_transfer::types::msgs::transfer::MsgTransfer as IbcMsgNftTransfer; +use ibc::apps::transfer::types::msgs::transfer::MsgTransfer as IbcMsgTransfer; +use ibc::core::channel::types::msgs::{ + MsgAcknowledgement as IbcMsgAcknowledgement, + MsgRecvPacket as IbcMsgRecvPacket, MsgTimeout as IbcMsgTimeout, +}; +use ibc::core::handler::types::msgs::MsgEnvelope; +use ibc::primitives::proto::Protobuf; +use namada_token::ShieldingTransfer; + +/// The different variants of an Ibc message +#[derive(Debug, Clone)] +pub enum IbcMessage { + /// Ibc Envelop + Envelope(Box), + /// Ibc transaprent transfer + Transfer(MsgTransfer), + /// NFT transfer + NftTransfer(MsgNftTransfer), + /// Receiving a packet + RecvPacket(MsgRecvPacket), + /// Acknowledgement + AckPacket(MsgAcknowledgement), + /// Timeout + Timeout(MsgTimeout), +} + +/// IBC transfer message with `Transfer` +#[derive(Debug, Clone)] +pub struct MsgTransfer { + /// IBC transfer message + pub message: IbcMsgTransfer, + /// Shieleded transfer for MASP transaction + pub transfer: Option, +} + +impl BorshSerialize for MsgTransfer { + fn serialize( + &self, + writer: &mut W, + ) -> std::io::Result<()> { + let encoded_msg = self.message.clone().encode_vec(); + let members = (encoded_msg, self.transfer.clone()); + BorshSerialize::serialize(&members, writer) + } +} + +impl BorshDeserialize for MsgTransfer { + fn deserialize_reader( + reader: &mut R, + ) -> std::io::Result { + use std::io::{Error, ErrorKind}; + let (msg, transfer): (Vec, Option) = + BorshDeserialize::deserialize_reader(reader)?; + let message = IbcMsgTransfer::decode_vec(&msg) + .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; + Ok(Self { message, transfer }) + } +} + +/// IBC NFT transfer message with `Transfer` +#[derive(Debug, Clone)] +pub struct MsgNftTransfer { + /// IBC NFT transfer message + pub message: IbcMsgNftTransfer, + /// Shieleded transfer for MASP transaction + pub transfer: Option, +} + +impl BorshSerialize for MsgNftTransfer { + fn serialize( + &self, + writer: &mut W, + ) -> std::io::Result<()> { + let encoded_msg = self.message.clone().encode_vec(); + let members = (encoded_msg, self.transfer.clone()); + BorshSerialize::serialize(&members, writer) + } +} + +impl BorshDeserialize for MsgNftTransfer { + fn deserialize_reader( + reader: &mut R, + ) -> std::io::Result { + use std::io::{Error, ErrorKind}; + let (msg, transfer): (Vec, Option) = + BorshDeserialize::deserialize_reader(reader)?; + let message = IbcMsgNftTransfer::decode_vec(&msg) + .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; + Ok(Self { message, transfer }) + } +} + +/// IBC receiving packet message with `Transfer` +#[derive(Debug, Clone)] +pub struct MsgRecvPacket { + /// IBC receiving packet message + pub message: IbcMsgRecvPacket, + /// Shieleded transfer for MASP transaction + pub transfer: Option, +} + +impl BorshSerialize for MsgRecvPacket { + fn serialize( + &self, + writer: &mut W, + ) -> std::io::Result<()> { + let encoded_msg = self.message.clone().encode_vec(); + let members = (encoded_msg, self.transfer.clone()); + BorshSerialize::serialize(&members, writer) + } +} + +impl BorshDeserialize for MsgRecvPacket { + fn deserialize_reader( + reader: &mut R, + ) -> std::io::Result { + use std::io::{Error, ErrorKind}; + let (msg, transfer): (Vec, Option) = + BorshDeserialize::deserialize_reader(reader)?; + let message = IbcMsgRecvPacket::decode_vec(&msg) + .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; + Ok(Self { message, transfer }) + } +} + +/// IBC acknowledgement message with `Transfer` for refunding to a shielded +/// address +#[derive(Debug, Clone)] +pub struct MsgAcknowledgement { + /// IBC acknowledgement message + pub message: IbcMsgAcknowledgement, + /// Shieleded transfer for MASP transaction + pub transfer: Option, +} + +impl BorshSerialize for MsgAcknowledgement { + fn serialize( + &self, + writer: &mut W, + ) -> std::io::Result<()> { + let encoded_msg = self.message.clone().encode_vec(); + let members = (encoded_msg, self.transfer.clone()); + BorshSerialize::serialize(&members, writer) + } +} + +impl BorshDeserialize for MsgAcknowledgement { + fn deserialize_reader( + reader: &mut R, + ) -> std::io::Result { + use std::io::{Error, ErrorKind}; + let (msg, transfer): (Vec, Option) = + BorshDeserialize::deserialize_reader(reader)?; + let message = IbcMsgAcknowledgement::decode_vec(&msg) + .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; + Ok(Self { message, transfer }) + } +} + +/// IBC timeout packet message with `Transfer` for refunding to a shielded +/// address +#[derive(Debug, Clone)] +pub struct MsgTimeout { + /// IBC timeout message + pub message: IbcMsgTimeout, + /// Shieleded transfer for MASP transaction + pub transfer: Option, +} + +impl BorshSerialize for MsgTimeout { + fn serialize( + &self, + writer: &mut W, + ) -> std::io::Result<()> { + let encoded_msg = self.message.clone().encode_vec(); + let members = (encoded_msg, self.transfer.clone()); + BorshSerialize::serialize(&members, writer) + } +} + +impl BorshDeserialize for MsgTimeout { + fn deserialize_reader( + reader: &mut R, + ) -> std::io::Result { + use std::io::{Error, ErrorKind}; + let (msg, transfer): (Vec, Option) = + BorshDeserialize::deserialize_reader(reader)?; + let message = IbcMsgTimeout::decode_vec(&msg) + .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; + Ok(Self { message, transfer }) + } +} diff --git a/crates/ibc/src/nft.rs b/crates/ibc/src/nft.rs new file mode 100644 index 0000000000..a1f05502a9 --- /dev/null +++ b/crates/ibc/src/nft.rs @@ -0,0 +1,193 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use ibc::apps::nft_transfer::context::{NftClassContext, NftContext}; +use ibc::apps::nft_transfer::types::error::NftTransferError; +use ibc::apps::nft_transfer::types::{ + ClassData, ClassId, ClassUri, PrefixedClassId, TokenData, TokenId, TokenUri, +}; + +/// NFT class +#[derive(Clone, Debug)] +pub struct NftClass { + /// NFT class ID + pub class_id: PrefixedClassId, + /// NFT class URI + pub class_uri: Option, + /// NFT class data + pub class_data: Option, +} + +impl BorshSerialize for NftClass { + fn serialize( + &self, + writer: &mut W, + ) -> std::io::Result<()> { + BorshSerialize::serialize(&self.class_id.to_string(), writer)?; + match &self.class_uri { + Some(uri) => { + BorshSerialize::serialize(&true, writer)?; + BorshSerialize::serialize(&uri.to_string(), writer)?; + } + None => BorshSerialize::serialize(&false, writer)?, + } + match &self.class_data { + Some(data) => { + BorshSerialize::serialize(&true, writer)?; + BorshSerialize::serialize(&data.to_string(), writer) + } + None => BorshSerialize::serialize(&false, writer), + } + } +} + +impl BorshDeserialize for NftClass { + fn deserialize_reader( + reader: &mut R, + ) -> std::io::Result { + use std::io::{Error, ErrorKind}; + let class_id: String = BorshDeserialize::deserialize_reader(reader)?; + let class_id = class_id.parse().map_err(|e: NftTransferError| { + Error::new(ErrorKind::InvalidData, e.to_string()) + })?; + + let is_uri: bool = BorshDeserialize::deserialize_reader(reader)?; + let class_uri = if is_uri { + let uri_str: String = BorshDeserialize::deserialize_reader(reader)?; + Some(uri_str.parse().map_err(|e: NftTransferError| { + Error::new(ErrorKind::InvalidData, e.to_string()) + })?) + } else { + None + }; + + let is_data: bool = BorshDeserialize::deserialize_reader(reader)?; + let class_data = if is_data { + let data_str: String = + BorshDeserialize::deserialize_reader(reader)?; + Some(data_str.parse().map_err(|e: NftTransferError| { + Error::new(ErrorKind::InvalidData, e.to_string()) + })?) + } else { + None + }; + + Ok(Self { + class_id, + class_uri, + class_data, + }) + } +} + +impl NftClassContext for NftClass { + fn get_id(&self) -> &ClassId { + &self.class_id.base_class_id + } + + fn get_uri(&self) -> Option<&ClassUri> { + self.class_uri.as_ref() + } + + fn get_data(&self) -> Option<&ClassData> { + self.class_data.as_ref() + } +} + +/// NFT metadata +#[derive(Clone, Debug)] +pub struct NftMetadata { + /// NFT class ID + pub class_id: PrefixedClassId, + /// NFT ID + pub token_id: TokenId, + /// NFT URI + pub token_uri: Option, + /// NFT data + pub token_data: Option, +} + +impl BorshSerialize for NftMetadata { + fn serialize( + &self, + writer: &mut W, + ) -> std::io::Result<()> { + BorshSerialize::serialize(&self.class_id.to_string(), writer)?; + BorshSerialize::serialize(&self.token_id.to_string(), writer)?; + match &self.token_uri { + Some(uri) => { + BorshSerialize::serialize(&true, writer)?; + BorshSerialize::serialize(&uri.to_string(), writer)?; + } + None => BorshSerialize::serialize(&false, writer)?, + } + match &self.token_data { + Some(data) => { + BorshSerialize::serialize(&true, writer)?; + BorshSerialize::serialize(&data.to_string(), writer) + } + None => BorshSerialize::serialize(&false, writer), + } + } +} + +impl BorshDeserialize for NftMetadata { + fn deserialize_reader( + reader: &mut R, + ) -> std::io::Result { + use std::io::{Error, ErrorKind}; + let class_id: String = BorshDeserialize::deserialize_reader(reader)?; + let class_id = class_id.parse().map_err(|e: NftTransferError| { + Error::new(ErrorKind::InvalidData, e.to_string()) + })?; + + let token_id: String = BorshDeserialize::deserialize_reader(reader)?; + let token_id = token_id.parse().map_err(|e: NftTransferError| { + Error::new(ErrorKind::InvalidData, e.to_string()) + })?; + + let is_uri: bool = BorshDeserialize::deserialize_reader(reader)?; + let token_uri = if is_uri { + let uri_str: String = BorshDeserialize::deserialize_reader(reader)?; + Some(uri_str.parse().map_err(|e: NftTransferError| { + Error::new(ErrorKind::InvalidData, e.to_string()) + })?) + } else { + None + }; + + let is_data: bool = BorshDeserialize::deserialize_reader(reader)?; + let token_data = if is_data { + let data_str: String = + BorshDeserialize::deserialize_reader(reader)?; + Some(data_str.parse().map_err(|e: NftTransferError| { + Error::new(ErrorKind::InvalidData, e.to_string()) + })?) + } else { + None + }; + + Ok(Self { + class_id, + token_id, + token_uri, + token_data, + }) + } +} + +impl NftContext for NftMetadata { + fn get_class_id(&self) -> &ClassId { + &self.class_id.base_class_id + } + + fn get_id(&self) -> &TokenId { + &self.token_id + } + + fn get_uri(&self) -> Option<&TokenUri> { + self.token_uri.as_ref() + } + + fn get_data(&self) -> Option<&TokenData> { + self.token_data.as_ref() + } +} diff --git a/crates/ibc/src/storage.rs b/crates/ibc/src/storage.rs index 9d4334612d..36e6dd4458 100644 --- a/crates/ibc/src/storage.rs +++ b/crates/ibc/src/storage.rs @@ -2,17 +2,17 @@ use std::str::FromStr; -use namada_core::address::{Address, InternalAddress, HASH_LEN, SHA_HASH_LEN}; -use namada_core::ibc::apps::nft_transfer::types::{PrefixedClassId, TokenId}; -use namada_core::ibc::core::client::types::Height; -use namada_core::ibc::core::host::types::identifiers::{ +use ibc::apps::nft_transfer::types::{PrefixedClassId, TokenId}; +use ibc::core::client::types::Height; +use ibc::core::host::types::identifiers::{ ChannelId, ClientId, ConnectionId, PortId, Sequence, }; -use namada_core::ibc::core::host::types::path::{ +use ibc::core::host::types::path::{ AckPath, ChannelEndPath, ClientConnectionPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath, ConnectionPath, Path, PortPath, ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; +use namada_core::address::{Address, InternalAddress, HASH_LEN, SHA_HASH_LEN}; use namada_core::ibc::IbcTokenHash; use namada_core::storage::{DbKeySeg, Key, KeySeg}; use namada_core::token::Amount; diff --git a/crates/light_sdk/src/transaction/transfer.rs b/crates/light_sdk/src/transaction/transfer.rs index 3275447ac7..84475660ea 100644 --- a/crates/light_sdk/src/transaction/transfer.rs +++ b/crates/light_sdk/src/transaction/transfer.rs @@ -1,43 +1,98 @@ -use borsh_ext::BorshSerializeExt; use namada_sdk::address::Address; use namada_sdk::hash::Hash; use namada_sdk::key::common; use namada_sdk::token::DenominatedAmount; use namada_sdk::tx::data::GasLimit; -use namada_sdk::tx::{Authorization, Tx, TxError}; +use namada_sdk::tx::{ + Authorization, Tx, TxError, TX_SHIELDED_TRANSFER_WASM, + TX_SHIELDING_TRANSFER_WASM, TX_TRANSPARENT_TRANSFER_WASM, + TX_UNSHIELDING_TRANSFER_WASM, +}; use super::{attach_fee, attach_fee_signature, GlobalArgs}; use crate::transaction; -const TX_TRANSFER_WASM: &str = "tx_transfer.wasm"; - /// A transfer transaction #[derive(Debug, Clone)] pub struct Transfer(Tx); impl Transfer { - /// Build a raw Transfer transaction from the given parameters - pub fn new( + /// Build a transparent transfer transaction from the given parameters + pub fn transparent( source: Address, target: Address, token: Address, amount: DenominatedAmount, - // TODO(namada#2596): handle masp here - shielded: Option, args: GlobalArgs, ) -> Self { - let init_proposal = namada_sdk::token::Transfer { + let data = namada_sdk::token::TransparentTransfer { + source, + target, + token, + amount, + }; + + Self(transaction::build_tx( + args, + data, + TX_TRANSPARENT_TRANSFER_WASM.to_string(), + )) + } + + /// Build a shielded transfer transaction from the given parameters + pub fn shielded(shielded_section_hash: Hash, args: GlobalArgs) -> Self { + let data = namada_sdk::token::ShieldedTransfer { + section_hash: shielded_section_hash, + }; + + Self(transaction::build_tx( + args, + data, + TX_SHIELDED_TRANSFER_WASM.to_string(), + )) + } + + /// Build a shielding transfer transaction from the given parameters + pub fn shielding( + source: Address, + token: Address, + amount: DenominatedAmount, + shielded_section_hash: Hash, + args: GlobalArgs, + ) -> Self { + let data = namada_sdk::token::ShieldingTransfer { source, + token, + amount, + shielded_section_hash, + }; + + Self(transaction::build_tx( + args, + data, + TX_SHIELDING_TRANSFER_WASM.to_string(), + )) + } + + /// Build an unshielding transfer transaction from the given parameters + pub fn unshielding( + target: Address, + token: Address, + amount: DenominatedAmount, + shielded_section_hash: Hash, + args: GlobalArgs, + ) -> Self { + let data = namada_sdk::token::UnshieldingTransfer { target, token, amount, - shielded, + shielded_section_hash, }; Self(transaction::build_tx( args, - init_proposal.serialize_to_vec(), - TX_TRANSFER_WASM.to_string(), + data, + TX_UNSHIELDING_TRANSFER_WASM.to_string(), )) } diff --git a/crates/macros/src/lib.rs b/crates/macros/src/lib.rs index 66694edba8..b1be2dcc02 100644 --- a/crates/macros/src/lib.rs +++ b/crates/macros/src/lib.rs @@ -28,9 +28,9 @@ pub fn transaction(_attr: TokenStream, input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as ItemFn); let ident = &ast.sig.ident; let gen = quote! { - // Use `wee_alloc` as the global allocator. + // Use `rlsf` as the global allocator. #[global_allocator] - static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; + static ALLOC: rlsf::SmallGlobalTlsf = rlsf::SmallGlobalTlsf::new(); #ast @@ -88,9 +88,9 @@ pub fn validity_predicate( let ast = parse_macro_input!(input as ItemFn); let ident = &ast.sig.ident; let gen = quote! { - // Use `wee_alloc` as the global allocator. + // Use `rlsf` as the global allocator. #[global_allocator] - static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; + static ALLOC: rlsf::SmallGlobalTlsf = rlsf::SmallGlobalTlsf::new(); #ast diff --git a/crates/namada/Cargo.toml b/crates/namada/Cargo.toml index 3f500eb42c..502966354f 100644 --- a/crates/namada/Cargo.toml +++ b/crates/namada/Cargo.toml @@ -19,14 +19,11 @@ default = ["wasm-runtime"] mainnet = ["namada_core/mainnet"] std = ["namada_sdk/std"] wasm-runtime = [ - "loupe", "parity-wasm", "rayon", "wasm-instrument", "wasmer-cache", "wasmer-compiler-singlepass", - "wasmer-engine-dylib", - "wasmer-engine-universal", "wasmer-vm", "wasmer", ] @@ -92,7 +89,6 @@ namada_ethereum_bridge = { path = "../ethereum_bridge", default-features = false namada_gas = { path = "../gas" } namada_governance = { path = "../governance" } namada_ibc = { path = "../ibc" } -namada_macros = { path = "../macros" } namada_migrations = { path = "../migrations", optional = true } namada_parameters = { path = "../parameters" } namada_proof_of_stake = { path = "../proof_of_stake" } @@ -106,61 +102,36 @@ namada_vote_ext = { path = "../vote_ext" } namada_vp_env = { path = "../vp_env" } async-trait = { version = "0.1.51", optional = true } -bimap.workspace = true borsh.workspace = true borsh-ext.workspace = true -circular-queue.workspace = true clru.workspace = true -data-encoding.workspace = true -derivation-path.workspace = true -derivative.workspace = true -ethbridge-bridge-contract.workspace = true ethers.workspace = true eyre.workspace = true -futures.workspace = true itertools.workspace = true -konst.workspace = true linkme = {workspace = true, optional = true} -loupe = { version = "0.1.3", optional = true } masp_primitives.workspace = true masp_proofs.workspace = true -num256.workspace = true -num-traits.workspace = true -orion.workspace = true -owo-colors = "3.5.0" parity-wasm = { version = "0.45.0", features = ["sign_ext"], optional = true } -paste.workspace = true proptest = { workspace = true, optional = true } prost.workspace = true rand.workspace = true -rand_core.workspace = true rayon = { version = "=1.5.3", optional = true } -regex.workspace = true ripemd.workspace = true -serde.workspace = true serde_json.workspace = true sha2.workspace = true -slip10_ed25519.workspace = true smooth-operator.workspace = true tempfile = { version = "3.2.0", optional = true } tendermint-rpc = { workspace = true, optional = true } thiserror.workspace = true tiny-bip39.workspace = true -tiny-hderive.workspace = true -toml.workspace = true tracing.workspace = true uint = "0.9.5" wasm-instrument = { workspace = true, optional = true } wasmer = { workspace = true, optional = true } -wasmer-cache = { git = "https://github.com/heliaxdev/wasmer", rev = "255054f7f58b7b4a525f2fee6b9b86422d1ca15b", optional = true } +wasmer-cache = { workspace = true, optional = true } wasmer-compiler-singlepass = { workspace = true, optional = true } -wasmer-engine-dylib = { git = "https://github.com/heliaxdev/wasmer", rev = "255054f7f58b7b4a525f2fee6b9b86422d1ca15b", optional = true } -wasmer-engine-universal = { workspace = true, optional = true } -wasmer-vm = { git = "https://github.com/heliaxdev/wasmer", rev = "255054f7f58b7b4a525f2fee6b9b86422d1ca15b", optional = true } -# Greater versions break in `test_tx_stack_limiter` and `test_vp_stack_limiter` -wat = "=1.0.71" +wasmer-vm = { workspace = true, optional = true } wasmparser.workspace = true -zeroize.workspace = true [target.'cfg(not(target_family = "wasm"))'.dependencies] tokio = { workspace = true, features = ["full"] } diff --git a/crates/namada/src/ledger/governance/mod.rs b/crates/namada/src/ledger/governance/mod.rs index 65e56879d8..93d566f9c4 100644 --- a/crates/namada/src/ledger/governance/mod.rs +++ b/crates/namada/src/ledger/governance/mod.rs @@ -84,11 +84,14 @@ where }; // Is VP triggered by a governance proposal? - let is_governance_proposal = is_proposal_accepted( + if is_proposal_accepted( &self.ctx.pre(), tx_data.tx.data(tx_data.cmt).unwrap_or_default().as_ref(), ) - .unwrap_or_default(); + .unwrap_or_default() + { + return Ok(()); + } let native_token = self.ctx.pre().get_native_token()?; @@ -96,8 +99,7 @@ where let actions = self.ctx.read_actions()?; // There must be at least one action if any of the keys belong to gov - if !is_governance_proposal - && actions.is_empty() + if actions.is_empty() && keys_changed.iter().any(gov_storage::is_governance_key) { tracing::info!( diff --git a/crates/namada/src/ledger/mod.rs b/crates/namada/src/ledger/mod.rs index 14c4a8b622..2f952e4f99 100644 --- a/crates/namada/src/ledger/mod.rs +++ b/crates/namada/src/ledger/mod.rs @@ -61,15 +61,11 @@ mod dry_run_tx { Gas::try_from(wrapper.gas_limit).into_storage_result()?; let tx_gas_meter = RefCell::new(TxGasMeter::new(gas_limit)); let tx_result = protocol::apply_wrapper_tx( - tx.clone(), + &tx, &wrapper, &request.data, - ShellParams::new( - &tx_gas_meter, - &mut temp_state, - &mut ctx.vp_wasm_cache, - &mut ctx.tx_wasm_cache, - ), + &tx_gas_meter, + &mut temp_state, None, ) .into_storage_result()?; @@ -102,6 +98,12 @@ mod dry_run_tx { &mut ctx.tx_wasm_cache, ), ); + let is_accepted = matches!(&batched_tx_result, Ok(result) if result.is_accepted()); + if is_accepted { + temp_state.write_log_mut().commit_tx_to_batch(); + } else { + temp_state.write_log_mut().drop_tx(); + } tx_result .batch_results .0 diff --git a/crates/namada/src/ledger/native_vp/ibc/context.rs b/crates/namada/src/ledger/native_vp/ibc/context.rs index ab6832c92e..0baaad84c1 100644 --- a/crates/namada/src/ledger/native_vp/ibc/context.rs +++ b/crates/namada/src/ledger/native_vp/ibc/context.rs @@ -9,8 +9,7 @@ use namada_core::storage::Epochs; use namada_gas::MEMORY_ACCESS_GAS_PER_BYTE; use namada_ibc::event::IbcEvent; use namada_ibc::{IbcCommonContext, IbcStorageContext}; -use namada_sdk::events::log::dumb_queries; -use namada_sdk::events::{Event, EventTypeBuilder}; +use namada_sdk::events::Event; use namada_state::{StateRead, StorageError, StorageRead, StorageWrite}; use namada_vp_env::VpEnv; @@ -195,28 +194,6 @@ where Ok(()) } - fn get_ibc_events( - &self, - event_type: impl AsRef, - ) -> Result> { - let matcher = dumb_queries::QueryMatcher::with_prefix( - EventTypeBuilder::new_of::() - .with_segment(event_type) - .build(), - ); - Ok(self - .event - .iter() - .filter_map(|event| { - if matcher.matches(event) { - IbcEvent::try_from(event).ok() - } else { - None - } - }) - .collect()) - } - fn transfer_token( &mut self, src: &Address, @@ -376,13 +353,6 @@ where unimplemented!("Validation doesn't emit an event") } - fn get_ibc_events( - &self, - _event_type: impl AsRef, - ) -> Result> { - unimplemented!("Validation doesn't get an event") - } - fn transfer_token( &mut self, _src: &Address, diff --git a/crates/namada/src/ledger/native_vp/ibc/mod.rs b/crates/namada/src/ledger/native_vp/ibc/mod.rs index 334b26ce39..303e4abcdc 100644 --- a/crates/namada/src/ledger/native_vp/ibc/mod.rs +++ b/crates/namada/src/ledger/native_vp/ibc/mod.rs @@ -13,6 +13,7 @@ use namada_core::arith::{self, checked}; use namada_core::collections::HashSet; use namada_core::storage::Key; use namada_gas::{IBC_ACTION_EXECUTE_GAS, IBC_ACTION_VALIDATE_GAS}; +use namada_governance::is_proposal_accepted; use namada_ibc::event::IbcEvent; use namada_ibc::{ Error as ActionError, IbcActions, NftTransferModule, TransferModule, @@ -43,6 +44,8 @@ pub enum Error { NativeVpError(#[from] native_vp::Error), #[error("IBC VP error: Decoding error: {0}")] Decoding(#[from] std::io::Error), + #[error("IBC VP error: governance proposal change is invalid")] + InvalidGovernanceChange, #[error("IBC VP error: IBC message is required as transaction data")] NoTxData, #[error("IBC VP error: IBC action error: {0}")] @@ -83,6 +86,20 @@ where keys_changed: &BTreeSet, _verifiers: &BTreeSet
, ) -> VpResult<()> { + // Is VP triggered by a governance proposal? + if is_proposal_accepted( + &self.ctx.pre(), + batched_tx + .tx + .data(batched_tx.cmt) + .unwrap_or_default() + .as_ref(), + ) + .unwrap_or_default() + { + return Ok(()); + } + let tx_data = batched_tx.tx.data(batched_tx.cmt).ok_or(Error::NoTxData)?; @@ -418,7 +435,6 @@ mod tests { use crate::core::address::testing::{ established_address_1, established_address_2, nam, }; - use crate::core::ibc::{MsgNftTransfer, MsgTransfer}; use crate::core::storage::Epoch; use crate::ibc::apps::nft_transfer::types::events::{ RecvEvent as NftRecvEvent, TokenTraceEvent, @@ -498,7 +514,7 @@ mod tests { next_sequence_recv_key, next_sequence_send_key, nft_class_key, nft_metadata_key, receipt_key, }; - use crate::ibc::{NftClass, NftMetadata}; + use crate::ibc::{MsgNftTransfer, MsgTransfer, NftClass, NftMetadata}; use crate::key::testing::keypair_1; use crate::ledger::gas::VpGasMeter; use crate::ledger::parameters::storage::{ diff --git a/crates/namada/src/ledger/native_vp/masp.rs b/crates/namada/src/ledger/native_vp/masp.rs index fba665b10f..0d32b9199a 100644 --- a/crates/namada/src/ledger/native_vp/masp.rs +++ b/crates/namada/src/ledger/native_vp/masp.rs @@ -18,13 +18,12 @@ use namada_core::booleans::BoolResultUnitExt; use namada_core::collections::HashSet; use namada_core::ibc::apps::transfer::types::is_sender_chain_source; use namada_core::ibc::apps::transfer::types::packet::PacketData; -use namada_core::masp::{addr_taddr, encode_asset_type, ibc_taddr}; +use namada_core::masp::{addr_taddr, encode_asset_type, ibc_taddr, MaspEpoch}; use namada_core::storage::Key; use namada_gas::GasMetering; use namada_governance::storage::is_proposal_accepted; use namada_ibc::event::{IbcEvent, PacketAck}; -use namada_ibc::IbcCommonContext; -use namada_proof_of_stake::Epoch; +use namada_ibc::{IbcCommonContext, IbcMessage}; use namada_sdk::masp::{verify_shielded_tx, TAddrData}; use namada_state::{ConversionState, OptionExt, ResultExt, StateRead}; use namada_token::read_denom; @@ -39,6 +38,7 @@ use token::storage_key::{ use token::Amount; use crate::address::{InternalAddress, IBC, MASP}; +use crate::ibc::{MsgRecvPacket, MsgTransfer}; use crate::ledger::ibc::storage; use crate::ledger::ibc::storage::{ ibc_trace_key, ibc_trace_key_prefix, is_ibc_commitment_key, @@ -51,7 +51,6 @@ use crate::sdk::ibc::core::channel::types::acknowledgement::AcknowledgementStatu use crate::sdk::ibc::core::channel::types::commitment::{ compute_ack_commitment, AcknowledgementCommitment, PacketCommitment, }; -use crate::sdk::ibc::{IbcMessage, MsgRecvPacket, MsgTransfer}; use crate::token; use crate::token::MaspDigitPos; use crate::uint::{Uint, I320}; @@ -641,9 +640,38 @@ where tx_data: &BatchedTxRef<'_>, keys_changed: &BTreeSet, ) -> Result<()> { - let epoch = self.ctx.get_block_epoch()?; + let masp_epoch_multiplier = + namada_parameters::read_masp_epoch_multiplier_parameter( + self.ctx.state, + )?; + let masp_epoch = MaspEpoch::try_from_epoch( + self.ctx.get_block_epoch()?, + masp_epoch_multiplier, + ) + .map_err(|msg| { + Error::NativeVpError(native_vp::Error::new_const(msg)) + })?; let conversion_state = self.ctx.state.in_mem().get_conversion_state(); - let (shielded_tx, ibc_msgs) = self.ctx.get_shielded_action(tx_data)?; + let ibc_msgs = self.ctx.get_shielded_action(tx_data)?; + + // Get the Transaction object from the actions + let masp_section_ref = namada_tx::action::get_masp_section_ref( + &self.ctx, + )? + .ok_or_else(|| { + native_vp::Error::new_const( + "Missing MASP section reference in action", + ) + })?; + let shielded_tx = tx_data + .tx + .get_section(&masp_section_ref) + .and_then(|section| section.masp_tx()) + .ok_or_else(|| { + native_vp::Error::new_const( + "Missing MASP section in transaction", + ) + })?; if u64::from(self.ctx.get_block_height()?) > u64::from(shielded_tx.expiry_height()) @@ -672,7 +700,7 @@ where .get(&masp_address_hash) .unwrap_or(&ValueSum::zero()), &shielded_tx.sapling_value_balance(), - epoch, + masp_epoch, &changed_balances.tokens, conversion_state, )?; @@ -698,7 +726,7 @@ where &shielded_tx, &mut changed_balances, &mut transparent_tx_pool, - epoch, + masp_epoch, conversion_state, &mut signers, )?; @@ -845,7 +873,7 @@ fn validate_transparent_input( vin: &TxIn, changed_balances: &mut ChangedBalances, transparent_tx_pool: &mut I128Sum, - epoch: Epoch, + epoch: MaspEpoch, conversion_state: &ConversionState, signers: &mut BTreeSet, ) -> Result<()> { @@ -932,7 +960,7 @@ fn validate_transparent_output( out: &TxOut, changed_balances: &mut ChangedBalances, transparent_tx_pool: &mut I128Sum, - epoch: Epoch, + epoch: MaspEpoch, conversion_state: &ConversionState, ) -> Result<()> { // Non-masp destinations subtract from transparent tx pool @@ -998,7 +1026,7 @@ fn validate_transparent_bundle( shielded_tx: &Transaction, changed_balances: &mut ChangedBalances, transparent_tx_pool: &mut I128Sum, - epoch: Epoch, + epoch: MaspEpoch, conversion_state: &ConversionState, signers: &mut BTreeSet, ) -> Result<()> { @@ -1057,7 +1085,7 @@ fn verify_sapling_balancing_value( pre: &ValueSum, post: &ValueSum, sapling_value_balance: &I128Sum, - target_epoch: Epoch, + target_epoch: MaspEpoch, tokens: &BTreeMap, conversion_state: &ConversionState, ) -> Result<()> { @@ -1117,6 +1145,7 @@ where let non_allowed_changes = masp_keys_changed.iter().any(|key| { !is_masp_transfer_key(key) && !is_masp_token_map_key(key) }); + let masp_token_map_changed = masp_keys_changed .iter() .any(|key| is_masp_token_map_key(key)); diff --git a/crates/namada/src/ledger/native_vp/multitoken.rs b/crates/namada/src/ledger/native_vp/multitoken.rs index e8f130d437..1d88396dd2 100644 --- a/crates/namada/src/ledger/native_vp/multitoken.rs +++ b/crates/namada/src/ledger/native_vp/multitoken.rs @@ -8,6 +8,9 @@ use namada_governance::is_proposal_accepted; use namada_parameters::storage::is_native_token_transferable; use namada_state::StateRead; use namada_token::storage_key::is_any_token_parameter_key; +use namada_tx::action::{ + Action, Bond, ClaimRewards, GovAction, PosAction, Read, Withdraw, +}; use namada_tx::BatchedTxRef; use namada_vp_env::VpEnv; use thiserror::Error; @@ -22,9 +25,18 @@ use crate::token::storage_key::{ use crate::token::Amount; use crate::vm::WasmCacheAccess; +/// The owner of some balance change. +#[derive(Copy, Clone, Eq, PartialEq)] +enum Owner<'a> { + Account(&'a Address), + Protocol, +} + #[allow(missing_docs)] #[derive(Error, Debug)] pub enum Error { + #[error("Multitoken VP error: governance proposal change is invalid")] + InvalidGovernanceChange, #[error("Multitoken VP error: Native VP error: {0}")] NativeVpError(#[from] native_vp::Error), } @@ -55,21 +67,51 @@ where keys_changed: &BTreeSet, verifiers: &BTreeSet
, ) -> Result<()> { + // Is VP triggered by a governance proposal? + if is_proposal_accepted( + &self.ctx.pre(), + tx_data.tx.data(tx_data.cmt).unwrap_or_default().as_ref(), + ) + .unwrap_or_default() + { + return Ok(()); + } + let native_token = self.ctx.pre().ctx.get_native_token()?; let is_native_token_transferable = is_native_token_transferable(&self.ctx.pre())?; - // Native token can be transferred to `PoS` or `Gov` even if - // `is_native_token_transferable` is false - let is_allowed_inc = |token: &Address, target: &Address| -> bool { + let actions = self.ctx.read_actions()?; + // The native token can be transferred to and out of the `PoS` and `Gov` + // accounts, even if `is_native_token_transferable` is false + let is_allowed_inc = |token: &Address, bal_owner: &Address| -> bool { *token != native_token || is_native_token_transferable - || *target == POS - || *target == GOV + || (!actions.is_empty() + && actions.iter().all(|action| { + has_bal_inc_protocol_action( + action, + if *bal_owner == POS || *bal_owner == GOV { + Owner::Protocol + } else { + Owner::Account(bal_owner) + }, + ) + })) }; - let is_allowed_dec = |token: &Address, target: &Address| -> bool { + let is_allowed_dec = |token: &Address, bal_owner: &Address| -> bool { *token != native_token || is_native_token_transferable - || (*target != POS && *target != GOV) + || (!actions.is_empty() + && actions.iter().all(|action| { + has_bal_dec_protocol_action( + action, + if *bal_owner == POS || *bal_owner == GOV { + Owner::Protocol + } else { + Owner::Account(bal_owner) + }, + ) + })) }; let mut inc_changes: HashMap = HashMap::new(); @@ -306,6 +348,56 @@ where } } +fn has_bal_inc_protocol_action(action: &Action, owner: Owner<'_>) -> bool { + match action { + Action::Pos( + PosAction::ClaimRewards(ClaimRewards { validator, source }) + | PosAction::Withdraw(Withdraw { validator, source }), + ) => match owner { + Owner::Account(owner) => { + source.as_ref().unwrap_or(validator) == owner + } + // NB: pos or gov's balance can increase + Owner::Protocol => true, + }, + // NB: only pos or gov balances can decrease with these actions + Action::Pos(PosAction::Bond(Bond { .. })) + | Action::Gov(GovAction::InitProposal { .. }) => { + owner == Owner::Protocol + } + // NB: every other case is invalid + _ => false, + } +} + +fn has_bal_dec_protocol_action(action: &Action, owner: Owner<'_>) -> bool { + match action { + Action::Pos(PosAction::Bond(Bond { + validator, source, .. + })) => match owner { + Owner::Account(owner) => { + source.as_ref().unwrap_or(validator) == owner + } + // NB: pos or gov's balance can decrease + Owner::Protocol => true, + }, + Action::Gov(GovAction::InitProposal { author: source }) => { + match owner { + Owner::Account(owner) => source == owner, + // NB: pos or gov's balance can decrease + Owner::Protocol => true, + } + } + // NB: only pos or gov balances can decrease with these actions + Action::Pos( + PosAction::ClaimRewards(ClaimRewards { .. }) + | PosAction::Withdraw(Withdraw { .. }), + ) => owner == Owner::Protocol, + // NB: every other case is invalid + _ => false, + } +} + #[cfg(test)] mod tests { use std::cell::RefCell; @@ -316,6 +408,7 @@ mod tests { use namada_parameters::storage::get_native_token_transferable_key; use namada_state::testing::TestState; use namada_state::StorageWrite; + use namada_tx::action::Write; use namada_tx::data::TxType; use namada_tx::{Authorization, BatchedTx, Code, Data, Section, Tx}; @@ -828,6 +921,13 @@ mod tests { let src = established_address_1(); let dest = POS; let keys_changed = transfer(&mut state, &src, &dest); + state + .push_action(Action::Pos(PosAction::Bond(Bond { + validator: established_address_1(), + source: None, + amount: Amount::native_whole(90), + }))) + .unwrap(); // disable native token transfer let key = get_native_token_transferable_key(); @@ -864,8 +964,13 @@ mod tests { fn test_native_token_transferable_from_gov() { let mut state = init_state(); let src = GOV; - let dest = POS; + let dest = established_address_1(); let keys_changed = transfer(&mut state, &src, &dest); + state + .push_action(Action::Gov(GovAction::InitProposal { + author: established_address_1(), + })) + .unwrap(); // disable native token transfer let key = get_native_token_transferable_key(); @@ -897,4 +1002,95 @@ mod tests { Err(_) ); } + + #[test] + fn test_native_token_transferable_to_gov() { + let mut state = init_state(); + let src = established_address_1(); + let dest = GOV; + let keys_changed = transfer(&mut state, &src, &dest); + state + .push_action(Action::Gov(GovAction::InitProposal { + author: established_address_1(), + })) + .unwrap(); + + // disable native token transfer + let key = get_native_token_transferable_key(); + state.write(&key, false).unwrap(); + + let tx_index = TxIndex::default(); + let BatchedTx { tx, cmt } = dummy_tx(&state); + let gas_meter = RefCell::new(VpGasMeter::new_from_tx_meter( + &TxGasMeter::new_from_sub_limit(u64::MAX.into()), + )); + let (vp_wasm_cache, _vp_cache_dir) = wasm_cache(); + let mut verifiers = BTreeSet::new(); + verifiers.insert(src); + let ctx = Ctx::new( + &ADDRESS, + &state, + &tx, + &cmt, + &tx_index, + &gas_meter, + &keys_changed, + &verifiers, + vp_wasm_cache, + ); + + let vp = MultitokenVp { ctx }; + assert_matches!( + vp.validate_tx(&tx.batch_ref_tx(&cmt), &keys_changed, &verifiers), + Ok(_) + ); + } + + /// Check that even if native token transfers are disabled, we can + /// still claim PoS rewards. + #[test] + fn test_native_token_transferable_from_pos() { + let mut state = init_state(); + + // simulate claiming PoS rewards + let src = POS; + let dest = established_address_1(); + let keys_changed = transfer(&mut state, &src, &dest); + state + .push_action(Action::Pos(PosAction::ClaimRewards(ClaimRewards { + validator: established_address_1(), + source: None, + }))) + .unwrap(); + + // disable native token transfer + let key = get_native_token_transferable_key(); + state.write(&key, false).unwrap(); + + let tx_index = TxIndex::default(); + let BatchedTx { tx, cmt } = dummy_tx(&state); + let gas_meter = RefCell::new(VpGasMeter::new_from_tx_meter( + &TxGasMeter::new_from_sub_limit(u64::MAX.into()), + )); + let (vp_wasm_cache, _vp_cache_dir) = wasm_cache(); + let mut verifiers = BTreeSet::new(); + verifiers.insert(src); + let ctx = Ctx::new( + &ADDRESS, + &state, + &tx, + &cmt, + &tx_index, + &gas_meter, + &keys_changed, + &verifiers, + vp_wasm_cache, + ); + + let vp = MultitokenVp { ctx }; + assert_matches!( + vp.validate_tx(&tx.batch_ref_tx(&cmt), &keys_changed, &verifiers), + Ok(_) + ); + } } diff --git a/crates/namada/src/ledger/pgf/mod.rs b/crates/namada/src/ledger/pgf/mod.rs index ff042286fe..d7548c1cfb 100644 --- a/crates/namada/src/ledger/pgf/mod.rs +++ b/crates/namada/src/ledger/pgf/mod.rs @@ -59,6 +59,20 @@ where // Find the actions applied in the tx let actions = self.ctx.read_actions()?; + // Is VP triggered by a governance proposal? + if is_proposal_accepted( + &self.ctx.pre(), + batched_tx + .tx + .data(batched_tx.cmt) + .unwrap_or_default() + .as_ref(), + ) + .unwrap_or_default() + { + return Ok(()); + } + // There must be at least one action if any of the keys belong to PGF if actions.is_empty() && keys_changed.iter().any(pgf_storage::is_pgf_key) diff --git a/crates/namada/src/ledger/protocol/mod.rs b/crates/namada/src/ledger/protocol/mod.rs index 74e17fbae3..b19098e18d 100644 --- a/crates/namada/src/ledger/protocol/mod.rs +++ b/crates/namada/src/ledger/protocol/mod.rs @@ -7,19 +7,17 @@ use borsh_ext::BorshSerializeExt; use eyre::{eyre, WrapErr}; use namada_core::booleans::BoolResultUnitExt; use namada_core::hash::Hash; -use namada_core::storage::Key; use namada_events::extend::{ ComposeEvent, Height as HeightAttr, TxHash as TxHashAttr, }; use namada_events::EventLevel; use namada_gas::TxGasMeter; -use namada_sdk::tx::TX_TRANSFER_WASM; use namada_state::StorageWrite; use namada_token::event::{TokenEvent, TokenOperation, UserAccount}; -use namada_tx::data::protocol::ProtocolTxType; +use namada_tx::data::protocol::{ProtocolTx, ProtocolTxType}; use namada_tx::data::{ - BatchResults, BatchedTxResult, TxResult, TxType, VpStatusFlags, VpsResult, - WrapperTx, + BatchResults, BatchedTxResult, ExtendedTxResult, TxResult, VpStatusFlags, + VpsResult, WrapperTx, }; use namada_tx::{BatchedTxRef, Tx}; use namada_vote_ext::EthereumTxData; @@ -63,8 +61,6 @@ pub enum Error { TxRunnerError(vm::wasm::run::Error), #[error("{0:?}")] ProtocolTxError(#[from] eyre::Error), - #[error("Txs must either be encrypted or a decryption of an encrypted tx")] - TxTypeError, #[error("The atomic batch failed at inner transaction {0}")] FailingAtomicBatch(Hash), #[error("Gas error: {0}")] @@ -165,8 +161,9 @@ pub type Result = std::result::Result; pub struct DispatchError { /// The result of the function call pub error: Error, - /// The tx result produced. It could produced even in case of an error - pub tx_result: Option>, + /// The extended tx result produced. It could be produced even in case of + /// an error + pub tx_result: Option>, } impl From for DispatchError { @@ -178,51 +175,104 @@ impl From for DispatchError { } } +/// Arguments for transactions' execution +pub enum DispatchArgs<'a, CA: 'static + WasmCacheAccess + Sync> { + /// Protocol tx data + Protocol(&'a ProtocolTx), + /// Raw tx data + Raw { + /// The tx index + tx_index: TxIndex, + /// The result of the corresponding wrapper tx (missing if governance + /// transaction) + wrapper_tx_result: Option>, + /// Vp cache + vp_wasm_cache: &'a mut VpCache, + /// Tx cache + tx_wasm_cache: &'a mut TxCache, + }, + /// Wrapper tx data + Wrapper { + /// The wrapper header + wrapper: &'a WrapperTx, + /// The transaction bytes for gas accounting + tx_bytes: &'a [u8], + /// The block proposer + block_proposer: &'a Address, + }, +} + /// Dispatch a given transaction to be applied based on its type. Some storage /// updates may be derived and applied natively rather than via the wasm /// environment, in which case validity predicates will be bypassed. -#[allow(clippy::too_many_arguments)] pub fn dispatch_tx<'a, D, H, CA>( - tx: Tx, - tx_bytes: &'a [u8], - tx_index: TxIndex, + tx: &Tx, + dispatch_args: DispatchArgs<'a, CA>, tx_gas_meter: &'a RefCell, state: &'a mut WlState, - vp_wasm_cache: &'a mut VpCache, - tx_wasm_cache: &'a mut TxCache, - block_proposer: Option<&Address>, -) -> std::result::Result, DispatchError> +) -> std::result::Result, DispatchError> where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, CA: 'static + WasmCacheAccess + Sync, { - match tx.header().tx_type { - // Raw trasaction type is allowed only for governance proposals - TxType::Raw => { - // No bundles of governance transactions, just take the first one - let cmt = tx.first_commitments().ok_or(Error::MissingInnerTxs)?; - let batched_tx_result = apply_wasm_tx( - BatchedTxRef { tx: &tx, cmt }, - &tx_index, - ShellParams { + match dispatch_args { + DispatchArgs::Raw { + tx_index, + wrapper_tx_result, + vp_wasm_cache, + tx_wasm_cache, + } => { + if let Some(tx_result) = wrapper_tx_result { + // TODO(namada#2597): handle masp fee payment in the first inner + // tx if necessary + // Replay protection check on the batch + let tx_hash = tx.raw_header_hash(); + if state.write_log().has_replay_protection_entry(&tx_hash) { + // If the same batch has already been committed in + // this block, skip execution and return + return Err(DispatchError { + error: Error::ReplayAttempt(tx_hash), + tx_result: None, + }); + } + + dispatch_inner_txs( + tx, + tx_result, + tx_index, tx_gas_meter, state, vp_wasm_cache, tx_wasm_cache, - }, - )?; - - Ok(TxResult { - gas_used: tx_gas_meter.borrow().get_tx_consumed_gas(), - batch_results: BatchResults( - [(cmt.get_hash(), Ok(batched_tx_result))] - .into_iter() - .collect(), - ), - }) + ) + } else { + // Governance proposal. We don't allow tx batches in this case, + // just take the first one + let cmt = + tx.first_commitments().ok_or(Error::MissingInnerTxs)?; + let batched_tx_result = apply_wasm_tx( + tx.batch_ref_tx(cmt), + &tx_index, + ShellParams { + tx_gas_meter, + state, + vp_wasm_cache, + tx_wasm_cache, + }, + )?; + Ok(TxResult { + gas_used: tx_gas_meter.borrow().get_tx_consumed_gas(), + batch_results: BatchResults( + [(cmt.get_hash(), Ok(batched_tx_result))] + .into_iter() + .collect(), + ), + } + .to_extended_result(None)) + } } - TxType::Protocol(protocol_tx) => { + DispatchArgs::Protocol(protocol_tx) => { // No bundles of protocol transactions, only take the first one let cmt = tx.first_commitments().ok_or(Error::MissingInnerTxs)?; let batched_tx_result = @@ -235,106 +285,113 @@ where .collect(), ), ..Default::default() - }) + } + .to_extended_result(None)) } - TxType::Wrapper(ref wrapper) => { - let mut tx_result = apply_wrapper_tx( - tx.clone(), + DispatchArgs::Wrapper { + wrapper, + tx_bytes, + block_proposer, + } => { + let tx_result = apply_wrapper_tx( + tx, wrapper, tx_bytes, - ShellParams { - tx_gas_meter, - state, - vp_wasm_cache, - tx_wasm_cache, - }, - block_proposer, + tx_gas_meter, + state, + Some(block_proposer), ) .map_err(|e| Error::WrapperRunnerError(e.to_string()))?; - // Replay protection check on the batch - let tx_hash = tx.raw_header_hash(); - if state.write_log().has_replay_protection_entry(&tx_hash) { - // If the same batch has already been committed in - // this block, skip execution and return + Ok(tx_result.to_extended_result(None)) + } + } +} + +fn dispatch_inner_txs<'a, D, H, CA>( + tx: &Tx, + tx_result: TxResult, + tx_index: TxIndex, + tx_gas_meter: &'a RefCell, + state: &'a mut WlState, + vp_wasm_cache: &'a mut VpCache, + tx_wasm_cache: &'a mut TxCache, +) -> std::result::Result, DispatchError> +where + D: 'static + DB + for<'iter> DBIter<'iter> + Sync, + H: 'static + StorageHasher + Sync, + CA: 'static + WasmCacheAccess + Sync, +{ + let mut extended_tx_result = tx_result.to_extended_result(None); + + // TODO(namada#2597): handle masp fee payment in the first inner tx + // if necessary + for cmt in tx.commitments() { + match apply_wasm_tx( + tx.batch_ref_tx(cmt), + &tx_index, + ShellParams { + tx_gas_meter, + state, + vp_wasm_cache, + tx_wasm_cache, + }, + ) { + Err(Error::GasError(ref msg)) => { + // Gas error aborts the execution of the entire batch + extended_tx_result.tx_result.gas_used = + tx_gas_meter.borrow().get_tx_consumed_gas(); + extended_tx_result.tx_result.batch_results.0.insert( + cmt.get_hash(), + Err(Error::GasError(msg.to_owned())), + ); + state.write_log_mut().drop_tx(); return Err(DispatchError { - error: Error::ReplayAttempt(tx_hash), - tx_result: None, + error: Error::GasError(msg.to_owned()), + tx_result: Some(extended_tx_result), }); } + res => { + let is_accepted = + matches!(&res, Ok(result) if result.is_accepted()); + + extended_tx_result + .tx_result + .batch_results + .0 + .insert(cmt.get_hash(), res); + extended_tx_result.tx_result.gas_used = + tx_gas_meter.borrow().get_tx_consumed_gas(); + if is_accepted { + // If the transaction was a masp one append the + // transaction refs for the events + if let Some(masp_section_ref) = + namada_tx::action::get_masp_section_ref(state) + .map_err(Error::StateError)? + { + extended_tx_result + .masp_tx_refs + .0 + .push(masp_section_ref); + } + state.write_log_mut().commit_tx_to_batch(); + } else { + state.write_log_mut().drop_tx(); - // TODO(namada#2597): handle masp fee payment in the first inner tx - // if necessary - for cmt in tx.commitments() { - match apply_wasm_tx( - tx.batch_ref_tx(cmt), - &tx_index, - ShellParams { - tx_gas_meter, - state, - vp_wasm_cache, - tx_wasm_cache, - }, - ) { - Err(Error::GasError(ref msg)) => { - // Gas error aborts the execution of the entire batch - tx_result.gas_used = - tx_gas_meter.borrow().get_tx_consumed_gas(); - tx_result.batch_results.0.insert( - cmt.get_hash(), - Err(Error::GasError(msg.to_owned())), - ); - state.write_log_mut().drop_tx(); + if tx.header.atomic { + // Stop the execution of an atomic batch at the + // first failed transaction return Err(DispatchError { - error: Error::GasError(msg.to_owned()), - tx_result: Some(tx_result), + error: Error::FailingAtomicBatch(cmt.get_hash()), + tx_result: Some(extended_tx_result), }); } - res => { - let is_accepted = - matches!(&res, Ok(result) if result.is_accepted()); - - tx_result.batch_results.0.insert(cmt.get_hash(), res); - tx_result.gas_used = - tx_gas_meter.borrow().get_tx_consumed_gas(); - if is_accepted { - state.write_log_mut().commit_tx_to_batch(); - } else { - state.write_log_mut().drop_tx(); - - if tx.header.atomic { - // Stop the execution of an atomic batch at the - // first failed transaction - return Err(DispatchError { - error: Error::FailingAtomicBatch( - cmt.get_hash(), - ), - tx_result: Some(tx_result), - }); - } - } - } - }; + } } - Ok(tx_result) - } + }; } -} -/// Load the wasm hash for a transfer from storage. -/// -/// # Panics -/// If the transaction hash is not found in storage -pub fn get_transfer_hash_from_storage(storage: &S) -> Hash -where - S: StorageRead, -{ - let transfer_code_name_key = - Key::wasm_code_name(TX_TRANSFER_WASM.to_string()); - storage - .read(&transfer_code_name_key) - .expect("Could not read the storage") - .expect("Expected tx transfer hash in storage") + Ok(extended_tx_result) } /// Performs the required operation on a wrapper transaction: @@ -343,40 +400,38 @@ where /// - gas accounting // TODO(namada#2597): this must signal to the caller if we need masp fee payment // in the first inner tx of the batch -pub(crate) fn apply_wrapper_tx( - tx: Tx, +pub(crate) fn apply_wrapper_tx( + tx: &Tx, wrapper: &WrapperTx, tx_bytes: &[u8], - mut shell_params: ShellParams<'_, S, D, H, CA>, + tx_gas_meter: &RefCell, + state: &mut S, block_proposer: Option<&Address>, ) -> Result> where S: State + Sync, D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, - CA: 'static + WasmCacheAccess + Sync, { let wrapper_tx_hash = tx.header_hash(); // Write wrapper tx hash to storage - shell_params - .state + state .write_log_mut() .write_tx_hash(wrapper_tx_hash) .expect("Error while writing tx hash to storage"); // Charge fee before performing any fallible operations - charge_fee(wrapper, wrapper_tx_hash, &mut shell_params, block_proposer)?; + charge_fee(wrapper, wrapper_tx_hash, state, block_proposer)?; // Account for gas - shell_params - .tx_gas_meter + tx_gas_meter .borrow_mut() .add_wrapper_gas(tx_bytes) .map_err(|err| Error::GasError(err.to_string()))?; Ok(TxResult { - gas_used: shell_params.tx_gas_meter.borrow().get_tx_consumed_gas(), + gas_used: tx_gas_meter.borrow().get_tx_consumed_gas(), batch_results: BatchResults::default(), }) } @@ -385,34 +440,30 @@ where /// - Fee amount overflows /// - Not enough funds are available to pay the entire amount of the fee /// - The accumulated fee amount to be credited to the block proposer overflows -fn charge_fee( +fn charge_fee( wrapper: &WrapperTx, wrapper_tx_hash: Hash, - shell_params: &mut ShellParams<'_, S, D, H, CA>, + state: &mut S, block_proposer: Option<&Address>, ) -> Result<()> where S: State + Sync, D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, - CA: 'static + WasmCacheAccess + Sync, { // Charge or check fees before propagating any possible error let payment_result = match block_proposer { - Some(block_proposer) => transfer_fee( - shell_params.state, - block_proposer, - wrapper, - wrapper_tx_hash, - ), + Some(block_proposer) => { + transfer_fee(state, block_proposer, wrapper, wrapper_tx_hash) + } None => { - check_fees(shell_params.state, wrapper)?; + check_fees(state, wrapper)?; Ok(()) } }; // Commit tx write log even in case of subsequent errors - shell_params.state.write_log_mut().commit_tx(); + state.write_log_mut().commit_tx(); payment_result } @@ -1270,7 +1321,7 @@ mod tests { // "execute" a dummy tx, by manually performing its state changes let (dummy_tx, changed_keys, verifiers) = { - let mut tx = Tx::from_type(TxType::Raw); + let mut tx = Tx::from_type(namada_tx::data::TxType::Raw); tx.set_code(namada_tx::Code::new(vec![], None)); tx.set_data(namada_tx::Data::new(vec![])); diff --git a/crates/namada/src/vm/host_env.rs b/crates/namada/src/vm/host_env.rs index ed09242f16..8984b4ac5f 100644 --- a/crates/namada/src/vm/host_env.rs +++ b/crates/namada/src/vm/host_env.rs @@ -1,5 +1,6 @@ //! Virtual machine's host environment exposes functions that may be called from //! within a virtual machine. + use std::cell::RefCell; use std::collections::BTreeSet; use std::fmt::Debug; @@ -92,7 +93,6 @@ pub type TxResult = std::result::Result; /// A transaction's host environment pub struct TxVmEnv where - MEM: VmMemory, D: DB + for<'iter> DBIter<'iter>, H: StorageHasher, CA: WasmCacheAccess, @@ -150,7 +150,6 @@ where impl TxVmEnv where - MEM: VmMemory, D: DB + for<'iter> DBIter<'iter>, H: StorageHasher, CA: WasmCacheAccess, @@ -228,7 +227,7 @@ where impl Clone for TxVmEnv where - MEM: VmMemory, + MEM: Clone, D: DB + for<'iter> DBIter<'iter>, H: StorageHasher, CA: WasmCacheAccess, @@ -306,7 +305,6 @@ where /// A validity predicate's host environment pub struct VpVmEnv where - MEM: VmMemory, D: DB + for<'iter> DBIter<'iter>, H: StorageHasher, EVAL: VpEvaluator, @@ -392,7 +390,6 @@ impl VpVmEnv where D: DB + for<'iter> DBIter<'iter>, H: StorageHasher, - MEM: VmMemory, EVAL: VpEvaluator, CA: WasmCacheAccess, { @@ -452,7 +449,7 @@ where impl Clone for VpVmEnv where - MEM: VmMemory, + MEM: Clone, D: DB + for<'iter> DBIter<'iter>, H: StorageHasher, EVAL: VpEvaluator, @@ -590,7 +587,7 @@ where /// Add a gas cost incured in a transaction pub fn tx_charge_gas( - env: &TxVmEnv, + env: &mut TxVmEnv, used_gas: u64, ) -> TxResult<()> where @@ -614,7 +611,7 @@ where /// Called from VP wasm to request to use the given gas amount pub fn vp_charge_gas( - env: &VpVmEnv, + env: &mut VpVmEnv, used_gas: u64, ) -> vp_host_fns::EnvResult<()> where @@ -631,7 +628,7 @@ where /// Storage `has_key` function exposed to the wasm VM Tx environment. It will /// try to check the write log first and if no entry found then the storage. pub fn tx_has_key( - env: &TxVmEnv, + env: &mut TxVmEnv, key_ptr: u64, key_len: u64, ) -> TxResult @@ -663,7 +660,7 @@ where /// Returns `-1` when the key is not present, or the length of the data when /// the key is present (the length may be `0`). pub fn tx_read( - env: &TxVmEnv, + env: &mut TxVmEnv, key_ptr: u64, key_len: u64, ) -> TxResult @@ -706,7 +703,7 @@ where /// Returns `-1` when the key is not present, or the length of the data when /// the key is present (the length may be `0`). pub fn tx_read_temp( - env: &TxVmEnv, + env: &mut TxVmEnv, key_ptr: u64, key_len: u64, ) -> TxResult @@ -752,7 +749,7 @@ where /// any) back to the guest, the second step reads the value from cache into a /// pre-allocated buffer with the obtained size. pub fn tx_result_buffer( - env: &TxVmEnv, + env: &mut TxVmEnv, result_ptr: u64, ) -> TxResult<()> where @@ -776,7 +773,7 @@ where /// It will try to get an iterator from the storage and return the corresponding /// ID of the iterator, ordered by storage keys. pub fn tx_iter_prefix( - env: &TxVmEnv, + env: &mut TxVmEnv, prefix_ptr: u64, prefix_len: u64, ) -> TxResult @@ -816,7 +813,7 @@ where /// Returns `-1` when the key is not present, or the length of the data when /// the key is present (the length may be `0`). pub fn tx_iter_next( - env: &TxVmEnv, + env: &mut TxVmEnv, iter_id: u64, ) -> TxResult where @@ -827,25 +824,25 @@ where { tracing::debug!("tx_iter_next iter_id {}", iter_id,); - let state = env.state(); let iterators = unsafe { env.ctx.iterators.get_mut() }; let iter_id = PrefixIteratorId::new(iter_id); while let Some((key, val, iter_gas)) = iterators.next(iter_id) { - let (log_val, log_gas) = state - .write_log() - .read( - &Key::parse(key.clone()) - .map_err(TxRuntimeError::StorageDataError)?, - ) - .into_storage_result()?; + let (log_val, log_gas) = { + let state = env.state(); + let (log_val, log_gas) = state + .write_log() + .read( + &Key::parse(key.clone()) + .map_err(TxRuntimeError::StorageDataError)?, + ) + .into_storage_result()?; + (log_val.cloned(), log_gas) + }; tx_charge_gas::(env, checked!(iter_gas + log_gas)?)?; match log_val { - Some(write_log::StorageModification::Write { ref value }) => { - let key_val = borsh::to_vec(&KeyVal { - key, - val: value.clone(), - }) - .map_err(TxRuntimeError::EncodingError)?; + Some(write_log::StorageModification::Write { value }) => { + let key_val = borsh::to_vec(&KeyVal { key, val: value }) + .map_err(TxRuntimeError::EncodingError)?; let len: i64 = key_val .len() .try_into() @@ -881,7 +878,7 @@ where /// Storage write function exposed to the wasm VM Tx environment. The given /// key/value will be written to the write log. pub fn tx_write( - env: &TxVmEnv, + env: &mut TxVmEnv, key_ptr: u64, key_len: u64, val_ptr: u64, @@ -923,7 +920,7 @@ where /// given key/value will be written only to the write log. It will be never /// written to the storage. pub fn tx_write_temp( - env: &TxVmEnv, + env: &mut TxVmEnv, key_ptr: u64, key_len: u64, val_ptr: u64, @@ -961,7 +958,7 @@ where } fn check_address_existence( - env: &TxVmEnv, + env: &mut TxVmEnv, key: &Key, ) -> TxResult<()> where @@ -1008,7 +1005,7 @@ where /// Storage delete function exposed to the wasm VM Tx environment. The given /// key/value will be written as deleted to the write log. pub fn tx_delete( - env: &TxVmEnv, + env: &mut TxVmEnv, key_ptr: u64, key_len: u64, ) -> TxResult<()> @@ -1038,7 +1035,7 @@ where /// Expose the functionality to emit events to the wasm VM's Tx environment. /// An emitted event will land in the write log. pub fn tx_emit_event( - env: &TxVmEnv, + env: &mut TxVmEnv, event_ptr: u64, event_len: u64, ) -> TxResult<()> @@ -1065,7 +1062,7 @@ where /// Expose the functionality to query events from the wasm VM's Tx environment. pub fn tx_get_events( - env: &TxVmEnv, + env: &mut TxVmEnv, event_type_ptr: u64, event_type_len: u64, ) -> TxResult @@ -1106,7 +1103,7 @@ where /// Returns `-1` when the key is not present, or the length of the data when /// the key is present (the length may be `0`). pub fn vp_read_pre( - env: &VpVmEnv, + env: &mut VpVmEnv, key_ptr: u64, key_len: u64, ) -> vp_host_fns::EnvResult @@ -1156,7 +1153,7 @@ where /// Returns `-1` when the key is not present, or the length of the data when /// the key is present (the length may be `0`). pub fn vp_read_post( - env: &VpVmEnv, + env: &mut VpVmEnv, key_ptr: u64, key_len: u64, ) -> vp_host_fns::EnvResult @@ -1201,7 +1198,7 @@ where /// Returns `-1` when the key is not present, or the length of the data when /// the key is present (the length may be `0`). pub fn vp_read_temp( - env: &VpVmEnv, + env: &mut VpVmEnv, key_ptr: u64, key_len: u64, ) -> vp_host_fns::EnvResult @@ -1249,7 +1246,7 @@ where /// any) back to the guest, the second step reads the value from cache into a /// pre-allocated buffer with the obtained size. pub fn vp_result_buffer( - env: &VpVmEnv, + env: &mut VpVmEnv, result_ptr: u64, ) -> vp_host_fns::EnvResult<()> where @@ -1274,7 +1271,7 @@ where /// Storage `has_key` in prior state (before tx execution) function exposed to /// the wasm VM VP environment. It will try to read from the storage. pub fn vp_has_key_pre( - env: &VpVmEnv, + env: &mut VpVmEnv, key_ptr: u64, key_len: u64, ) -> vp_host_fns::EnvResult @@ -1305,7 +1302,7 @@ where /// to the wasm VM VP environment. It will try to check the write log first and /// if no entry found then the storage. pub fn vp_has_key_post( - env: &VpVmEnv, + env: &mut VpVmEnv, key_ptr: u64, key_len: u64, ) -> vp_host_fns::EnvResult @@ -1337,7 +1334,7 @@ where /// the storage and return the corresponding ID of the iterator, ordered by /// storage keys. pub fn vp_iter_prefix_pre( - env: &VpVmEnv, + env: &mut VpVmEnv, prefix_ptr: u64, prefix_len: u64, ) -> vp_host_fns::EnvResult @@ -1376,7 +1373,7 @@ where /// the storage and return the corresponding ID of the iterator, ordered by /// storage keys. pub fn vp_iter_prefix_post( - env: &VpVmEnv, + env: &mut VpVmEnv, prefix_ptr: u64, prefix_len: u64, ) -> vp_host_fns::EnvResult @@ -1417,7 +1414,7 @@ where /// Returns `-1` when the key is not present, or the length of the data when /// the key is present (the length may be `0`). pub fn vp_iter_next( - env: &VpVmEnv, + env: &mut VpVmEnv, iter_id: u64, ) -> vp_host_fns::EnvResult where @@ -1450,7 +1447,7 @@ where /// Verifier insertion function exposed to the wasm VM Tx environment. pub fn tx_insert_verifier( - env: &TxVmEnv, + env: &mut TxVmEnv, addr_ptr: u64, addr_len: u64, ) -> TxResult<()> @@ -1484,7 +1481,7 @@ where /// Update a validity predicate function exposed to the wasm VM Tx environment pub fn tx_update_validity_predicate( - env: &TxVmEnv, + env: &mut TxVmEnv, addr_ptr: u64, addr_len: u64, code_hash_ptr: u64, @@ -1535,7 +1532,7 @@ where /// Initialize a new account established address. #[allow(clippy::too_many_arguments)] pub fn tx_init_account( - env: &TxVmEnv, + env: &mut TxVmEnv, code_hash_ptr: u64, code_hash_len: u64, code_tag_ptr: u64, @@ -1591,7 +1588,7 @@ where /// Getting the chain ID function exposed to the wasm VM Tx environment. pub fn tx_get_chain_id( - env: &TxVmEnv, + env: &mut TxVmEnv, result_ptr: u64, ) -> TxResult<()> where @@ -1614,7 +1611,7 @@ where /// environment. The height is that of the block to which the current /// transaction is being applied. pub fn tx_get_block_height( - env: &TxVmEnv, + env: &mut TxVmEnv, ) -> TxResult where MEM: VmMemory, @@ -1632,7 +1629,7 @@ where /// environment. The index is that of the transaction being applied /// in the current block. pub fn tx_get_tx_index( - env: &TxVmEnv, + env: &mut TxVmEnv, ) -> TxResult where MEM: VmMemory, @@ -1654,7 +1651,7 @@ where /// environment. The height is that of the block to which the current /// transaction is being applied. pub fn vp_get_tx_index( - env: &VpVmEnv, + env: &mut VpVmEnv, ) -> vp_host_fns::EnvResult where MEM: VmMemory, @@ -1673,7 +1670,7 @@ where /// environment. The epoch is that of the block to which the current /// transaction is being applied. pub fn tx_get_block_epoch( - env: &TxVmEnv, + env: &mut TxVmEnv, ) -> TxResult where MEM: VmMemory, @@ -1689,7 +1686,7 @@ where /// Get predecessor epochs function exposed to the wasm VM Tx environment. pub fn tx_get_pred_epochs( - env: &TxVmEnv, + env: &mut TxVmEnv, ) -> TxResult where MEM: VmMemory, @@ -1716,7 +1713,7 @@ where /// Get the native token's address pub fn tx_get_native_token( - env: &TxVmEnv, + env: &mut TxVmEnv, result_ptr: u64, ) -> TxResult<()> where @@ -1744,7 +1741,7 @@ where /// Getting the block header function exposed to the wasm VM Tx environment. pub fn tx_get_block_header( - env: &TxVmEnv, + env: &mut TxVmEnv, height: u64, ) -> TxResult where @@ -1776,7 +1773,7 @@ where /// Getting the chain ID function exposed to the wasm VM VP environment. pub fn vp_get_chain_id( - env: &VpVmEnv, + env: &mut VpVmEnv, result_ptr: u64, ) -> vp_host_fns::EnvResult<()> where @@ -1800,7 +1797,7 @@ where /// environment. The height is that of the block to which the current /// transaction is being applied. pub fn vp_get_block_height( - env: &VpVmEnv, + env: &mut VpVmEnv, ) -> vp_host_fns::EnvResult where MEM: VmMemory, @@ -1817,7 +1814,7 @@ where /// Getting the block header function exposed to the wasm VM VP environment. pub fn vp_get_block_header( - env: &VpVmEnv, + env: &mut VpVmEnv, height: u64, ) -> vp_host_fns::EnvResult where @@ -1850,7 +1847,7 @@ where /// Getting the transaction hash function exposed to the wasm VM VP environment. pub fn vp_get_tx_code_hash( - env: &VpVmEnv, + env: &mut VpVmEnv, result_ptr: u64, ) -> vp_host_fns::EnvResult<()> where @@ -1883,7 +1880,7 @@ where /// environment. The epoch is that of the block to which the current /// transaction is being applied. pub fn vp_get_block_epoch( - env: &VpVmEnv, + env: &mut VpVmEnv, ) -> vp_host_fns::EnvResult where MEM: VmMemory, @@ -1900,7 +1897,7 @@ where /// Get predecessor epochs function exposed to the wasm VM VP environment. pub fn vp_get_pred_epochs( - env: &VpVmEnv, + env: &mut VpVmEnv, ) -> vp_host_fns::EnvResult where MEM: VmMemory, @@ -1924,7 +1921,7 @@ where /// Expose the functionality to query events from the wasm VM's VP environment. pub fn vp_get_events( - env: &VpVmEnv, + env: &mut VpVmEnv, event_type_ptr: u64, event_type_len: u64, ) -> vp_host_fns::EnvResult @@ -1958,7 +1955,7 @@ where /// performance #[allow(clippy::too_many_arguments)] pub fn vp_verify_tx_section_signature( - env: &VpVmEnv, + env: &mut VpVmEnv, hash_list_ptr: u64, hash_list_len: u64, public_keys_map_ptr: u64, @@ -2040,7 +2037,7 @@ where /// printed at the [`tracing::Level::INFO`]. This function is for development /// only. pub fn tx_log_string( - env: &TxVmEnv, + env: &mut TxVmEnv, str_ptr: u64, str_len: u64, ) -> TxResult<()> @@ -2060,7 +2057,7 @@ where /// Validate a VP WASM code hash in a tx environment. fn tx_validate_vp_code_hash( - env: &TxVmEnv, + env: &mut TxVmEnv, code_hash: &[u8], code_tag: &Option, ) -> TxResult<()> @@ -2072,12 +2069,12 @@ where { let code_hash = Hash::try_from(code_hash) .map_err(|e| TxRuntimeError::InvalidVpCodeHash(e.to_string()))?; - let state = env.state(); // First check that code hash corresponds to the code tag if it is present if let Some(tag) = code_tag { let hash_key = Key::wasm_hash(tag); - let (result, gas) = state + let (result, gas) = env + .state() .db_read(&hash_key) .map_err(TxRuntimeError::StateError)?; tx_charge_gas::(env, gas)?; @@ -2108,7 +2105,7 @@ where // Then check that the corresponding VP code does indeed exist let code_key = Key::wasm_code(&code_hash); - let is_present = state.has_key(&code_key)?; + let is_present = env.state().has_key(&code_key)?; if !is_present { return Err(TxRuntimeError::InvalidVpCodeHash( "The corresponding VP code doesn't exist".to_string(), @@ -2118,8 +2115,9 @@ where } /// Set the sentinel for an invalid tx section commitment -pub fn tx_set_commitment_sentinel(env: &TxVmEnv) -where +pub fn tx_set_commitment_sentinel( + env: &mut TxVmEnv, +) where D: 'static + DB + for<'iter> DBIter<'iter>, H: 'static + StorageHasher, MEM: VmMemory, @@ -2132,7 +2130,7 @@ where /// Verify a transaction signature #[allow(clippy::too_many_arguments)] pub fn tx_verify_tx_section_signature( - env: &TxVmEnv, + env: &mut TxVmEnv, hash_list_ptr: u64, hash_list_len: u64, public_keys_map_ptr: u64, @@ -2204,7 +2202,7 @@ where /// Appends the new note commitments to the tree in storage pub fn tx_update_masp_note_commitment_tree( - env: &TxVmEnv, + env: &mut TxVmEnv, transaction_ptr: u64, transaction_len: u64, ) -> TxResult @@ -2241,7 +2239,7 @@ where /// Yield a byte array value from the guest. pub fn tx_yield_value( - env: &TxVmEnv, + env: &mut TxVmEnv, buf_ptr: u64, buf_len: u64, ) -> TxResult<()> @@ -2263,7 +2261,7 @@ where /// Evaluate a validity predicate with the given input data. pub fn vp_eval( - env: &VpVmEnv, + env: &mut VpVmEnv, vp_code_hash_ptr: u64, vp_code_hash_len: u64, input_data_ptr: u64, @@ -2315,7 +2313,7 @@ where /// Get the native token's address pub fn vp_get_native_token( - env: &VpVmEnv, + env: &mut VpVmEnv, result_ptr: u64, ) -> vp_host_fns::EnvResult<()> where @@ -2340,7 +2338,7 @@ where /// printed at the [`tracing::Level::INFO`]. This function is for development /// only. pub fn vp_log_string( - env: &VpVmEnv, + env: &mut VpVmEnv, str_ptr: u64, str_len: u64, ) -> vp_host_fns::EnvResult<()> @@ -2361,7 +2359,7 @@ where /// Yield a byte array value from the guest. pub fn vp_yield_value( - env: &VpVmEnv, + env: &mut VpVmEnv, buf_ptr: u64, buf_len: u64, ) -> vp_host_fns::EnvResult<()> @@ -2385,6 +2383,8 @@ where /// A helper module for testing #[cfg(feature = "testing")] pub mod testing { + use std::rc::Rc; + use super::*; use crate::vm::memory::testing::NativeMemory; use crate::vm::wasm::memory::WasmMemory; @@ -2451,15 +2451,14 @@ pub mod testing { S: State, CA: WasmCacheAccess, { - let store = crate::vm::wasm::compilation_cache::common::store(); - let initial_memory = - crate::vm::wasm::memory::prepare_tx_memory(&store).unwrap(); - let mut wasm_memory = WasmMemory::default(); - wasm_memory.inner.initialize(initial_memory); + let mut store = crate::vm::wasm::compilation_cache::common::store(); + + let wasm_memory = + crate::vm::wasm::memory::prepare_tx_memory(&mut store).unwrap(); let (write_log, in_mem, db) = state.split_borrow(); - TxVmEnv::new( - wasm_memory, + let mut env = TxVmEnv::new( + WasmMemory::new(Rc::new(RefCell::new(store))), write_log, in_mem, db, @@ -2476,7 +2475,10 @@ pub mod testing { vp_wasm_cache, #[cfg(feature = "wasm-runtime")] tx_wasm_cache, - ) + ); + + env.memory.init_from(&wasm_memory); + env } /// Setup a validity predicate environment diff --git a/crates/namada/src/vm/memory.rs b/crates/namada/src/vm/memory.rs index e55117726c..fe53a6c832 100644 --- a/crates/namada/src/vm/memory.rs +++ b/crates/namada/src/vm/memory.rs @@ -9,28 +9,28 @@ pub trait VmMemory: Clone + Send + Sync { /// Returns bytes read from memory together with the associated gas cost. fn read_bytes( - &self, + &mut self, offset: u64, len: usize, ) -> Result<(Vec, u64), Self::Error>; /// Write bytes to memory. Returns the gas cost. fn write_bytes( - &self, + &mut self, offset: u64, bytes: impl AsRef<[u8]>, ) -> Result; /// Returns string read from memory together with the associated gas cost. fn read_string( - &self, + &mut self, offset: u64, len: usize, ) -> Result<(String, u64), Self::Error>; /// Write string to memory. Returns the gas cost. fn write_string( - &self, + &mut self, offset: u64, string: String, ) -> Result; @@ -55,7 +55,7 @@ pub mod testing { type Error = Infallible; fn read_bytes( - &self, + &mut self, offset: u64, len: usize, ) -> Result<(Vec, u64)> { @@ -64,7 +64,7 @@ pub mod testing { } fn write_bytes( - &self, + &mut self, offset: u64, bytes: impl AsRef<[u8]>, ) -> Result { @@ -77,7 +77,7 @@ pub mod testing { } fn read_string( - &self, + &mut self, offset: u64, len: usize, ) -> Result<(String, u64)> { @@ -88,7 +88,7 @@ pub mod testing { Ok((string, 0)) } - fn write_string(&self, offset: u64, string: String) -> Result { + fn write_string(&mut self, offset: u64, string: String) -> Result { let bytes = string.as_bytes(); let len = bytes.len(); let target = diff --git a/crates/namada/src/vm/wasm/compilation_cache/common.rs b/crates/namada/src/vm/wasm/compilation_cache/common.rs index b23d79e50c..146d03df3a 100644 --- a/crates/namada/src/vm/wasm/compilation_cache/common.rs +++ b/crates/namada/src/vm/wasm/compilation_cache/common.rs @@ -1,8 +1,7 @@ //! WASM compilation cache. +//! //! The cache is backed by in-memory LRU cache with configurable size -//! limit and a file system cache of compiled modules (either to dynamic libs -//! compiled via the `dylib` module, or serialized modules compiled via the -//! `universal` module). +//! limit and a file system cache of serialized modules. use std::collections::hash_map::RandomState; use std::fs; @@ -496,9 +495,6 @@ fn hash_of_code(code: impl AsRef<[u8]>) -> Hash { fn compile( code: impl AsRef<[u8]>, ) -> Result<(Module, Store), wasm::run::Error> { - // There's an issue with dylib compiler on mac in linker and on linux - // with the dylib's store loading the dylib from a file, so we're caching a - // module serialized to bytes instead for now. universal::compile(code).map_err(wasm::run::Error::CompileError) } @@ -581,39 +577,6 @@ mod universal { } } -/// A dynamic library engine compilation. -mod dylib { - use super::*; - - #[allow(dead_code)] - #[cfg(windows)] - pub const FILE_EXT: &str = "dll"; - #[allow(dead_code)] - #[cfg(all(not(unix), target_os = "macos"))] - pub const FILE_EXT: &str = "dylib"; - #[allow(dead_code)] - #[cfg(all(unix, not(target_os = "macos")))] - pub const FILE_EXT: &str = "so"; - - /// Compile wasm to a dynamic library - #[allow(dead_code)] - pub fn compile( - code: impl AsRef<[u8]>, - ) -> Result<(Module, Store), wasmer::CompileError> { - let store = store(); - let module = Module::new(&store, code.as_ref())?; - Ok((module, store)) - } - - /// Dylib WASM store - #[allow(dead_code)] - pub fn store() -> Store { - let compiler = wasmer_compiler_singlepass::Singlepass::default(); - let engine = wasmer_engine_dylib::Dylib::new(compiler).engine(); - Store::new_with_tunables(&engine, memory::vp_limit()) - } -} - /// Testing helpers #[cfg(any(test, feature = "testing"))] pub mod testing { @@ -1063,10 +1026,6 @@ mod test { /// Get the WASM code bytes, its hash and find the compiled module's size fn load_wasm(file: impl AsRef) -> WasmWithMeta { - // When `WeightScale` calls `loupe::size_of_val` in the cache, for some - // reason it returns 8 bytes more than the same call in here. - let _extra_bytes = 8; - let file = file.as_ref(); let code = fs::read(file).unwrap(); let hash = hash_of_code(&code); diff --git a/crates/namada/src/vm/wasm/host_env.rs b/crates/namada/src/vm/wasm/host_env.rs index 1dc86a9a09..0d8d740693 100644 --- a/crates/namada/src/vm/wasm/host_env.rs +++ b/crates/namada/src/vm/wasm/host_env.rs @@ -4,86 +4,58 @@ //! imports, so they can be called from inside the wasm. use namada_state::{DBIter, StorageHasher, DB}; -use wasmer::{ - Function, HostEnvInitError, ImportObject, Instance, Store, WasmerEnv, -}; +use wasmer::{Function, FunctionEnv, Imports}; use crate::vm::host_env::{TxVmEnv, VpEvaluator, VpVmEnv}; use crate::vm::wasm::memory::WasmMemory; use crate::vm::{host_env, WasmCacheAccess}; -impl WasmerEnv for TxVmEnv -where - D: DB + for<'iter> DBIter<'iter> + 'static, - H: StorageHasher + 'static, - CA: WasmCacheAccess + 'static, -{ - fn init_with_instance( - &mut self, - instance: &Instance, - ) -> std::result::Result<(), HostEnvInitError> { - self.memory.init_env_memory(&instance.exports) - } -} - -impl WasmerEnv for VpVmEnv -where - D: DB + for<'iter> DBIter<'iter> + 'static, - H: StorageHasher + 'static, - EVAL: VpEvaluator + 'static, - CA: WasmCacheAccess + 'static, -{ - fn init_with_instance( - &mut self, - instance: &Instance, - ) -> std::result::Result<(), HostEnvInitError> { - self.memory.init_env_memory(&instance.exports) - } -} - /// Prepare imports (memory and host functions) exposed to the vm guest running /// transaction code #[allow(clippy::too_many_arguments)] pub fn tx_imports( - wasm_store: &Store, + wasm_store: &mut impl wasmer::AsStoreMut, env: TxVmEnv, -) -> ImportObject +) -> Imports where D: DB + for<'iter> DBIter<'iter> + 'static, H: StorageHasher + 'static, CA: WasmCacheAccess + 'static, { + let env = FunctionEnv::new(wasm_store, env); + wasmer::imports! { - // default namespace + // Default namespace "env" => { - // Wasm middleware gas injection hook - "gas" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_charge_gas), - "namada_tx_read" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_read), - "namada_tx_read_temp" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_read_temp), - "namada_tx_result_buffer" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_result_buffer), - "namada_tx_has_key" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_has_key), - "namada_tx_write" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_write), - "namada_tx_write_temp" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_write_temp), - "namada_tx_delete" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_delete), - "namada_tx_iter_prefix" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_iter_prefix), - "namada_tx_iter_next" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_iter_next), - "namada_tx_insert_verifier" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_insert_verifier), - "namada_tx_update_validity_predicate" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_update_validity_predicate), - "namada_tx_init_account" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_init_account), - "namada_tx_emit_event" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_emit_event), - "namada_tx_get_events" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_get_events), - "namada_tx_get_chain_id" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_get_chain_id), - "namada_tx_get_tx_index" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_get_tx_index), - "namada_tx_get_block_height" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_get_block_height), - "namada_tx_get_block_header" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_get_block_header), - "namada_tx_get_block_epoch" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_get_block_epoch), - "namada_tx_get_pred_epochs" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_get_pred_epochs), - "namada_tx_get_native_token" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_get_native_token), - "namada_tx_log_string" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_log_string), - "namada_tx_set_commitment_sentinel" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_set_commitment_sentinel), - "namada_tx_verify_tx_section_signature" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_verify_tx_section_signature), - "namada_tx_update_masp_note_commitment_tree" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_update_masp_note_commitment_tree), - "namada_tx_yield_value" => Function::new_native_with_env(wasm_store, env.clone(), host_env::tx_yield_value), + // Gas injection hook + "gas" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_1(host_env::tx_charge_gas)), + // Tx Host functions + "namada_tx_delete" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_2(host_env::tx_delete)), + "namada_tx_emit_event" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_2(host_env::tx_emit_event)), + "namada_tx_get_block_epoch" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_0(host_env::tx_get_block_epoch)), + "namada_tx_get_block_header" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_1(host_env::tx_get_block_header)), + "namada_tx_get_block_height" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_0(host_env::tx_get_block_height)), + "namada_tx_get_chain_id" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_1(host_env::tx_get_chain_id)), + "namada_tx_get_events" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_2(host_env::tx_get_events)), + "namada_tx_get_native_token" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_1(host_env::tx_get_native_token)), + "namada_tx_get_pred_epochs" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_0(host_env::tx_get_pred_epochs)), + "namada_tx_get_tx_index" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_0(host_env::tx_get_tx_index)), + "namada_tx_has_key" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_2(host_env::tx_has_key)), + "namada_tx_init_account" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_7(host_env::tx_init_account)), + "namada_tx_insert_verifier" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_2(host_env::tx_insert_verifier)), + "namada_tx_iter_next" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_1(host_env::tx_iter_next)), + "namada_tx_iter_prefix" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_2(host_env::tx_iter_prefix)), + "namada_tx_log_string" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_2(host_env::tx_log_string)), + "namada_tx_read" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_2(host_env::tx_read)), + "namada_tx_read_temp" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_2(host_env::tx_read_temp)), + "namada_tx_result_buffer" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_1(host_env::tx_result_buffer)), + "namada_tx_set_commitment_sentinel" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_0(host_env::tx_set_commitment_sentinel)), + "namada_tx_update_masp_note_commitment_tree" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_2(host_env::tx_update_masp_note_commitment_tree)), + "namada_tx_update_validity_predicate" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_6(host_env::tx_update_validity_predicate)), + "namada_tx_verify_tx_section_signature" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_7(host_env::tx_verify_tx_section_signature)), + "namada_tx_write" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_4(host_env::tx_write)), + "namada_tx_write_temp" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_4(host_env::tx_write_temp)), + "namada_tx_yield_value" => Function::new_typed_with_env(wasm_store, &env, wrap_tx::_2(host_env::tx_yield_value)), }, } } @@ -91,42 +63,347 @@ where /// Prepare imports (memory and host functions) exposed to the vm guest running /// validity predicate code pub fn vp_imports( - wasm_store: &Store, + wasm_store: &mut impl wasmer::AsStoreMut, env: VpVmEnv, -) -> ImportObject +) -> Imports where D: DB + for<'iter> DBIter<'iter> + 'static, H: StorageHasher + 'static, EVAL: VpEvaluator + 'static, CA: WasmCacheAccess + 'static, { + let env = FunctionEnv::new(wasm_store, env); + wasmer::imports! { - // default namespace + // Default namespace "env" => { - // Wasm middleware gas injection hook - "gas" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_charge_gas), - "namada_vp_read_pre" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_read_pre), - "namada_vp_read_post" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_read_post), - "namada_vp_read_temp" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_read_temp), - "namada_vp_result_buffer" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_result_buffer), - "namada_vp_has_key_pre" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_has_key_pre), - "namada_vp_has_key_post" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_has_key_post), - "namada_vp_iter_prefix_pre" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_iter_prefix_pre), - "namada_vp_iter_prefix_post" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_iter_prefix_pre), - "namada_vp_iter_next" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_iter_next), - "namada_vp_get_chain_id" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_get_chain_id), - "namada_vp_get_tx_index" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_get_tx_index), - "namada_vp_get_block_height" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_get_block_height), - "namada_vp_get_block_header" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_get_block_header), - "namada_vp_get_tx_code_hash" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_get_tx_code_hash), - "namada_vp_get_block_epoch" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_get_block_epoch), - "namada_vp_get_pred_epochs" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_get_pred_epochs), - "namada_vp_get_events" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_get_events), - "namada_vp_yield_value" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_yield_value), - "namada_vp_verify_tx_section_signature" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_verify_tx_section_signature), - "namada_vp_eval" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_eval), - "namada_vp_get_native_token" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_get_native_token), - "namada_vp_log_string" => Function::new_native_with_env(wasm_store, env.clone(), host_env::vp_log_string), + // Gas injection hook + "gas" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_1(host_env::vp_charge_gas)), + // VP Host functions + "namada_vp_eval" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_4(host_env::vp_eval)), + "namada_vp_get_block_header" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_1(host_env::vp_get_block_header)), + "namada_vp_get_block_height" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_0(host_env::vp_get_block_height)), + "namada_vp_get_chain_id" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_1(host_env::vp_get_chain_id)), + "namada_vp_get_events" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_2(host_env::vp_get_events)), + "namada_vp_get_native_token" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_1(host_env::vp_get_native_token)), + "namada_vp_get_pred_epochs" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_0(host_env::vp_get_pred_epochs)), + "namada_vp_get_tx_code_hash" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_1(host_env::vp_get_tx_code_hash)), + "namada_vp_get_tx_index" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_0(host_env::vp_get_tx_index)), + "namada_vp_has_key_post" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_2(host_env::vp_has_key_post)), + "namada_vp_has_key_pre" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_2(host_env::vp_has_key_pre)), + "namada_vp_iter_next" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_1(host_env::vp_iter_next)), + "namada_vp_iter_prefix_post" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_2(host_env::vp_iter_prefix_post)), + "namada_vp_iter_prefix_pre" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_2(host_env::vp_iter_prefix_pre)), + "namada_vp_log_string" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_2(host_env::vp_log_string)), + "namada_vp_read_post" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_2(host_env::vp_read_post)), + "namada_vp_read_pre" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_2(host_env::vp_read_pre)), + "namada_vp_read_temp" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_2(host_env::vp_read_temp)), + "namada_vp_result_buffer" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_1(host_env::vp_result_buffer)), + "namada_vp_verify_tx_section_signature" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_9(host_env::vp_verify_tx_section_signature)), + "namada_vp_yield_value" => Function::new_typed_with_env(wasm_store, &env, wrap_vp::_2(host_env::vp_yield_value)), }, } } + +// TODO(namada#3313): Attempt to reduce the boilerplate of this module with +// macros, traits or something of this sort... +mod wrap_tx { + //! Wrap tx host functions with any number of arguments in a callback + //! that can be passed to [`wasmer`], to be used by the guest wasm code. + + #![allow(missing_docs)] + + use namada_state::{DBIter, StorageHasher, DB}; + use wasmer::FunctionEnvMut; + + use crate::vm::host_env::TxVmEnv; + use crate::vm::wasm::memory::WasmMemory; + use crate::vm::WasmCacheAccess; + + pub(super) fn _0( + f: F, + ) -> impl Fn(FunctionEnvMut<'_, TxVmEnv>) -> RET + where + D: DB + for<'iter> DBIter<'iter> + 'static, + H: StorageHasher + 'static, + CA: WasmCacheAccess + 'static, + F: Fn(&mut TxVmEnv) -> RET, + { + move |mut env| f(env.data_mut()) + } + + pub(super) fn _1( + f: F, + ) -> impl Fn(FunctionEnvMut<'_, TxVmEnv>, ARG0) -> RET + where + D: DB + for<'iter> DBIter<'iter> + 'static, + H: StorageHasher + 'static, + CA: WasmCacheAccess + 'static, + F: Fn(&mut TxVmEnv, ARG0) -> RET, + { + move |mut env, arg0| f(env.data_mut(), arg0) + } + + pub(super) fn _2( + f: F, + ) -> impl Fn(FunctionEnvMut<'_, TxVmEnv>, ARG0, ARG1) -> RET + where + D: DB + for<'iter> DBIter<'iter> + 'static, + H: StorageHasher + 'static, + CA: WasmCacheAccess + 'static, + F: Fn(&mut TxVmEnv, ARG0, ARG1) -> RET, + { + move |mut env, arg0, arg1| f(env.data_mut(), arg0, arg1) + } + + pub(super) fn _4( + f: F, + ) -> impl Fn( + FunctionEnvMut<'_, TxVmEnv>, + ARG0, + ARG1, + ARG2, + ARG3, + ) -> RET + where + D: DB + for<'iter> DBIter<'iter> + 'static, + H: StorageHasher + 'static, + CA: WasmCacheAccess + 'static, + F: Fn( + &mut TxVmEnv, + ARG0, + ARG1, + ARG2, + ARG3, + ) -> RET, + { + move |mut env, arg0, arg1, arg2, arg3| { + f(env.data_mut(), arg0, arg1, arg2, arg3) + } + } + + pub(super) fn _6( + f: F, + ) -> impl Fn( + FunctionEnvMut<'_, TxVmEnv>, + ARG0, + ARG1, + ARG2, + ARG3, + ARG4, + ARG5, + ) -> RET + where + D: DB + for<'iter> DBIter<'iter> + 'static, + H: StorageHasher + 'static, + CA: WasmCacheAccess + 'static, + F: Fn( + &mut TxVmEnv, + ARG0, + ARG1, + ARG2, + ARG3, + ARG4, + ARG5, + ) -> RET, + { + move |mut env, arg0, arg1, arg2, arg3, arg4, arg5| { + f(env.data_mut(), arg0, arg1, arg2, arg3, arg4, arg5) + } + } + + pub(super) fn _7< + F, + ARG0, + ARG1, + ARG2, + ARG3, + ARG4, + ARG5, + ARG6, + RET, + D, + H, + CA, + >( + f: F, + ) -> impl Fn( + FunctionEnvMut<'_, TxVmEnv>, + ARG0, + ARG1, + ARG2, + ARG3, + ARG4, + ARG5, + ARG6, + ) -> RET + where + D: DB + for<'iter> DBIter<'iter> + 'static, + H: StorageHasher + 'static, + CA: WasmCacheAccess + 'static, + F: Fn( + &mut TxVmEnv, + ARG0, + ARG1, + ARG2, + ARG3, + ARG4, + ARG5, + ARG6, + ) -> RET, + { + move |mut env, arg0, arg1, arg2, arg3, arg4, arg5, arg6| { + f(env.data_mut(), arg0, arg1, arg2, arg3, arg4, arg5, arg6) + } + } +} + +// TODO(namada#3313): Attempt to reduce the boilerplate of this module with +// macros, traits or something of this sort... +mod wrap_vp { + //! Wrap vp host functions with any number of arguments in a callback + //! that can be passed to [`wasmer`], to be used by the guest wasm code. + + #![allow(missing_docs)] + + use namada_state::{DBIter, StorageHasher, DB}; + use wasmer::FunctionEnvMut; + + use crate::vm::host_env::{VpEvaluator, VpVmEnv}; + use crate::vm::wasm::memory::WasmMemory; + use crate::vm::WasmCacheAccess; + + pub(super) fn _0( + f: F, + ) -> impl Fn(FunctionEnvMut<'_, VpVmEnv>) -> RET + where + D: DB + for<'iter> DBIter<'iter> + 'static, + H: StorageHasher + 'static, + CA: WasmCacheAccess + 'static, + EVAL: VpEvaluator + 'static, + F: Fn(&mut VpVmEnv) -> RET, + { + move |mut env| f(env.data_mut()) + } + + pub(super) fn _1( + f: F, + ) -> impl Fn(FunctionEnvMut<'_, VpVmEnv>, ARG0) -> RET + where + D: DB + for<'iter> DBIter<'iter> + 'static, + H: StorageHasher + 'static, + CA: WasmCacheAccess + 'static, + EVAL: VpEvaluator + 'static, + F: Fn(&mut VpVmEnv, ARG0) -> RET, + { + move |mut env, arg0| f(env.data_mut(), arg0) + } + + pub(super) fn _2( + f: F, + ) -> impl Fn( + FunctionEnvMut<'_, VpVmEnv>, + ARG0, + ARG1, + ) -> RET + where + D: DB + for<'iter> DBIter<'iter> + 'static, + H: StorageHasher + 'static, + CA: WasmCacheAccess + 'static, + EVAL: VpEvaluator + 'static, + F: Fn(&mut VpVmEnv, ARG0, ARG1) -> RET, + { + move |mut env, arg0, arg1| f(env.data_mut(), arg0, arg1) + } + + pub(super) fn _4( + f: F, + ) -> impl Fn( + FunctionEnvMut<'_, VpVmEnv>, + ARG0, + ARG1, + ARG2, + ARG3, + ) -> RET + where + D: DB + for<'iter> DBIter<'iter> + 'static, + H: StorageHasher + 'static, + CA: WasmCacheAccess + 'static, + EVAL: VpEvaluator + 'static, + F: Fn( + &mut VpVmEnv, + ARG0, + ARG1, + ARG2, + ARG3, + ) -> RET, + { + move |mut env, arg0, arg1, arg2, arg3| { + f(env.data_mut(), arg0, arg1, arg2, arg3) + } + } + + pub(super) fn _9< + F, + ARG0, + ARG1, + ARG2, + ARG3, + ARG4, + ARG5, + ARG6, + ARG7, + ARG8, + RET, + D, + H, + EVAL, + CA, + >( + f: F, + ) -> impl Fn( + FunctionEnvMut<'_, VpVmEnv>, + ARG0, + ARG1, + ARG2, + ARG3, + ARG4, + ARG5, + ARG6, + ARG7, + ARG8, + ) -> RET + where + D: DB + for<'iter> DBIter<'iter> + 'static, + H: StorageHasher + 'static, + CA: WasmCacheAccess + 'static, + EVAL: VpEvaluator + 'static, + F: Fn( + &mut VpVmEnv, + ARG0, + ARG1, + ARG2, + ARG3, + ARG4, + ARG5, + ARG6, + ARG7, + ARG8, + ) -> RET, + { + move |mut env, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8| { + f( + env.data_mut(), + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + ) + } + } +} diff --git a/crates/namada/src/vm/wasm/memory.rs b/crates/namada/src/vm/wasm/memory.rs index 451301ec9b..95272ccdba 100644 --- a/crates/namada/src/vm/wasm/memory.rs +++ b/crates/namada/src/vm/wasm/memory.rs @@ -1,18 +1,20 @@ //! Wasm memory is used for bi-directionally passing data between the host and a //! wasm instance. +use std::cell::RefCell; use std::ptr::NonNull; +use std::rc::Rc; use std::str::Utf8Error; -use std::sync::Arc; use borsh_ext::BorshSerializeExt; use namada_gas::MEMORY_ACCESS_GAS_PER_BYTE; use namada_sdk::arith::{self, checked}; use namada_tx::BatchedTxRef; use thiserror::Error; +use wasmer::sys::BaseTunables; use wasmer::{ - vm, BaseTunables, HostEnvInitError, LazyInit, Memory, MemoryError, - MemoryType, Pages, TableType, Target, Tunables, WASM_PAGE_SIZE, + vm, Memory, MemoryError, MemoryType, Pages, Store, TableType, Target, + Tunables, WASM_PAGE_SIZE, }; use wasmer_vm::{ MemoryStyle, TableStyle, VMMemoryDefinition, VMTableDefinition, @@ -24,12 +26,16 @@ use crate::vm::types::VpInput; #[allow(missing_docs)] #[derive(Error, Debug)] pub enum Error { + #[error("Attempted to modify read-only memory")] + ReadOnly, #[error("Offset {0}+{1} overflows 32 bits storage")] OverflowingOffset(u64, usize), #[error("Failed initializing the memory: {0}")] InitMemoryError(wasmer::MemoryError), - #[error("Memory ouf of bounds: {0}")] - MemoryOutOfBounds(wasmer::MemoryError), + #[error("Failed to grow memory: {0}")] + Grow(wasmer::MemoryError), + #[error("Wasm memory access error: {0}")] + Access(#[from] wasmer::MemoryAccessError), #[error("Encoding error: {0}")] EncodingError(std::io::Error), #[error("Memory is not initialized")] @@ -47,7 +53,9 @@ pub type Result = std::result::Result; // The bounds are set in number of pages, the actual size is multiplied by // `wasmer::WASM_PAGE_SIZE = 64kiB`. -// TODO set bounds to accommodate for wasm env size +// +// TODO: set bounds to accommodate for wasm env size +// /// Initial pages in tx memory pub const TX_MEMORY_INIT_PAGES: u32 = 100; // 6.4 MiB /// Mamixmum pages in tx memory @@ -58,7 +66,9 @@ pub const VP_MEMORY_INIT_PAGES: u32 = 100; // 6.4 MiB pub const VP_MEMORY_MAX_PAGES: u32 = 200; // 12.8 MiB /// Prepare memory for instantiating a transaction module -pub fn prepare_tx_memory(store: &wasmer::Store) -> Result { +pub fn prepare_tx_memory( + store: &mut impl wasmer::AsStoreMut, +) -> Result { let mem_type = wasmer::MemoryType::new( TX_MEMORY_INIT_PAGES, Some(TX_MEMORY_MAX_PAGES), @@ -68,7 +78,9 @@ pub fn prepare_tx_memory(store: &wasmer::Store) -> Result { } /// Prepare memory for instantiating a validity predicate module -pub fn prepare_vp_memory(store: &wasmer::Store) -> Result { +pub fn prepare_vp_memory( + store: &mut impl wasmer::AsStoreMut, +) -> Result { let mem_type = wasmer::MemoryType::new( VP_MEMORY_INIT_PAGES, Some(VP_MEMORY_MAX_PAGES), @@ -89,6 +101,7 @@ pub struct TxCallInput { /// Write transaction inputs into wasm memory pub fn write_tx_inputs( + store: &mut impl wasmer::AsStoreMut, memory: &wasmer::Memory, tx_data: &BatchedTxRef<'_>, ) -> Result { @@ -96,7 +109,7 @@ pub fn write_tx_inputs( let tx_data_bytes = tx_data.serialize_to_vec(); let tx_data_len = tx_data_bytes.len() as _; - write_memory_bytes(memory, tx_data_ptr, tx_data_bytes)?; + write_memory_bytes(store, memory, tx_data_ptr, tx_data_bytes)?; Ok(TxCallInput { tx_data_ptr, @@ -127,6 +140,7 @@ pub struct VpCallInput { /// Write validity predicate inputs into wasm memory pub fn write_vp_inputs( + store: &mut impl wasmer::AsStoreMut, memory: &wasmer::Memory, VpInput { addr, @@ -158,7 +172,7 @@ pub fn write_vp_inputs( &verifiers_bytes[..], ] .concat(); - write_memory_bytes(memory, addr_ptr, bytes)?; + write_memory_bytes(store, memory, addr_ptr, bytes)?; Ok(VpCallInput { addr_ptr, @@ -174,12 +188,25 @@ pub fn write_vp_inputs( /// Check that the given offset and length fits into the memory bounds. If not, /// it will try to grow the memory. -fn check_bounds(memory: &Memory, base_addr: u64, offset: usize) -> Result<()> { +fn check_bounds( + store: &mut S, + memory: &Memory, + base_addr: u64, + offset: usize, + grow_callback: F, +) -> Result<()> +where + S: wasmer::AsStoreMut, + F: Fn(u64, &Memory, &mut S) -> Result<()>, +{ + let store_mut = store.as_store_mut(); + let memview = memory.view(&store_mut); + tracing::debug!( "check_bounds pages {}, data_size {}, base_addr {base_addr}, offset \ {offset}", - memory.size().0, - memory.data_size(), + memview.size().0, + memview.data_size(), ); let desired_offset = base_addr .checked_add(offset as u64) @@ -193,89 +220,119 @@ fn check_bounds(memory: &Memory, base_addr: u64, offset: usize) -> Result<()> { } }) .ok_or(Error::OverflowingOffset(base_addr, offset))?; - if memory.data_size() < desired_offset { - let cur_pages = memory.size().0 as usize; - let capacity = checked!(cur_pages * WASM_PAGE_SIZE)?; - // usizes should be at least 32 bits wide on most architectures, - // so this cast shouldn't cause panics, given the invariant that - // `desired_offset` is at most a 32 bit wide value. moreover, - // `capacity` should not be larger than `memory.data_size()`, - // so this subtraction should never fail - let desired_offset = usize::try_from(desired_offset)?; - let missing = checked!(desired_offset - capacity)?; - // extrapolate the number of pages missing to allow addressing - // the desired memory offset - let req_pages = - checked!((missing + WASM_PAGE_SIZE - 1) / WASM_PAGE_SIZE)?; - let req_pages: u32 = u32::try_from(req_pages)?; - tracing::debug!(req_pages, "Attempting to grow wasm memory"); - memory.grow(req_pages).map_err(Error::MemoryOutOfBounds)?; - tracing::debug!( - mem_size = memory.data_size(), - "Wasm memory size has been successfully extended" - ); + if memview.data_size() < desired_offset { + grow_callback(desired_offset, memory, store)?; } Ok(()) } /// Read bytes from memory at the given offset and length fn read_memory_bytes( + store: &mut impl wasmer::AsStoreMut, memory: &Memory, offset: u64, len: usize, ) -> Result> { - check_bounds(memory, offset, len)?; - let offset = usize::try_from(offset)?; - let vec: Vec<_> = memory.view()[offset..checked!(offset + len)?] - .iter() - .map(|cell| cell.get()) - .collect(); - Ok(vec) + check_bounds( + store, + memory, + offset, + len, + |_desired_offset, _memory, _store| Err(Error::ReadOnly), + )?; + let mut buf = vec![0; len]; + memory.view(&store.as_store_mut()).read(offset, &mut buf)?; + Ok(buf) } /// Write bytes into memory at the given offset fn write_memory_bytes( + store: &mut impl wasmer::AsStoreMut, memory: &Memory, offset: u64, bytes: impl AsRef<[u8]>, ) -> Result<()> { - let slice = bytes.as_ref(); - let len = slice.len(); - check_bounds(memory, offset, len as _)?; - let offset = usize::try_from(offset)?; - memory.view()[offset..checked!(offset + len)?] - .iter() - .zip(slice.iter()) - .for_each(|(cell, v)| cell.set(*v)); + let buf = bytes.as_ref(); + check_bounds( + store, + memory, + offset, + buf.len() as _, + |desired_offset, memory, store| { + let store_mut = store.as_store_mut(); + let memview = memory.view(&store_mut); + + let cur_pages = memview.size().0 as usize; + let capacity = checked!(cur_pages * WASM_PAGE_SIZE)?; + + // usizes should be at least 32 bits wide on most architectures, + // so this cast shouldn't cause panics, given the invariant that + // `desired_offset` is at most a 32 bit wide value. moreover, + // `capacity` should not be larger than `memory.data_size()`, + // so this subtraction should never fail + let desired_offset = usize::try_from(desired_offset)?; + let missing = checked!(desired_offset - capacity)?; + + // extrapolate the number of pages missing to allow addressing + // the desired memory offset + let req_pages = + checked!((missing + WASM_PAGE_SIZE - 1) / WASM_PAGE_SIZE)?; + let req_pages: u32 = u32::try_from(req_pages)?; + + tracing::debug!(req_pages, "Attempting to grow wasm memory"); + + memory.grow(store, req_pages).map_err(Error::Grow)?; + tracing::debug!( + mem_size = memory.view(&store.as_store_mut()).data_size(), + "Wasm memory size has been successfully extended" + ); + + Ok(()) + }, + )?; + memory.view(&store.as_store_mut()).write(offset, buf)?; Ok(()) } /// The wasm memory -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub struct WasmMemory { - pub(crate) inner: LazyInit, + store: Rc>, + memory: Rc>>, } +// TODO(namada#3313): Wasm memory is neither `Send` nor `Sync`, but we must +// implement it for now for the code to compile. +unsafe impl Send for WasmMemory {} +unsafe impl Sync for WasmMemory {} + impl WasmMemory { - /// Initialize the memory from the given exports, used to implement - /// [`wasmer::WasmerEnv`]. - pub fn init_env_memory( - &mut self, - exports: &wasmer::Exports, - ) -> std::result::Result<(), HostEnvInitError> { - // "`TxEnv` holds a reference to the Wasm `Memory`, which itself - // internally holds a reference to the instance which owns that - // memory. However the instance itself also holds a reference to - // the `TxEnv` when it is instantiated, thus creating a circular - // reference. - // You can work around this by using `get_with_generics_weak` which - // creates a weak reference to the `Instance` internally." - // - let memory = exports.get_with_generics_weak("memory")?; - if !self.inner.initialize(memory) { + /// Build a new wasm memory. + pub fn new(store: Rc>) -> Self { + Self { + store, + memory: Rc::new(RefCell::new(None)), + } + } + + /// Initialize the host memory with a pointer to the given memory. + pub fn init_from(&mut self, memory: &Memory) { + if self.memory.borrow().is_some() { tracing::error!("wasm memory is already initialized"); + return; } - Ok(()) + *self.memory.borrow_mut() = Some(memory.clone()); + } + + /// Access the inner [`Memory`]. + #[inline] + fn access(&self, f: F) -> Result + where + F: FnOnce(&Memory) -> Result, + { + let borrow = self.memory.borrow(); + let memory = borrow.as_ref().ok_or(Error::UninitializedMemory)?; + f(memory) } } @@ -284,29 +341,45 @@ impl VmMemory for WasmMemory { /// Read bytes from memory at the given offset and length, return the bytes /// and the gas cost - fn read_bytes(&self, offset: u64, len: usize) -> Result<(Vec, u64)> { - let memory = self.inner.get_ref().ok_or(Error::UninitializedMemory)?; - let bytes = read_memory_bytes(memory, offset, len)?; - let len = bytes.len() as u64; - let gas = checked!(len * MEMORY_ACCESS_GAS_PER_BYTE)?; - Ok((bytes, gas)) + fn read_bytes( + &mut self, + offset: u64, + len: usize, + ) -> Result<(Vec, u64)> { + self.access(|memory| { + let mut store = self.store.borrow_mut(); + let bytes = read_memory_bytes(&mut *store, memory, offset, len)?; + let len = bytes.len() as u64; + let gas = checked!(len * MEMORY_ACCESS_GAS_PER_BYTE)?; + Ok((bytes, gas)) + }) } /// Write bytes into memory at the given offset and return the gas cost - fn write_bytes(&self, offset: u64, bytes: impl AsRef<[u8]>) -> Result { - // No need for a separate gas multiplier for writes since we are only - // writing to memory and we already charge gas for every memory page - // allocated - let len = bytes.as_ref().len() as u64; - let gas = checked!(len * MEMORY_ACCESS_GAS_PER_BYTE)?; - let memory = self.inner.get_ref().ok_or(Error::UninitializedMemory)?; - write_memory_bytes(memory, offset, bytes)?; - Ok(gas) + fn write_bytes( + &mut self, + offset: u64, + bytes: impl AsRef<[u8]>, + ) -> Result { + self.access(|memory| { + // No need for a separate gas multiplier for writes since we are + // only writing to memory and we already charge gas for + // every memory page allocated + let len = bytes.as_ref().len() as u64; + let gas = checked!(len * MEMORY_ACCESS_GAS_PER_BYTE)?; + let mut store = self.store.borrow_mut(); + write_memory_bytes(&mut *store, memory, offset, bytes)?; + Ok(gas) + }) } /// Read string from memory at the given offset and bytes length, and return /// the gas cost - fn read_string(&self, offset: u64, len: usize) -> Result<(String, u64)> { + fn read_string( + &mut self, + offset: u64, + len: usize, + ) -> Result<(String, u64)> { let (bytes, gas) = self.read_bytes(offset, len)?; let string = std::str::from_utf8(&bytes) .map_err(Error::InvalidUtf8String)? @@ -316,12 +389,11 @@ impl VmMemory for WasmMemory { /// Write string into memory at the given offset and return the gas cost #[allow(dead_code)] - fn write_string(&self, offset: u64, string: String) -> Result { + fn write_string(&mut self, offset: u64, string: String) -> Result { self.write_bytes(offset, string.as_bytes()) } } -#[derive(loupe::MemoryUsage)] /// A custom [`Tunables`] to set a WASM memory limits. /// /// Adapted from . @@ -341,6 +413,7 @@ pub fn vp_limit() -> Limit { let limit = Pages(VP_MEMORY_MAX_PAGES); Limit { limit, base } } + /// A [`Limit`] with memory limit setup for transaction WASM execution. pub fn tx_limit() -> Limit { let base = BaseTunables::for_target(&Target::default()); @@ -412,7 +485,7 @@ impl Tunables for Limit { &self, ty: &MemoryType, style: &MemoryStyle, - ) -> std::result::Result, MemoryError> { + ) -> std::result::Result { let adjusted = self.adjust_memory(ty); self.validate_memory(&adjusted)?; self.base.create_host_memory(&adjusted, style) @@ -427,7 +500,7 @@ impl Tunables for Limit { ty: &MemoryType, style: &MemoryStyle, vm_definition_location: NonNull, - ) -> std::result::Result, MemoryError> { + ) -> std::result::Result { let adjusted = self.adjust_memory(ty); self.validate_memory(&adjusted)?; self.base @@ -442,7 +515,7 @@ impl Tunables for Limit { &self, ty: &TableType, style: &TableStyle, - ) -> std::result::Result, String> { + ) -> std::result::Result { self.base.create_host_table(ty, style) } @@ -455,14 +528,18 @@ impl Tunables for Limit { ty: &TableType, style: &TableStyle, vm_definition_location: NonNull, - ) -> std::result::Result, String> { + ) -> std::result::Result { self.base.create_vm_table(ty, style, vm_definition_location) } } #[cfg(test)] pub mod tests { - use wasmer::{wat2wasm, Cranelift, Instance, Module, Store}; + use wasmer::sys::Features; + use wasmer::{ + wat2wasm, Cranelift, Engine, Instance, Module, NativeEngineExt, Store, + Target, + }; use super::*; @@ -479,14 +556,19 @@ pub mod tests { // Any compiler and any engine do the job here let compiler = Cranelift::default(); - let engine = wasmer_engine_universal::Universal::new(compiler).engine(); + let mut engine = ::new( + Box::new(compiler), + Target::default(), + Features::default(), + ); let base = BaseTunables::for_target(&Target::default()); let limit = Pages(24); let tunables = Limit { limit, base }; + engine.set_tunables(tunables); // Create a store, that holds the engine and our custom tunables - let store = Store::new_with_tunables(&engine, tunables); + let mut store = Store::new(engine); println!("Compiling module..."); let module = Module::new(&store, wasm_bytes).unwrap(); @@ -495,7 +577,8 @@ pub mod tests { let import_object = wasmer::imports! {}; // Now at this point, our custom tunables are used - let instance = Instance::new(&module, &import_object).unwrap(); + let instance = + Instance::new(&mut store, &module, &import_object).unwrap(); // Check what happened let mut memories: Vec = instance @@ -508,6 +591,6 @@ pub mod tests { let first_memory = memories.pop().unwrap(); println!("Memory of this instance: {:?}", first_memory); - assert_eq!(first_memory.ty().maximum.unwrap(), limit); + assert_eq!(first_memory.ty(&store).maximum.unwrap(), limit); } } diff --git a/crates/namada/src/vm/wasm/run.rs b/crates/namada/src/vm/wasm/run.rs index 002081a288..eb54aa62de 100644 --- a/crates/namada/src/vm/wasm/run.rs +++ b/crates/namada/src/vm/wasm/run.rs @@ -6,6 +6,7 @@ use std::error::Error as _; use std::fmt::Debug; use std::marker::PhantomData; use std::num::NonZeroU32; +use std::rc::Rc; use borsh::BorshDeserialize; use namada_core::validity_predicate::VpError; @@ -16,7 +17,8 @@ use namada_tx::{BatchedTxRef, Commitment, Section, Tx, TxCommitments}; use parity_wasm::elements::Instruction::*; use parity_wasm::elements::{self, SignExtInstruction}; use thiserror::Error; -use wasmer::{BaseTunables, Module, Store}; +use wasmer::sys::{BaseTunables, Features}; +use wasmer::{Engine, Module, NativeEngineExt, Store, Target}; use super::memory::{Limit, WasmMemory}; use super::TxCache; @@ -191,6 +193,7 @@ where let (module, store) = fetch_or_compile(tx_wasm_cache, &tx_code.code, state, gas_meter)?; + let store = Rc::new(RefCell::new(store)); let mut iterators: PrefixIterators<'_, ::D> = PrefixIterators::default(); @@ -200,8 +203,8 @@ where let sentinel = RefCell::new(TxSentinel::default()); let (write_log, in_mem, db) = state.split_borrow(); - let env = TxVmEnv::new( - WasmMemory::default(), + let mut env = TxVmEnv::new( + WasmMemory::new(Rc::clone(&store)), write_log, in_mem, db, @@ -218,51 +221,69 @@ where tx_wasm_cache, ); - let imports = tx_imports(&store, env); - // Instantiate the wasm module - let instance = wasmer::Instance::new(&module, &imports) - .map_err(|e| Error::InstantiationError(Box::new(e)))?; + let instance = { + let mut store = store.borrow_mut(); + let imports = tx_imports(&mut *store, env.clone()); + wasmer::Instance::new(&mut *store, &module, &imports) + .map_err(|e| Error::InstantiationError(Box::new(e)))? + }; - // We need to write the inputs in the memory exported from the wasm - // module - let memory = instance + // Fetch guest's main memory + let guest_memory = instance .exports .get_memory("memory") .map_err(Error::MissingModuleMemory)?; + + env.memory.init_from(guest_memory); + + // Write the inputs in the memory exported from the wasm + // module let memory::TxCallInput { tx_data_ptr, tx_data_len, - } = memory::write_tx_inputs(memory, &batched_tx) - .map_err(Error::MemoryError)?; + } = { + let mut store = store.borrow_mut(); + memory::write_tx_inputs(&mut *store, guest_memory, &batched_tx) + .map_err(Error::MemoryError)? + }; + // Get the module's entrypoint to be called - let apply_tx = instance - .exports - .get_function(TX_ENTRYPOINT) - .map_err(Error::MissingModuleEntrypoint)? - .native::<(u64, u64), u64>() - .map_err(|error| Error::UnexpectedModuleEntrypointInterface { - entrypoint: TX_ENTRYPOINT, - error, - })?; - let ok = apply_tx.call(tx_data_ptr, tx_data_len).map_err(|err| { - tracing::debug!("Tx WASM failed with {}", err); - match *sentinel.borrow() { - TxSentinel::None => Error::RuntimeError(err), - TxSentinel::OutOfGas => Error::GasError(err.to_string()), - TxSentinel::InvalidCommitment => { - Error::MissingSection(err.to_string()) + let apply_tx = { + let store = store.borrow(); + instance + .exports + .get_function(TX_ENTRYPOINT) + .map_err(Error::MissingModuleEntrypoint)? + .typed::<(u64, u64), u64>(&*store) + .map_err(|error| Error::UnexpectedModuleEntrypointInterface { + entrypoint: TX_ENTRYPOINT, + error, + })? + }; + let ok = apply_tx + .call( + unsafe { &mut *RefCell::as_ptr(&*store) }, + tx_data_ptr, + tx_data_len, + ) + .map_err(|err| { + tracing::debug!("Tx WASM failed with {}", err); + match *sentinel.borrow() { + TxSentinel::None => Error::RuntimeError(err), + TxSentinel::OutOfGas => Error::GasError(err.to_string()), + TxSentinel::InvalidCommitment => { + Error::MissingSection(err.to_string()) + } } - } - })?; + })?; + + // NB: early drop this data to avoid memory errors + _ = (instance, env); if ok == 1 { Ok(verifiers) } else { - // NB: drop imports so we can safely access the - // `&mut` ptrs we shared with the guest - _ = (instance, imports); - let err = yielded_value.take().map_or_else( || Ok("Execution ended abruptly with an unknown error".to_owned()), |borsh_encoded_err| { @@ -306,6 +327,7 @@ where state, gas_meter, )?; + let store = Rc::new(RefCell::new(store)); let mut iterators: PrefixIterators<'_, ::D> = PrefixIterators::default(); @@ -318,8 +340,8 @@ where cache_access: PhantomData, }; let BatchedTxRef { tx, cmt } = batched_tx; - let env = VpVmEnv::new( - WasmMemory::default(), + let mut env = VpVmEnv::new( + WasmMemory::new(Rc::clone(&store)), address, state.write_log(), state.in_mem(), @@ -338,9 +360,14 @@ where ); let yielded_value_borrow = env.ctx.yielded_value; - let imports = vp_imports(&store, env); + + let imports = { + let mut store = store.borrow_mut(); + vp_imports(&mut *store, env.clone()) + }; run_vp( + store, module, imports, &vp_code_hash, @@ -349,20 +376,26 @@ where keys_changed, verifiers, yielded_value_borrow, + |guest_memory| env.memory.init_from(guest_memory), ) } #[allow(clippy::too_many_arguments)] -fn run_vp( +fn run_vp( + store: Rc>, module: wasmer::Module, - vp_imports: wasmer::ImportObject, + vp_imports: wasmer::Imports, vp_code_hash: &Hash, input_data: &BatchedTxRef<'_>, address: &Address, keys_changed: &BTreeSet, verifiers: &BTreeSet
, yielded_value: HostRef>>, -) -> Result<()> { + mut init_memory_callback: F, +) -> Result<()> +where + F: FnMut(&wasmer::Memory), +{ let input: VpInput<'_> = VpInput { addr: address, data: input_data, @@ -371,15 +404,22 @@ fn run_vp( }; // Instantiate the wasm module - let instance = wasmer::Instance::new(&module, &vp_imports) - .map_err(|e| Error::InstantiationError(Box::new(e)))?; + let instance = { + let mut store = store.borrow_mut(); + wasmer::Instance::new(&mut *store, &module, &vp_imports) + .map_err(|e| Error::InstantiationError(Box::new(e)))? + }; - // We need to write the inputs in the memory exported from the wasm - // module - let memory = instance + // Fetch guest's main memory + let guest_memory = instance .exports .get_memory("memory") .map_err(Error::MissingModuleMemory)?; + + init_memory_callback(guest_memory); + + // Write the inputs in the memory exported from the wasm + // module let memory::VpCallInput { addr_ptr, addr_len, @@ -389,20 +429,28 @@ fn run_vp( keys_changed_len, verifiers_ptr, verifiers_len, - } = memory::write_vp_inputs(memory, input).map_err(Error::MemoryError)?; + } = { + let mut store = store.borrow_mut(); + memory::write_vp_inputs(&mut *store, guest_memory, input) + .map_err(Error::MemoryError)? + }; // Get the module's entrypoint to be called - let validate_tx = instance - .exports - .get_function(VP_ENTRYPOINT) - .map_err(Error::MissingModuleEntrypoint)? - .native::<(u64, u64, u64, u64, u64, u64, u64, u64), u64>() - .map_err(|error| Error::UnexpectedModuleEntrypointInterface { - entrypoint: VP_ENTRYPOINT, - error, - })?; + let validate_tx = { + let store = store.borrow(); + instance + .exports + .get_function(VP_ENTRYPOINT) + .map_err(Error::MissingModuleEntrypoint)? + .typed::<(u64, u64, u64, u64, u64, u64, u64, u64), u64>(&*store) + .map_err(|error| Error::UnexpectedModuleEntrypointInterface { + entrypoint: VP_ENTRYPOINT, + error, + })? + }; let is_valid = validate_tx .call( + unsafe { &mut *RefCell::as_ptr(&*store) }, addr_ptr, addr_len, data_ptr, @@ -438,13 +486,12 @@ fn run_vp( "wasm vp" ); + // NB: early drop this data to avoid memory errors + _ = (instance, vp_imports); + if is_valid == 1 { Ok(()) } else { - // NB: drop imports so we can safely access the - // `&mut` ptrs we shared with the guest - _ = (instance, vp_imports); - unsafe { yielded_value.get_mut() }.take().map_or_else( || Err(Error::VpError(VpError::Unspecified)), |borsh_encoded_err| { @@ -526,15 +573,20 @@ where &ctx.state(), gas_meter, )?; + let store = Rc::new(RefCell::new(store)); - let env = VpVmEnv { - memory: WasmMemory::default(), + let mut env = VpVmEnv { + memory: WasmMemory::new(Rc::clone(&store)), ctx, }; let yielded_value_borrow = env.ctx.yielded_value; - let imports = vp_imports(&store, env); + let imports = { + let mut store = store.borrow_mut(); + vp_imports(&mut *store, env.clone()) + }; run_vp( + store, module, imports, &vp_code_hash, @@ -543,6 +595,7 @@ where keys_changed, verifiers, yielded_value_borrow, + |guest_memory| env.memory.init_from(guest_memory), ) } } @@ -551,10 +604,16 @@ where pub fn untrusted_wasm_store(limit: Limit) -> wasmer::Store { // Use Singlepass compiler with the default settings let compiler = wasmer_compiler_singlepass::Singlepass::default(); - wasmer::Store::new_with_tunables( - &wasmer_engine_universal::Universal::new(compiler).engine(), - limit, - ) + let mut engine = ::new( + Box::new(compiler), + // NB: The default target corresponds to the host's triplet + Target::default(), + // NB: WASM features are validated via `validate_untrusted_wasm`, + // so we can use the default features here + Features::default(), + ); + engine.set_tunables(limit); + wasmer::Store::new(engine) } /// Inject gas counter and stack-height limiter into the given wasm code @@ -881,14 +940,17 @@ mod tests { use borsh_ext::BorshSerializeExt; use itertools::Either; + use namada_sdk::arith::checked; use namada_state::StorageWrite; use namada_test_utils::TestWasms; use namada_token::DenominatedAmount; use namada_tx::data::{Fee, TxType}; use namada_tx::{Code, Data}; use test_log::test; + use wasmer::WASM_PAGE_SIZE; use wasmer_vm::TrapCode; + use super::memory::{TX_MEMORY_INIT_PAGES, VP_MEMORY_INIT_PAGES}; use super::*; use crate::state::testing::TestState; use crate::tx::data::eval_vp::EvalVp; @@ -926,15 +988,15 @@ mod tests { let error = execute_tx_with_code(tx_code).expect_err(PANIC_MSG); assert!( matches!( - assert_rt_mem_error(&error, PANIC_MSG), + assert_tx_rt_mem_error(&error, PANIC_MSG), memory::Error::OverflowingOffset(18446744073709551615, 1), ), "{PANIC_MSG}" ); } - /// Extract a wasm runtime memory error from some [`Error`]. - fn assert_rt_mem_error<'err>( + /// Extract a tx wasm runtime memory error from some [`Error`]. + fn assert_tx_rt_mem_error<'err>( error: &'err Error, assert_msg: &str, ) -> &'err memory::Error { @@ -955,6 +1017,29 @@ mod tests { .unwrap_or_else(|| panic!("{assert_msg}: {tx_mem_err}")) } + /// Extract a vp wasm runtime memory error from some [`Error`]. + fn assert_vp_rt_mem_error<'err>( + error: &'err Error, + assert_msg: &str, + ) -> &'err memory::Error { + let Error::RuntimeError(rt_error) = error else { + panic!("{assert_msg}: {error}"); + }; + let source_err = + rt_error.source().expect("No runtime error source found"); + let downcasted_tx_rt_err: &vp_host_fns::RuntimeError = source_err + .downcast_ref() + .unwrap_or_else(|| panic!("{assert_msg}: {source_err}")); + let vp_host_fns::RuntimeError::MemoryError(vp_mem_err) = + downcasted_tx_rt_err + else { + panic!("{assert_msg}: {downcasted_tx_rt_err}"); + }; + vp_mem_err + .downcast_ref() + .unwrap_or_else(|| panic!("{assert_msg}: {vp_mem_err}")) + } + /// Test that when a transaction wasm goes over the stack-height limit, the /// execution is aborted. #[test] @@ -1288,7 +1373,7 @@ mod tests { // of memory match result { // Dylib engine error (used anywhere except mac) - Err(Error::MemoryError(memory::Error::MemoryOutOfBounds( + Err(Error::MemoryError(memory::Error::Grow( wasmer::MemoryError::CouldNotGrow { .. }, ))) => {} Err(error) => { @@ -1352,7 +1437,7 @@ mod tests { // of memory match result { // Dylib engine error (used anywhere except mac) - Err(Error::MemoryError(memory::Error::MemoryOutOfBounds( + Err(Error::MemoryError(memory::Error::Grow( wasmer::MemoryError::CouldNotGrow { .. }, ))) => { // as expected @@ -1792,6 +1877,116 @@ mod tests { assert!(matches!(result.unwrap_err(), Error::GasError(_))); } + #[test] + fn test_tx_ro_memory_wont_grow() { + // a transaction that accesses memory out of bounds + let out_of_bounds_index = + checked!(2usize * TX_MEMORY_INIT_PAGES as usize * WASM_PAGE_SIZE) + .unwrap(); + let tx_code = wasmer::wat2wasm(format!( + r#" + (module + (import "env" "namada_tx_read" (func (param i64 i64) (result i64))) + (func (param i64 i64) (result i64) + i64.const {out_of_bounds_index} + i64.const 1 + (call 0) + ) + (memory 16) + (export "memory" (memory 0)) + (export "_apply_tx" (func 1)) + ) + "# + ).as_bytes()) + .expect("unexpected error converting wat2wasm") + .into_owned(); + + const PANIC_MSG: &str = + "Test should have failed with a wasm runtime memory error"; + + let error = execute_tx_with_code(tx_code).expect_err(PANIC_MSG); + assert!( + matches!( + assert_tx_rt_mem_error(&error, PANIC_MSG), + memory::Error::ReadOnly, + ), + "{PANIC_MSG}" + ); + } + + #[test] + fn test_vp_ro_memory_wont_grow() { + // vp code that accesses memory out of bounds + let out_of_bounds_index = + checked!(2usize * VP_MEMORY_INIT_PAGES as usize * WASM_PAGE_SIZE) + .unwrap(); + let vp_code = wasmer::wat2wasm(format!( + r#" + (module + (type (;0;) (func (param i64 i64 i64 i64 i64 i64 i64 i64) (result i64))) + (import "env" "namada_vp_read_pre" (func (param i64 i64) (result i64))) + + (func $_validate_tx (type 0) (param i64 i64 i64 i64 i64 i64 i64 i64) (result i64) + i64.const {out_of_bounds_index} + i64.const 1 + (call 0) + ) + + (table (;0;) 1 1 funcref) + (memory (;0;) 16) + (global (;0;) (mut i32) (i32.const 1048576)) + (export "memory" (memory 0)) + (export "_validate_tx" (func $_validate_tx))) + "#).as_bytes(), + ) + .expect("unexpected error converting wat2wasm").into_owned(); + + const PANIC_MSG: &str = + "Test should have failed with a wasm runtime memory error"; + + let error = execute_vp_with_code(vp_code).expect_err(PANIC_MSG); + assert!( + matches!( + assert_vp_rt_mem_error(&error, PANIC_MSG), + memory::Error::ReadOnly, + ), + "{PANIC_MSG}" + ); + } + + fn execute_vp_with_code(vp_code: Vec) -> Result<()> { + let mut outer_tx = Tx::from_type(TxType::Raw); + outer_tx.push_default_inner_tx(); + let tx_index = TxIndex::default(); + let mut state = TestState::default(); + let addr = state.in_mem_mut().address_gen.generate_address("rng seed"); + let gas_meter = RefCell::new(VpGasMeter::new_from_tx_meter( + &TxGasMeter::new_from_sub_limit(TX_GAS_LIMIT.into()), + )); + let keys_changed = BTreeSet::new(); + let verifiers = BTreeSet::new(); + let (vp_cache, _) = wasm::compilation_cache::common::testing::cache(); + // store the vp code + let code_hash = Hash::sha256(&vp_code); + let code_len = vp_code.len() as u64; + let key = Key::wasm_code(&code_hash); + let len_key = Key::wasm_code_len(&code_hash); + state.write(&key, vp_code).unwrap(); + state.write(&len_key, code_len).unwrap(); + + vp( + code_hash, + &outer_tx.batch_ref_first_tx(), + &tx_index, + &addr, + &state, + &gas_meter, + &keys_changed, + &verifiers, + vp_cache, + ) + } + fn execute_tx_with_code(tx_code: Vec) -> Result> { let tx_data = vec![]; let tx_index = TxIndex::default(); @@ -1895,36 +2090,7 @@ mod tests { ) .expect("unexpected error converting wat2wasm").into_owned(); - let mut outer_tx = Tx::from_type(TxType::Raw); - outer_tx.push_default_inner_tx(); - let tx_index = TxIndex::default(); - let mut state = TestState::default(); - let addr = state.in_mem_mut().address_gen.generate_address("rng seed"); - let gas_meter = RefCell::new(VpGasMeter::new_from_tx_meter( - &TxGasMeter::new_from_sub_limit(TX_GAS_LIMIT.into()), - )); - let keys_changed = BTreeSet::new(); - let verifiers = BTreeSet::new(); - let (vp_cache, _) = wasm::compilation_cache::common::testing::cache(); - // store the vp code - let code_hash = Hash::sha256(&vp_code); - let code_len = vp_code.len() as u64; - let key = Key::wasm_code(&code_hash); - let len_key = Key::wasm_code_len(&code_hash); - state.write(&key, vp_code).unwrap(); - state.write(&len_key, code_len).unwrap(); - - vp( - code_hash, - &outer_tx.batch_ref_first_tx(), - &tx_index, - &addr, - &state, - &gas_meter, - &keys_changed, - &verifiers, - vp_cache, - ) + execute_vp_with_code(vp_code) } fn get_trap_code(error: &Error) -> Either { diff --git a/crates/node/src/bench_utils.rs b/crates/node/src/bench_utils.rs index dbfd52a848..31343c7c70 100644 --- a/crates/node/src/bench_utils.rs +++ b/crates/node/src/bench_utils.rs @@ -26,7 +26,6 @@ use namada::core::masp::{ }; use namada::core::storage::{BlockHeight, Epoch, Key, KeySeg, TxIndex}; use namada::core::time::DateTimeUtc; -use namada::core::token::{Amount, DenominatedAmount, Transfer}; use namada::events::extend::{ComposeEvent, MaspTxBatchRefs, MaspTxBlockIndex}; use namada::events::Event; use namada::governance::storage::proposal::ProposalType; @@ -74,7 +73,12 @@ use namada::ledger::native_vp::ibc::get_dummy_header; use namada::ledger::queries::{ Client, EncodedResponseQuery, RequestCtx, RequestQuery, Router, RPC, }; +use namada::masp::MaspTxRefs; use namada::state::StorageRead; +use namada::token::{ + Amount, DenominatedAmount, ShieldedTransfer, ShieldingTransfer, + UnshieldingTransfer, +}; use namada::tx::data::pos::Bond; use namada::tx::data::{ BatchResults, BatchedTxResult, Fee, TxResult, VpsResult, @@ -90,7 +94,7 @@ use namada_apps_lib::cli::context::FromContext; use namada_apps_lib::cli::Context; use namada_apps_lib::wallet::{defaults, CliWalletUtils}; use namada_sdk::masp::{ - self, ContextSyncStatus, ShieldedContext, ShieldedTransfer, ShieldedUtils, + self, ContextSyncStatus, ShieldedContext, ShieldedUtils, }; pub use namada_sdk::tx::{ TX_BECOME_VALIDATOR_WASM, TX_BOND_WASM, TX_BRIDGE_POOL_WASM, @@ -100,10 +104,11 @@ pub use namada_sdk::tx::{ TX_CLAIM_REWARDS_WASM, TX_DEACTIVATE_VALIDATOR_WASM, TX_IBC_WASM, TX_INIT_ACCOUNT_WASM, TX_INIT_PROPOSAL as TX_INIT_PROPOSAL_WASM, TX_REACTIVATE_VALIDATOR_WASM, TX_REDELEGATE_WASM, TX_RESIGN_STEWARD, - TX_REVEAL_PK as TX_REVEAL_PK_WASM, TX_TRANSFER_WASM, TX_UNBOND_WASM, - TX_UNJAIL_VALIDATOR_WASM, TX_UPDATE_ACCOUNT_WASM, - TX_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL as TX_VOTE_PROPOSAL_WASM, - TX_WITHDRAW_WASM, VP_USER_WASM, + TX_REVEAL_PK as TX_REVEAL_PK_WASM, TX_SHIELDED_TRANSFER_WASM, + TX_SHIELDING_TRANSFER_WASM, TX_TRANSPARENT_TRANSFER_WASM, TX_UNBOND_WASM, + TX_UNJAIL_VALIDATOR_WASM, TX_UNSHIELDING_TRANSFER_WASM, + TX_UPDATE_ACCOUNT_WASM, TX_UPDATE_STEWARD_COMMISSION, + TX_VOTE_PROPOSAL as TX_VOTE_PROPOSAL_WASM, TX_WITHDRAW_WASM, VP_USER_WASM, }; use namada_sdk::wallet::Wallet; use namada_sdk::{Namada, NamadaImpl}; @@ -180,6 +185,7 @@ impl Default for BenchShell { sender, None, None, + None, 50 * 1024 * 1024, // 50 kiB 50 * 1024 * 1024, // 50 kiB ); @@ -439,8 +445,12 @@ impl BenchShell { ) .unwrap(); - namada::token::conversion::update_allowed_conversions(&mut self.state) + if self.state.is_masp_new_epoch(true).unwrap() { + namada::token::conversion::update_allowed_conversions( + &mut self.state, + ) .unwrap(); + } } pub fn init_ibc_client_state(&mut self, addr_key: Key) -> ClientId { @@ -922,12 +932,18 @@ impl Client for BenchShell { .with(MaspTxBlockIndex(TxIndex::must_from_usize( idx, ))) - .with(MaspTxBatchRefs( - vec![ - tx.first_commitments().unwrap().get_hash(), - ] - .into(), - )) + .with(MaspTxBatchRefs(MaspTxRefs(vec![ + tx.sections + .iter() + .find_map(|section| { + if let Section::MaspTx(_) = section { + Some(section.get_hash()) + } else { + None + } + }) + .unwrap(), + ]))) .into(); namada::tendermint::abci::Event::from(event) }) @@ -1077,43 +1093,61 @@ impl BenchShieldedCtx { ) .unwrap() .map( - |ShieldedTransfer { + |masp::ShieldedTransfer { builder: _, masp_tx, metadata: _, epoch: _, }| masp_tx, - ); + ) + .expect("MASP must have shielded part"); let mut hasher = Sha256::new(); - let shielded_section_hash = shielded.clone().map(|transaction| { - namada::core::hash::Hash( - Section::MaspTx(transaction) - .hash(&mut hasher) - .finalize_reset() - .into(), + let shielded_section_hash = namada::core::hash::Hash( + Section::MaspTx(shielded.clone()) + .hash(&mut hasher) + .finalize_reset() + .into(), + ); + let tx = if source.effective_address() == MASP + && target.effective_address() == MASP + { + namada.client().generate_tx( + TX_SHIELDED_TRANSFER_WASM, + ShieldedTransfer { + section_hash: shielded_section_hash, + }, + Some(shielded), + None, + vec![&defaults::albert_keypair()], ) - }); - - let tx = namada.client().generate_tx( - TX_TRANSFER_WASM, - Transfer { - source: source.effective_address(), - target: target.effective_address(), - token: address::testing::nam(), - amount: if source.effective_address().eq(&MASP) - && target.effective_address().eq(&MASP) - { - DenominatedAmount::native(0.into()) - } else { - DenominatedAmount::native(amount) + } else if target.effective_address() == MASP { + namada.client().generate_tx( + TX_SHIELDING_TRANSFER_WASM, + ShieldingTransfer { + source: source.effective_address(), + token: address::testing::nam(), + amount: DenominatedAmount::native(amount), + shielded_section_hash, }, - shielded: shielded_section_hash, - }, - shielded, - None, - vec![&defaults::albert_keypair()], - ); + Some(shielded), + None, + vec![&defaults::albert_keypair()], + ) + } else { + namada.client().generate_tx( + TX_UNSHIELDING_TRANSFER_WASM, + UnshieldingTransfer { + target: target.effective_address(), + token: address::testing::nam(), + amount: DenominatedAmount::native(amount), + shielded_section_hash, + }, + Some(shielded), + None, + vec![&defaults::albert_keypair()], + ) + }; let NamadaImpl { client, wallet, @@ -1172,12 +1206,13 @@ impl BenchShieldedCtx { timeout_timestamp_on_b: timeout_timestamp, }; - let transfer = - Transfer::deserialize(&mut tx.tx.data(&tx.cmt).unwrap().as_slice()) - .unwrap(); + let transfer = ShieldingTransfer::deserialize( + &mut tx.tx.data(&tx.cmt).unwrap().as_slice(), + ) + .unwrap(); let masp_tx = tx .tx - .get_section(&transfer.shielded.unwrap()) + .get_section(&transfer.shielded_section_hash) .unwrap() .masp_tx() .unwrap(); diff --git a/crates/node/src/lib.rs b/crates/node/src/lib.rs index bac9eb2062..f210bb8a71 100644 --- a/crates/node/src/lib.rs +++ b/crates/node/src/lib.rs @@ -43,6 +43,7 @@ use namada_apps_lib::config::utils::{ convert_tm_addr_to_socket_addr, num_of_threads, }; use namada_apps_lib::{config, wasm_loader}; +use namada_sdk::migrations::ScheduledMigration; use namada_sdk::state::StateRead; use once_cell::unsync::Lazy; use sysinfo::{RefreshKind, System, SystemExt}; @@ -196,7 +197,11 @@ fn emit_warning_on_non_64bit_cpu() { } /// Run the ledger with an async runtime -pub fn run(config: config::Ledger, wasm_dir: PathBuf) { +pub fn run( + config: config::Ledger, + wasm_dir: PathBuf, + scheduled_migration: Option, +) { emit_warning_on_non_64bit_cpu(); let logical_cores = num_cpus::get(); @@ -232,7 +237,7 @@ pub fn run(config: config::Ledger, wasm_dir: PathBuf) { .enable_all() .build() .unwrap() - .block_on(run_aux(config, wasm_dir)); + .block_on(run_aux(config, wasm_dir, scheduled_migration)); } /// Resets the tendermint_node state and removes database files @@ -311,25 +316,9 @@ pub fn update_db_keys(config: config::Ledger, updates: PathBuf, dry_run: bool) { let db_path = config.shell.db_dir(&chain_id); let db = storage::PersistentDB::open(db_path, None); - let mut db_visitor = storage::RocksDBUpdateVisitor::new(&db); - - for change in &updates.changes { - match change.update(&mut db_visitor) { - Ok(status) => { - tracing::info!("{}", status); - } - e => { - tracing::error!( - "Attempt to write to key/pattern <{}> failed.", - change.pattern() - ); - e.unwrap(); - } - } - } + let batch = db.apply_migration_to_batch(updates.changes).unwrap(); if !dry_run { tracing::info!("Persisting DB changes..."); - let batch = db_visitor.take_batch(); db.exec_batch(batch).expect("Failed to execute write batch"); db.flush(true).expect("Failed to flush data to disk"); @@ -357,8 +346,13 @@ pub fn rollback(config: config::Ledger) -> Result<(), shell::Error> { /// them to the ledger. /// /// All must be alive for correct functioning. -async fn run_aux(config: config::Ledger, wasm_dir: PathBuf) { - let setup_data = run_aux_setup(&config, &wasm_dir).await; +async fn run_aux( + config: config::Ledger, + wasm_dir: PathBuf, + scheduled_migration: Option, +) { + let setup_data = + run_aux_setup(&config, &wasm_dir, scheduled_migration).await; // Create an `AbortableSpawner` for signalling shut down from the shell or // from Tendermint @@ -431,12 +425,14 @@ struct RunAuxSetup { vp_wasm_compilation_cache: u64, tx_wasm_compilation_cache: u64, db_block_cache_size_bytes: u64, + scheduled_migration: Option, } /// Return some variables used to start child processes of the ledger. async fn run_aux_setup( config: &config::Ledger, wasm_dir: &PathBuf, + scheduled_migration: Option, ) -> RunAuxSetup { // Prefetch needed wasm artifacts wasm_loader::pre_fetch_wasm(wasm_dir).await; @@ -523,6 +519,7 @@ async fn run_aux_setup( vp_wasm_compilation_cache, tx_wasm_compilation_cache, db_block_cache_size_bytes, + scheduled_migration, } } @@ -546,6 +543,7 @@ fn start_abci_broadcaster_shell( vp_wasm_compilation_cache, tx_wasm_compilation_cache, db_block_cache_size_bytes, + scheduled_migration, } = setup_data; // Channels for validators to send protocol txs to be broadcast to the @@ -596,6 +594,7 @@ fn start_abci_broadcaster_shell( broadcaster_sender, eth_oracle, &db_cache, + scheduled_migration, vp_wasm_compilation_cache, tx_wasm_compilation_cache, ); @@ -888,6 +887,7 @@ pub fn test_genesis_files( broadcast_sender, None, None, + None, 50 * 1024 * 1024, 50 * 1024 * 1024, ); diff --git a/crates/node/src/shell/finalize_block.rs b/crates/node/src/shell/finalize_block.rs index 257d16216e..7adbcd17ba 100644 --- a/crates/node/src/shell/finalize_block.rs +++ b/crates/node/src/shell/finalize_block.rs @@ -15,14 +15,14 @@ use namada::ledger::events::EmitEvents; use namada::ledger::gas::GasMetering; use namada::ledger::ibc; use namada::ledger::pos::namada_proof_of_stake; -use namada::ledger::protocol::DispatchError; +use namada::ledger::protocol::{DispatchArgs, DispatchError}; +use namada::masp::MaspTxRefs; use namada::proof_of_stake; use namada::proof_of_stake::storage::{ find_validator_by_raw_hash, write_last_block_proposer_address, }; use namada::state::write_log::StorageModification; use namada::state::{ResultExt, StorageWrite, EPOCH_SWITCH_BLOCKS_DELAY}; -use namada::token::utils::is_masp_tx; use namada::tx::data::protocol::ProtocolTxType; use namada::tx::data::VpStatusFlags; use namada::tx::event::{Batch, Code}; @@ -67,6 +67,7 @@ where // Begin the new block and check if a new epoch has begun let (height, new_epoch) = self.update_state(req.header); + let is_masp_new_epoch = self.state.is_masp_new_epoch(new_epoch)?; let (current_epoch, _gas) = self.state.in_mem().get_current_epoch(); let update_for_tendermint = matches!( @@ -76,7 +77,7 @@ where tracing::info!( "Block height: {height}, epoch: {current_epoch}, is new epoch: \ - {new_epoch}." + {new_epoch}, is masp new epoch: {is_masp_new_epoch}." ); if update_for_tendermint { tracing::info!( @@ -111,7 +112,7 @@ where new_epoch, )?; // - Token - token::finalize_block(&mut self.state, emit_events, new_epoch)?; + token::finalize_block(&mut self.state, emit_events, is_masp_new_epoch)?; // - PoS // - Must be applied after governance in case it changes PoS params proof_of_stake::finalize_block( @@ -146,214 +147,29 @@ where // Tracks the accepted transactions self.state.in_mem_mut().block.results = BlockResults::default(); let mut changed_keys = BTreeSet::new(); - for (tx_index, processed_tx) in req.txs.iter().enumerate() { - let tx = if let Ok(tx) = Tx::try_from(processed_tx.tx.as_ref()) { - tx - } else { - tracing::error!( - "FinalizeBlock received a tx that could not be \ - deserialized to a Tx type. This is likely a protocol \ - transaction." - ); - continue; - }; - - let result_code = ResultCode::from_u32(processed_tx.result.code) - .expect("Result code conversion should not fail"); - - // If [`process_proposal`] rejected a Tx due to invalid signature, - // emit an event here and move on to next tx. - if result_code == ResultCode::InvalidSig { - let base_event = match tx.header().tx_type { - TxType::Wrapper(_) | TxType::Protocol(_) => { - new_tx_event(&tx, height.0) - } - _ => { - tracing::error!( - "Internal logic error: FinalizeBlock received a \ - tx with an invalid signature error code that \ - could not be deserialized to a WrapperTx / \ - ProtocolTx type" - ); - continue; - } - }; - response.events.emit( - base_event - .with(Code(result_code)) - .with(Info(format!( - "Tx rejected: {}", - &processed_tx.result.info - ))) - .with(GasUsed(0.into())), - ); - continue; - } - if tx.validate_tx().is_err() { - tracing::error!( - "Internal logic error: FinalizeBlock received tx that \ - could not be deserialized to a valid TxType" - ); - continue; - }; - let tx_header = tx.header(); - // If [`process_proposal`] rejected a Tx, emit an event here and - // move on to next tx - if result_code != ResultCode::Ok { - response.events.emit( - new_tx_event(&tx, height.0) - .with(Code(result_code)) - .with(Info(format!( - "Tx rejected: {}", - &processed_tx.result.info - ))) - .with(GasUsed(0.into())), - ); - continue; - } - - let (tx_gas_meter, block_proposer) = match &tx_header.tx_type { - TxType::Wrapper(wrapper) => { - stats.increment_wrapper_txs(); - let gas_limit = match Gas::try_from(wrapper.gas_limit) { - Ok(value) => value, - Err(_) => { - response.events.emit( - new_tx_event(&tx, height.0) - .with(Code(ResultCode::InvalidTx)) - .with(Info( - "The wrapper gas limit overflowed gas \ - representation" - .to_owned(), - )) - .with(GasUsed(0.into())), - ); - continue; - } - }; - let gas_meter = TxGasMeter::new(gas_limit); - for cmt in tx.commitments() { - if let Some(code_sec) = tx - .get_section(cmt.code_sechash()) - .and_then(|x| Section::code_sec(x.as_ref())) - { - stats.increment_tx_type( - code_sec.code.hash().to_string(), - ); - } - } - (gas_meter, Some(&native_block_proposer_address)) - } - TxType::Raw => { - tracing::error!( - "Internal logic error: FinalizeBlock received a \ - TxType::Raw transaction" - ); - continue; - } - TxType::Protocol(protocol_tx) => match protocol_tx.tx { - ProtocolTxType::BridgePoolVext - | ProtocolTxType::BridgePool - | ProtocolTxType::ValSetUpdateVext - | ProtocolTxType::ValidatorSetUpdate => { - (TxGasMeter::new_from_sub_limit(0.into()), None) - } - ProtocolTxType::EthEventsVext => { - let ext = - ethereum_tx_data_variants::EthEventsVext::try_from( - &tx, - ) - .unwrap(); - if self - .mode - .get_validator_address() - .map(|validator| { - validator == &ext.data.validator_addr - }) - .unwrap_or(false) - { - for event in ext.data.ethereum_events.iter() { - self.mode.dequeue_eth_event(event); - } - } - (TxGasMeter::new_from_sub_limit(0.into()), None) - } - ProtocolTxType::EthereumEvents => { - let digest = - ethereum_tx_data_variants::EthereumEvents::try_from( - &tx - ).unwrap(); - if let Some(address) = - self.mode.get_validator_address().cloned() - { - let this_signer = &( - address, - self.state.in_mem().get_last_block_height(), - ); - for MultiSignedEthEvent { event, signers } in - &digest.events - { - if signers.contains(this_signer) { - self.mode.dequeue_eth_event(event); - } - } - } - (TxGasMeter::new_from_sub_limit(0.into()), None) - } - }, - }; - let replay_protection_hashes = - if matches!(tx_header.tx_type, TxType::Wrapper(_)) { - Some(ReplayProtectionHashes { - raw_header_hash: tx.raw_header_hash(), - header_hash: tx.header_hash(), - }) - } else { - None - }; - let tx_gas_meter = RefCell::new(tx_gas_meter); - let mut tx_event = new_tx_event(&tx, height.0); - let is_atomic_batch = tx.header.atomic; - let commitments_len = tx.commitments().len() as u64; - let tx_hash = tx.header_hash(); - - let dispatch_result = protocol::dispatch_tx( - tx, - processed_tx.tx.as_ref(), - TxIndex::must_from_usize(tx_index), - &tx_gas_meter, - &mut self.state, - &mut self.vp_wasm_cache, - &mut self.tx_wasm_cache, - block_proposer, - ); - let tx_gas_meter = tx_gas_meter.into_inner(); - let consumed_gas = tx_gas_meter.get_tx_consumed_gas(); - - // save the gas cost - self.update_tx_gas(tx_hash, consumed_gas.into()); + // Execute wrapper and protocol transactions + let successful_wrappers = self.retrieve_and_execute_transactions( + &native_block_proposer_address, + &req.txs, + ExecutionArgs { + response: &mut response, + changed_keys: &mut changed_keys, + stats: &mut stats, + height, + }, + ); - self.evaluate_tx_result( - &mut response, - dispatch_result, - TxData { - is_atomic_batch, - tx_header: &tx_header, - commitments_len, - tx_index, - replay_protection_hashes, - consumed_gas, - height, - }, - TxLogs { - tx_event: &mut tx_event, - stats: &mut stats, - changed_keys: &mut changed_keys, - }, - ); - response.events.emit(tx_event); - } + // Execute inner transactions + self.execute_tx_batches( + successful_wrappers, + ExecutionArgs { + response: &mut response, + changed_keys: &mut changed_keys, + stats: &mut stats, + height, + }, + ); stats.set_tx_cache_size( self.tx_wasm_cache.get_size(), @@ -404,8 +220,8 @@ where /// Sets the metadata necessary for a new block, including the height, /// validator changes, and evidence of byzantine behavior. Applies slashes - /// if necessary. Returns a bool indicating if a new epoch began and the - /// height of the new block. + /// if necessary. Returns a boolean indicating if a new epoch and the height + /// of the new block. fn update_state(&mut self, header: Header) -> (BlockHeight, bool) { let height = self.state.in_mem().get_last_block_height().next_height(); @@ -524,25 +340,39 @@ where } } - // Evaluate the result of a batch. Commit or drop the storage changes, - // update stats and event, manage replay protection. + // Evaluate the result of a transaction. Commit or drop the storage changes, + // update stats and event, manage replay protection. For successful wrapper + // transactions return the relevant data and delay the evaluation after the + // batch execution fn evaluate_tx_result( &mut self, response: &mut shim::response::FinalizeBlock, - dispatch_result: std::result::Result< - namada::tx::data::TxResult, + extended_dispatch_result: std::result::Result< + namada::tx::data::ExtendedTxResult, DispatchError, >, tx_data: TxData<'_>, mut tx_logs: TxLogs<'_>, - ) { - match dispatch_result { - Ok(tx_result) => self.handle_inner_tx_results( - response, - tx_result, - tx_data, - &mut tx_logs, - ), + ) -> Option { + match extended_dispatch_result { + Ok(extended_tx_result) => match tx_data.tx.header.tx_type { + TxType::Wrapper(_) => { + // Return withouth emitting any events + return Some(WrapperCache { + tx: tx_data.tx.to_owned(), + tx_index: tx_data.tx_index, + gas_meter: tx_data.tx_gas_meter, + event: tx_logs.tx_event, + tx_result: extended_tx_result.tx_result, + }); + } + _ => self.handle_inner_tx_results( + response, + extended_tx_result, + tx_data, + &mut tx_logs, + ), + }, Err(DispatchError { error: protocol::Error::WrapperRunnerError(msg), tx_result: _, @@ -557,7 +387,7 @@ where ); tx_logs .tx_event - .extend(GasUsed(tx_data.consumed_gas)) + .extend(GasUsed(tx_data.tx_gas_meter.get_tx_consumed_gas())) .extend(Info(msg.to_string())) .extend(Code(ResultCode::InvalidTx)); // Make sure to clean the write logs for the next transaction @@ -582,7 +412,7 @@ where tx_logs .tx_event - .extend(GasUsed(tx_data.consumed_gas)) + .extend(GasUsed(tx_data.tx_gas_meter.get_tx_consumed_gas())) .extend(Info(msg.to_string())) .extend(Code(ResultCode::WasmRuntimeError)); @@ -595,6 +425,9 @@ where ); } } + + response.events.emit(tx_logs.tx_event); + None } // Evaluate the results of all the transactions of the batch. Commit or drop @@ -602,7 +435,7 @@ where fn handle_inner_tx_results( &mut self, response: &mut shim::response::FinalizeBlock, - tx_result: namada::tx::data::TxResult, + extended_tx_result: namada::tx::data::ExtendedTxResult, tx_data: TxData<'_>, tx_logs: &mut TxLogs<'_>, ) { @@ -612,8 +445,8 @@ where commit_batch_hash, is_any_tx_invalid, } = temp_log.check_inner_results( - &tx_result, - tx_data.tx_header, + &extended_tx_result.tx_result, + extended_tx_result.masp_tx_refs, tx_data.tx_index, tx_data.height, ); @@ -624,8 +457,10 @@ where let unrun_txs = tx_data .commitments_len .checked_sub( - u64::try_from(tx_result.batch_results.0.len()) - .expect("Should be able to convert to u64"), + u64::try_from( + extended_tx_result.tx_result.batch_results.0.len(), + ) + .expect("Should be able to convert to u64"), ) .expect("Shouldn't underflow"); temp_log.stats.set_failing_atomic_batch(unrun_txs); @@ -654,16 +489,16 @@ where tx_logs .tx_event - .extend(GasUsed(tx_result.gas_used)) + .extend(GasUsed(extended_tx_result.tx_result.gas_used)) .extend(Info("Check batch for result.".to_string())) - .extend(Batch(&tx_result.to_result_string())); + .extend(Batch(&extended_tx_result.tx_result.to_result_string())); } fn handle_batch_error( &mut self, response: &mut shim::response::FinalizeBlock, msg: &Error, - tx_result: namada::tx::data::TxResult, + extended_tx_result: namada::tx::data::ExtendedTxResult, tx_data: TxData<'_>, tx_logs: &mut TxLogs<'_>, ) { @@ -673,8 +508,8 @@ where commit_batch_hash, is_any_tx_invalid: _, } = temp_log.check_inner_results( - &tx_result, - tx_data.tx_header, + &extended_tx_result.tx_result, + extended_tx_result.masp_tx_refs, tx_data.tx_index, tx_data.height, ); @@ -682,8 +517,10 @@ where let unrun_txs = tx_data .commitments_len .checked_sub( - u64::try_from(tx_result.batch_results.0.len()) - .expect("Should be able to convert to u64"), + u64::try_from( + extended_tx_result.tx_result.batch_results.0.len(), + ) + .expect("Should be able to convert to u64"), ) .expect("Shouldn't underflow"); @@ -714,51 +551,361 @@ where tx_logs .tx_event - .extend(Batch(&tx_result.to_result_string())); + .extend(Batch(&extended_tx_result.tx_result.to_result_string())); } fn handle_batch_error_reprot(&mut self, err: &Error, tx_data: TxData<'_>) { - // If user transaction didn't fail because of out of gas nor - // invalid section commitment, commit its hash to prevent - // replays - if matches!(tx_data.tx_header.tx_type, TxType::Wrapper(_)) { - if !matches!( - err, - Error::TxApply(protocol::Error::GasError(_)) - | Error::TxApply(protocol::Error::ReplayAttempt(_)) + // If user transaction didn't fail because of out of gas nor replay + // attempt, commit its hash to prevent replays. If it failed because of + // a replay attempt just remove the redundant wrapper hash + if !matches!( + err, + Error::TxApply(protocol::Error::GasError(_)) + | Error::TxApply(protocol::Error::ReplayAttempt(_)) + ) { + self.commit_batch_hash(tx_data.replay_protection_hashes); + } else if let Error::TxApply(protocol::Error::ReplayAttempt(_)) = err { + // Remove the wrapper hash but keep the inner tx + // hash. A replay of the wrapper is impossible since + // the inner tx hash is committed to storage and + // we validate the wrapper against that hash too + let header_hash = tx_data + .replay_protection_hashes + .expect("This cannot fail") + .header_hash; + self.state + .redundant_tx_hash(&header_hash) + .expect("Error while marking tx hash as redundant"); + } + } + + // Get the transactions from the consensus engine, preprocess and execute + // them. Return the cache of successful wrapper transactions later used when + // executing the inner txs. + fn retrieve_and_execute_transactions( + &mut self, + native_block_proposer_address: &Address, + processed_txs: &[shim::request::ProcessedTx], + ExecutionArgs { + response, + changed_keys, + stats, + height, + }: ExecutionArgs<'_>, + ) -> Vec { + let mut successful_wrappers = vec![]; + + for (tx_index, processed_tx) in processed_txs.iter().enumerate() { + let tx = if let Ok(tx) = Tx::try_from(processed_tx.tx.as_ref()) { + tx + } else { + tracing::error!( + "FinalizeBlock received a tx that could not be \ + deserialized to a Tx type. This is likely a protocol \ + transaction." + ); + continue; + }; + + let result_code = ResultCode::from_u32(processed_tx.result.code) + .expect("Result code conversion should not fail"); + + // If [`process_proposal`] rejected a Tx due to invalid signature, + // emit an event here and move on to next tx. + if result_code == ResultCode::InvalidSig { + let base_event = match tx.header().tx_type { + TxType::Wrapper(_) | TxType::Protocol(_) => { + new_tx_event(&tx, height.0) + } + _ => { + tracing::error!( + "Internal logic error: FinalizeBlock received a \ + tx with an invalid signature error code that \ + could not be deserialized to a WrapperTx / \ + ProtocolTx type" + ); + continue; + } + }; + response.events.emit( + base_event + .with(Code(result_code)) + .with(Info(format!( + "Tx rejected: {}", + &processed_tx.result.info + ))) + .with(GasUsed(0.into())), + ); + continue; + } + + if tx.validate_tx().is_err() { + tracing::error!( + "Internal logic error: FinalizeBlock received tx that \ + could not be deserialized to a valid TxType" + ); + continue; + }; + let tx_header = tx.header(); + // If [`process_proposal`] rejected a Tx, emit an event here and + // move on to next tx + if result_code != ResultCode::Ok { + response.events.emit( + new_tx_event(&tx, height.0) + .with(Code(result_code)) + .with(Info(format!( + "Tx rejected: {}", + &processed_tx.result.info + ))) + .with(GasUsed(0.into())), + ); + continue; + } + + let (dispatch_args, tx_gas_meter): ( + DispatchArgs<'_, WasmCacheRwAccess>, + TxGasMeter, + ) = match &tx_header.tx_type { + TxType::Wrapper(wrapper) => { + stats.increment_wrapper_txs(); + + let gas_limit = match Gas::try_from(wrapper.gas_limit) { + Ok(value) => value, + Err(_) => { + response.events.emit( + new_tx_event(&tx, height.0) + .with(Code(ResultCode::InvalidTx)) + .with(Info( + "The wrapper gas limit overflowed gas \ + representation" + .to_owned(), + )) + .with(GasUsed(0.into())), + ); + continue; + } + }; + let tx_gas_meter = TxGasMeter::new(gas_limit); + for cmt in tx.commitments() { + if let Some(code_sec) = tx + .get_section(cmt.code_sechash()) + .and_then(|x| Section::code_sec(x.as_ref())) + { + stats.increment_tx_type( + code_sec.code.hash().to_string(), + ); + } + } + ( + DispatchArgs::Wrapper { + wrapper, + tx_bytes: processed_tx.tx.as_ref(), + block_proposer: native_block_proposer_address, + }, + tx_gas_meter, + ) + } + TxType::Raw => { + tracing::error!( + "Internal logic error: FinalizeBlock received a \ + TxType::Raw transaction" + ); + continue; + } + TxType::Protocol(protocol_tx) => { + match protocol_tx.tx { + ProtocolTxType::BridgePoolVext + | ProtocolTxType::BridgePool + | ProtocolTxType::ValSetUpdateVext + | ProtocolTxType::ValidatorSetUpdate => (), + + ProtocolTxType::EthEventsVext => { + let ext = + ethereum_tx_data_variants::EthEventsVext::try_from(&tx) + .unwrap(); + if self + .mode + .get_validator_address() + .map(|validator| { + validator == &ext.data.validator_addr + }) + .unwrap_or(false) + { + for event in ext.data.ethereum_events.iter() { + self.mode.dequeue_eth_event(event); + } + } + } + ProtocolTxType::EthereumEvents => { + let digest = + ethereum_tx_data_variants::EthereumEvents::try_from( + &tx, + ) + .unwrap(); + if let Some(address) = + self.mode.get_validator_address().cloned() + { + let this_signer = &( + address, + self.state.in_mem().get_last_block_height(), + ); + for MultiSignedEthEvent { event, signers } in + &digest.events + { + if signers.contains(this_signer) { + self.mode.dequeue_eth_event(event); + } + } + } + } + } + ( + DispatchArgs::Protocol(protocol_tx), + TxGasMeter::new_from_sub_limit(0.into()), + ) + } + }; + let tx_event = new_tx_event(&tx, height.0); + let is_atomic_batch = tx.header.atomic; + let commitments_len = tx.commitments().len() as u64; + let tx_hash = tx.header_hash(); + let tx_gas_meter = RefCell::new(tx_gas_meter); + + let dispatch_result = protocol::dispatch_tx( + &tx, + dispatch_args, + &tx_gas_meter, + &mut self.state, + ); + let tx_gas_meter = tx_gas_meter.into_inner(); + let consumed_gas = tx_gas_meter.get_tx_consumed_gas(); + + // save the gas cost + self.update_tx_gas(tx_hash, consumed_gas.into()); + + if let Some(wrapper_cache) = self.evaluate_tx_result( + response, + dispatch_result, + TxData { + is_atomic_batch, + tx: &tx, + commitments_len, + tx_index, + replay_protection_hashes: None, + tx_gas_meter, + height, + }, + TxLogs { + tx_event, + stats, + changed_keys, + }, ) { - self.commit_batch_hash(tx_data.replay_protection_hashes); - } else if let Error::TxApply(protocol::Error::ReplayAttempt(_)) = - err - { - // Remove the wrapper hash but keep the inner tx - // hash. A replay of the wrapper is impossible since - // the inner tx hash is committed to storage and - // we validate the wrapper against that hash too - let header_hash = tx_data - .replay_protection_hashes - .expect("This cannot fail") - .header_hash; - self.state - .redundant_tx_hash(&header_hash) - .expect("Error while marking tx hash as redundant"); + successful_wrappers.push(wrapper_cache); } } + + successful_wrappers + } + + // Execute the transaction batches for successful wrapper transactions + fn execute_tx_batches( + &mut self, + successful_wrappers: Vec, + ExecutionArgs { + response, + changed_keys, + stats, + height, + }: ExecutionArgs<'_>, + ) { + for WrapperCache { + mut tx, + tx_index, + gas_meter: tx_gas_meter, + event: tx_event, + tx_result: wrapper_tx_result, + } in successful_wrappers + { + let tx_hash = tx.header_hash(); + let is_atomic_batch = tx.header.atomic; + let commitments_len = tx.commitments().len() as u64; + let replay_protection_hashes = Some(ReplayProtectionHashes { + raw_header_hash: tx.raw_header_hash(), + header_hash: tx.header_hash(), + }); + + // change tx type to raw for execution + tx.update_header(TxType::Raw); + let tx_gas_meter = RefCell::new(tx_gas_meter); + let dispatch_result = protocol::dispatch_tx( + &tx, + DispatchArgs::Raw { + tx_index: TxIndex::must_from_usize(tx_index), + wrapper_tx_result: Some(wrapper_tx_result), + vp_wasm_cache: &mut self.vp_wasm_cache, + tx_wasm_cache: &mut self.tx_wasm_cache, + }, + &tx_gas_meter, + &mut self.state, + ); + let tx_gas_meter = tx_gas_meter.into_inner(); + let consumed_gas = tx_gas_meter.get_tx_consumed_gas(); + + // update the gas cost of the corresponding wrapper + self.update_tx_gas(tx_hash, consumed_gas.into()); + + self.evaluate_tx_result( + response, + dispatch_result, + TxData { + is_atomic_batch, + tx: &tx, + commitments_len, + tx_index, + replay_protection_hashes, + tx_gas_meter, + height, + }, + TxLogs { + tx_event, + stats, + changed_keys, + }, + ); + } } } +struct ExecutionArgs<'finalize> { + response: &'finalize mut shim::response::FinalizeBlock, + changed_keys: &'finalize mut BTreeSet, + stats: &'finalize mut InternalStats, + height: BlockHeight, +} + +// Caches the execution of a wrapper transaction to be used when later executing +// the inner batch +struct WrapperCache { + tx: Tx, + tx_index: usize, + gas_meter: TxGasMeter, + event: Event, + tx_result: namada::tx::data::TxResult, +} + struct TxData<'tx> { is_atomic_batch: bool, - tx_header: &'tx namada::tx::Header, + tx: &'tx Tx, commitments_len: u64, tx_index: usize, replay_protection_hashes: Option, - consumed_gas: Gas, + tx_gas_meter: TxGasMeter, height: BlockHeight, } struct TxLogs<'finalize> { - tx_event: &'finalize mut Event, + tx_event: Event, stats: &'finalize mut InternalStats, changed_keys: &'finalize mut BTreeSet, } @@ -818,20 +965,16 @@ impl<'finalize> TempTxLogs { fn check_inner_results( &mut self, tx_result: &namada::tx::data::TxResult, - tx_header: &namada::tx::Header, + masp_tx_refs: MaspTxRefs, tx_index: usize, height: BlockHeight, ) -> ValidityFlags { let mut flags = ValidityFlags::default(); - let mut masp_cmts = vec![]; for (cmt_hash, batched_result) in &tx_result.batch_results.0 { match batched_result { Ok(result) => { if result.is_accepted() { - if is_masp_tx(&result.changed_keys) { - masp_cmts.push(*cmt_hash); - } tracing::trace!( "all VPs accepted inner tx {} storage \ modification {:#?}", @@ -876,13 +1019,10 @@ impl<'finalize> TempTxLogs { } } Err(e) => { - // this branch can only be reached by inner txs tracing::trace!("Inner tx {} failed: {}", cmt_hash, e); // If inner transaction didn't fail because of invalid // section commitment, commit its hash to prevent replays - if matches!(tx_header.tx_type, TxType::Wrapper(_)) - && !matches!(e, protocol::Error::MissingSection(_)) - { + if !matches!(e, protocol::Error::MissingSection(_)) { flags.commit_batch_hash = true; } @@ -894,10 +1034,10 @@ impl<'finalize> TempTxLogs { // If at least one of the inner transactions is a valid masp tx, update // the events - if !masp_cmts.is_empty() { + if !masp_tx_refs.0.is_empty() { self.tx_event .extend(MaspTxBlockIndex(TxIndex::must_from_usize(tx_index))); - self.tx_event.extend(MaspTxBatchRefs(masp_cmts.into())); + self.tx_event.extend(MaspTxBatchRefs(masp_tx_refs)); } flags @@ -1171,9 +1311,8 @@ mod test_finalize_block { ) } - /// Check that if a wrapper tx was rejected by [`process_proposal`], - /// check that the correct event is returned. Check that it does - /// not appear in the queue of txs to be decrypted + /// Check that if a wrapper tx was rejected by [`process_proposal`], the + /// correct event is returned. #[test] fn test_process_proposal_rejected_wrapper_tx() { let (mut shell, _, _, _) = setup(); @@ -1190,24 +1329,36 @@ mod test_finalize_block { ) .unwrap(); + // Need ordered tx hashes because the events can be emitted out of order + let mut ordered_hashes = vec![]; // create some wrapper txs for i in 0u64..4 { - let (_, mut processed_tx) = mk_wrapper_tx(&shell, &keypair); + let (tx, mut processed_tx) = mk_wrapper_tx(&shell, &keypair); processed_tx.result.code = u32::try_from(i.rem_euclid(2)).unwrap(); processed_txs.push(processed_tx); + ordered_hashes.push(tx.header_hash()); } // check that the correct events were created - for (index, event) in shell + for event in shell .finalize_block(FinalizeBlock { txs: processed_txs.clone(), ..Default::default() }) .expect("Test failed") .iter() - .enumerate() { assert_eq!(*event.kind(), APPLIED_TX); + let hash = event.read_attribute::().expect("Test failed"); + let index = ordered_hashes + .iter() + .enumerate() + .find_map( + |(idx, tx_hash)| { + if tx_hash == &hash { Some(idx) } else { None } + }, + ) + .unwrap(); let code = event .read_attribute::() .expect("Test failed") @@ -1560,6 +1711,27 @@ mod test_finalize_block { }); } + /// Test the correct transition to a new masp epoch + #[test] + fn test_masp_epoch_progression() { + let (mut shell, _broadcaster, _, _eth_control) = setup(); + + let masp_epoch_multiplier = + namada::ledger::parameters::read_masp_epoch_multiplier_parameter( + &shell.state, + ) + .unwrap(); + + assert_eq!(shell.state.get_block_epoch().unwrap(), Epoch::default()); + + for _ in 1..masp_epoch_multiplier { + shell.start_new_epoch(None); + assert!(!shell.state.is_masp_new_epoch(true).unwrap()); + } + shell.start_new_epoch(None); + assert!(shell.state.is_masp_new_epoch(true).unwrap()); + } + /// Test that the finalize block handler never commits changes directly to /// the DB. #[test] @@ -3098,10 +3270,10 @@ mod test_finalize_block { // transaction } - /// Test that if a transaction fails because of out-of-gas, - /// invalid signature or wrong section commitment, its hash - /// is not committed to storage. Also checks that a tx failing for other - /// reason has its hash written to storage. + /// Test that if a transaction fails because of out-of-gas, invalid + /// signature or wrong section commitment, its hash is not committed to + /// storage. Also checks that a tx failing for other reasons has its + /// hash written to storage. #[test] fn test_tx_hash_handling() { let (mut shell, _broadcaster, _, _) = setup(); diff --git a/crates/node/src/shell/governance.rs b/crates/node/src/shell/governance.rs index dbde3d0204..758ec735d8 100644 --- a/crates/node/src/shell/governance.rs +++ b/crates/node/src/shell/governance.rs @@ -403,33 +403,51 @@ where let cmt = tx.first_commitments().unwrap().to_owned(); let dispatch_result = protocol::dispatch_tx( - tx, - &[], /* this is used to compute the fee - * based on the code size. We dont - * need it here. */ - TxIndex::default(), - &RefCell::new(TxGasMeter::new_from_sub_limit(u64::MAX.into())), /* No gas limit for governance proposal */ + &tx, + protocol::DispatchArgs::Raw { + tx_index: TxIndex::default(), + wrapper_tx_result: None, + vp_wasm_cache: &mut shell.vp_wasm_cache, + tx_wasm_cache: &mut shell.tx_wasm_cache, + }, + // No gas limit for governance proposal + &RefCell::new(TxGasMeter::new_from_sub_limit(u64::MAX.into())), &mut shell.state, - &mut shell.vp_wasm_cache, - &mut shell.tx_wasm_cache, - None, ); shell .state .delete(&pending_execution_key) .expect("Should be able to delete the storage."); match dispatch_result { - Ok(tx_result) => match tx_result.batch_results.0.get(&cmt.get_hash()) { + Ok(extended_tx_result) => match extended_tx_result + .tx_result + .batch_results + .0 + .get(&cmt.get_hash()) + { Some(Ok(batched_result)) if batched_result.is_accepted() => { shell.state.commit_tx(); Ok(true) } + Some(Err(e)) => { + tracing::warn!( + "Error executing governance proposal {}", + e.to_string() + ); + shell.state.drop_tx(); + Ok(false) + } _ => { + tracing::warn!("not sure what happen"); shell.state.drop_tx(); Ok(false) } }, - Err(_) => { + Err(e) => { + tracing::warn!( + "Error executing governance proposal {}", + e.error.to_string() + ); shell.state.drop_tx(); Ok(false) } diff --git a/crates/node/src/shell/mod.rs b/crates/node/src/shell/mod.rs index cecdb51eca..2ace0f620a 100644 --- a/crates/node/src/shell/mod.rs +++ b/crates/node/src/shell/mod.rs @@ -64,6 +64,8 @@ use namada::vm::{WasmCacheAccess, WasmCacheRwAccess}; use namada::vote_ext::EthereumTxData; use namada_apps_lib::wallet::{self, ValidatorData, ValidatorKeys}; use namada_sdk::eth_bridge::{EthBridgeQueries, EthereumOracleConfig}; +use namada_sdk::migrations; +use namada_sdk::migrations::ScheduledMigration; use namada_sdk::tendermint::AppHash; use thiserror::Error; use tokio::sync::mpsc::{Receiver, UnboundedSender}; @@ -351,6 +353,8 @@ where storage_read_past_height_limit: Option, /// Log of events emitted by `FinalizeBlock` ABCI calls. event_log: EventLog, + /// A migration that can be scheduled at a given block height + pub scheduled_migration: Option>, } /// Storage key filter to store the diffs into the storage. Return `false` for @@ -401,6 +405,7 @@ where broadcast_sender: UnboundedSender>, eth_oracle: Option, db_cache: Option<&D::Cache>, + scheduled_migration: Option>, vp_wasm_compilation_cache: u64, tx_wasm_compilation_cache: u64, ) -> Self { @@ -510,6 +515,17 @@ where TendermintMode::Seed => ShellMode::Seed, }; + if let Some(schedule_migration) = scheduled_migration.as_ref() { + let current = state.get_block_height().unwrap_or_default(); + if schedule_migration.height < current { + panic!( + "Cannot schedule a migration earlier than the latest \ + block height({})", + current + ); + } + } + let mut shell = Self { chain_id, state, @@ -531,6 +547,7 @@ where storage_read_past_height_limit, // TODO(namada#3237): config event log params event_log: EventLog::default(), + scheduled_migration, }; shell.update_eth_oracle(&Default::default()); shell @@ -648,9 +665,14 @@ where self.state .commit_block() .expect("Encountered a storage error while committing a block"); - - let merkle_root = self.state.in_mem().merkle_root(); let committed_height = self.state.in_mem().get_last_block_height(); + migrations::commit( + self.state.db(), + committed_height, + &mut self.scheduled_migration, + ); + let merkle_root = self.state.in_mem().merkle_root(); + tracing::info!( "Committed block hash: {merkle_root}, height: {committed_height}", ); @@ -1513,6 +1535,7 @@ mod test_utils { sender, Some(eth_oracle), None, + None, vp_wasm_compilation_cache, tx_wasm_compilation_cache, ); diff --git a/crates/node/src/shell/testing/node.rs b/crates/node/src/shell/testing/node.rs index 279c7ba433..d01a750edb 100644 --- a/crates/node/src/shell/testing/node.rs +++ b/crates/node/src/shell/testing/node.rs @@ -333,6 +333,15 @@ impl MockNode { self.genesis_dir().join("wallet.toml") } + pub fn block_height(&self) -> BlockHeight { + self.shell + .lock() + .unwrap() + .state + .get_block_height() + .unwrap_or_default() + } + pub fn current_epoch(&self) -> Epoch { self.shell.lock().unwrap().state.in_mem().last_epoch } @@ -371,6 +380,21 @@ impl MockNode { .0 } + pub fn next_masp_epoch(&mut self) -> Epoch { + let masp_epoch_multiplier = + namada::parameters::read_masp_epoch_multiplier_parameter( + &self.shell.lock().unwrap().state, + ) + .unwrap(); + let mut epoch = Epoch::default(); + + for _ in 0..masp_epoch_multiplier { + epoch = self.next_epoch(); + } + + epoch + } + pub fn native_token(&self) -> Address { let locked = self.shell.lock().unwrap(); locked.state.get_native_token().unwrap() diff --git a/crates/node/src/shims/abcipp_shim.rs b/crates/node/src/shims/abcipp_shim.rs index 4583666472..1ba7b2c50f 100644 --- a/crates/node/src/shims/abcipp_shim.rs +++ b/crates/node/src/shims/abcipp_shim.rs @@ -10,6 +10,7 @@ use namada::core::storage::BlockHeight; use namada::proof_of_stake::storage::find_validator_by_raw_hash; use namada::time::{DateTimeUtc, Utc}; use namada::tx::data::hash_tx; +use namada_sdk::migrations::ScheduledMigration; use tokio::sync::broadcast; use tokio::sync::mpsc::UnboundedSender; use tower::Service; @@ -48,6 +49,7 @@ impl AbcippShim { broadcast_sender: UnboundedSender>, eth_oracle: Option, db_cache: &rocksdb::Cache, + scheduled_migration: Option, vp_wasm_compilation_cache: u64, tx_wasm_compilation_cache: u64, ) -> (Self, AbciService, broadcast::Sender<()>) { @@ -65,6 +67,7 @@ impl AbcippShim { broadcast_sender, eth_oracle, Some(db_cache), + scheduled_migration, vp_wasm_compilation_cache, tx_wasm_compilation_cache, ), diff --git a/crates/node/src/storage/mod.rs b/crates/node/src/storage/mod.rs index 5e3c030cf8..49d37c81a8 100644 --- a/crates/node/src/storage/mod.rs +++ b/crates/node/src/storage/mod.rs @@ -173,6 +173,7 @@ mod tests { tx_allowlist: vec![], implicit_vp_code_hash: Default::default(), epochs_per_year: 365, + masp_epoch_multiplier: 2, max_signatures_per_transaction: 10, fee_unshielding_gas_limit: 0, minimum_gas_price: Default::default(), diff --git a/crates/node/src/storage/rocksdb.rs b/crates/node/src/storage/rocksdb.rs index c5b91e95c8..36a527fa18 100644 --- a/crates/node/src/storage/rocksdb.rs +++ b/crates/node/src/storage/rocksdb.rs @@ -72,7 +72,7 @@ use namada::storage::{ SUBSPACE_CF, }; use namada_sdk::arith::checked; -use namada_sdk::migrations::DBUpdateVisitor; +use namada_sdk::migrations::{DBUpdateVisitor, DbUpdateType}; use rayon::prelude::*; use regex::Regex; use rocksdb::{ @@ -82,6 +82,7 @@ use rocksdb::{ }; use crate::config::utils::num_of_threads; +use crate::storage; // TODO the DB schema will probably need some kind of versioning @@ -695,6 +696,7 @@ impl RocksDB { impl DB for RocksDB { type Cache = rocksdb::Cache; + type Migrator = DbUpdateType; type WriteBatch = RocksDBWriteBatch; fn open( @@ -1402,6 +1404,31 @@ impl DB for RocksDB { Ok(()) } + + #[inline] + fn apply_migration_to_batch( + &self, + updates: impl IntoIterator, + ) -> Result { + let mut db_visitor = storage::RocksDBUpdateVisitor::new(self); + for change in updates.into_iter() { + match change.update(&mut db_visitor) { + Ok(status) => { + tracing::info!("{}", status); + } + Err(e) => { + let error = format!( + "Attempt to write to key/pattern <{}> failed:\n{}.", + change.pattern(), + e + ); + tracing::error!(error); + return Err(Error::DBError(error)); + } + } + } + Ok(db_visitor.take_batch()) + } } /// A struct that can visit a set of updates, diff --git a/crates/parameters/Cargo.toml b/crates/parameters/Cargo.toml index 6be22eda9c..131f49118c 100644 --- a/crates/parameters/Cargo.toml +++ b/crates/parameters/Cargo.toml @@ -24,5 +24,4 @@ namada_core = { path = "../core" } namada_macros = { path = "../macros" } namada_storage = { path = "../storage" } -borsh.workspace = true thiserror.workspace = true diff --git a/crates/parameters/src/lib.rs b/crates/parameters/src/lib.rs index edd9dcb505..b8dbe12a88 100644 --- a/crates/parameters/src/lib.rs +++ b/crates/parameters/src/lib.rs @@ -74,6 +74,7 @@ where tx_allowlist, implicit_vp_code_hash, epochs_per_year, + masp_epoch_multiplier, max_signatures_per_transaction, minimum_gas_price, fee_unshielding_gas_limit, @@ -135,6 +136,9 @@ where let epochs_per_year_key = storage::get_epochs_per_year_key(); storage.write(&epochs_per_year_key, epochs_per_year)?; + let masp_epoch_multiplier_key = storage::get_masp_epoch_multiplier_key(); + storage.write(&masp_epoch_multiplier_key, masp_epoch_multiplier)?; + let max_signatures_per_transaction_key = storage::get_max_signatures_per_transaction_key(); storage.write( @@ -282,6 +286,21 @@ where .into_storage_result() } +/// Read the the masp epoch multiplier parameter from store +pub fn read_masp_epoch_multiplier_parameter( + storage: &S, +) -> namada_storage::Result +where + S: StorageRead, +{ + // read multiplier + let masp_epoch_multiplier_key = storage::get_masp_epoch_multiplier_key(); + let epoch_multiplier = storage.read(&masp_epoch_multiplier_key)?; + epoch_multiplier + .ok_or(ReadError::ParametersMissing) + .into_storage_result() +} + /// Read the cost per unit of gas for the provided token pub fn read_gas_cost( storage: &S, @@ -367,6 +386,9 @@ where .ok_or(ReadError::ParametersMissing) .into_storage_result()?; + // read masp epoch multiplier + let masp_epoch_multiplier = read_masp_epoch_multiplier_parameter(storage)?; + // read the maximum signatures per transaction let max_signatures_per_transaction_key = storage::get_max_signatures_per_transaction_key(); @@ -407,6 +429,7 @@ where tx_allowlist, implicit_vp_code_hash: Some(implicit_vp_code_hash), epochs_per_year, + masp_epoch_multiplier, max_signatures_per_transaction, minimum_gas_price, fee_unshielding_gas_limit, @@ -452,6 +475,7 @@ where tx_allowlist: vec![], implicit_vp_code_hash: Default::default(), epochs_per_year: 365, + masp_epoch_multiplier: 2, max_signatures_per_transaction: 10, fee_unshielding_gas_limit: 0, minimum_gas_price: Default::default(), diff --git a/crates/parameters/src/storage.rs b/crates/parameters/src/storage.rs index ce649b07c1..27204f9568 100644 --- a/crates/parameters/src/storage.rs +++ b/crates/parameters/src/storage.rs @@ -29,6 +29,7 @@ struct Keys { // ======================================== epoch_duration: &'static str, epochs_per_year: &'static str, + masp_epoch_multiplier: &'static str, implicit_vp: &'static str, max_expected_time_per_block: &'static str, tx_allowlist: &'static str, @@ -135,6 +136,11 @@ pub fn get_epochs_per_year_key() -> Key { get_epochs_per_year_key_at_addr(ADDRESS) } +/// Storage key used for masp_epoch_multiplier parameter. +pub fn get_masp_epoch_multiplier_key() -> Key { + get_masp_epoch_multiplier_key_at_addr(ADDRESS) +} + /// Storage key used for the max proposal bytes. pub fn get_max_proposal_bytes_key() -> Key { get_max_proposal_bytes_key_at_addr(ADDRESS) diff --git a/crates/proof_of_stake/Cargo.toml b/crates/proof_of_stake/Cargo.toml index 578ed50d18..0bcb8a5c4d 100644 --- a/crates/proof_of_stake/Cargo.toml +++ b/crates/proof_of_stake/Cargo.toml @@ -34,10 +34,8 @@ namada_parameters = { path = "../parameters" } namada_trans_token = { path = "../trans_token" } borsh.workspace = true -data-encoding.workspace = true konst.workspace = true linkme = {workspace = true, optional = true} -num-traits.workspace = true once_cell.workspace = true proptest = { workspace = true, optional = true } serde.workspace = true diff --git a/crates/proof_of_stake/src/lib.rs b/crates/proof_of_stake/src/lib.rs index 749c1121d4..19b003541f 100644 --- a/crates/proof_of_stake/src/lib.rs +++ b/crates/proof_of_stake/src/lib.rs @@ -2724,6 +2724,7 @@ pub mod test_utils { tx_allowlist: vec![], implicit_vp_code_hash: Some(Hash::default()), epochs_per_year: 10000000, + masp_epoch_multiplier: 2, max_signatures_per_transaction: 15, fee_unshielding_gas_limit: 10000, minimum_gas_price: BTreeMap::new(), diff --git a/crates/proof_of_stake/src/types/mod.rs b/crates/proof_of_stake/src/types/mod.rs index 936c17507a..6be5b78fdb 100644 --- a/crates/proof_of_stake/src/types/mod.rs +++ b/crates/proof_of_stake/src/types/mod.rs @@ -534,7 +534,8 @@ impl Position { } } -/// Validator's state. +/// Validator's state. May correspond to the validator set within which the +/// validator belongs. #[derive( Debug, Clone, @@ -547,19 +548,22 @@ impl Position { Eq, )] pub enum ValidatorState { - /// A validator who may participate in the consensus + /// A validator who may participate in the consensus and is one of the top + /// `max_validator_slots` validators with stake above + /// `validator_stake_threshold` Consensus, - /// A validator who does not have enough stake to be considered in the - /// `Consensus` validator set but still may have active bonds and unbonds + /// A validator who has stake greater than the `validator_stake_threshold` + /// but is not one of the top `max_validator_slots` validators who have + /// such stake BelowCapacity, /// A validator who has stake less than the `validator_stake_threshold` /// parameter BelowThreshold, /// A validator who is deactivated via a tx when a validator no longer - /// wants to be one (not implemented yet) + /// wants to be considered for consensus Inactive, - /// A `Jailed` validator has been prohibited from participating in - /// consensus due to a misbehavior + /// A validator who is prohibited from participating in + /// consensus due to a misbehavior or downtime Jailed, } diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml index 6497eea6b6..c58da446e1 100644 --- a/crates/sdk/Cargo.toml +++ b/crates/sdk/Cargo.toml @@ -46,6 +46,7 @@ testing = [ "namada_ibc/testing", "namada_proof_of_stake/testing", "namada_storage/testing", + "namada_token/testing", "namada_tx/testing", "async-client", "proptest", @@ -125,7 +126,6 @@ serde_json.workspace = true sha2.workspace = true slip10_ed25519.workspace = true smooth-operator.workspace = true -tendermint-config.workspace = true tendermint-rpc = { workspace = true, optional = true } thiserror.workspace = true tiny-bip39.workspace = true @@ -159,6 +159,7 @@ namada_proof_of_stake = { path = "../proof_of_stake", default-features = false, namada_state = { path = "../state", features = ["testing"] } namada_storage = { path = "../storage", features = ["testing"] } namada_test_utils = { path = "../test_utils" } +namada_token = { path = "../token", features = ["testing"] } namada_tx = { path = "../tx", features = ["testing"]} namada_vote_ext = {path = "../vote_ext"} diff --git a/crates/sdk/src/args.rs b/crates/sdk/src/args.rs index b8cbe7ad06..8db6155e6f 100644 --- a/crates/sdk/src/args.rs +++ b/crates/sdk/src/args.rs @@ -10,7 +10,7 @@ use namada_core::dec::Dec; use namada_core::ethereum_events::EthAddress; use namada_core::keccak::KeccakHash; use namada_core::key::{common, SchemeType}; -use namada_core::masp::PaymentAddress; +use namada_core::masp::{MaspEpoch, PaymentAddress}; use namada_core::storage::{BlockHeight, Epoch}; use namada_core::time::DateTimeUtc; use namada_core::{storage, token}; @@ -59,10 +59,12 @@ pub trait NamadaTypes: Clone + std::fmt::Debug { + From; /// Represents the address of an Ethereum endpoint type EthereumAddress: Clone + std::fmt::Debug; - /// Represents a viewing key + /// Represents a shielded viewing key type ViewingKey: Clone + std::fmt::Debug; - /// Represents a spending key + /// Represents a shielded spending key type SpendingKey: Clone + std::fmt::Debug; + /// Represents a shielded payment address + type PaymentAddress: Clone + std::fmt::Debug; /// Represents the owner of a balance type BalanceOwner: Clone + std::fmt::Debug; /// Represents a public key @@ -101,6 +103,7 @@ impl NamadaTypes for SdkTypes { type Data = Vec; type EthereumAddress = (); type Keypair = namada_core::key::common::SecretKey; + type PaymentAddress = namada_core::masp::PaymentAddress; type PublicKey = namada_core::key::common::PublicKey; type SpendingKey = namada_core::masp::ExtendedSpendingKey; type TendermintAddress = tendermint_rpc::Url; @@ -226,15 +229,15 @@ impl From for InputAmount { } } -/// Transfer transaction arguments +/// Transparent transfer transaction arguments #[derive(Clone, Debug)] -pub struct TxTransfer { +pub struct TxTransparentTransfer { /// Common tx arguments pub tx: Tx, /// Transfer source address - pub source: C::TransferSource, + pub source: C::Address, /// Transfer target address - pub target: C::TransferTarget, + pub target: C::Address, /// Transferred token address pub token: C::Address, /// Transferred token amount @@ -243,26 +246,26 @@ pub struct TxTransfer { pub tx_code_path: PathBuf, } -impl TxBuilder for TxTransfer { +impl TxBuilder for TxTransparentTransfer { fn tx(self, func: F) -> Self where F: FnOnce(Tx) -> Tx, { - TxTransfer { + TxTransparentTransfer { tx: func(self.tx), ..self } } } -impl TxTransfer { +impl TxTransparentTransfer { /// Transfer source address - pub fn source(self, source: C::TransferSource) -> Self { + pub fn source(self, source: C::Address) -> Self { Self { source, ..self } } /// Transfer target address - pub fn receiver(self, target: C::TransferTarget) -> Self { + pub fn receiver(self, target: C::Address) -> Self { Self { target, ..self } } @@ -285,14 +288,94 @@ impl TxTransfer { } } -impl TxTransfer { +impl TxTransparentTransfer { /// Build a transaction from this builder pub async fn build( &mut self, context: &impl Namada, - ) -> crate::error::Result<(namada_tx::Tx, SigningTxData, Option)> - { - tx::build_transfer(context, self).await + ) -> crate::error::Result<(namada_tx::Tx, SigningTxData)> { + tx::build_transparent_transfer(context, self).await + } +} + +/// Shielded transfer transaction arguments +#[derive(Clone, Debug)] +pub struct TxShieldedTransfer { + /// Common tx arguments + pub tx: Tx, + /// Transfer source spending key + pub source: C::SpendingKey, + /// Transfer target address + pub target: C::PaymentAddress, + /// Transferred token address + pub token: C::Address, + /// Transferred token amount + pub amount: InputAmount, + /// Path to the TX WASM code file + pub tx_code_path: PathBuf, +} + +impl TxShieldedTransfer { + /// Build a transaction from this builder + pub async fn build( + &mut self, + context: &impl Namada, + ) -> crate::error::Result<(namada_tx::Tx, SigningTxData)> { + tx::build_shielded_transfer(context, self).await + } +} + +/// Shielding transfer transaction arguments +#[derive(Clone, Debug)] +pub struct TxShieldingTransfer { + /// Common tx arguments + pub tx: Tx, + /// Transfer source address + pub source: C::Address, + /// Transfer target address + pub target: C::PaymentAddress, + /// Transferred token address + pub token: C::Address, + /// Transferred token amount + pub amount: InputAmount, + /// Path to the TX WASM code file + pub tx_code_path: PathBuf, +} + +impl TxShieldingTransfer { + /// Build a transaction from this builder + pub async fn build( + &mut self, + context: &impl Namada, + ) -> crate::error::Result<(namada_tx::Tx, SigningTxData, MaspEpoch)> { + tx::build_shielding_transfer(context, self).await + } +} + +/// Unshielding transfer transaction arguments +#[derive(Clone, Debug)] +pub struct TxUnshieldingTransfer { + /// Common tx arguments + pub tx: Tx, + /// Transfer source spending key + pub source: C::SpendingKey, + /// Transfer target address + pub target: C::Address, + /// Transferred token address + pub token: C::Address, + /// Transferred token amount + pub amount: InputAmount, + /// Path to the TX WASM code file + pub tx_code_path: PathBuf, +} + +impl TxUnshieldingTransfer { + /// Build a transaction from this builder + pub async fn build( + &mut self, + context: &impl Namada, + ) -> crate::error::Result<(namada_tx::Tx, SigningTxData)> { + tx::build_unshielding_transfer(context, self).await } } @@ -414,7 +497,7 @@ impl TxIbcTransfer { pub async fn build( &self, context: &impl Namada, - ) -> crate::error::Result<(namada_tx::Tx, SigningTxData, Option)> + ) -> crate::error::Result<(namada_tx::Tx, SigningTxData, Option)> { tx::build_ibc_transfer(context, self).await } @@ -1312,7 +1395,7 @@ pub struct QueryConversions { /// Address of a token pub token: Option, /// Epoch of the asset - pub epoch: Option, + pub epoch: Option, } /// Query token balance(s) @@ -1878,7 +1961,7 @@ pub struct SignTx { /// block height. pub struct ShieldedSync { /// The ledger address - pub ledger_address: C::TendermintAddress, + pub ledger_address: C::ConfigRpcTendermintAddress, /// The number of txs to fetch before caching pub batch_size: u64, /// Height to start syncing from. Defaults to the correct one. diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs index b504a32797..ad1c4ce4a8 100644 --- a/crates/sdk/src/lib.rs +++ b/crates/sdk/src/lib.rs @@ -21,7 +21,7 @@ pub use { bip39, masp_primitives, masp_proofs, namada_account as account, namada_gas as gas, namada_governance as governance, namada_proof_of_stake as proof_of_stake, namada_state as state, - namada_storage as storage, zeroize, + namada_storage as storage, namada_token as token, zeroize, }; pub mod eth_bridge; @@ -51,36 +51,35 @@ use std::path::PathBuf; use std::str::FromStr; use args::{InputAmount, SdkTypes}; +use io::Io; +use masp::{ShieldedContext, ShieldedUtils}; use namada_core::address::Address; use namada_core::collections::HashSet; use namada_core::dec::Dec; use namada_core::ethereum_events::EthAddress; use namada_core::ibc::core::host::types::identifiers::{ChannelId, PortId}; use namada_core::key::*; -use namada_core::masp::{TransferSource, TransferTarget}; +use namada_core::masp::{ExtendedSpendingKey, PaymentAddress, TransferSource}; use namada_tx::data::wrapper::GasLimit; use namada_tx::Tx; +use rpc::{denominate_amount, format_denominated_amount, query_native_token}; +use signing::SigningTxData; +use token::{DenominatedAmount, NATIVE_MAX_DECIMAL_PLACES}; use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; - -use crate::io::Io; -use crate::masp::{ShieldedContext, ShieldedUtils}; -use crate::rpc::{ - denominate_amount, format_denominated_amount, query_native_token, -}; -use crate::signing::SigningTxData; -use crate::token::{DenominatedAmount, NATIVE_MAX_DECIMAL_PLACES}; -use crate::tx::{ +use tx::{ ProcessTxResponse, TX_BECOME_VALIDATOR_WASM, TX_BOND_WASM, TX_BRIDGE_POOL_WASM, TX_CHANGE_COMMISSION_WASM, TX_CHANGE_CONSENSUS_KEY_WASM, TX_CHANGE_METADATA_WASM, TX_CLAIM_REWARDS_WASM, TX_DEACTIVATE_VALIDATOR_WASM, TX_IBC_WASM, TX_INIT_ACCOUNT_WASM, TX_INIT_PROPOSAL, TX_REACTIVATE_VALIDATOR_WASM, - TX_REDELEGATE_WASM, TX_RESIGN_STEWARD, TX_REVEAL_PK, TX_TRANSFER_WASM, - TX_UNBOND_WASM, TX_UNJAIL_VALIDATOR_WASM, TX_UPDATE_ACCOUNT_WASM, + TX_REDELEGATE_WASM, TX_RESIGN_STEWARD, TX_REVEAL_PK, + TX_SHIELDED_TRANSFER_WASM, TX_SHIELDING_TRANSFER_WASM, + TX_TRANSPARENT_TRANSFER_WASM, TX_UNBOND_WASM, TX_UNJAIL_VALIDATOR_WASM, + TX_UNSHIELDING_TRANSFER_WASM, TX_UPDATE_ACCOUNT_WASM, TX_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL, TX_WITHDRAW_WASM, VP_USER_WASM, }; -use crate::wallet::{Wallet, WalletIo, WalletStorage}; +use wallet::{Wallet, WalletIo, WalletStorage}; /// Default gas-limit pub const DEFAULT_GAS_LIMIT: u64 = 25_000; @@ -172,20 +171,78 @@ pub trait Namada: Sized + MaybeSync + MaybeSend { } } - /// Make a TxTransfer builder from the given minimum set of arguments - fn new_transfer( + /// Make a TxTransparentTransfer builder from the given minimum set of + /// arguments + fn new_transparent_transfer( &self, - source: TransferSource, - target: TransferTarget, + source: Address, + target: Address, + token: Address, + amount: InputAmount, + ) -> args::TxTransparentTransfer { + args::TxTransparentTransfer { + source, + target, + token, + amount, + tx_code_path: PathBuf::from(TX_TRANSPARENT_TRANSFER_WASM), + tx: self.tx_builder(), + } + } + + /// Make a TxShieldedTransfer builder from the given minimum set of + /// arguments + fn new_shielded_transfer( + &self, + source: ExtendedSpendingKey, + target: PaymentAddress, + token: Address, + amount: InputAmount, + ) -> args::TxShieldedTransfer { + args::TxShieldedTransfer { + source, + target, + token, + amount, + tx_code_path: PathBuf::from(TX_SHIELDED_TRANSFER_WASM), + tx: self.tx_builder(), + } + } + + /// Make a TxShieldingTransfer builder from the given minimum set of + /// arguments + fn new_shielding_transfer( + &self, + source: Address, + target: PaymentAddress, token: Address, amount: InputAmount, - ) -> args::TxTransfer { - args::TxTransfer { + ) -> args::TxShieldingTransfer { + args::TxShieldingTransfer { source, target, token, amount, - tx_code_path: PathBuf::from(TX_TRANSFER_WASM), + tx_code_path: PathBuf::from(TX_SHIELDING_TRANSFER_WASM), + tx: self.tx_builder(), + } + } + + /// Make a TxUnshieldingTransfer builder from the given minimum set of + /// arguments + fn new_unshielding_transfer( + &self, + source: ExtendedSpendingKey, + target: Address, + token: Address, + amount: InputAmount, + ) -> args::TxUnshieldingTransfer { + args::TxUnshieldingTransfer { + source, + target, + token, + amount, + tx_code_path: PathBuf::from(TX_UNSHIELDING_TRANSFER_WASM), tx: self.tx_builder(), } } @@ -798,24 +855,29 @@ where /// Tests and strategies for transactions #[cfg(any(test, feature = "testing"))] pub mod testing { + use borsh_ext::BorshSerializeExt; use governance::ProposalType; use ibc::primitives::proto::Any; + use masp_primitives::transaction::components::sapling::builder::StoredBuildParams; use namada_account::{InitAccount, UpdateAccount}; use namada_core::address::testing::{ arb_established_address, arb_non_internal_address, }; - use namada_core::address::MASP; use namada_core::eth_bridge_pool::PendingTransfer; use namada_core::hash::testing::arb_hash; use namada_core::key::testing::arb_common_keypair; use namada_core::masp::addr_taddr; - use namada_core::token::testing::{arb_denominated_amount, arb_transfer}; - use namada_core::token::Transfer; + use namada_core::token::testing::arb_denominated_amount; use namada_governance::storage::proposal::testing::{ arb_init_proposal, arb_vote_proposal, }; use namada_governance::{InitProposalData, VoteProposalData}; use namada_ibc::testing::arb_ibc_any; + use namada_token::testing::arb_transparent_transfer; + use namada_token::{ + ShieldedTransfer, ShieldingTransfer, TransparentTransfer, + UnshieldingTransfer, + }; use namada_tx::data::pgf::UpdateStewardCommission; use namada_tx::data::pos::{ BecomeValidator, Bond, CommissionChange, ConsensusKeyChange, @@ -866,7 +928,10 @@ pub mod testing { UpdateAccount(UpdateAccount), VoteProposal(VoteProposalData), Withdraw(Withdraw), - Transfer(Transfer), + TransparentTransfer(TransparentTransfer), + ShieldedTransfer(ShieldedTransfer, (StoredBuildParams, String)), + ShieldingTransfer(ShieldingTransfer, (StoredBuildParams, String)), + UnshieldingTransfer(UnshieldingTransfer, (StoredBuildParams, String)), Bond(Bond), Redelegation(Redelegation), UpdateStewardCommission(UpdateStewardCommission), @@ -1022,17 +1087,17 @@ pub mod testing { prop_compose! { /// Generate an arbitrary transfer transaction - pub fn arb_transfer_tx()( + pub fn arb_transparent_transfer_tx()( mut header in arb_header(), wrapper in arb_wrapper_tx(), - transfer in arb_transfer(), + transfer in arb_transparent_transfer(), code_hash in arb_hash(), ) -> (Tx, TxData) { header.tx_type = TxType::Wrapper(Box::new(wrapper)); let mut tx = Tx { header, sections: vec![] }; tx.add_data(transfer.clone()); - tx.add_code_from_hash(code_hash, Some(TX_TRANSFER_WASM.to_owned())); - (tx, TxData::Transfer(transfer)) + tx.add_code_from_hash(code_hash, Some(TX_TRANSPARENT_TRANSFER_WASM.to_owned())); + (tx, TxData::TransparentTransfer(transfer)) } } @@ -1046,56 +1111,62 @@ pub mod testing { Shielded, // Shielding transaction Shielding, - // Deshielding transaction - Deshielding, + // Unshielding transaction + Unshielding, } prop_compose! { /// Generate an arbitrary transfer transaction - pub fn arb_masp_transfer_tx()(transfer in arb_transfer())( + pub fn arb_masp_transfer_tx()(transfer in arb_transparent_transfer())( mut header in arb_header(), wrapper in arb_wrapper_tx(), code_hash in arb_hash(), - (masp_tx_type, (shielded_transfer, asset_types)) in prop_oneof![ + (masp_tx_type, (shielded_transfer, asset_types, build_params)) in prop_oneof![ (Just(MaspTxType::Shielded), arb_shielded_transfer(0..MAX_ASSETS)), (Just(MaspTxType::Shielding), arb_shielding_transfer(addr_taddr(transfer.source.clone()), 1)), - (Just(MaspTxType::Deshielding), arb_deshielding_transfer(addr_taddr(transfer.target.clone()), 1)), + (Just(MaspTxType::Unshielding), arb_deshielding_transfer(addr_taddr(transfer.target.clone()), 1)), ], - mut transfer in Just(transfer), + transfer in Just(transfer), ) -> (Tx, TxData) { header.tx_type = TxType::Wrapper(Box::new(wrapper)); let mut tx = Tx { header, sections: vec![] }; - match masp_tx_type { + let shielded_section_hash = tx.add_masp_tx_section(shielded_transfer.masp_tx).1; + let build_param_bytes = + data_encoding::HEXLOWER.encode(&build_params.serialize_to_vec()); + let tx_data = match masp_tx_type { MaspTxType::Shielded => { - transfer.source = MASP; - transfer.target = MASP; - transfer.amount = token::Amount::zero().into(); + tx.add_code_from_hash(code_hash, Some(TX_SHIELDED_TRANSFER_WASM.to_owned())); + let data = ShieldedTransfer { section_hash: shielded_section_hash }; + tx.add_data(data.clone()); + TxData::ShieldedTransfer(data, (build_params, build_param_bytes)) }, MaspTxType::Shielding => { - transfer.target = MASP; // Set the transparent amount and token let (decoded, value) = asset_types.iter().next().unwrap(); - transfer.amount = DenominatedAmount::new( + let token = decoded.token.clone(); + let amount = DenominatedAmount::new( token::Amount::from_masp_denominated(*value, decoded.position), decoded.denom, ); - transfer.token = decoded.token.clone(); + tx.add_code_from_hash(code_hash, Some(TX_SHIELDING_TRANSFER_WASM.to_owned())); + let data = ShieldingTransfer {source: transfer.source, token, amount, shielded_section_hash }; + tx.add_data(data.clone()); + TxData::ShieldingTransfer(data, (build_params, build_param_bytes)) }, - MaspTxType::Deshielding => { - transfer.source = MASP; + MaspTxType::Unshielding => { // Set the transparent amount and token let (decoded, value) = asset_types.iter().next().unwrap(); - transfer.amount = DenominatedAmount::new( + let token = decoded.token.clone(); + let amount = DenominatedAmount::new( token::Amount::from_masp_denominated(*value, decoded.position), decoded.denom, ); - transfer.token = decoded.token.clone(); + tx.add_code_from_hash(code_hash, Some(TX_UNSHIELDING_TRANSFER_WASM.to_owned())); + let data = UnshieldingTransfer {target: transfer.target, token, amount, shielded_section_hash }; + tx.add_data(data.clone()); + TxData::UnshieldingTransfer(data, (build_params, build_param_bytes)) }, - } - let masp_tx_hash = tx.add_masp_tx_section(shielded_transfer.masp_tx).1; - transfer.shielded = Some(masp_tx_hash); - tx.add_data(transfer.clone()); - tx.add_code_from_hash(code_hash, Some(TX_TRANSFER_WASM.to_owned())); + }; tx.add_masp_builder(MaspBuilder { asset_types: asset_types.into_keys().collect(), // Store how the Info objects map to Descriptors/Outputs @@ -1103,9 +1174,9 @@ pub mod testing { // Store the data that was used to construct the Transaction builder: shielded_transfer.builder, // Link the Builder to the Transaction by hash code - target: masp_tx_hash, + target: shielded_section_hash, }); - (tx, TxData::Transfer(transfer)) + (tx, tx_data) } } @@ -1484,7 +1555,7 @@ pub mod testing { /// Generate an arbitrary tx pub fn arb_tx() -> impl Strategy { prop_oneof![ - arb_transfer_tx(), + arb_transparent_transfer_tx(), arb_masp_transfer_tx(), arb_bond_tx(), arb_unbond_tx(), diff --git a/crates/sdk/src/masp.rs b/crates/sdk/src/masp.rs index 7afb6cd0de..43bfac59f7 100644 --- a/crates/sdk/src/masp.rs +++ b/crates/sdk/src/masp.rs @@ -16,14 +16,12 @@ use masp_primitives::consensus::MainNetwork as Network; use masp_primitives::consensus::TestNetwork as Network; use masp_primitives::convert::AllowedConversion; use masp_primitives::ff::PrimeField; -use masp_primitives::group::GroupEncoding; use masp_primitives::memo::MemoBytes; use masp_primitives::merkle_tree::{ CommitmentTree, IncrementalWitness, MerklePath, }; use masp_primitives::sapling::keys::FullViewingKey; use masp_primitives::sapling::note_encryption::*; -use masp_primitives::sapling::redjubjub::PublicKey; use masp_primitives::sapling::{ Diversifier, Node, Note, Nullifier, ViewingKey, }; @@ -31,10 +29,12 @@ use masp_primitives::transaction::builder::{self, *}; use masp_primitives::transaction::components::sapling::builder::{ RngBuildParams, SaplingMetadata, }; +use masp_primitives::transaction::components::sapling::{ + Authorized as SaplingAuthorized, Bundle as SaplingBundle, +}; use masp_primitives::transaction::components::transparent::builder::TransparentBuilder; use masp_primitives::transaction::components::{ - ConvertDescription, I128Sum, OutputDescription, SpendDescription, TxOut, - U64Sum, ValueSum, + I128Sum, OutputDescription, TxOut, U64Sum, ValueSum, }; use masp_primitives::transaction::fees::fixed::FeeRule; use masp_primitives::transaction::sighash::{signature_hash, SignableInput}; @@ -43,11 +43,10 @@ use masp_primitives::transaction::{ Authorization, Authorized, Transaction, TransactionData, Unauthorized, }; use masp_primitives::zip32::{ExtendedFullViewingKey, ExtendedSpendingKey}; -use masp_proofs::bellman::groth16::PreparedVerifyingKey; +use masp_proofs::bellman::groth16::VerifyingKey; use masp_proofs::bls12_381::Bls12; use masp_proofs::prover::LocalTxProver; -#[cfg(not(feature = "testing"))] -use masp_proofs::sapling::SaplingVerificationContext; +use masp_proofs::sapling::BatchValidator; use namada_core::address::Address; use namada_core::collections::{HashMap, HashSet}; use namada_core::dec::Dec; @@ -55,20 +54,23 @@ pub use namada_core::masp::{ encode_asset_type, AssetData, BalanceOwner, ExtendedViewingKey, PaymentAddress, TAddrData, TransferSource, TransferTarget, }; -use namada_core::storage::{BlockHeight, Epoch, TxIndex}; +use namada_core::masp::{MaspEpoch, MaspTxRefs}; +use namada_core::storage::{BlockHeight, TxIndex}; use namada_core::time::{DateTimeUtc, DurationSecs}; use namada_core::uint::Uint; use namada_events::extend::{ + MaspTxBatchRefs as MaspTxBatchRefsAttr, MaspTxBlockIndex as MaspTxBlockIndexAttr, ReadFromEventAttributes, }; -use namada_ibc::IbcMessage; use namada_macros::BorshDeserializer; #[cfg(feature = "migrations")] use namada_migrations::*; use namada_state::StorageError; -use namada_token::{self as token, Denomination, MaspDigitPos, Transfer}; -use namada_tx::{IndexedTx, Tx, TxCommitments}; -use rand_core::{CryptoRng, OsRng, RngCore}; +use namada_token::{self as token, Denomination, MaspDigitPos}; +use namada_tx::{IndexedTx, Tx}; +use rand::rngs::StdRng; +use rand_core::{CryptoRng, OsRng, RngCore, SeedableRng}; +use smooth_operator::checked; use thiserror::Error; use crate::error::{Error, QueryError}; @@ -97,10 +99,10 @@ pub const OUTPUT_NAME: &str = "masp-output.params"; pub const CONVERT_NAME: &str = "masp-convert.params"; /// Type alias for convenience and profit -pub type IndexedNoteData = BTreeMap; +pub type IndexedNoteData = BTreeMap>; /// Type alias for the entries of [`IndexedNoteData`] iterators -pub type IndexedNoteEntry = (IndexedTx, Transaction); +pub type IndexedNoteEntry = (IndexedTx, Vec); /// Shielded transfer #[derive(Clone, Debug, BorshSerialize, BorshDeserialize, BorshDeserializer)] @@ -112,7 +114,7 @@ pub struct ShieldedTransfer { /// Metadata pub metadata: SaplingMetadata, /// Epoch in which the transaction was created - pub epoch: Epoch, + pub epoch: MaspEpoch, } /// Shielded pool data for a token @@ -138,17 +140,14 @@ pub enum TransferErr { General(#[from] Error), } -#[derive(Debug, Clone)] -struct ExtractedMaspTxs(Vec<(TxCommitments, Transaction)>); - /// MASP verifying keys pub struct PVKs { /// spend verifying key - pub spend_vk: PreparedVerifyingKey, + pub spend_vk: VerifyingKey, /// convert verifying key - pub convert_vk: PreparedVerifyingKey, + pub convert_vk: VerifyingKey, /// output verifying key - pub output_vk: PreparedVerifyingKey, + pub output_vk: VerifyingKey, } lazy_static! { @@ -182,9 +181,9 @@ lazy_static! { convert_path.as_path(), ); PVKs { - spend_vk: params.spend_vk, - convert_vk: params.convert_vk, - output_vk: params.output_vk + spend_vk: params.spend_params.vk, + convert_vk: params.convert_params.vk, + output_vk: params.output_params.vk } }; } @@ -198,76 +197,6 @@ fn load_pvks() -> &'static PVKs { &VERIFIYING_KEYS } -/// check_spend wrapper -pub fn check_spend( - spend: &SpendDescription<::SaplingAuth>, - sighash: &[u8; 32], - #[cfg(not(feature = "testing"))] ctx: &mut SaplingVerificationContext, - #[cfg(feature = "testing")] - ctx: &mut testing::MockSaplingVerificationContext, - parameters: &PreparedVerifyingKey, -) -> bool { - let zkproof = - masp_proofs::bellman::groth16::Proof::read(spend.zkproof.as_slice()); - let zkproof = match zkproof { - Ok(zkproof) => zkproof, - _ => return false, - }; - - ctx.check_spend( - spend.cv, - spend.anchor, - &spend.nullifier.0, - PublicKey(spend.rk.0), - sighash, - spend.spend_auth_sig, - zkproof, - parameters, - ) -} - -/// check_output wrapper -pub fn check_output( - output: &OutputDescription<<::SaplingAuth as masp_primitives::transaction::components::sapling::Authorization>::Proof>, - #[cfg(not(feature = "testing"))] ctx: &mut SaplingVerificationContext, - #[cfg(feature = "testing")] - ctx: &mut testing::MockSaplingVerificationContext, - parameters: &PreparedVerifyingKey, -) -> bool { - let zkproof = - masp_proofs::bellman::groth16::Proof::read(output.zkproof.as_slice()); - let zkproof = match zkproof { - Ok(zkproof) => zkproof, - _ => return false, - }; - let epk = - masp_proofs::jubjub::ExtendedPoint::from_bytes(&output.ephemeral_key.0); - let epk = match epk.into() { - Some(p) => p, - None => return false, - }; - - ctx.check_output(output.cv, output.cmu, epk, zkproof, parameters) -} - -/// check convert wrapper -pub fn check_convert( - convert: &ConvertDescription<<::SaplingAuth as masp_primitives::transaction::components::sapling::Authorization>::Proof>, - #[cfg(not(feature = "testing"))] ctx: &mut SaplingVerificationContext, - #[cfg(feature = "testing")] - ctx: &mut testing::MockSaplingVerificationContext, - parameters: &PreparedVerifyingKey, -) -> bool { - let zkproof = - masp_proofs::bellman::groth16::Proof::read(convert.zkproof.as_slice()); - let zkproof = match zkproof { - Ok(zkproof) => zkproof, - _ => return false, - }; - - ctx.check_convert(convert.cv, convert.anchor, zkproof, parameters) -} - /// Represents an authorization where the Sapling bundle is authorized and the /// transparent bundle is unauthorized. pub struct PartialAuthorized; @@ -313,12 +242,12 @@ pub fn partial_deauthorize( /// Verify a shielded transaction. pub fn verify_shielded_tx( transaction: &Transaction, - mut consume_verify_gas: F, + consume_verify_gas: F, ) -> Result<(), StorageError> where - F: FnMut(u64) -> std::result::Result<(), StorageError>, + F: Fn(u64) -> std::result::Result<(), StorageError>, { - tracing::info!("entered verify_shielded_tx()"); + tracing::debug!("entered verify_shielded_tx()"); let sapling_bundle = if let Some(bundle) = transaction.sapling_bundle() { bundle @@ -343,8 +272,7 @@ where // for now we need to continue to compute it here. let sighash = signature_hash(&unauth_tx_data, &SignableInput::Shielded, &txid_parts); - - tracing::info!("sighash computed"); + tracing::debug!("sighash computed"); let PVKs { spend_vk, @@ -353,49 +281,103 @@ where } = load_pvks(); #[cfg(not(feature = "testing"))] - let mut ctx = SaplingVerificationContext::new(true); + let mut ctx = BatchValidator::new(); #[cfg(feature = "testing")] - let mut ctx = testing::MockSaplingVerificationContext::new(true); - for spend in &sapling_bundle.shielded_spends { - consume_verify_gas(namada_gas::MASP_VERIFY_SPEND_GAS)?; - if !check_spend(spend, sighash.as_ref(), &mut ctx, spend_vk) { - return Err(StorageError::SimpleMessage("Invalid shielded spend")); - } - } - for convert in &sapling_bundle.shielded_converts { - consume_verify_gas(namada_gas::MASP_VERIFY_CONVERT_GAS)?; - if !check_convert(convert, &mut ctx, convert_vk) { - return Err(StorageError::SimpleMessage( - "Invalid shielded conversion", - )); - } + let mut ctx = testing::MockBatchValidator::default(); + + // Charge gas before check bundle + charge_masp_check_bundle_gas(sapling_bundle, &consume_verify_gas)?; + + if !ctx.check_bundle(sapling_bundle.to_owned(), sighash.as_ref().to_owned()) + { + tracing::debug!("failed check bundle"); + return Err(StorageError::SimpleMessage("Invalid sapling bundle")); } - for output in &sapling_bundle.shielded_outputs { - consume_verify_gas(namada_gas::MASP_VERIFY_OUTPUT_GAS)?; - if !check_output(output, &mut ctx, output_vk) { - return Err(StorageError::SimpleMessage("Invalid shielded output")); - } + tracing::debug!("passed check bundle"); + + // Charge gas before final validation + charge_masp_validate_gas(sapling_bundle, consume_verify_gas)?; + if !ctx.validate(spend_vk, convert_vk, output_vk, OsRng) { + return Err(StorageError::SimpleMessage( + "Invalid proofs or signatures", + )); } + Ok(()) +} - tracing::info!("passed spend/output verification"); +// Charge gas for the check_bundle operation which does not leverage concurrency +fn charge_masp_check_bundle_gas( + sapling_bundle: &SaplingBundle, + consume_verify_gas: F, +) -> Result<(), namada_state::StorageError> +where + F: Fn(u64) -> std::result::Result<(), namada_state::StorageError>, +{ + consume_verify_gas(checked!( + (sapling_bundle.shielded_spends.len() as u64) + * namada_gas::MASP_SPEND_CHECK_GAS + )?)?; + + consume_verify_gas(checked!( + (sapling_bundle.shielded_converts.len() as u64) + * namada_gas::MASP_CONVERT_CHECK_GAS + )?)?; + + consume_verify_gas(checked!( + (sapling_bundle.shielded_outputs.len() as u64) + * namada_gas::MASP_OUTPUT_CHECK_GAS + )?) +} - let assets_and_values: I128Sum = sapling_bundle.value_balance.clone(); +// Charge gas for the final validation, taking advtange of concurrency for +// proofs verification but not for signatures +fn charge_masp_validate_gas( + sapling_bundle: &SaplingBundle, + consume_verify_gas: F, +) -> Result<(), namada_state::StorageError> +where + F: Fn(u64) -> std::result::Result<(), namada_state::StorageError>, +{ + // Signatures gas + consume_verify_gas(checked!( + // Add one for the binding signature + ((sapling_bundle.shielded_spends.len() as u64) + 1) + * namada_gas::MASP_VERIFY_SIG_GAS + )?)?; + + // If at least one note is present charge the fixed costs. Then charge the + // variable cost for every other note, amortized on the fixed expected + // number of cores + if let Some(remaining_notes) = + sapling_bundle.shielded_spends.len().checked_sub(1) + { + consume_verify_gas(namada_gas::MASP_FIXED_SPEND_GAS)?; + consume_verify_gas(checked!( + namada_gas::MASP_VARIABLE_SPEND_GAS * remaining_notes as u64 + / namada_gas::MASP_PARALLEL_GAS_DIVIDER + )?)?; + } - tracing::info!( - "accumulated {} assets/values", - assets_and_values.components().len() - ); + if let Some(remaining_notes) = + sapling_bundle.shielded_converts.len().checked_sub(1) + { + consume_verify_gas(namada_gas::MASP_FIXED_CONVERT_GAS)?; + consume_verify_gas(checked!( + namada_gas::MASP_VARIABLE_CONVERT_GAS * remaining_notes as u64 + / namada_gas::MASP_PARALLEL_GAS_DIVIDER + )?)?; + } - consume_verify_gas(namada_gas::MASP_VERIFY_FINAL_GAS)?; - let result = ctx.final_check( - assets_and_values, - sighash.as_ref(), - sapling_bundle.authorization.binding_sig, - ); - tracing::info!("final check result {result}"); - if !result { - return Err(StorageError::SimpleMessage("MASP final check failed")); + if let Some(remaining_notes) = + sapling_bundle.shielded_outputs.len().checked_sub(1) + { + consume_verify_gas(namada_gas::MASP_FIXED_OUTPUT_GAS)?; + consume_verify_gas(checked!( + namada_gas::MASP_VARIABLE_OUTPUT_GAS * remaining_notes as u64 + / namada_gas::MASP_PARALLEL_GAS_DIVIDER + )?)?; } + Ok(()) } @@ -510,7 +492,7 @@ pub struct MaspChange { } /// a masp amount -pub type MaspAmount = ValueSum<(Option, Address), token::Change>; +pub type MaspAmount = ValueSum<(Option, Address), token::Change>; /// An extension of Option's cloned method for pair types fn cloned_pair((a, b): (&T, &U)) -> (T, U) { @@ -662,35 +644,37 @@ impl ShieldedContext { } /// Update the merkle tree of witnesses the first time we - /// scan a new MASP transaction. + /// scan new MASP transactions. fn update_witness_map( &mut self, indexed_tx: IndexedTx, - shielded: &Transaction, + shielded: &[Transaction], ) -> Result<(), Error> { let mut note_pos = self.tree.size(); self.tx_note_map.insert(indexed_tx, note_pos); - for so in shielded - .sapling_bundle() - .map_or(&vec![], |x| &x.shielded_outputs) - { - // Create merkle tree leaf node from note commitment - let node = Node::new(so.cmu.to_repr()); - // Update each merkle tree in the witness map with the latest - // addition - for (_, witness) in self.witness_map.iter_mut() { - witness.append(node).map_err(|()| { + + for tx in shielded { + for so in + tx.sapling_bundle().map_or(&vec![], |x| &x.shielded_outputs) + { + // Create merkle tree leaf node from note commitment + let node = Node::new(so.cmu.to_repr()); + // Update each merkle tree in the witness map with the latest + // addition + for (_, witness) in self.witness_map.iter_mut() { + witness.append(node).map_err(|()| { + Error::Other("note commitment tree is full".to_string()) + })?; + } + self.tree.append(node).map_err(|()| { Error::Other("note commitment tree is full".to_string()) })?; + // Finally, make it easier to construct merkle paths to this new + // note + let witness = IncrementalWitness::::from_tree(&self.tree); + self.witness_map.insert(note_pos, witness); + note_pos += 1; } - self.tree.append(node).map_err(|()| { - Error::Other("note commitment tree is full".to_string()) - })?; - // Finally, make it easier to construct merkle paths to this new - // note - let witness = IncrementalWitness::::from_tree(&self.tree); - self.witness_map.insert(note_pos, witness); - note_pos += 1; } Ok(()) } @@ -829,21 +813,19 @@ impl ShieldedContext { .block .data; - for idx in txs_results { + for (idx, masp_sections_refs) in txs_results { let tx = Tx::try_from(block[idx.0 as usize].as_ref()) .map_err(|e| Error::Other(e.to_string()))?; - let extracted_masp_txs = Self::extract_masp_tx(&tx).await?; + let extracted_masp_txs = + Self::extract_masp_tx(&tx, &masp_sections_refs).await?; // Collect the current transactions - for (inner_tx, transaction) in extracted_masp_txs.0 { - shielded_txs.insert( - IndexedTx { - height: height.into(), - index: idx, - inner_tx, - }, - transaction, - ); - } + shielded_txs.insert( + IndexedTx { + height: height.into(), + index: idx, + }, + extracted_masp_txs, + ); } } @@ -851,58 +833,35 @@ impl ShieldedContext { } /// Extract the relevant shield portions of a [`Tx`], if any. - async fn extract_masp_tx(tx: &Tx) -> Result { + async fn extract_masp_tx( + tx: &Tx, + masp_section_refs: &MaspTxRefs, + ) -> Result, Error> { // NOTE: simply looking for masp sections attached to the tx // is not safe. We don't validate the sections attached to a // transaction se we could end up with transactions carrying // an unnecessary masp section. We must instead look for the - // required masp sections in the signed commitments (hashes) - // of the transactions' data sections - let mut txs = vec![]; - - // Expect transaction - for cmt in tx.commitments() { - let tx_data = tx.data(cmt).ok_or_else(|| { - Error::Other("Missing data section".to_string()) - })?; - let maybe_masp_tx = match Transfer::try_from_slice(&tx_data) { - Ok(transfer) => Some(transfer), - Err(_) => { - // This should be a MASP over IBC transaction, it - // could be a ShieldedTransfer or an Envelope - // message, need to try both - extract_payload_from_shielded_action(&tx_data).await.ok() - } - } - .map(|transfer| { - if let Some(hash) = transfer.shielded { - let masp_tx = tx - .get_section(&hash) - .ok_or_else(|| { - Error::Other( - "Missing masp section in transaction" - .to_string(), - ) - })? - .masp_tx() - .ok_or_else(|| { - Error::Other("Missing masp transaction".to_string()) - })?; - - Ok::<_, Error>(Some(masp_tx)) - } else { - Ok(None) + // required masp sections coming from the events + + masp_section_refs + .0 + .iter() + .try_fold(vec![], |mut acc, hash| { + match tx + .get_section(hash) + .and_then(|section| section.masp_tx()) + .ok_or_else(|| { + Error::Other( + "Missing expected masp transaction".to_string(), + ) + }) { + Ok(transaction) => { + acc.push(transaction); + Ok(acc) + } + Err(e) => Err(e), } }) - .transpose()? - .flatten(); - - if let Some(transaction) = maybe_masp_tx { - txs.push((cmt.to_owned(), transaction)); - } - } - - Ok(ExtractedMaspTxs(txs)) } /// Applies the given transaction to the supplied context. More precisely, @@ -916,7 +875,7 @@ impl ShieldedContext { pub fn scan_tx( &mut self, indexed_tx: IndexedTx, - shielded: &Transaction, + shielded: &[Transaction], vk: &ViewingKey, ) -> Result<(), Error> { // For tracking the account changes caused by this Transaction @@ -925,42 +884,78 @@ impl ShieldedContext { let mut note_pos = self.tx_note_map[&indexed_tx]; // Listen for notes sent to our viewing keys, only if we are syncing // (i.e. in a confirmed status) - for so in shielded - .sapling_bundle() - .map_or(&vec![], |x| &x.shielded_outputs) - { - // Let's try to see if this viewing key can decrypt latest - // note - let notes = self.pos_map.entry(*vk).or_default(); - let decres = try_sapling_note_decryption::<_, OutputDescription<<::SaplingAuth as masp_primitives::transaction::components::sapling::Authorization>::Proof>>( + for tx in shielded { + for so in + tx.sapling_bundle().map_or(&vec![], |x| &x.shielded_outputs) + { + // Let's try to see if this viewing key can decrypt latest + // note + let notes = self.pos_map.entry(*vk).or_default(); + let decres = try_sapling_note_decryption::<_, OutputDescription<<::SaplingAuth as masp_primitives::transaction::components::sapling::Authorization>::Proof>>( &NETWORK, 1.into(), &PreparedIncomingViewingKey::new(&vk.ivk()), so, ); - // So this current viewing key does decrypt this current note... - if let Some((note, pa, memo)) = decres { - // Add this note to list of notes decrypted by this viewing - // key - notes.insert(note_pos); - // Compute the nullifier now to quickly recognize when spent - let nf = note.nf( - &vk.nk, - note_pos.try_into().map_err(|_| { - Error::Other("Can not get nullifier".to_string()) - })?, - ); - self.note_map.insert(note_pos, note); - self.memo_map.insert(note_pos, memo); - // The payment address' diversifier is required to spend - // note - self.div_map.insert(note_pos, *pa.diversifier()); - self.nf_map.insert(nf, note_pos); + // So this current viewing key does decrypt this current + // note... + if let Some((note, pa, memo)) = decres { + // Add this note to list of notes decrypted by this + // viewing key + notes.insert(note_pos); + // Compute the nullifier now to quickly recognize when + // spent + let nf = note.nf( + &vk.nk, + note_pos.try_into().map_err(|_| { + Error::Other( + "Can not get nullifier".to_string(), + ) + })?, + ); + self.note_map.insert(note_pos, note); + self.memo_map.insert(note_pos, memo); + // The payment address' diversifier is required to spend + // note + self.div_map.insert(note_pos, *pa.diversifier()); + self.nf_map.insert(nf, note_pos); + // Note the account changes + let balance = transaction_delta + .entry(*vk) + .or_insert_with(I128Sum::zero); + *balance += I128Sum::from_nonnegative( + note.asset_type, + note.value as i128, + ) + .map_err(|()| { + Error::Other( + "found note with invalid value or asset type" + .to_string(), + ) + })?; + self.vk_map.insert(note_pos, *vk); + } + note_pos += 1; + } + } + } + + // Cancel out those of our notes that have been spent + for tx in shielded { + for ss in + tx.sapling_bundle().map_or(&vec![], |x| &x.shielded_spends) + { + // If the shielded spend's nullifier is in our map, then target + // note is rendered unusable + if let Some(note_pos) = self.nf_map.get(&ss.nullifier) { + self.spents.insert(*note_pos); // Note the account changes let balance = transaction_delta - .entry(*vk) + .entry(self.vk_map[note_pos]) .or_insert_with(I128Sum::zero); - *balance += I128Sum::from_nonnegative( + let note = self.note_map[note_pos]; + + *balance -= I128Sum::from_nonnegative( note.asset_type, note.value as i128, ) @@ -970,37 +965,7 @@ impl ShieldedContext { .to_string(), ) })?; - self.vk_map.insert(note_pos, *vk); } - note_pos += 1; - } - } - - // Cancel out those of our notes that have been spent - for ss in shielded - .sapling_bundle() - .map_or(&vec![], |x| &x.shielded_spends) - { - // If the shielded spend's nullifier is in our map, then target note - // is rendered unusable - if let Some(note_pos) = self.nf_map.get(&ss.nullifier) { - self.spents.insert(*note_pos); - // Note the account changes - let balance = transaction_delta - .entry(self.vk_map[note_pos]) - .or_insert_with(I128Sum::zero); - let note = self.note_map[note_pos]; - - *balance -= I128Sum::from_nonnegative( - note.asset_type, - note.value as i128, - ) - .map_err(|()| { - Error::Other( - "found note with invalid value or asset type" - .to_string(), - ) - })?; } } @@ -1154,7 +1119,7 @@ impl ShieldedContext { client: &(impl Client + Sync), io: &impl Io, vk: &ViewingKey, - target_epoch: Epoch, + target_epoch: MaspEpoch, ) -> Result, Error> { // First get the unexchanged balance if let Some(balance) = self.compute_shielded_balance(vk).await? { @@ -1235,7 +1200,7 @@ impl ShieldedContext { client: &(impl Client + Sync), io: &impl Io, mut input: I128Sum, - target_epoch: Epoch, + target_epoch: MaspEpoch, mut conversions: Conversions, ) -> Result<(I128Sum, I128Sum, Conversions), Error> { // Where we will store our exchanged value @@ -1361,7 +1326,7 @@ impl ShieldedContext { context: &impl Namada, vk: &ViewingKey, target: I128Sum, - target_epoch: Epoch, + target_epoch: MaspEpoch, ) -> Result< ( I128Sum, @@ -1455,7 +1420,7 @@ impl ShieldedContext { &mut self, client: &C, amt: I128Sum, - target_epoch: Epoch, + target_epoch: MaspEpoch, ) -> (ValueSum, I128Sum) { let mut res = ValueSum::zero(); let mut undecoded = ValueSum::zero(); @@ -1555,9 +1520,6 @@ impl ShieldedContext { // No shielded components are needed when neither source nor destination // are shielded - use rand::rngs::StdRng; - use rand_core::SeedableRng; - let spending_key = source.spending_key(); let payment_address = target.payment_address(); // No shielded components are needed when neither source nor @@ -1574,7 +1536,7 @@ impl ShieldedContext { let _ = shielded.load().await; } // Determine epoch in which to submit potential shielded transaction - let epoch = rpc::query_epoch(context.client()).await?; + let epoch = rpc::query_masp_epoch(context.client()).await?; // Context required for storing which notes are in the source's // possession let memo = MemoBytes::empty(); @@ -1881,7 +1843,7 @@ impl ShieldedContext { // Cache the generated transfer let mut shielded_ctx = context.shielded_mut().await; shielded_ctx - .pre_cache_transaction(context, &masp_tx) + .pre_cache_transaction(context, &[masp_tx.clone()]) .await?; } @@ -1900,7 +1862,7 @@ impl ShieldedContext { async fn pre_cache_transaction( &mut self, context: &impl Namada, - masp_tx: &Transaction, + masp_tx: &[Transaction], ) -> Result<(), Error> { let vks: Vec<_> = context .wallet() @@ -1920,7 +1882,6 @@ impl ShieldedContext { .index .checked_add(1) .expect("Tx index shouldn't overflow"), - inner_tx: TxCommitments::default(), } }); self.sync_status = ContextSyncStatus::Speculative; @@ -1962,7 +1923,7 @@ impl ShieldedContext { async fn convert_amount( &mut self, client: &C, - epoch: Epoch, + epoch: MaspEpoch, token: &Address, denom: Denomination, val: token::Amount, @@ -2002,7 +1963,7 @@ async fn get_indexed_masp_events_at_height( client: &C, height: BlockHeight, first_idx_to_query: Option, -) -> Result>, Error> { +) -> Result>, Error> { let first_idx_to_query = first_idx_to_query.unwrap_or_default(); Ok(client @@ -2021,7 +1982,14 @@ async fn get_indexed_masp_events_at_height( .ok()?; if tx_index >= first_idx_to_query { - Some(tx_index) + // Extract the references to the correct masp sections + let masp_section_refs = + MaspTxBatchRefsAttr::read_from_event_attributes( + &event.attributes, + ) + .ok()?; + + Some((tx_index, masp_section_refs)) } else { None } @@ -2030,45 +1998,6 @@ async fn get_indexed_masp_events_at_height( })) } -// Extract the Transaction hash from a masp over ibc message -async fn extract_payload_from_shielded_action( - tx_data: &[u8], -) -> Result { - let message = namada_ibc::decode_message(tx_data) - .map_err(|e| Error::Other(e.to_string()))?; - - let result = match message { - IbcMessage::Transfer(msg) => msg.transfer.ok_or_else(|| { - Error::Other("Missing masp tx in the ibc message".to_string()) - })?, - IbcMessage::NftTransfer(msg) => msg.transfer.ok_or_else(|| { - Error::Other("Missing masp tx in the ibc message".to_string()) - })?, - IbcMessage::RecvPacket(msg) => msg.transfer.ok_or_else(|| { - Error::Other("Missing masp tx in the ibc message".to_string()) - })?, - IbcMessage::AckPacket(msg) => { - // Refund tokens by the ack message - msg.transfer.ok_or_else(|| { - Error::Other("Missing masp tx in the ibc message".to_string()) - })? - } - IbcMessage::Timeout(msg) => { - // Refund tokens by the timeout message - msg.transfer.ok_or_else(|| { - Error::Other("Missing masp tx in the ibc message".to_string()) - })? - } - IbcMessage::Envelope(_) => { - return Err(Error::Other( - "Unexpected ibc message for masp".to_string(), - )); - } - }; - - Ok(result) -} - mod tests { /// quick and dirty test. will fail on size check #[test] @@ -2189,12 +2118,15 @@ pub mod testing { use bls12_381::{G1Affine, G2Affine}; use masp_primitives::consensus::testing::arb_height; use masp_primitives::constants::SPENDING_KEY_GENERATOR; + use masp_primitives::group::GroupEncoding; use masp_primitives::sapling::prover::TxProver; - use masp_primitives::sapling::redjubjub::Signature; + use masp_primitives::sapling::redjubjub::{PublicKey, Signature}; use masp_primitives::sapling::{ProofGenerationKey, Rseed}; + use masp_primitives::transaction::components::sapling::builder::StoredBuildParams; + use masp_primitives::transaction::components::sapling::Bundle; use masp_primitives::transaction::components::GROTH_PROOF_SIZE; use masp_primitives::transaction::TransparentAddress; - use masp_proofs::bellman::groth16::Proof; + use masp_proofs::bellman::groth16::{self, Proof}; use proptest::prelude::*; use proptest::sample::SizeRange; use proptest::test_runner::TestRng; @@ -2208,129 +2140,58 @@ pub mod testing { use crate::masp_primitives::sapling::keys::OutgoingViewingKey; use crate::masp_primitives::sapling::redjubjub::PrivateKey; use crate::masp_primitives::transaction::components::transparent::testing::arb_transparent_address; - use crate::masp_proofs::sapling::SaplingVerificationContextInner; - use crate::storage::testing::arb_epoch; use crate::token::testing::arb_denomination; - /// A context object for verifying the Sapling components of a single Zcash - /// transaction. Same as SaplingVerificationContext, but always assumes the - /// proofs to be valid. - pub struct MockSaplingVerificationContext { - inner: SaplingVerificationContextInner, - zip216_enabled: bool, + /// A context object for verifying the Sapling components of MASP + /// transactions. Same as BatchValidator, but always assumes the + /// proofs and signatures to be valid. + pub struct MockBatchValidator { + inner: BatchValidator, } - impl MockSaplingVerificationContext { - /// Construct a new context to be used with a single transaction. - pub fn new(zip216_enabled: bool) -> Self { - MockSaplingVerificationContext { - inner: SaplingVerificationContextInner::new(), - zip216_enabled, + impl Default for MockBatchValidator { + fn default() -> Self { + MockBatchValidator { + inner: BatchValidator::new(), } } + } - /// Perform consensus checks on a Sapling SpendDescription, while - /// accumulating its value commitment inside the context for later use. - #[allow(clippy::too_many_arguments)] - pub fn check_spend( - &mut self, - cv: jubjub::ExtendedPoint, - anchor: bls12_381::Scalar, - nullifier: &[u8; 32], - rk: PublicKey, - sighash_value: &[u8; 32], - spend_auth_sig: Signature, - zkproof: Proof, - _verifying_key: &PreparedVerifyingKey, - ) -> bool { - let zip216_enabled = true; - self.inner.check_spend( - cv, - anchor, - nullifier, - rk, - sighash_value, - spend_auth_sig, - zkproof, - &mut (), - |_, rk, msg, spend_auth_sig| { - rk.verify_with_zip216( - &msg, - &spend_auth_sig, - SPENDING_KEY_GENERATOR, - zip216_enabled, - ) - }, - |_, _proof, _public_inputs| true, - ) - } - - /// Perform consensus checks on a Sapling SpendDescription, while - /// accumulating its value commitment inside the context for later use. - #[allow(clippy::too_many_arguments)] - pub fn check_convert( - &mut self, - cv: jubjub::ExtendedPoint, - anchor: bls12_381::Scalar, - zkproof: Proof, - _verifying_key: &PreparedVerifyingKey, - ) -> bool { - self.inner.check_convert( - cv, - anchor, - zkproof, - &mut (), - |_, _proof, _public_inputs| true, - ) - } - - /// Perform consensus checks on a Sapling OutputDescription, while - /// accumulating its value commitment inside the context for later use. - pub fn check_output( + impl MockBatchValidator { + /// Checks the bundle against Sapling-specific consensus rules, and adds + /// its proof and signatures to the validator. + /// + /// Returns `false` if the bundle doesn't satisfy all of the consensus + /// rules. This `BatchValidator` can continue to be used + /// regardless, but some or all of the proofs and signatures + /// from this bundle may have already been added to the batch even if + /// it fails other consensus rules. + pub fn check_bundle( &mut self, - cv: jubjub::ExtendedPoint, - cmu: bls12_381::Scalar, - epk: jubjub::ExtendedPoint, - zkproof: Proof, - _verifying_key: &PreparedVerifyingKey, + bundle: Bundle< + masp_primitives::transaction::components::sapling::Authorized, + >, + sighash: [u8; 32], ) -> bool { - self.inner.check_output( - cv, - cmu, - epk, - zkproof, - |_proof, _public_inputs| true, - ) - } - - /// Perform consensus checks on the valueBalance and bindingSig parts of - /// a Sapling transaction. All SpendDescriptions and - /// OutputDescriptions must have been checked before calling - /// this function. - pub fn final_check( - &self, - value_balance: I128Sum, - sighash_value: &[u8; 32], - binding_sig: Signature, + self.inner.check_bundle(bundle, sighash) + } + + /// Batch-validates the accumulated bundles. + /// + /// Returns `true` if every proof and signature in every bundle added to + /// the batch validator is valid, or `false` if one or more are + /// invalid. No attempt is made to figure out which of the + /// accumulated bundles might be invalid; if that information is + /// desired, construct separate [`BatchValidator`]s for sub-batches of + /// the bundles. + pub fn validate( + self, + _spend_vk: &groth16::VerifyingKey, + _convert_vk: &groth16::VerifyingKey, + _output_vk: &groth16::VerifyingKey, + mut _rng: R, ) -> bool { - self.inner.final_check( - value_balance, - sighash_value, - binding_sig, - |bvk, msg, binding_sig| { - // Compute the signature's message for bvk/binding_sig - let mut data_to_be_signed = [0u8; 64]; - data_to_be_signed[0..32].copy_from_slice(&bvk.0.to_bytes()); - data_to_be_signed[32..64].copy_from_slice(msg); - - bvk.verify_with_zip216( - &data_to_be_signed, - &binding_sig, - VALUE_COMMITMENT_RANDOMNESS_GENERATOR, - self.zip216_enabled, - ) - }, - ) + true } } @@ -2844,13 +2705,20 @@ pub mod testing { } } + prop_compose! { + /// Generate an arbitrary masp epoch + pub fn arb_masp_epoch()(epoch: u64) -> MaspEpoch{ + MaspEpoch::new(epoch) + } + } + prop_compose! { /// Generate an arbitrary pre-asset type pub fn arb_pre_asset_type()( token in arb_address(), denom in arb_denomination(), position in arb_masp_digit_pos(), - epoch in option::of(arb_epoch()), + epoch in option::of(arb_masp_epoch()), ) -> AssetData { AssetData { token, @@ -2960,23 +2828,24 @@ pub mod testing { asset_range: impl Into, )(asset_range in Just(asset_range.into()))( (builder, asset_types) in arb_shielded_builder(asset_range), - epoch in arb_epoch(), + epoch in arb_masp_epoch(), prover_rng in arb_rng().prop_map(TestCsprng), mut rng in arb_rng().prop_map(TestCsprng), bparams_rng in arb_rng().prop_map(TestCsprng), - ) -> (ShieldedTransfer, HashMap) { + ) -> (ShieldedTransfer, HashMap, StoredBuildParams) { + let mut rng_build_params = RngBuildParams::new(bparams_rng); let (masp_tx, metadata) = builder.clone().build( &MockTxProver(Mutex::new(prover_rng)), &FeeRule::non_standard(U64Sum::zero()), &mut rng, - &mut RngBuildParams::new(bparams_rng), + &mut rng_build_params, ).unwrap(); (ShieldedTransfer { builder: builder.map_builder(WalletMap), metadata, masp_tx, epoch, - }, asset_types) + }, asset_types, rng_build_params.to_stored().unwrap()) } } @@ -2990,23 +2859,24 @@ pub mod testing { source, asset_range, ), - epoch in arb_epoch(), + epoch in arb_masp_epoch(), prover_rng in arb_rng().prop_map(TestCsprng), mut rng in arb_rng().prop_map(TestCsprng), bparams_rng in arb_rng().prop_map(TestCsprng), - ) -> (ShieldedTransfer, HashMap) { + ) -> (ShieldedTransfer, HashMap, StoredBuildParams) { + let mut rng_build_params = RngBuildParams::new(bparams_rng); let (masp_tx, metadata) = builder.clone().build( &MockTxProver(Mutex::new(prover_rng)), &FeeRule::non_standard(U64Sum::zero()), &mut rng, - &mut RngBuildParams::new(bparams_rng), + &mut rng_build_params, ).unwrap(); (ShieldedTransfer { builder: builder.map_builder(WalletMap), metadata, masp_tx, epoch, - }, asset_types) + }, asset_types, rng_build_params.to_stored().unwrap()) } } @@ -3020,23 +2890,24 @@ pub mod testing { target, asset_range, ), - epoch in arb_epoch(), + epoch in arb_masp_epoch(), prover_rng in arb_rng().prop_map(TestCsprng), mut rng in arb_rng().prop_map(TestCsprng), bparams_rng in arb_rng().prop_map(TestCsprng), - ) -> (ShieldedTransfer, HashMap) { + ) -> (ShieldedTransfer, HashMap, StoredBuildParams) { + let mut rng_build_params = RngBuildParams::new(bparams_rng); let (masp_tx, metadata) = builder.clone().build( &MockTxProver(Mutex::new(prover_rng)), &FeeRule::non_standard(U64Sum::zero()), &mut rng, - &mut RngBuildParams::new(bparams_rng), + &mut rng_build_params, ).unwrap(); (ShieldedTransfer { builder: builder.map_builder(WalletMap), metadata, masp_tx, epoch, - }, asset_types) + }, asset_types, rng_build_params.to_stored().unwrap()) } } } diff --git a/crates/sdk/src/migrations.rs b/crates/sdk/src/migrations.rs index 0e2eb1a8c1..df28424238 100644 --- a/crates/sdk/src/migrations.rs +++ b/crates/sdk/src/migrations.rs @@ -6,11 +6,15 @@ use core::fmt::Formatter; use core::fmt::{Display, Formatter}; #[cfg(feature = "migrations")] use core::str::FromStr; +use std::marker::PhantomData; +use std::path::{Path, PathBuf}; use borsh::{BorshDeserialize, BorshSerialize}; use borsh_ext::BorshSerializeExt; use data_encoding::HEXUPPER; -use namada_core::storage::Key; +use eyre::eyre; +use namada_core::hash::Hash; +use namada_core::storage::{BlockHeight, Key}; #[cfg(feature = "migrations")] use namada_macros::derive_borshdeserializer; #[cfg(feature = "migrations")] @@ -19,9 +23,9 @@ use namada_macros::typehash; use namada_migrations::TypeHash; #[cfg(feature = "migrations")] use namada_migrations::*; -use namada_storage::DbColFam; +use namada_storage::{DbColFam, DbMigration, DB}; use regex::Regex; -use serde::de::{Error, Visitor}; +use serde::de::{DeserializeOwned, Error, Visitor}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "migrations")] @@ -35,7 +39,7 @@ pub trait DBUpdateVisitor { fn get_pattern(&self, pattern: Regex) -> Vec<(String, Vec)>; } -#[derive(Clone, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] enum UpdateBytes { Raw { to_write: Vec, @@ -46,7 +50,7 @@ enum UpdateBytes { }, } -#[derive(Clone, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] /// A value to be added to the database that can be /// validated. pub struct UpdateValue { @@ -171,7 +175,7 @@ impl<'de> Deserialize<'de> for UpdateValue { deserializer.deserialize_any(UpdateValueVisitor) } } -#[derive(Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] /// An update to the database pub enum DbUpdateType { Add { @@ -190,6 +194,8 @@ pub enum DbUpdateType { RepeatDelete(String, DbColFam), } +impl DbMigration for DbUpdateType {} + #[cfg(feature = "migrations")] impl DbUpdateType { /// Get the key or pattern being modified as string @@ -280,7 +286,6 @@ impl DbUpdateType { /// Validate a DB change and persist it if so. The debug representation of /// the new value is returned for logging purposes. - #[allow(dead_code)] pub fn update( &self, db: &mut DB, @@ -352,11 +357,81 @@ impl DbUpdateType { } } -#[derive(Serialize, Deserialize)] -pub struct DbChanges { - pub changes: Vec, +/// A set of key-value changes to be applied to +/// the db at a specified height. +#[derive(Debug, Clone)] +pub struct ScheduledMigration { + /// The height at which to perform the changes + pub height: BlockHeight, + /// The actual set of changes + pub path: PathBuf, + /// A hash of the expected contents in the file + pub hash: Hash, + /// For keeping track of what data type we deserialize the + /// contents of the file to. + phantom: PhantomData, +} + +impl ScheduledMigration +where + D: DbMigration + DeserializeOwned, +{ + /// Read in a migrations json and a hash to verify the contents + /// against. Also needs a height for which the changes are scheduled. + pub fn from_path( + path: impl AsRef, + hash: Hash, + height: BlockHeight, + ) -> eyre::Result { + let scheduled_migration = Self { + height, + path: path.as_ref().to_path_buf(), + hash, + phantom: Default::default(), + }; + scheduled_migration.validate()?; + Ok(scheduled_migration) + } + + fn load(&self) -> eyre::Result> { + let update_json = self.validate()?; + serde_json::from_str(&update_json) + .map_err(|_| eyre!("Could not parse the updates file as json")) + } + + fn validate(&self) -> eyre::Result { + let update_json = + std::fs::read_to_string(&self.path).map_err(|_| { + eyre!( + "Could not find or read updates file at the specified \ + path." + ) + })?; + // validate contents against provided hash + if Hash::sha256(update_json.as_bytes()) != self.hash { + Err(eyre!( + "Provided hash did not match the contents at the specified \ + path." + )) + } else { + Ok(update_json) + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct DbChanges { + pub changes: Vec, } +impl IntoIterator for DbChanges { + type IntoIter = std::vec::IntoIter; + type Item = D; + + fn into_iter(self) -> Self::IntoIter { + self.changes.into_iter() + } +} #[cfg(feature = "migrations")] impl Display for DbUpdateType { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { @@ -431,6 +506,43 @@ impl Display for UpdateStatus { } } +/// Check if a scheduled migration should take place at this block height. +/// If so, apply it to the DB. +pub fn commit( + db: &D, + height: BlockHeight, + migration: &mut Option>, +) where + D::Migrator: DeserializeOwned, +{ + let maybe_migration = migration; + let migration = match maybe_migration.as_ref() { + Some(migration) if height == migration.height => { + maybe_migration.take().unwrap().load().unwrap() + } + _ => return, + }; + + tracing::info!( + "A migration is scheduled to take place at this block height. \ + Starting..." + ); + + match db.apply_migration_to_batch(migration) { + Ok(batch) => { + tracing::info!("Persisting DB changes..."); + db.exec_batch(batch).expect("Failed to execute write batch"); + } + Err(e) => { + panic!( + "Failed to execute migration, no changes persisted. \ + Encountered error: {}", + e + ); + } + } +} + #[cfg(feature = "migrations")] derive_borshdeserializer!(Vec::); #[cfg(feature = "migrations")] @@ -467,3 +579,35 @@ static BTREEMAP_STRING_ADDRESS: fn() = || { }, ); }; + +#[cfg(test)] +mod test_migrations { + use namada_core::token::Amount; + + use super::*; + + /// Check that if the hash of the file is wrong, the scheduled + /// migration will not load. + #[test] + fn test_scheduled_migration_validate() { + let file = tempfile::Builder::new().tempfile().expect("Test failed"); + let updates = [DbUpdateType::Add { + key: Key::parse("bing/fucking/bong").expect("Test failed"), + cf: DbColFam::SUBSPACE, + value: Amount::native_whole(1337).into(), + force: false, + }]; + let changes = DbChanges { + changes: updates.into_iter().collect(), + }; + let json = serde_json::to_string(&changes).expect("Test failed"); + let hash = Hash::sha256("derpy derp".as_bytes()); + std::fs::write(file.path(), json).expect("Test failed"); + let migration = ScheduledMigration::::from_path( + file.path(), + hash, + Default::default(), + ); + assert!(migration.is_err()); + } +} diff --git a/crates/sdk/src/queries/shell.rs b/crates/sdk/src/queries/shell.rs index caaff8f7fb..071939bdd2 100644 --- a/crates/sdk/src/queries/shell.rs +++ b/crates/sdk/src/queries/shell.rs @@ -13,7 +13,7 @@ use namada_core::arith::checked; use namada_core::dec::Dec; use namada_core::hash::Hash; use namada_core::hints; -use namada_core::masp::TokenMap; +use namada_core::masp::{MaspEpoch, TokenMap}; use namada_core::storage::{ self, BlockHeight, BlockResults, Epoch, KeySeg, PrefixValue, }; @@ -41,7 +41,7 @@ type ConversionWithoutPath = ( Address, Denomination, MaspDigitPos, - Epoch, + MaspEpoch, masp_primitives::transaction::components::I128Sum, ); @@ -49,7 +49,7 @@ type Conversion = ( Address, Denomination, MaspDigitPos, - Epoch, + MaspEpoch, masp_primitives::transaction::components::I128Sum, MerklePath, ); @@ -63,6 +63,9 @@ router! {SHELL, // Epoch of the last committed block ( "epoch" ) -> Epoch = epoch, + // Masp epoch of the last committed block + ( "masp_epoch" ) -> MaspEpoch = masp_epoch, + // The address of the native token ( "native_token" ) -> Address = native_token, @@ -321,6 +324,20 @@ where Ok(data) } +fn masp_epoch( + ctx: RequestCtx<'_, D, H, V, T>, +) -> namada_storage::Result +where + D: 'static + DB + for<'iter> DBIter<'iter> + Sync, + H: 'static + StorageHasher + Sync, +{ + let epoch = ctx.state.in_mem().last_epoch; + let masp_epoch_multiplier = + namada_parameters::read_masp_epoch_multiplier_parameter(ctx.state)?; + MaspEpoch::try_from_epoch(epoch, masp_epoch_multiplier) + .map_err(namada_storage::Error::new_const) +} + fn native_token( ctx: RequestCtx<'_, D, H, V, T>, ) -> namada_storage::Result
diff --git a/crates/sdk/src/queries/vp/pos.rs b/crates/sdk/src/queries/vp/pos.rs index 6aadad4b66..96db66e559 100644 --- a/crates/sdk/src/queries/vp/pos.rs +++ b/crates/sdk/src/queries/vp/pos.rs @@ -33,7 +33,7 @@ use namada_proof_of_stake::types::{ Slash, ValidatorMetaData, WeightedValidator, }; use namada_proof_of_stake::{bond_amount, query_reward_tokens}; -use namada_state::{DBIter, StorageHasher, DB}; +use namada_state::{DBIter, KeySeg, StorageHasher, DB}; use namada_storage::collections::lazy_map; use namada_storage::OptionExt; @@ -643,6 +643,13 @@ where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, { + // Sanitize the input to make sure it doesn't crash in + // `namada_proof_of_stake::storage_key::validator_address_raw_hash_key` + if namada_storage::DbKeySeg::parse(tm_addr.clone()).is_err() { + return Err(namada_storage::Error::new_const( + "Invalid Tendermint address", + )); + } namada_proof_of_stake::storage::find_validator_by_raw_hash( ctx.state, tm_addr, ) @@ -776,3 +783,43 @@ fn enrich_bonds_and_unbonds( total_withdrawable, }) } + +#[cfg(test)] +mod test { + use super::*; + use crate::queries::testing::TestClient; + use crate::queries::{RequestCtx, RequestQuery, Router}; + + #[tokio::test] + async fn test_validator_by_tm_addr_sanitized_input() { + let client = TestClient::new(POS); + + // Test request with an invalid path - the trailing slash ends up being + // part of the input where in `fn validator_by_tm_addr` the + // parameter will be: + // `tm_addr = "52894D2ABA1614EF24CC1DDAE127A7A2386DE3BB/"` + let request = RequestQuery { + path: "/validator_by_tm_addr/\ + 52894D2ABA1614EF24CC1DDAE127A7A2386DE3BB/" + .to_owned(), + data: Default::default(), + height: 0_u32.into(), + prove: Default::default(), + }; + let ctx = RequestCtx { + event_log: &client.event_log, + state: &client.state, + vp_wasm_cache: (), + tx_wasm_cache: (), + storage_read_past_height_limit: None, + }; + let result = POS.handle(ctx, &request); + assert!(result.is_err()); + assert!( + result + .unwrap_err() + .to_string() + .contains("Invalid Tendermint address") + ) + } +} diff --git a/crates/sdk/src/rpc.rs b/crates/sdk/src/rpc.rs index d54a0e0e36..8b42fea411 100644 --- a/crates/sdk/src/rpc.rs +++ b/crates/sdk/src/rpc.rs @@ -15,6 +15,7 @@ use namada_core::collections::{HashMap, HashSet}; use namada_core::hash::Hash; use namada_core::ibc::IbcTokenHash; use namada_core::key::common; +use namada_core::masp::MaspEpoch; use namada_core::storage::{ BlockHeight, BlockResults, Epoch, Key, PrefixValue, }; @@ -31,6 +32,7 @@ use namada_governance::storage::proposal::StorageProposal; use namada_governance::utils::{ compute_proposal_result, ProposalResult, ProposalVotes, Vote, }; +use namada_ibc::is_ibc_denom; use namada_ibc::storage::{ ibc_trace_key, ibc_trace_key_prefix, is_ibc_trace_key, }; @@ -48,7 +50,6 @@ use crate::args::InputAmount; use crate::control_flow::time; use crate::error::{EncodingError, Error, QueryError, TxSubmitError}; use crate::events::{extend, Event}; -use crate::ibc::is_ibc_denom; use crate::internal_macros::echo_error; use crate::io::Io; use crate::masp::MaspTokenRewardData; @@ -137,6 +138,13 @@ pub async fn query_epoch( convert_response::(RPC.shell().epoch(client).await) } +/// Query the masp epoch of the last committed block +pub async fn query_masp_epoch( + client: &C, +) -> Result { + convert_response::(RPC.shell().masp_epoch(client).await) +} + /// Query the address of the native token pub async fn query_native_token( client: &C, @@ -312,7 +320,7 @@ pub async fn query_conversion( Address, Denomination, MaspDigitPos, - Epoch, + MaspEpoch, masp_primitives::transaction::components::I128Sum, MerklePath, )> { @@ -331,7 +339,7 @@ pub async fn query_conversions( Address, Denomination, MaspDigitPos, - Epoch, + MaspEpoch, masp_primitives::transaction::components::I128Sum, ), >, diff --git a/crates/sdk/src/signing.rs b/crates/sdk/src/signing.rs index f6c5e4f840..a6e1ef5f44 100644 --- a/crates/sdk/src/signing.rs +++ b/crates/sdk/src/signing.rs @@ -17,15 +17,13 @@ use namada_core::collections::{HashMap, HashSet}; use namada_core::key::*; use namada_core::masp::{AssetData, ExtendedViewingKey, PaymentAddress}; use namada_core::sign::SignatureIndex; -use namada_core::token; -use namada_core::token::Transfer; -// use namada_core::storage::Key; use namada_core::token::{Amount, DenominatedAmount}; use namada_governance::storage::proposal::{ InitProposalData, ProposalType, VoteProposalData, }; use namada_governance::storage::vote::ProposalVote; use namada_parameters::storage as parameter_storage; +use namada_token as token; use namada_token::storage_key::balance_key; use namada_tx::data::pgf::UpdateStewardCommission; use namada_tx::data::pos::BecomeValidator; @@ -50,10 +48,11 @@ use crate::tx::{ TX_CHANGE_METADATA_WASM, TX_CLAIM_REWARDS_WASM, TX_DEACTIVATE_VALIDATOR_WASM, TX_IBC_WASM, TX_INIT_ACCOUNT_WASM, TX_INIT_PROPOSAL, TX_REACTIVATE_VALIDATOR_WASM, TX_REDELEGATE_WASM, - TX_RESIGN_STEWARD, TX_REVEAL_PK, TX_TRANSFER_WASM, TX_UNBOND_WASM, - TX_UNJAIL_VALIDATOR_WASM, TX_UPDATE_ACCOUNT_WASM, - TX_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL, TX_WITHDRAW_WASM, - VP_USER_WASM, + TX_RESIGN_STEWARD, TX_REVEAL_PK, TX_SHIELDED_TRANSFER_WASM, + TX_SHIELDING_TRANSFER_WASM, TX_TRANSPARENT_TRANSFER_WASM, TX_UNBOND_WASM, + TX_UNJAIL_VALIDATOR_WASM, TX_UNSHIELDING_TRANSFER_WASM, + TX_UPDATE_ACCOUNT_WASM, TX_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL, + TX_WITHDRAW_WASM, VP_USER_WASM, }; pub use crate::wallet::store::AddressVpType; use crate::wallet::{Wallet, WalletIo}; @@ -703,25 +702,61 @@ fn format_outputs(output: &mut Vec) { } } +enum TokenTransfer<'a> { + Transparent(&'a token::TransparentTransfer), + Shielded, + Shielding(&'a token::ShieldingTransfer), + Unshielding(&'a token::UnshieldingTransfer), +} + +impl TokenTransfer<'_> { + fn source(&self) -> Option<&Address> { + match self { + TokenTransfer::Transparent(transfer) => Some(&transfer.source), + TokenTransfer::Shielded => None, + TokenTransfer::Shielding(transfer) => Some(&transfer.source), + TokenTransfer::Unshielding(_) => None, + } + } + + fn target(&self) -> Option<&Address> { + match self { + TokenTransfer::Transparent(transfer) => Some(&transfer.target), + TokenTransfer::Shielded => None, + TokenTransfer::Shielding(_) => None, + TokenTransfer::Unshielding(transfer) => Some(&transfer.target), + } + } + + fn token_and_amount(&self) -> Option<(&Address, DenominatedAmount)> { + match self { + TokenTransfer::Transparent(transfer) => { + Some((&transfer.token, transfer.amount)) + } + TokenTransfer::Shielded => None, + TokenTransfer::Shielding(transfer) => { + Some((&transfer.token, transfer.amount)) + } + TokenTransfer::Unshielding(transfer) => { + Some((&transfer.token, transfer.amount)) + } + } + } +} + /// Adds a Ledger output for the sender and destination for transparent and MASP /// transactions -pub async fn make_ledger_masp_endpoints( +async fn make_ledger_token_transfer_endpoints( tokens: &HashMap, output: &mut Vec, - transfer: &Transfer, + transfer: TokenTransfer<'_>, builder: Option<&MaspBuilder>, assets: &HashMap, ) { - if transfer.source != MASP { - output.push(format!("Sender : {}", transfer.source)); - if transfer.target == MASP { - make_ledger_amount_addr( - tokens, - output, - transfer.amount, - &transfer.token, - "Sending ", - ); + if let Some(source) = transfer.source() { + output.push(format!("Sender : {}", source)); + if let Some((token, amount)) = transfer.token_and_amount() { + make_ledger_amount_addr(tokens, output, amount, token, "Sending "); } } else if let Some(builder) = builder { for sapling_input in builder.builder.sapling_inputs() { @@ -738,14 +773,14 @@ pub async fn make_ledger_masp_endpoints( .await; } } - if transfer.target != MASP { - output.push(format!("Destination : {}", transfer.target)); - if transfer.source == MASP { + if let Some(target) = transfer.target() { + output.push(format!("Destination : {}", target)); + if let Some((token, amount)) = transfer.token_and_amount() { make_ledger_amount_addr( tokens, output, - transfer.amount, - &transfer.token, + amount, + token, "Receiving ", ); } @@ -764,15 +799,6 @@ pub async fn make_ledger_masp_endpoints( .await; } } - if transfer.source != MASP && transfer.target != MASP { - make_ledger_amount_addr( - tokens, - output, - transfer.amount, - &transfer.token, - "", - ); - } } /// Convert decimal numbers into the format used by Ledger. Specifically remove @@ -1248,8 +1274,37 @@ pub async fn to_ledger_vector( HEXLOWER.encode(&extra_code_hash.0) )]); } - } else if code_sec.tag == Some(TX_TRANSFER_WASM.to_string()) { - let transfer = Transfer::try_from_slice( + } else if code_sec.tag == Some(TX_TRANSPARENT_TRANSFER_WASM.to_string()) + { + let transfer = token::TransparentTransfer::try_from_slice( + &tx.data(cmt) + .ok_or_else(|| Error::Other("Invalid Data".to_string()))?, + ) + .map_err(|err| { + Error::from(EncodingError::Conversion(err.to_string())) + })?; + + tv.name = "Transfer_0".to_string(); + + tv.output.push("Type : TransparentTransfer".to_string()); + make_ledger_token_transfer_endpoints( + &tokens, + &mut tv.output, + TokenTransfer::Transparent(&transfer), + None, + &HashMap::default(), + ) + .await; + make_ledger_token_transfer_endpoints( + &tokens, + &mut tv.output_expert, + TokenTransfer::Transparent(&transfer), + None, + &HashMap::default(), + ) + .await; + } else if code_sec.tag == Some(TX_SHIELDED_TRANSFER_WASM.to_string()) { + let transfer = token::ShieldedTransfer::try_from_slice( &tx.data(cmt) .ok_or_else(|| Error::Other("Invalid Data".to_string()))?, ) @@ -1258,43 +1313,134 @@ pub async fn to_ledger_vector( })?; // To facilitate lookups of MASP AssetTypes let mut asset_types = HashMap::new(); - let builder = if let Some(shielded_hash) = transfer.shielded { - tx.sections.iter().find_map(|x| match x { - Section::MaspBuilder(builder) - if builder.target == shielded_hash => - { - for decoded in &builder.asset_types { - match decoded.encode() { - Err(_) => None, - Ok(asset) => { - asset_types.insert(asset, decoded.clone()); - Some(builder) - } - }?; - } - Some(builder) + let builder = tx.sections.iter().find_map(|x| match x { + Section::MaspBuilder(builder) + if builder.target == transfer.section_hash => + { + for decoded in &builder.asset_types { + match decoded.encode() { + Err(_) => None, + Ok(asset) => { + asset_types.insert(asset, decoded.clone()); + Some(builder) + } + }?; } - _ => None, - }) - } else { - None - }; + Some(builder) + } + _ => None, + }); - tv.name = "Transfer_0".to_string(); + tv.name = "ShieldedTransfer_0".to_string(); + + tv.output.push("Type : ShieldedTransfer".to_string()); + make_ledger_token_transfer_endpoints( + &tokens, + &mut tv.output, + TokenTransfer::Shielded, + builder, + &asset_types, + ) + .await; + make_ledger_token_transfer_endpoints( + &tokens, + &mut tv.output_expert, + TokenTransfer::Shielded, + builder, + &asset_types, + ) + .await; + } else if code_sec.tag == Some(TX_SHIELDING_TRANSFER_WASM.to_string()) { + let transfer = token::ShieldingTransfer::try_from_slice( + &tx.data(cmt) + .ok_or_else(|| Error::Other("Invalid Data".to_string()))?, + ) + .map_err(|err| { + Error::from(EncodingError::Conversion(err.to_string())) + })?; + // To facilitate lookups of MASP AssetTypes + let mut asset_types = HashMap::new(); + let builder = tx.sections.iter().find_map(|x| match x { + Section::MaspBuilder(builder) + if builder.target == transfer.shielded_section_hash => + { + for decoded in &builder.asset_types { + match decoded.encode() { + Err(_) => None, + Ok(asset) => { + asset_types.insert(asset, decoded.clone()); + Some(builder) + } + }?; + } + Some(builder) + } + _ => None, + }); + + tv.name = "ShieldingTransfer_0".to_string(); + + tv.output.push("Type : ShieldingTransfer".to_string()); + make_ledger_token_transfer_endpoints( + &tokens, + &mut tv.output, + TokenTransfer::Shielding(&transfer), + builder, + &asset_types, + ) + .await; + make_ledger_token_transfer_endpoints( + &tokens, + &mut tv.output_expert, + TokenTransfer::Shielding(&transfer), + builder, + &asset_types, + ) + .await; + } else if code_sec.tag == Some(TX_UNSHIELDING_TRANSFER_WASM.to_string()) + { + let transfer = token::UnshieldingTransfer::try_from_slice( + &tx.data(cmt) + .ok_or_else(|| Error::Other("Invalid Data".to_string()))?, + ) + .map_err(|err| { + Error::from(EncodingError::Conversion(err.to_string())) + })?; + // To facilitate lookups of MASP AssetTypes + let mut asset_types = HashMap::new(); + let builder = tx.sections.iter().find_map(|x| match x { + Section::MaspBuilder(builder) + if builder.target == transfer.shielded_section_hash => + { + for decoded in &builder.asset_types { + match decoded.encode() { + Err(_) => None, + Ok(asset) => { + asset_types.insert(asset, decoded.clone()); + Some(builder) + } + }?; + } + Some(builder) + } + _ => None, + }); + + tv.name = "UnshieldingTransfer_0".to_string(); - tv.output.push("Type : Transfer".to_string()); - make_ledger_masp_endpoints( + tv.output.push("Type : UnshieldingTransfer".to_string()); + make_ledger_token_transfer_endpoints( &tokens, &mut tv.output, - &transfer, + TokenTransfer::Unshielding(&transfer), builder, &asset_types, ) .await; - make_ledger_masp_endpoints( + make_ledger_token_transfer_endpoints( &tokens, &mut tv.output_expert, - &transfer, + TokenTransfer::Unshielding(&transfer), builder, &asset_types, ) diff --git a/crates/sdk/src/tx.rs b/crates/sdk/src/tx.rs index 3c81abe447..9b7cf111f3 100644 --- a/crates/sdk/src/tx.rs +++ b/crates/sdk/src/tx.rs @@ -35,14 +35,13 @@ use namada_core::ibc::core::channel::types::timeout::TimeoutHeight; use namada_core::ibc::core::client::types::Height as IbcHeight; use namada_core::ibc::core::host::types::identifiers::{ChannelId, PortId}; use namada_core::ibc::primitives::Timestamp as IbcTimestamp; -use namada_core::ibc::{is_nft_trace, MsgNftTransfer, MsgTransfer}; use namada_core::key::{self, *}; use namada_core::masp::{ - AssetData, PaymentAddress, TransferSource, TransferTarget, + AssetData, MaspEpoch, PaymentAddress, TransferSource, TransferTarget, }; +use namada_core::storage; use namada_core::storage::Epoch; use namada_core::time::DateTimeUtc; -use namada_core::{storage, token}; use namada_governance::cli::onchain::{ DefaultProposal, OnChainProposal, PgfFundingProposal, PgfStewardProposal, }; @@ -52,10 +51,12 @@ use namada_governance::storage::proposal::{ }; use namada_governance::storage::vote::ProposalVote; use namada_ibc::storage::{channel_key, ibc_token}; +use namada_ibc::{is_nft_trace, MsgNftTransfer, MsgTransfer}; use namada_proof_of_stake::parameters::{ PosParams, MAX_VALIDATOR_METADATA_LEN, }; use namada_proof_of_stake::types::{CommissionPair, ValidatorState}; +use namada_token as token; use namada_token::storage_key::balance_key; use namada_token::DenominatedAmount; use namada_tx::data::pgf::UpdateStewardCommission; @@ -101,8 +102,14 @@ pub const TX_VOTE_PROPOSAL: &str = "tx_vote_proposal.wasm"; pub const TX_REVEAL_PK: &str = "tx_reveal_pk.wasm"; /// Update validity predicate WASM path pub const TX_UPDATE_ACCOUNT_WASM: &str = "tx_update_account.wasm"; -/// Transfer transaction WASM path -pub const TX_TRANSFER_WASM: &str = "tx_transfer.wasm"; +/// Transparent transfer transaction WASM path +pub const TX_TRANSPARENT_TRANSFER_WASM: &str = "tx_transparent_transfer.wasm"; +/// Shielded transfer transaction WASM path +pub const TX_SHIELDED_TRANSFER_WASM: &str = "tx_shielded_transfer.wasm"; +/// Shielding transfer transaction WASM path +pub const TX_SHIELDING_TRANSFER_WASM: &str = "tx_shielding_transfer.wasm"; +/// Unshielding transfer transaction WASM path +pub const TX_UNSHIELDING_TRANSFER_WASM: &str = "tx_unshielding_transfer.wasm"; /// IBC transaction WASM path pub const TX_IBC_WASM: &str = "tx_ibc.wasm"; /// User validity predicate WASM path @@ -2438,7 +2445,7 @@ pub async fn build_pgf_stewards_proposal( pub async fn build_ibc_transfer( context: &impl Namada, args: &args::TxIbcTransfer, -) -> Result<(Tx, SigningTxData, Option)> { +) -> Result<(Tx, SigningTxData, Option)> { let refund_target = get_refund_target(context, &args.source, &args.refund_target).await?; @@ -2554,14 +2561,13 @@ pub async fn build_ibc_transfer( let transfer = shielded_parts.map(|(shielded_transfer, asset_types)| { let masp_tx_hash = tx.add_masp_tx_section(shielded_transfer.masp_tx.clone()).1; - let transfer = token::Transfer { - source: source.clone(), + let transfer = token::ShieldingTransfer { // The token will be escrowed to IBC address - target: Address::Internal(InternalAddress::Ibc), + source: source.clone(), token: args.token.clone(), amount: validated_amount, // Link the Transfer to the MASP Transaction by hash code - shielded: Some(masp_tx_hash), + shielded_section_hash: masp_tx_hash, }; tx.add_masp_builder(MaspBuilder { asset_types, @@ -2814,62 +2820,54 @@ pub fn build_batch( Ok((batched_tx, signing_data)) } -/// Submit an ordinary transfer -pub async fn build_transfer( +/// Build a transparent transfer +pub async fn build_transparent_transfer( context: &N, - args: &mut args::TxTransfer, -) -> Result<(Tx, SigningTxData, Option)> { - let default_signer = Some(args.source.effective_address()); + args: &mut args::TxTransparentTransfer, +) -> Result<(Tx, SigningTxData)> { + let source = &args.source; + let target = &args.target; + + let default_signer = Some(source.clone()); let signing_data = signing::aux_signing_data( context, &args.tx, - Some(args.source.effective_address()), + Some(source.clone()), default_signer, ) .await?; + // Transparent fee payment let (fee_amount, updated_balance) = - if let TransferSource::ExtendedSpendingKey(_) = args.source { - // MASP fee payment - (validate_fee(context, &args.tx).await?, None) - } else { - // Transparent fee payment - validate_transparent_fee(context, &args.tx, &signing_data.fee_payer) - .await - .map(|(fee_amount, updated_balance)| { - (fee_amount, Some(updated_balance)) - })? - }; - - // TODO(namada#2596): need multiple source/targets here for masp fee payment - // targets or leave the fees on the MASP balance - let source = args.source.effective_address(); - let target = args.target.effective_address(); + validate_transparent_fee(context, &args.tx, &signing_data.fee_payer) + .await + .map(|(fee_amount, updated_balance)| { + (fee_amount, Some(updated_balance)) + })?; // Check that the source address exists on chain source_exists_or_err(source.clone(), args.tx.force, context).await?; // Check that the target address exists on chain target_exists_or_err(target.clone(), args.tx.force, context).await?; - // validate the amount given + // Validate the amount given let validated_amount = validate_amount(context, args.amount, &args.token, args.tx.force) .await?; - // If source is transparent check the balance (MASP balance is checked when - // constructing the shielded part) + // Check the balance of the source if let Some(updated_balance) = updated_balance { - let check_balance = if updated_balance.source == source + let check_balance = if &updated_balance.source == source && updated_balance.token == args.token { CheckBalance::Balance(updated_balance.post_balance) } else { - CheckBalance::Query(balance_key(&args.token, &source)) + CheckBalance::Query(balance_key(&args.token, source)) }; check_balance_too_low_err( &args.token, - &source, + source, validated_amount.amount(), check_balance, args.tx.force, @@ -2878,60 +2876,184 @@ pub async fn build_transfer( .await?; } - let masp_addr = MASP; + // Construct the corresponding transparent Transfer object + let transfer = token::TransparentTransfer { + source: source.clone(), + target: target.clone(), + token: args.token.clone(), + amount: validated_amount, + }; - // If the transaction is shielded, redact the amount and token - // types by setting the transparent value to 0 and token type to a constant. - // This has no side-effect because transaction is to self. - let (transparent_amount, transparent_token) = - if source == masp_addr && target == masp_addr { - // TODO(namada#1677): Refactor me, we shouldn't rely on any specific - // token here. - (token::Amount::zero().into(), context.native_token()) - } else { - (validated_amount, args.token.clone()) - }; + let tx = build_pow_flag( + context, + &args.tx, + args.tx_code_path.clone(), + transfer, + do_nothing, + fee_amount, + &signing_data.fee_payer, + ) + .await?; + Ok((tx, signing_data)) +} + +/// Build a shielded transfer +pub async fn build_shielded_transfer( + context: &N, + args: &mut args::TxShieldedTransfer, +) -> Result<(Tx, SigningTxData)> { + let default_signer = Some(MASP); + let signing_data = signing::aux_signing_data( + context, + &args.tx, + Some(MASP), + default_signer, + ) + .await?; + + // Shielded fee payment + let fee_amount = validate_fee(context, &args.tx).await?; + + // Validate the amount given + let validated_amount = + validate_amount(context, args.amount, &args.token, args.tx.force) + .await?; // TODO(namada#2597): this function should also take another arg as the fees // token and amount let shielded_parts = construct_shielded_parts( context, - &args.source, - &args.target, + &TransferSource::ExtendedSpendingKey(args.source), + &TransferTarget::PaymentAddress(args.target), &args.token, validated_amount, !(args.tx.dry_run || args.tx.dry_run_wrapper), ) - .await?; - let shielded_tx_epoch = shielded_parts.as_ref().map(|trans| trans.0.epoch); + .await? + .expect("Shielded transfer must have shielded parts"); + + let add_shielded_parts = + |tx: &mut Tx, data: &mut token::ShieldedTransfer| { + // Add the MASP Transaction and its Builder to facilitate validation + let ( + ShieldedTransfer { + builder, + masp_tx, + metadata, + epoch: _, + }, + asset_types, + ) = shielded_parts; + // Add a MASP Transaction section to the Tx and get the tx hash + let section_hash = tx.add_masp_tx_section(masp_tx).1; - // Construct the corresponding transparent Transfer object - let transfer = token::Transfer { - source: source.clone(), - target: target.clone(), - token: transparent_token.clone(), - amount: transparent_amount, - // Link the Transfer to the MASP Transaction by hash code - shielded: None, + tx.add_masp_builder(MaspBuilder { + asset_types, + // Store how the Info objects map to Descriptors/Outputs + metadata, + // Store the data that was used to construct the Transaction + builder, + // Link the Builder to the Transaction by hash code + target: section_hash, + }); + + data.section_hash = section_hash; + tracing::debug!("Transfer data {data:?}"); + Ok(()) + }; + + // Construct the tx data with a placeholder shielded section hash + let data = token::ShieldedTransfer { + section_hash: Hash::zero(), }; + let tx = build_pow_flag( + context, + &args.tx, + args.tx_code_path.clone(), + data, + add_shielded_parts, + fee_amount, + &signing_data.fee_payer, + ) + .await?; + Ok((tx, signing_data)) +} - let add_shielded = |tx: &mut Tx, transfer: &mut token::Transfer| { - // Add the MASP Transaction and its Builder to facilitate validation - if let Some(( - ShieldedTransfer { - builder, - masp_tx, - metadata, - epoch: _, - }, - asset_types, - )) = shielded_parts +/// Build a shielding transfer +pub async fn build_shielding_transfer( + context: &N, + args: &mut args::TxShieldingTransfer, +) -> Result<(Tx, SigningTxData, MaspEpoch)> { + let source = &args.source; + let default_signer = Some(source.clone()); + let signing_data = signing::aux_signing_data( + context, + &args.tx, + Some(source.clone()), + default_signer, + ) + .await?; + + // Transparent fee payment + let (fee_amount, updated_balance) = + validate_transparent_fee(context, &args.tx, &signing_data.fee_payer) + .await + .map(|(fee_amount, updated_balance)| { + (fee_amount, Some(updated_balance)) + })?; + + // Validate the amount given + let validated_amount = + validate_amount(context, args.amount, &args.token, args.tx.force) + .await?; + + // Check the balance of the source + if let Some(updated_balance) = updated_balance { + let check_balance = if &updated_balance.source == source + && updated_balance.token == args.token { - // Add a MASP Transaction section to the Tx and get the tx hash - let masp_tx_hash = tx.add_masp_tx_section(masp_tx).1; - transfer.shielded = Some(masp_tx_hash); + CheckBalance::Balance(updated_balance.post_balance) + } else { + CheckBalance::Query(balance_key(&args.token, source)) + }; - tracing::debug!("Transfer data {:?}", transfer); + check_balance_too_low_err( + &args.token, + source, + validated_amount.amount(), + check_balance, + args.tx.force, + context, + ) + .await?; + } + + let shielded_parts = construct_shielded_parts( + context, + &TransferSource::Address(source.clone()), + &TransferTarget::PaymentAddress(args.target), + &args.token, + validated_amount, + !(args.tx.dry_run || args.tx.dry_run_wrapper), + ) + .await? + .expect("Shielding transfer must have shielded parts"); + let shielded_tx_epoch = shielded_parts.0.epoch; + + let add_shielded_parts = + |tx: &mut Tx, data: &mut token::ShieldingTransfer| { + // Add the MASP Transaction and its Builder to facilitate validation + let ( + ShieldedTransfer { + builder, + masp_tx, + metadata, + epoch: _, + }, + asset_types, + ) = shielded_parts; + // Add a MASP Transaction section to the Tx and get the tx hash + let shielded_section_hash = tx.add_masp_tx_section(masp_tx).1; tx.add_masp_builder(MaspBuilder { asset_types, @@ -2940,17 +3062,28 @@ pub async fn build_transfer( // Store the data that was used to construct the Transaction builder, // Link the Builder to the Transaction by hash code - target: masp_tx_hash, + target: shielded_section_hash, }); + + data.shielded_section_hash = shielded_section_hash; + tracing::debug!("Transfer data {data:?}"); + Ok(()) }; - Ok(()) + + // Construct the tx data with a placeholder shielded section hash + let data = token::ShieldingTransfer { + source: source.clone(), + token: args.token.clone(), + amount: validated_amount, + shielded_section_hash: Hash::zero(), }; + let tx = build_pow_flag( context, &args.tx, args.tx_code_path.clone(), - transfer, - add_shielded, + data, + add_shielded_parts, fee_amount, &signing_data.fee_payer, ) @@ -2958,6 +3091,91 @@ pub async fn build_transfer( Ok((tx, signing_data, shielded_tx_epoch)) } +/// Build an unshielding transfer +pub async fn build_unshielding_transfer( + context: &N, + args: &mut args::TxUnshieldingTransfer, +) -> Result<(Tx, SigningTxData)> { + let default_signer = Some(MASP); + let signing_data = signing::aux_signing_data( + context, + &args.tx, + Some(MASP), + default_signer, + ) + .await?; + + // Shielded fee payment + let fee_amount = validate_fee(context, &args.tx).await?; + + // Validate the amount given + let validated_amount = + validate_amount(context, args.amount, &args.token, args.tx.force) + .await?; + + // TODO(namada#2597): this function should also take another arg as the fees + // token and amount + let shielded_parts = construct_shielded_parts( + context, + &TransferSource::ExtendedSpendingKey(args.source), + &TransferTarget::Address(args.target.clone()), + &args.token, + validated_amount, + !(args.tx.dry_run || args.tx.dry_run_wrapper), + ) + .await? + .expect("Shielding transfer must have shielded parts"); + + let add_shielded_parts = + |tx: &mut Tx, data: &mut token::UnshieldingTransfer| { + // Add the MASP Transaction and its Builder to facilitate validation + let ( + ShieldedTransfer { + builder, + masp_tx, + metadata, + epoch: _, + }, + asset_types, + ) = shielded_parts; + // Add a MASP Transaction section to the Tx and get the tx hash + let shielded_section_hash = tx.add_masp_tx_section(masp_tx).1; + + tx.add_masp_builder(MaspBuilder { + asset_types, + // Store how the Info objects map to Descriptors/Outputs + metadata, + // Store the data that was used to construct the Transaction + builder, + // Link the Builder to the Transaction by hash code + target: shielded_section_hash, + }); + + data.shielded_section_hash = shielded_section_hash; + tracing::debug!("Transfer data {data:?}"); + Ok(()) + }; + + // Construct the tx data with a placeholder shielded section hash + let data = token::UnshieldingTransfer { + target: args.target.clone(), + token: args.token.clone(), + amount: validated_amount, + shielded_section_hash: Hash::zero(), + }; + let tx = build_pow_flag( + context, + &args.tx, + args.tx_code_path.clone(), + data, + add_shielded_parts, + fee_amount, + &signing_data.fee_payer, + ) + .await?; + Ok((tx, signing_data)) +} + // Construct the shielded part of the transaction, if any async fn construct_shielded_parts( context: &N, @@ -2987,7 +3205,7 @@ async fn construct_shielded_parts( Err(Build(builder::Error::InsufficientFunds(_))) => { return Err(TxSubmitError::NegativeBalanceAfterTransfer( Box::new(source.effective_address()), - amount.amount().to_string_native(), + amount.to_string(), Box::new(token.clone()), ) .into()); @@ -3259,10 +3477,10 @@ pub async fn build_custom( } /// Generate IBC shielded transfer -pub async fn gen_ibc_shielded_transfer( +pub async fn gen_ibc_shielding_transfer( context: &N, args: args::GenIbcShieldedTransfer, -) -> Result> { +) -> Result> { let source = Address::Internal(InternalAddress::Ibc); let (src_port_id, src_channel_id) = get_ibc_src_port_channel(context, &args.port_id, &args.channel_id) @@ -3317,12 +3535,11 @@ pub async fn gen_ibc_shielded_transfer( if let Some(shielded_transfer) = shielded_transfer { let masp_tx_hash = Section::MaspTx(shielded_transfer.masp_tx.clone()).get_hash(); - let transfer = token::Transfer { + let transfer = token::ShieldingTransfer { source: source.clone(), - target: MASP, token: token.clone(), amount: validated_amount, - shielded: Some(masp_tx_hash), + shielded_section_hash: masp_tx_hash, }; Ok(Some((transfer, shielded_transfer.masp_tx))) } else { diff --git a/crates/sdk/src/wallet/mod.rs b/crates/sdk/src/wallet/mod.rs index 01db64feb8..d071af5ccc 100644 --- a/crates/sdk/src/wallet/mod.rs +++ b/crates/sdk/src/wallet/mod.rs @@ -14,13 +14,15 @@ use std::str::FromStr; use alias::Alias; use bip39::{Language, Mnemonic, MnemonicType, Seed}; use borsh::{BorshDeserialize, BorshSerialize}; -use namada_core::address::Address; +use namada_core::address::{Address, ImplicitAddress}; +use namada_core::arith::checked; use namada_core::collections::{HashMap, HashSet}; -use namada_core::ibc::is_ibc_denom; use namada_core::key::*; use namada_core::masp::{ ExtendedSpendingKey, ExtendedViewingKey, PaymentAddress, }; +use namada_core::time::DateTimeUtc; +use namada_ibc::is_ibc_denom; pub use pre_genesis::gen_key_to_store; use rand::CryptoRng; use rand_core::RngCore; @@ -33,6 +35,8 @@ pub use self::keys::{DecryptionError, StoredKeypair}; pub use self::store::{ConfirmationResponse, ValidatorData, ValidatorKeys}; use crate::wallet::store::{derive_hd_secret_key, derive_hd_spending_key}; +const DISPOSABLE_KEY_LIFETIME_IN_SECONDS: i64 = 5 * 60; // 5 minutes + /// Captures the interactive parts of the wallet's functioning pub trait WalletIo: Sized + Clone { /// Secure random number generator @@ -763,32 +767,53 @@ impl Wallet { &mut self, rng: &mut (impl CryptoRng + RngCore), ) -> common::SecretKey { - // Create the alias - let mut ctr = 1; - let mut alias = format!("disposable_{ctr}"); + #[allow(clippy::disallowed_methods)] + let current_unix_timestamp = DateTimeUtc::now().to_unix_timestamp(); + + let disposable_keys_to_gc = self + .store + .get_public_keys() + .keys() + .filter(|key_alias| { + check_if_disposable_key_and( + key_alias, + |_pkh, key_creation_unix_timestamp| { + let seconds_since_key_creation = checked!( + current_unix_timestamp + - key_creation_unix_timestamp + ) + .expect( + "Key should have been created before the current \ + time instant!", + ); + seconds_since_key_creation + > DISPOSABLE_KEY_LIFETIME_IN_SECONDS + }, + ) + }) + .cloned() + .collect::>(); - while self.store().contains_alias(&Alias::from(&alias)) { - ctr += 1; - alias = format!("disposable_{ctr}"); + for key_alias in disposable_keys_to_gc { + self.store.remove_alias(&key_alias); } - // Generate a disposable keypair to sign the wrapper if requested - // + + let sk = gen_secret_key(SchemeType::Ed25519, rng); + let key_alias = { + let pkh: PublicKeyHash = (&sk.to_public()).into(); + disposable_key_alias(&pkh, current_unix_timestamp) + }; + + println!("Created disposable keypair with alias {key_alias}"); + // TODO(namada#3239): once the wrapper transaction has been applied, // this key can be deleted from wallet (the transaction being // accepted is not enough cause we could end up doing a // rollback) - let (alias, disposable_keypair) = self - .gen_store_secret_key( - SchemeType::Ed25519, - Some(alias), - false, - None, - rng, - ) - .expect("Failed to initialize disposable keypair"); + self.insert_keypair(key_alias, false, sk.clone(), None, None, None) + .expect("Failed to store disposable signing key"); - println!("Created disposable keypair with alias {alias}"); - disposable_keypair + sk } /// Find the stored key by an alias, a public key hash or a public key. @@ -822,6 +847,25 @@ impl Wallet { ) } + /// Find a public key in the wallet from the given implicit address. + pub fn find_public_key_from_implicit_addr( + &self, + implicit_addr: &ImplicitAddress, + ) -> Result { + self.store + .get_public_keys() + .iter() + .find_map(|(_, pubkey)| { + (ImplicitAddress::from(pubkey) == *implicit_addr) + .then(|| pubkey.clone()) + }) + .ok_or_else(|| { + FindKeyError::KeyNotFound( + Address::Implicit(implicit_addr.clone()).to_string(), + ) + }) + } + /// Find the public key by an alias or a public key hash. pub fn find_public_key( &self, @@ -1094,3 +1138,124 @@ impl Wallet { self.store.remove_alias(&alias.into()) } } + +#[inline] +fn disposable_key_alias(pkh: &PublicKeyHash, timestamp: i64) -> String { + format!("disposable-key-{pkh}-created-at-{timestamp}") +} + +#[inline] +fn check_if_disposable_key_and bool>( + key_alias: &Alias, + callback: F, +) -> bool { + let Some((_, rest)) = key_alias.as_ref().split_once("disposable-key-") + else { + return false; + }; + let Some((key_hash_str, timestamp_str)) = rest.split_once("-created-at-") + else { + return false; + }; + let Some(key_hash): Option = + key_hash_str.to_uppercase().parse().ok() + else { + return false; + }; + let Some(timestamp): Option = timestamp_str.parse().ok() else { + return false; + }; + callback(&key_hash, timestamp) +} + +#[cfg(test)] +mod tests { + use namada_core::key::testing::{keypair_1, keypair_2, keypair_3}; + use rand_core::OsRng; + + use super::*; + + #[derive(Clone)] + struct TestWalletUtils; + + impl WalletIo for TestWalletUtils { + type Rng = OsRng; + } + + #[test] + fn test_disposable_key_alias_invalid() { + assert!(!check_if_disposable_key_and( + &Alias::from("bertha"), + |_h, _t| { panic!("Bertha's key is not disposable!") } + )); + } + + #[test] + fn test_disposable_key_alias_parsing() { + let sk = keypair_1(); + + let pkh: PublicKeyHash = (&sk.to_public()).into(); + let timestamp = 12345; + let alias = Alias::from(disposable_key_alias(&pkh, timestamp)); + + assert!(check_if_disposable_key_and(&alias, |h, t| { + assert_eq!(pkh, *h); + assert_eq!(timestamp, t); + true + })); + } + + #[test] + fn test_disposable_keys_are_garbage_collected() { + let mut wallet = Wallet { + utils: TestWalletUtils, + store: Default::default(), + decrypted_key_cache: Default::default(), + decrypted_spendkey_cache: Default::default(), + }; + + #[allow(clippy::disallowed_methods)] + let keys = [ + (keypair_1(), DateTimeUtc::now().to_unix_timestamp()), + // NB: these keys should be deleted + (keypair_2(), 0), + (keypair_3(), 0), + ]; + + for (sk, timestamp) in keys { + let pkh: PublicKeyHash = (&sk.to_public()).into(); + wallet.insert_keypair( + disposable_key_alias(&pkh, timestamp), + true, + sk, + None, + None, + None, + ); + } + + // add a new key - length should be 2 now + let new_key = wallet.gen_disposable_signing_key(&mut OsRng); + assert_eq!(wallet.store.get_public_keys().len(), 2); + + // check that indeed the first keypair was not gc'd + let keypair_1_pk = keypair_1().to_public(); + assert!( + wallet + .store + .get_public_keys() + .values() + .any(|pk| *pk == keypair_1_pk) + ); + + // check that the only other present key is the newly generated sk + let new_key_pk = new_key.to_public(); + assert!( + wallet + .store + .get_public_keys() + .values() + .any(|pk| *pk == new_key_pk) + ); + } +} diff --git a/crates/shielded_token/Cargo.toml b/crates/shielded_token/Cargo.toml index 567ec8a239..c9d7618ab9 100644 --- a/crates/shielded_token/Cargo.toml +++ b/crates/shielded_token/Cargo.toml @@ -23,7 +23,6 @@ namada_core = { path = "../core" } namada_parameters = { path = "../parameters" } namada_storage = { path = "../storage" } namada_trans_token = { path = "../trans_token" } -namada_tx = { path = "../tx" } borsh.workspace = true masp_primitives.workspace = true diff --git a/crates/shielded_token/src/conversion.rs b/crates/shielded_token/src/conversion.rs index 48ce07f42e..7e84957fa9 100644 --- a/crates/shielded_token/src/conversion.rs +++ b/crates/shielded_token/src/conversion.rs @@ -9,7 +9,6 @@ use namada_core::dec::Dec; #[cfg(any(feature = "multicore", test))] use namada_core::hash::Hash; use namada_core::uint::Uint; -use namada_parameters as parameters; use namada_storage::{StorageRead, StorageWrite}; use namada_trans_token::{ get_effective_total_native_supply, read_balance, read_denom, Amount, @@ -93,6 +92,7 @@ where pub fn calculate_masp_rewards( storage: &mut S, token: &Address, + masp_epochs_per_year: u64, ) -> namada_storage::Result<((u128, u128), Denomination)> where S: StorageWrite + StorageRead, @@ -110,10 +110,6 @@ where // total locked amount in the Shielded pool let total_tokens_in_masp = read_balance(storage, token, &masp_addr)?; - let epochs_per_year: u64 = storage - .read(¶meters::storage::get_epochs_per_year_key())? - .expect("epochs per year should properly decode"); - //// Values from the last epoch let last_inflation: Amount = storage .read(&masp_last_inflation_key(token))? @@ -153,7 +149,7 @@ where last_inflation.raw_amount(), kp_gain_nom, kd_gain_nom, - epochs_per_year, + masp_epochs_per_year, target_locked_dec, last_locked_dec, ); @@ -205,7 +201,7 @@ where last_inflation, kp_gain_nom, kd_gain_nom, - epochs_per_year, + masp_epochs_per_year, ); tracing::debug!("Token address: {:?}", token); tracing::debug!("inflation from the pd controller {:?}", inflation); @@ -236,7 +232,6 @@ where Ok(()) } -#[allow(clippy::arithmetic_side_effects)] #[cfg(any(feature = "multicore", test))] /// Update the MASP's allowed conversions pub fn update_allowed_conversions( @@ -254,10 +249,11 @@ where use masp_primitives::merkle_tree::FrozenCommitmentTree; use masp_primitives::sapling::Node; use masp_primitives::transaction::components::I128Sum as MaspAmount; - use namada_core::masp::encode_asset_type; - use namada_core::storage::Epoch; + use namada_core::arith::CheckedAdd; + use namada_core::masp::{encode_asset_type, MaspEpoch}; + use namada_parameters as parameters; use namada_storage::conversion_state::ConversionLeaf; - use namada_storage::{Error, ResultExt}; + use namada_storage::{Error, OptionExt, ResultExt}; use namada_trans_token::storage_key::balance_key; use namada_trans_token::{MaspDigitPos, NATIVE_MAX_DECIMAL_PLACES}; use rayon::iter::{ @@ -297,28 +293,28 @@ where native_token.clone(), NATIVE_MAX_DECIMAL_PLACES.into(), MaspDigitPos::Zero, - Some(Epoch(0)), + Some(MaspEpoch::zero()), ) .into_storage_result()?, encode_asset_type( native_token.clone(), NATIVE_MAX_DECIMAL_PLACES.into(), MaspDigitPos::One, - Some(Epoch(0)), + Some(MaspEpoch::zero()), ) .into_storage_result()?, encode_asset_type( native_token.clone(), NATIVE_MAX_DECIMAL_PLACES.into(), MaspDigitPos::Two, - Some(Epoch(0)), + Some(MaspEpoch::zero()), ) .into_storage_result()?, encode_asset_type( native_token.clone(), NATIVE_MAX_DECIMAL_PLACES.into(), MaspDigitPos::Three, - Some(Epoch(0)), + Some(MaspEpoch::zero()), ) .into_storage_result()?, ]; @@ -332,13 +328,25 @@ where calculate_masp_rewards_precision(storage, &native_token)?.0; // Reward all tokens according to above reward rates - let epoch = storage.get_block_epoch()?; - let prev_epoch = match epoch.prev() { + let masp_epoch_multiplier = + parameters::read_masp_epoch_multiplier_parameter(storage)?; + let masp_epoch = MaspEpoch::try_from_epoch( + storage.get_block_epoch()?, + masp_epoch_multiplier, + ) + .map_err(namada_storage::Error::new_const)?; + let prev_masp_epoch = match masp_epoch.prev() { Some(epoch) => epoch, None => return Ok(()), }; + let epochs_per_year = storage + .read::(¶meters::storage::get_epochs_per_year_key())? + .expect("epochs per year should properly decode"); + let masp_epochs_per_year = + checked!(epochs_per_year / masp_epoch_multiplier)?; for token in &masp_reward_keys { - let (reward, denom) = calculate_masp_rewards(storage, token)?; + let ((reward, precision), denom) = + calculate_masp_rewards(storage, token, masp_epochs_per_year)?; masp_reward_denoms.insert(token.clone(), denom); // Dispense a transparent reward in parallel to the shielded rewards let addr_bal = read_balance(storage, token, &masp_addr)?; @@ -357,25 +365,31 @@ where token.clone(), denom, digit, - Some(prev_epoch), + Some(prev_masp_epoch), + ) + .into_storage_result()?; + let new_asset = encode_asset_type( + token.clone(), + denom, + digit, + Some(masp_epoch), ) .into_storage_result()?; - let new_asset = - encode_asset_type(token.clone(), denom, digit, Some(epoch)) - .into_storage_result()?; if *token == native_token { // The amount that will be given of the new native token for // every amount of the native token given in the // previous epoch - let new_normed_inflation = Uint::from(normed_inflation) - .checked_add( - (Uint::from(normed_inflation) * Uint::from(reward.0)) - / reward.1, - ) - .and_then(|x| x.try_into().ok()) - .unwrap_or_else(|| { + let inflation_uint = Uint::from(normed_inflation); + let reward = Uint::from(reward); + let precision = Uint::from(precision); + let new_normed_inflation = checked!( + inflation_uint + (inflation_uint * reward) / precision + )?; + let new_normed_inflation = u128::try_from(new_normed_inflation) + .unwrap_or_else(|_| { tracing::warn!( - "MASP reward for {} assumed to be 0 because the \ + "MASP inflation for the native token {} is kept \ + the same as in the last epoch because the \ computed value is too large. Please check the \ inflation parameters.", token @@ -386,18 +400,21 @@ where // conversions are added together, the // intermediate native tokens cancel/ // telescope out + let cur_conv = MaspAmount::from_pair( + old_asset, + i128::try_from(normed_inflation) + .ok() + .and_then(i128::checked_neg) + .ok_or_err_msg("Current inflation overflow")?, + ); + let new_conv = MaspAmount::from_pair( + new_asset, + i128::try_from(new_normed_inflation) + .into_storage_result()?, + ); current_convs.insert( (token.clone(), denom, digit), - (MaspAmount::from_pair( - old_asset, - -i128::try_from(normed_inflation) - .into_storage_result()?, - ) + MaspAmount::from_pair( - new_asset, - i128::try_from(new_normed_inflation) - .into_storage_result()?, - )) - .into(), + checked!(cur_conv + &new_conv)?.into(), ); // Operations that happen exactly once for each token if digit == MaspDigitPos::Three { @@ -436,33 +453,39 @@ where // Express the inflation reward in real terms, that is, with // respect to the native asset in the zeroth // epoch - let real_reward = ((Uint::from(reward.0) - * Uint::from(ref_inflation)) - / normed_inflation) - .try_into() - .unwrap_or_else(|_| { - tracing::warn!( - "MASP reward for {} assumed to be 0 because the \ - computed value is too large. Please check the \ - inflation parameters.", - token - ); - 0u128 - }); + let reward_uint = Uint::from(reward); + let ref_inflation_uint = Uint::from(ref_inflation); + let inflation_uint = Uint::from(normed_inflation); + let real_reward = checked!( + (reward_uint * ref_inflation_uint) / inflation_uint + )? + .try_into() + .unwrap_or_else(|_| { + tracing::warn!( + "MASP reward for {} assumed to be 0 because the \ + computed value is too large. Please check the \ + inflation parameters.", + token + ); + 0u128 + }); // The conversion is computed such that if consecutive // conversions are added together, the // intermediate tokens cancel/ telescope out - let reward_i128 = - i128::try_from(reward.1).into_storage_result()?; + let precision_i128 = + i128::try_from(precision).into_storage_result()?; + let real_reward_i128 = + i128::try_from(real_reward).into_storage_result()?; current_convs.insert( (token.clone(), denom, digit), - (MaspAmount::from_pair(old_asset, -reward_i128) - + MaspAmount::from_pair(new_asset, reward_i128) - + MaspAmount::from_pair( - reward_assets[digit as usize], - i128::try_from(real_reward) - .into_storage_result()?, - )) + checked!( + MaspAmount::from_pair(old_asset, -precision_i128) + + &MaspAmount::from_pair(new_asset, precision_i128) + + &MaspAmount::from_pair( + reward_assets[digit as usize], + real_reward_i128, + ) + )? .into(), ); // Operations that happen exactly once for each token @@ -472,7 +495,7 @@ where total_reward = total_reward .checked_add( addr_bal - .u128_eucl_div_rem(reward) + .u128_eucl_div_rem((reward, precision)) .ok_or_else(|| { Error::new_const( "Total reward calculation overflow", @@ -492,7 +515,7 @@ where token: token.clone(), denom, digit_pos: digit, - epoch: prev_epoch, + epoch: prev_masp_epoch, conversion: MaspAmount::zero().into(), leaf_pos: 0, }, @@ -511,9 +534,13 @@ where .enumerate() .collect(); // ceil(assets.len() / num_threads) + + #[allow(clippy::arithmetic_side_effects)] let notes_per_thread_max = (assets.len() + num_threads - 1) / num_threads; // floor(assets.len() / num_threads) + #[allow(clippy::arithmetic_side_effects)] let notes_per_thread_min = assets.len() / num_threads; + // Now on each core, add the latest conversion to each conversion let conv_notes: Vec = assets .into_par_iter() @@ -524,7 +551,10 @@ where let cur_conv_key = (leaf.token.clone(), leaf.denom, leaf.digit_pos); if let Some(current_conv) = current_convs.get(&cur_conv_key) { // Use transitivity to update conversion - leaf.conversion += current_conv.clone(); + #[allow(clippy::arithmetic_side_effects)] + { + leaf.conversion += current_conv.clone(); + } } // Update conversion position to leaf we are about to create leaf.leaf_pos = idx; @@ -546,7 +576,9 @@ where // across multiple cores // Merkle trees must have exactly 2^n leaves to be mergeable let mut notes_per_thread_rounded = 1; + // Cannot overflow + #[allow(clippy::arithmetic_side_effects)] while notes_per_thread_max > notes_per_thread_rounded * 4 { notes_per_thread_rounded *= 2; } @@ -582,7 +614,7 @@ where // Add the decoding entry for the new asset type. An uncommitted // node position is used since this is not a conversion. let new_asset = - encode_asset_type(addr.clone(), denom, digit, Some(epoch)) + encode_asset_type(addr.clone(), denom, digit, Some(masp_epoch)) .into_storage_result()?; let tree_size = storage.conversion_state().tree.size(); storage.conversion_state_mut().assets.insert( @@ -591,7 +623,7 @@ where token: addr.clone(), denom, digit_pos: digit, - epoch, + epoch: masp_epoch, conversion: MaspAmount::zero().into(), leaf_pos: tree_size, }, diff --git a/crates/shielded_token/src/utils.rs b/crates/shielded_token/src/utils.rs index c29c3185c0..3d3240b18d 100644 --- a/crates/shielded_token/src/utils.rs +++ b/crates/shielded_token/src/utils.rs @@ -1,16 +1,11 @@ //! MASP utilities -use std::collections::BTreeSet; - use masp_primitives::merkle_tree::CommitmentTree; use masp_primitives::sapling::Node; use masp_primitives::transaction::Transaction; -use namada_core::storage; use namada_storage::{Error, Result, StorageRead, StorageWrite}; -use crate::storage_key::{ - is_masp_key, masp_commitment_tree_key, masp_nullifier_key, -}; +use crate::storage_key::{masp_commitment_tree_key, masp_nullifier_key}; // Writes the nullifiers of the provided masp transaction to storage fn reveal_nullifiers( @@ -72,11 +67,3 @@ pub fn handle_masp_tx( Ok(()) } - -/// Check if a transaction was a MASP transaction. This means -/// that at least one key owned by MASP was changed. We cannot -/// simply check that the MASP VP was triggered, as this can -/// be manually requested to be triggered by users. -pub fn is_masp_tx(changed_keys: &BTreeSet) -> bool { - changed_keys.iter().any(is_masp_key) -} diff --git a/crates/state/Cargo.toml b/crates/state/Cargo.toml index 69c34303af..56a80b261a 100644 --- a/crates/state/Cargo.toml +++ b/crates/state/Cargo.toml @@ -39,15 +39,11 @@ namada_replay_protection = { path = "../replay_protection" } namada_storage = { path = "../storage" } namada_tx = { path = "../tx" } -arse-merkle-tree.workspace = true borsh.workspace = true -ics23.workspace = true itertools.workspace = true linkme = {workspace = true, optional = true} -sha2.workspace = true smooth-operator.workspace = true thiserror.workspace = true -tiny-keccak.workspace = true tracing.workspace = true patricia_tree.workspace = true proptest = { workspace = true, optional = true } diff --git a/crates/state/src/lib.rs b/crates/state/src/lib.rs index b7ff50f837..f62ab1c862 100644 --- a/crates/state/src/lib.rs +++ b/crates/state/src/lib.rs @@ -758,6 +758,7 @@ mod tests { tx_allowlist: vec![], implicit_vp_code_hash: Some(Hash::zero()), epochs_per_year: 100, + masp_epoch_multiplier: 2, max_signatures_per_transaction: 15, fee_unshielding_gas_limit: 20_000, minimum_gas_price: BTreeMap::default(), diff --git a/crates/state/src/wl_state.rs b/crates/state/src/wl_state.rs index dbf6fac944..b5103ce723 100644 --- a/crates/state/src/wl_state.rs +++ b/crates/state/src/wl_state.rs @@ -5,6 +5,7 @@ use namada_core::address::Address; use namada_core::arith::checked; use namada_core::borsh::BorshSerializeExt; use namada_core::chain::ChainId; +use namada_core::masp::MaspEpoch; use namada_core::storage; use namada_core::time::DateTimeUtc; use namada_events::{EmitEvents, EventToEmit}; @@ -185,9 +186,32 @@ where self.in_mem.block.pred_epochs.new_epoch(height); tracing::info!("Began a new epoch {}", self.in_mem.block.epoch); } + Ok(new_epoch) } + /// Returns `true` if a new masp epoch has begun + pub fn is_masp_new_epoch(&self, is_new_epoch: bool) -> StorageResult { + let masp_epoch_multiplier = + namada_parameters::read_masp_epoch_multiplier_parameter(self)?; + let masp_new_epoch = is_new_epoch + && matches!( + self.in_mem.block.epoch.checked_rem(masp_epoch_multiplier), + Some(Epoch(0)) + ); + + if masp_new_epoch { + let masp_epoch = MaspEpoch::try_from_epoch( + self.in_mem.block.epoch, + masp_epoch_multiplier, + ) + .map_err(namada_storage::Error::new_const)?; + tracing::info!("Began a new masp epoch {masp_epoch}"); + } + + Ok(masp_new_epoch) + } + /// Commit the current block's write log to the storage and commit the block /// to DB. Starts a new block write log. pub fn commit_block(&mut self) -> StorageResult<()> { @@ -1344,3 +1368,27 @@ where Ok(()) } } + +impl namada_tx::action::Read for WlState +where + D: 'static + DB + for<'iter> DBIter<'iter>, + H: 'static + StorageHasher, +{ + type Err = Error; + + fn read_temp( + &self, + key: &storage::Key, + ) -> Result> { + let (log_val, _) = self.write_log().read_temp(key).unwrap(); + match log_val { + Some(value) => { + let value = + namada_core::borsh::BorshDeserialize::try_from_slice(value) + .map_err(Error::BorshCodingError)?; + Ok(Some(value)) + } + None => Ok(None), + } + } +} diff --git a/crates/storage/src/conversion_state.rs b/crates/storage/src/conversion_state.rs index 43ad69037d..3031783c72 100644 --- a/crates/storage/src/conversion_state.rs +++ b/crates/storage/src/conversion_state.rs @@ -4,11 +4,11 @@ use std::collections::BTreeMap; use namada_core::address::Address; use namada_core::borsh::{BorshDeserialize, BorshSerialize}; +use namada_core::masp::MaspEpoch; use namada_core::masp_primitives::asset_type::AssetType; use namada_core::masp_primitives::convert::AllowedConversion; use namada_core::masp_primitives::merkle_tree::FrozenCommitmentTree; use namada_core::masp_primitives::sapling; -use namada_core::storage::Epoch; use namada_core::token::{Denomination, MaspDigitPos}; use namada_macros::BorshDeserializer; #[cfg(feature = "migrations")] @@ -23,8 +23,8 @@ pub struct ConversionLeaf { pub denom: Denomination, /// The digit position covered by this asset type pub digit_pos: MaspDigitPos, - /// The epoch of the asset type - pub epoch: Epoch, + /// The masp epoch of the asset type + pub epoch: MaspEpoch, /// The actual conversion and generator pub conversion: AllowedConversion, /// The position of this leaf in the conversion tree diff --git a/crates/storage/src/db.rs b/crates/storage/src/db.rs index afaec5d230..2483ee850d 100644 --- a/crates/storage/src/db.rs +++ b/crates/storage/src/db.rs @@ -14,6 +14,8 @@ use namada_merkle_tree::{ StoreType, }; use regex::Regex; +use serde::de::DeserializeOwned; +use serde::Serialize; use thiserror::Error; use crate::conversion_state::ConversionState; @@ -122,6 +124,10 @@ pub trait DB: Debug { /// A handle for batch writes type WriteBatch: DBWriteBatch; + /// A type that can apply a key-value + /// change to DB. + type Migrator: DbMigration + DeserializeOwned; + /// Open the database from provided path fn open( db_path: impl AsRef, @@ -147,7 +153,7 @@ pub trait DB: Debug { fn read_block_header(&self, height: BlockHeight) -> Result>; /// Read the merkle tree stores with the given epoch. If a store_type is - /// given, it reads only the the specified tree. Otherwise, it reads all + /// given, it reads only the specified tree. Otherwise, it reads all /// trees. fn read_merkle_tree_stores( &self, @@ -277,6 +283,15 @@ pub trait DB: Debug { key: &Key, new_value: impl AsRef<[u8]>, ) -> Result<()>; + + /// Apply a series of key-value changes + /// to the DB. + fn apply_migration_to_batch( + &self, + _updates: impl IntoIterator, + ) -> Result { + unimplemented!() + } } /// A database prefix iterator. @@ -329,3 +344,8 @@ pub trait DBIter<'iter> { /// Atomic batch write. pub trait DBWriteBatch {} + +/// A type that can apply a key-value change to a DB +pub trait DbMigration: Debug + Clone + Serialize {} + +impl DbMigration for () {} diff --git a/crates/storage/src/mockdb.rs b/crates/storage/src/mockdb.rs index 20432d37ff..1de9122307 100644 --- a/crates/storage/src/mockdb.rs +++ b/crates/storage/src/mockdb.rs @@ -91,6 +91,7 @@ impl MockDB { impl DB for MockDB { /// There is no cache for MockDB type Cache = (); + type Migrator = (); type WriteBatch = MockDBWriteBatch; fn open(_db_path: impl AsRef, _cache: Option<&Self::Cache>) -> Self { diff --git a/crates/tests/Cargo.toml b/crates/tests/Cargo.toml index 75a2fbc0c9..6c76c5d816 100644 --- a/crates/tests/Cargo.toml +++ b/crates/tests/Cargo.toml @@ -37,29 +37,21 @@ namada_sdk = {path = "../sdk", default-features = false, features = ["tendermint namada_test_utils = {path = "../test_utils"} namada_tx_prelude = {path = "../tx_prelude"} namada_vp_prelude = {path = "../vp_prelude"} -async-trait.workspace = true -chrono.workspace = true concat-idents.workspace = true derivative.workspace = true -flate2.workspace = true hyper = {version = "0.14.20", features = ["full"]} ibc-testkit.workspace = true ics23.workspace = true itertools.workspace = true -lazy_static.workspace = true -num-traits.workspace = true proptest.workspace = true prost.workspace = true regex.workspace = true serde.workspace = true serde_json.workspace = true sha2.workspace = true -tar.workspace = true tempfile.workspace = true test-log.workspace = true tokio = {workspace = true, features = ["full"]} -tracing-subscriber.workspace = true -tracing.workspace = true [dev-dependencies] namada_apps_lib = {path = "../apps_lib", features = ["testing"]} @@ -75,11 +67,13 @@ data-encoding.workspace = true escargot = {workspace = true} # , features = ["print"]} expectrl.workspace = true eyre.workspace = true +flate2.workspace = true fs_extra.workspace = true once_cell.workspace = true pretty_assertions.workspace = true proptest-state-machine.workspace = true rand.workspace = true +tar.workspace = true tendermint-light-client.workspace = true test-log.workspace = true toml.workspace = true diff --git a/crates/tests/src/e2e/ibc_tests.rs b/crates/tests/src/e2e/ibc_tests.rs index 8673e865da..4e8dc13a2a 100644 --- a/crates/tests/src/e2e/ibc_tests.rs +++ b/crates/tests/src/e2e/ibc_tests.rs @@ -151,7 +151,16 @@ fn run_ledger_ibc() -> Result<()> { // Transfer 50000 received over IBC on Chain B let token = format!("{port_id_b}/{channel_id_b}/nam"); - transfer_on_chain(&test_b, BERTHA, ALBERT, token, 50000, BERTHA_KEY, true)?; + transfer_on_chain( + &test_b, + "transparent-transfer", + BERTHA, + ALBERT, + token, + 50000, + BERTHA_KEY, + true, + )?; check_balances_after_non_ibc(&port_id_b, &channel_id_b, &test_b)?; // Transfer 50000 back from the origin-specific account on Chain B to Chain @@ -235,7 +244,16 @@ fn run_ledger_ibc_with_hermes() -> Result<()> { // Transfer 50000 received over IBC on Chain B let token = format!("{port_id_b}/{channel_id_b}/nam"); - transfer_on_chain(&test_b, BERTHA, ALBERT, token, 50000, BERTHA_KEY, true)?; + transfer_on_chain( + &test_b, + "transparent-transfer", + BERTHA, + ALBERT, + token, + 50000, + BERTHA_KEY, + true, + )?; check_balances_after_non_ibc(&port_id_b, &channel_id_b, &test_b)?; // Transfer 50000 back from the origin-specific account on Chain B to Chain @@ -265,6 +283,7 @@ fn run_ledger_ibc_with_hermes() -> Result<()> { // Send a token to the shielded address on Chain A transfer_on_chain( &test_a, + "shield", ALBERT, AA_PAYMENT_ADDRESS, BTC, @@ -474,6 +493,7 @@ fn ibc_namada_gaia() -> Result<()> { // Shielded transfer on Namada transfer_on_chain( &test, + "transfer", A_SPENDING_KEY, AB_PAYMENT_ADDRESS, &ibc_denom, @@ -546,6 +566,7 @@ fn pgf_over_ibc_with_hermes() -> Result<()> { // Transfer to PGF account transfer_on_chain( &test_a, + "transparent-transfer", ALBERT, PGF_ADDRESS.to_string(), NAM, @@ -590,10 +611,13 @@ fn pgf_over_ibc_with_hermes() -> Result<()> { #[test] fn proposal_ibc_token_inflation() -> Result<()> { + const MASP_EPOCH_MULTIPLIER: u64 = 2; let update_genesis = |mut genesis: templates::All, base_dir: &_| { genesis.parameters.parameters.epochs_per_year = epochs_per_year_from_min_duration(60); + genesis.parameters.parameters.masp_epoch_multiplier = + MASP_EPOCH_MULTIPLIER; genesis.parameters.gov_params.min_proposal_grace_epochs = 3; genesis.parameters.ibc_params.default_mint_limit = Amount::max_signed(); @@ -659,8 +683,8 @@ fn proposal_ibc_token_inflation() -> Result<()> { )?; wait_for_packet_relay(&port_id_a, &channel_id_a, &test_a)?; - // wait the next epoch to dispense the rewrad - wait_epochs(&test_b, 1)?; + // wait the next masp epoch to dispense the reward + wait_epochs(&test_b, MASP_EPOCH_MULTIPLIER)?; // Check balances check_inflated_balance(&test_b)?; @@ -1659,8 +1683,10 @@ fn try_invalid_transfers( Ok(()) } +#[allow(clippy::too_many_arguments)] fn transfer_on_chain( test: &Test, + kind: impl AsRef, sender: impl AsRef, receiver: impl AsRef, token: impl AsRef, @@ -1672,7 +1698,7 @@ fn transfer_on_chain( let rpc = get_actor_rpc(test, Who::Validator(0)); let amount = amount.to_string(); let mut tx_args = vec![ - "transfer", + kind.as_ref(), "--source", sender.as_ref(), "--target", diff --git a/crates/tests/src/e2e/ledger_tests.rs b/crates/tests/src/e2e/ledger_tests.rs index e0a69364e9..792d700029 100644 --- a/crates/tests/src/e2e/ledger_tests.rs +++ b/crates/tests/src/e2e/ledger_tests.rs @@ -168,7 +168,7 @@ fn test_node_connectivity_and_consensus() -> Result<()> { // 3. Submit a valid token transfer tx let tx_args = [ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", @@ -852,7 +852,7 @@ fn pos_init_validator() -> Result<()> { // 3. Submit a delegation to the new validator First, transfer some tokens // to the validator's key for fees: let tx_args = vec![ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", @@ -892,7 +892,7 @@ fn pos_init_validator() -> Result<()> { // 4. Transfer some NAM to the new validator let validator_stake_str = &validator_stake.to_string_native(); let tx_args = vec![ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", @@ -994,7 +994,7 @@ fn ledger_many_txs_in_a_block() -> Result<()> { // A token transfer tx args let tx_args = Arc::new(vec![ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", @@ -1223,7 +1223,7 @@ fn double_signing_gets_slashed() -> Result<()> { // 5. Submit a valid token transfer tx to validator 0 let validator_one_rpc = get_actor_rpc(&test, Who::Validator(0)); let tx_args = [ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", @@ -2264,7 +2264,7 @@ fn rollback() -> Result<()> { // send a few transactions let txs_args = vec![vec![ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", diff --git a/crates/tests/src/integration/ledger_tests.rs b/crates/tests/src/integration/ledger_tests.rs index 40816bdf67..214ab32a1d 100644 --- a/crates/tests/src/integration/ledger_tests.rs +++ b/crates/tests/src/integration/ledger_tests.rs @@ -2,18 +2,24 @@ use std::collections::BTreeSet; use std::str::FromStr; use assert_matches::assert_matches; +use borsh::BorshDeserialize; use borsh_ext::BorshSerializeExt; use color_eyre::eyre::Result; use data_encoding::HEXLOWER; +use namada::account::AccountPublicKeysMap; use namada::core::collections::HashMap; -use namada::token; -use namada_apps_lib::wallet::defaults; +use namada::token::{self, Amount, DenominatedAmount}; +use namada_apps_lib::wallet::defaults::{self, albert_keypair}; use namada_core::dec::Dec; -use namada_core::storage::Epoch; +use namada_core::hash::Hash; +use namada_core::storage::{DbColFam, Epoch, Key}; use namada_core::token::NATIVE_MAX_DECIMAL_PLACES; use namada_node::shell::testing::client::run; +use namada_node::shell::testing::node::NodeResults; use namada_node::shell::testing::utils::{Bin, CapturedOutput}; -use namada_sdk::tx::{TX_TRANSFER_WASM, VP_USER_WASM}; +use namada_sdk::migrations; +use namada_sdk::queries::RPC; +use namada_sdk::tx::{TX_TRANSPARENT_TRANSFER_WASM, VP_USER_WASM}; use namada_test_utils::TestWasms; use test_log::test; @@ -53,7 +59,7 @@ fn ledger_txs_and_queries() -> Result<()> { let validator_one_rpc = "http://127.0.0.1:26567"; let (node, _services) = setup::setup()?; - let transfer = token::Transfer { + let transfer = token::TransparentTransfer { source: defaults::bertha_address(), target: defaults::albert_address(), token: node.native_token(), @@ -61,7 +67,6 @@ fn ledger_txs_and_queries() -> Result<()> { token::Amount::native_whole(10), token::NATIVE_MAX_DECIMAL_PLACES.into(), ), - shielded: None, } .serialize_to_vec(); let tx_data_path = node.test_dir.path().join("tx.data"); @@ -74,7 +79,7 @@ fn ledger_txs_and_queries() -> Result<()> { let txs_args = vec![ // 2. Submit a token transfer tx (from an established account) vec![ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", @@ -90,7 +95,7 @@ fn ledger_txs_and_queries() -> Result<()> { ], // Submit a token transfer tx (from an ed25519 implicit account) vec![ - "transfer", + "transparent-transfer", "--source", DAEWON, "--target", @@ -106,7 +111,7 @@ fn ledger_txs_and_queries() -> Result<()> { ], // Submit a token transfer tx (from a secp256k1 implicit account) vec![ - "transfer", + "transparent-transfer", "--source", ESTER, "--target", @@ -135,7 +140,7 @@ fn ledger_txs_and_queries() -> Result<()> { vec![ "tx", "--code-path", - TX_TRANSFER_WASM, + TX_TRANSPARENT_TRANSFER_WASM, "--data-path", &tx_data_path, "--owner", @@ -352,7 +357,7 @@ fn invalid_transactions() -> Result<()> { // 2. Submit an invalid transaction (trying to transfer tokens should fail // in the user's VP due to the wrong signer) let tx_args = vec![ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", @@ -381,7 +386,7 @@ fn invalid_transactions() -> Result<()> { let daewon_lower = DAEWON.to_lowercase(); let tx_args = vec![ - "transfer", + "transparent-transfer", "--source", DAEWON, "--signing-keys", @@ -970,7 +975,7 @@ fn proposal_submission() -> Result<()> { // vp and verify that the transaction succeeds, i.e. the non allowlisted // vp can still run let transfer = vec![ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", @@ -1381,7 +1386,7 @@ fn implicit_account_reveal_pk() -> Result<()> { // A token transfer tx Box::new(|source| { [ - "transfer", + "transparent-transfer", "--source", source, "--target", @@ -1438,7 +1443,7 @@ fn implicit_account_reveal_pk() -> Result<()> { let tx_args = tx_args(&key_alias); // 2b. Send some funds to the implicit account. let credit_args = vec![ - "transfer", + "transparent-transfer", "--source", BERTHA, "--target", @@ -1578,3 +1583,295 @@ fn change_validator_metadata() -> Result<()> { Ok(()) } + +// Test that fee payment is enforced and aligned with process proposal. The test +// generates a tx that subtract funds from the fee payer of a following tx. Test +// that wrappers (and fee payments) are evaluated before the inner transactions. +#[test] +fn enforce_fee_payment() -> Result<()> { + // This address doesn't matter for tests. But an argument is required. + let validator_one_rpc = "http://127.0.0.1:26567"; + // 1. start the ledger node + let (node, _services) = setup::setup()?; + + let tempdir = tempfile::tempdir().unwrap(); + let mut txs_bytes = vec![]; + + let captured = CapturedOutput::of(|| { + run( + &node, + Bin::Client, + vec![ + "balance", + "--owner", + ALBERT_KEY, + "--token", + NAM, + "--node", + validator_one_rpc, + ], + ) + }); + assert!(captured.result.is_ok()); + assert!(captured.contains("nam: 2000000")); + + run( + &node, + Bin::Client, + vec![ + "transparent-transfer", + "--source", + ALBERT_KEY, + "--target", + BERTHA, + "--token", + NAM, + "--amount", + // We want this transaction to consume all the remaining available + // balance. If we executed the inner txs right after the + // corresponding wrapper's fee payment this would succeed (but + // this is not the case) + "1900000", + "--output-folder-path", + tempdir.path().to_str().unwrap(), + "--dump-tx", + "--ledger-address", + validator_one_rpc, + ], + )?; + node.assert_success(); + let file_path = tempdir + .path() + .read_dir() + .unwrap() + .next() + .unwrap() + .unwrap() + .path(); + txs_bytes.push(std::fs::read(&file_path).unwrap()); + std::fs::remove_file(&file_path).unwrap(); + + run( + &node, + Bin::Client, + vec![ + "transparent-transfer", + "--source", + ALBERT_KEY, + "--target", + CHRISTEL, + "--token", + NAM, + "--amount", + "50", + "--gas-payer", + ALBERT_KEY, + "--output-folder-path", + tempdir.path().to_str().unwrap(), + "--dump-tx", + "--ledger-address", + validator_one_rpc, + ], + )?; + node.assert_success(); + let file_path = tempdir + .path() + .read_dir() + .unwrap() + .next() + .unwrap() + .unwrap() + .path(); + txs_bytes.push(std::fs::read(&file_path).unwrap()); + std::fs::remove_file(&file_path).unwrap(); + + let sk = albert_keypair(); + let pk = sk.to_public(); + + let native_token = node + .shell + .lock() + .unwrap() + .state + .in_mem() + .native_token + .clone(); + + let mut txs = vec![]; + for bytes in txs_bytes { + let mut tx = namada::tx::Tx::deserialize(&bytes).unwrap(); + tx.add_wrapper( + namada::tx::data::wrapper::Fee { + amount_per_gas_unit: DenominatedAmount::native( + Amount::native_whole(1), + ), + token: native_token.clone(), + }, + pk.clone(), + 100_000.into(), + ); + tx.sign_raw(vec![sk.clone()], AccountPublicKeysMap::default(), None); + tx.sign_wrapper(sk.clone()); + + txs.push(tx.to_bytes()); + } + + node.clear_results(); + node.submit_txs(txs); + { + let results = node.results.lock().unwrap(); + // If empty than failed in process proposal + assert!(!results.is_empty()); + + for result in results.iter() { + assert!(matches!(result, NodeResults::Ok)); + } + } + // Finalize the next block to execute the txs + node.clear_results(); + node.finalize_and_commit(); + { + let results = node.results.lock().unwrap(); + for result in results.iter() { + assert!(matches!(result, NodeResults::Ok)); + } + } + + // Assert balances + let captured = CapturedOutput::of(|| { + run( + &node, + Bin::Client, + vec![ + "balance", + "--owner", + ALBERT_KEY, + "--token", + NAM, + "--node", + validator_one_rpc, + ], + ) + }); + assert!(captured.result.is_ok()); + // This is the result of the two fee payemnts and the successful transfer to + // Christel + assert!(captured.contains("nam: 1799950")); + + let captured = CapturedOutput::of(|| { + run( + &node, + Bin::Client, + vec![ + "balance", + "--owner", + BERTHA, + "--token", + NAM, + "--node", + validator_one_rpc, + ], + ) + }); + assert!(captured.result.is_ok()); + // Bertha must not receive anything because the transaction fails. This is + // because we evaluate fee payments before the inner transactions, so by the + // time we execute the transfer, Albert doesn't have enough funds anynmore + assert!(captured.contains("nam: 2000000")); + + let captured = CapturedOutput::of(|| { + run( + &node, + Bin::Client, + vec![ + "balance", + "--owner", + CHRISTEL, + "--token", + NAM, + "--node", + validator_one_rpc, + ], + ) + }); + assert!(captured.result.is_ok()); + assert!(captured.contains("nam: 2000050")); + Ok(()) +} + +/// Test that a scheduled migration actually makes changes +/// to storage at the scheduled height. +#[test] +fn scheduled_migration() -> Result<()> { + let (node, _services) = setup::setup()?; + + // schedule a migration + let (hash, migrations_file) = make_migration_json(); + let scheduled_migration = migrations::ScheduledMigration::from_path( + migrations_file.path(), + hash, + 5.into(), + ) + .expect("Test failed"); + { + let mut locked = node.shell.lock().unwrap(); + locked.scheduled_migration = Some(scheduled_migration); + } + + while node.block_height().0 != 4 { + node.finalize_and_commit() + } + // check that the key doesn't exist before the scheduled block + let rt = tokio::runtime::Runtime::new().unwrap(); + let bytes = rt + .block_on(RPC.shell().storage_value( + &&node, + None, + None, + false, + &Key::parse("bing/fucking/bong").expect("Test failed"), + )) + .expect("Test failed") + .data; + assert!(bytes.is_empty()); + + // check that the key now exists and has the expected value + node.finalize_and_commit(); + let rt = tokio::runtime::Runtime::new().unwrap(); + let bytes = rt + .block_on(RPC.shell().storage_value( + &&node, + None, + None, + false, + &Key::parse("bing/fucking/bong").expect("Test failed"), + )) + .expect("Test failed") + .data; + let amount = Amount::try_from_slice(&bytes).expect("Test failed"); + assert_eq!(amount, Amount::native_whole(1337)); + + // check that no migration is scheduled + { + let locked = node.shell.lock().unwrap(); + assert!(locked.scheduled_migration.is_none()); + } + Ok(()) +} + +fn make_migration_json() -> (Hash, tempfile::NamedTempFile) { + let file = tempfile::Builder::new().tempfile().expect("Test failed"); + let updates = [migrations::DbUpdateType::Add { + key: Key::parse("bing/fucking/bong").expect("Test failed"), + cf: DbColFam::SUBSPACE, + value: Amount::native_whole(1337).into(), + force: false, + }]; + let changes = migrations::DbChanges { + changes: updates.into_iter().collect(), + }; + let json = serde_json::to_string(&changes).expect("Test failed"); + let hash = Hash::sha256(json.as_bytes()); + std::fs::write(file.path(), json).expect("Test failed"); + (hash, file) +} diff --git a/crates/tests/src/integration/masp.rs b/crates/tests/src/integration/masp.rs index 4912e3624a..5f7f6dfd1b 100644 --- a/crates/tests/src/integration/masp.rs +++ b/crates/tests/src/integration/masp.rs @@ -37,13 +37,13 @@ fn masp_incentives() -> Result<()> { // not invalidated. let (mut node, _services) = setup::setup()?; // Wait till epoch boundary - node.next_epoch(); + node.next_masp_epoch(); // Send 1 BTC from Albert to PA run( &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT, "--target", @@ -112,7 +112,7 @@ fn masp_incentives() -> Result<()> { assert!(captured.contains("nam: 0")); // Wait till epoch boundary - node.next_epoch(); + node.next_masp_epoch(); // sync the shielded context run( @@ -159,7 +159,7 @@ fn masp_incentives() -> Result<()> { }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 0.031")); + assert!(captured.contains("nam: 0.063")); // Assert NAM balance at MASP pool is exclusively the // rewards from the shielded BTC @@ -179,10 +179,10 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 0.031")); + assert!(captured.contains("nam: 0.063")); // Wait till epoch boundary - node.next_epoch(); + node.next_masp_epoch(); // sync the shielded context run( @@ -229,7 +229,7 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 0.09292")); + assert!(captured.contains("nam: 0.18887")); // Assert NAM balance at MASP pool is exclusively the // rewards from the shielded BTC @@ -249,17 +249,17 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 0.09331")); + assert!(captured.contains("nam: 0.18963")); // Wait till epoch boundary - node.next_epoch(); + node.next_masp_epoch(); // Send 0.001 ETH from Albert to PA(B) run( &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT, "--target", @@ -321,7 +321,7 @@ fn masp_incentives() -> Result<()> { assert!(captured.contains("nam: 0")); // Wait till epoch boundary - node.next_epoch(); + node.next_masp_epoch(); // sync the shielded context run( @@ -368,7 +368,7 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 0.362747")); + assert!(captured.contains("nam: 0.725514")); // Assert NAM balance at MASP pool is an accumulation of // rewards from both the shielded BTC and shielded ETH @@ -388,16 +388,16 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 0.674354")); + assert!(captured.contains("nam: 1.358764")); // Wait till epoch boundary - node.next_epoch(); + node.next_masp_epoch(); // Send 0.001 ETH from SK(B) to Christel run( &node, Bin::Client, vec![ - "transfer", + "unshield", "--source", B_SPENDING_KEY, "--target", @@ -441,7 +441,7 @@ fn masp_incentives() -> Result<()> { assert!(captured.result.is_ok()); assert!(captured.contains("eth: 0")); - node.next_epoch(); + node.next_masp_epoch(); // sync the shielded context run( &node, @@ -468,9 +468,9 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 0.725855")); + assert!(captured.contains("nam: 1.451732")); - node.next_epoch(); + node.next_masp_epoch(); // sync the shielded context run( &node, @@ -497,17 +497,17 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 1.595775")); + assert!(captured.contains("nam: 3.219616")); // Wait till epoch boundary - node.next_epoch(); + node.next_masp_epoch(); // Send 1 BTC from SK(A) to Christel run( &node, Bin::Client, vec![ - "transfer", + "unshield", "--source", A_SPENDING_KEY, "--target", @@ -568,7 +568,7 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 1.113911")); + assert!(captured.contains("nam: 2.268662")); // Assert NAM balance at MASP pool is // the accumulation of rewards from the shielded assets (BTC and ETH) @@ -588,10 +588,10 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 1.843775")); + assert!(captured.contains("nam: 3.723616")); // Wait till epoch boundary - node.next_epoch(); + node.next_masp_epoch(); // sync the shielded context run( &node, @@ -619,7 +619,7 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 1.113911")); + assert!(captured.contains("nam: 2.268662")); // Assert NAM balance at VK(B) is the rewards dispensed earlier // (since VK(A) has no shielded assets, no further rewards should @@ -640,7 +640,7 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 0.725855")); + assert!(captured.contains("nam: 1.451732")); // Assert NAM balance at MASP pool is // the accumulation of rewards from the shielded assets (BTC and ETH) @@ -660,11 +660,11 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 1.843775")); + assert!(captured.contains("nam: 3.723616")); // Wait till epoch boundary to prevent conversion expiry during transaction // construction - node.next_epoch(); + node.next_masp_epoch(); // sync the shielded context run( &node, @@ -677,7 +677,7 @@ fn masp_incentives() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "unshield", "--source", B_SPENDING_KEY, "--target", @@ -685,7 +685,7 @@ fn masp_incentives() -> Result<()> { "--token", NAM, "--amount", - "0.725855", + "1.451732", "--signing-keys", BERTHA_KEY, "--node", @@ -695,7 +695,7 @@ fn masp_incentives() -> Result<()> { node.assert_success(); // Wait till epoch boundary - node.next_epoch(); + node.next_masp_epoch(); // sync the shielded context run( &node, @@ -708,7 +708,7 @@ fn masp_incentives() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "unshield", "--source", A_SPENDING_KEY, "--target", @@ -716,7 +716,7 @@ fn masp_incentives() -> Result<()> { "--token", NAM, "--amount", - "1.113911", + "2.268662", "--signing-keys", ALBERT_KEY, "--node", @@ -795,7 +795,7 @@ fn masp_incentives() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 0.004009")); + assert!(captured.contains("nam: 0.003222")); Ok(()) } @@ -824,7 +824,7 @@ fn spend_unconverted_asset_type() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT, "--target", @@ -845,7 +845,7 @@ fn spend_unconverted_asset_type() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT, "--target", @@ -993,7 +993,7 @@ fn masp_txs_and_queries() -> Result<()> { // 1. Attempt to spend 15 BTC at SK(A) to Bertha ( vec![ - "transfer", + "unshield", "--source", A_SPENDING_KEY, "--target", @@ -1012,7 +1012,7 @@ fn masp_txs_and_queries() -> Result<()> { // 2. Send 20 BTC from Albert to PA(A) ( vec![ - "transfer", + "shield", "--source", ALBERT, "--target", @@ -1163,7 +1163,7 @@ fn masp_txs_and_queries() -> Result<()> { // 11. Send 20 BTC from SK(B) to Bertha ( vec![ - "transfer", + "unshield", "--source", B_SPENDING_KEY, "--target", @@ -1184,7 +1184,10 @@ fn masp_txs_and_queries() -> Result<()> { for (tx_args, tx_result) in &txs_args { node.assert_success(); // there is no need to dry run balance queries - let dry_run_args = if tx_args[0] == "transfer" { + let dry_run_args = if tx_args[0] == "transfer" + || tx_args[0] == "shield" + || tx_args[0] == "unshield" + { // We ensure transfers don't cross epoch boundaries. node.next_epoch(); vec![true, false] @@ -1198,7 +1201,7 @@ fn masp_txs_and_queries() -> Result<()> { Bin::Client, vec!["shielded-sync", "--node", validator_one_rpc], )?; - let tx_args = if dry_run && tx_args[0] == "transfer" { + let tx_args = if dry_run { [tx_args.clone(), vec!["--dry-run"]].concat() } else { tx_args.clone() @@ -1314,7 +1317,7 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT_KEY, "--target", @@ -1333,7 +1336,7 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT_KEY, "--target", @@ -1352,7 +1355,7 @@ fn multiple_unfetched_txs_same_block() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT_KEY, "--target", @@ -1548,7 +1551,7 @@ fn cross_epoch_unshield() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT, "--target", @@ -1583,7 +1586,7 @@ fn cross_epoch_unshield() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "unshield", "--source", A_SPENDING_KEY, "--target", @@ -1683,13 +1686,13 @@ fn dynamic_assets() -> Result<()> { )?; node.assert_success(); // Wait till epoch boundary - node.next_epoch(); + node.next_masp_epoch(); // Send 1 BTC from Albert to PA run( &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT, "--target", @@ -1770,7 +1773,7 @@ fn dynamic_assets() -> Result<()> { } // Wait till epoch boundary - node.next_epoch(); + node.next_masp_epoch(); // sync the shielded context run( &node, @@ -1823,7 +1826,7 @@ fn dynamic_assets() -> Result<()> { &node, Bin::Client, vec![ - "transfer", + "shield", "--source", ALBERT, "--target", @@ -1884,7 +1887,7 @@ fn dynamic_assets() -> Result<()> { assert!(captured.contains("nam: 0")); // Wait till epoch boundary - node.next_epoch(); + node.next_masp_epoch(); // sync the shielded context run( &node, @@ -1910,7 +1913,7 @@ fn dynamic_assets() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 0.0303")); + assert!(captured.contains("nam: 0.06262")); // Assert BTC balance at VK(A) is still 2 let captured = CapturedOutput::of(|| { @@ -1945,7 +1948,7 @@ fn dynamic_assets() -> Result<()> { } // Wait till epoch boundary - node.next_epoch(); + node.next_masp_epoch(); // sync the shielded context run( &node, @@ -1990,7 +1993,7 @@ fn dynamic_assets() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 0.07575")); + assert!(captured.contains("nam: 0.15655")); { // Stop decoding and distributing shielded rewards for BTC in next epoch @@ -2012,7 +2015,7 @@ fn dynamic_assets() -> Result<()> { } // Wait till epoch boundary - node.next_epoch(); + node.next_masp_epoch(); // sync the shielded context run( &node, @@ -2057,10 +2060,10 @@ fn dynamic_assets() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 0.07575")); + assert!(captured.contains("nam: 0.15655")); // Wait till epoch boundary - node.next_epoch(); + node.next_masp_epoch(); // sync the shielded context run( &node, @@ -2104,7 +2107,7 @@ fn dynamic_assets() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 0.07575")); + assert!(captured.contains("nam: 0.15655")); { // Start distributing shielded rewards for NAM in next epoch @@ -2120,7 +2123,7 @@ fn dynamic_assets() -> Result<()> { } // Wait till epoch boundary - node.next_epoch(); + node.next_masp_epoch(); // sync the shielded context run( &node, @@ -2164,7 +2167,7 @@ fn dynamic_assets() -> Result<()> { ) }); assert!(captured.result.is_ok()); - assert!(captured.contains("nam: 0.075825")); + assert!(captured.contains("nam: 0.156705")); Ok(()) } diff --git a/crates/tests/src/integration/setup.rs b/crates/tests/src/integration/setup.rs index 448ef59c08..441273e71e 100644 --- a/crates/tests/src/integration/setup.rs +++ b/crates/tests/src/integration/setup.rs @@ -211,6 +211,7 @@ fn create_node( shell_handlers.tx_broadcaster, shell_handlers.eth_oracle_channels, None, + None, 50 * 1024 * 1024, // 50 kiB 50 * 1024 * 1024, // 50 kiB ))), diff --git a/crates/tests/src/vm_host_env/tx.rs b/crates/tests/src/vm_host_env/tx.rs index f6f0ff580f..594391024d 100644 --- a/crates/tests/src/vm_host_env/tx.rs +++ b/crates/tests/src/vm_host_env/tx.rs @@ -354,7 +354,7 @@ mod native_tx_host_env { batched_tx, }: &mut TestTxEnv| { - let tx_env = vm::host_env::testing::tx_env( + let mut tx_env = vm::host_env::testing::tx_env( state, iterators, verifiers, @@ -371,7 +371,7 @@ mod native_tx_host_env { // Call the `host_env` function and unwrap any // runtime errors - $fn( &tx_env, $($arg),* ).unwrap() + $fn( &mut tx_env, $($arg),* ).unwrap() }) } }); @@ -398,7 +398,7 @@ mod native_tx_host_env { batched_tx }: &mut TestTxEnv| { - let tx_env = vm::host_env::testing::tx_env( + let mut tx_env = vm::host_env::testing::tx_env( state, iterators, verifiers, @@ -415,7 +415,7 @@ mod native_tx_host_env { // Call the `host_env` function and unwrap any // runtime errors - $fn( &tx_env, $($arg),* ).unwrap() + $fn( &mut tx_env, $($arg),* ).unwrap() }) } }); @@ -442,7 +442,7 @@ mod native_tx_host_env { batched_tx, }: &mut TestTxEnv| { - let tx_env = vm::host_env::testing::tx_env( + let mut tx_env = vm::host_env::testing::tx_env( state, iterators, verifiers, @@ -458,7 +458,7 @@ mod native_tx_host_env { ); // Call the `host_env` function - $fn( &tx_env, $($arg),* ) + $fn( &mut tx_env, $($arg),* ) }) } }); @@ -582,13 +582,18 @@ mod tests { // dbg!(&setup); let mut test_env = TestTxEnv::default(); - let tx_env = setup_host_env(&setup, &mut test_env); + let mut tx_env = setup_host_env(&setup, &mut test_env); // Can fail, but must not panic - let _res = - host_env::tx_read(&tx_env, setup.key_memory_ptr, setup.key_len()); - let _res = - host_env::tx_result_buffer(&tx_env, setup.read_buffer_memory_ptr); + let _res = host_env::tx_read( + &mut tx_env, + setup.key_memory_ptr, + setup.key_len(), + ); + let _res = host_env::tx_result_buffer( + &mut tx_env, + setup.read_buffer_memory_ptr, + ); } proptest! { @@ -603,10 +608,10 @@ mod tests { fn test_tx_charge_gas_cannot_panic_aux(setup: TestSetup, gas: u64) { let mut test_env = TestTxEnv::default(); - let tx_env = setup_host_env(&setup, &mut test_env); + let mut tx_env = setup_host_env(&setup, &mut test_env); // Can fail, but must not panic - let _res = host_env::tx_charge_gas(&tx_env, gas); + let _res = host_env::tx_charge_gas(&mut tx_env, gas); } proptest! { @@ -622,11 +627,11 @@ mod tests { // dbg!(&setup); let mut test_env = TestTxEnv::default(); - let tx_env = setup_host_env(&setup, &mut test_env); + let mut tx_env = setup_host_env(&setup, &mut test_env); // Can fail, but must not panic let _res = host_env::tx_has_key( - &tx_env, + &mut tx_env, setup.key_memory_ptr, setup.key_len(), ); @@ -645,18 +650,18 @@ mod tests { // dbg!(&setup); let mut test_env = TestTxEnv::default(); - let tx_env = setup_host_env(&setup, &mut test_env); + let mut tx_env = setup_host_env(&setup, &mut test_env); // Can fail, but must not panic let _res = host_env::tx_write( - &tx_env, + &mut tx_env, setup.key_memory_ptr, setup.key_len(), setup.val_memory_ptr, setup.val_len(), ); let _res = host_env::tx_write_temp( - &tx_env, + &mut tx_env, setup.key_memory_ptr, setup.key_len(), setup.val_memory_ptr, @@ -677,11 +682,14 @@ mod tests { // dbg!(&setup); let mut test_env = TestTxEnv::default(); - let tx_env = setup_host_env(&setup, &mut test_env); + let mut tx_env = setup_host_env(&setup, &mut test_env); // Can fail, but must not panic - let _res = - host_env::tx_delete(&tx_env, setup.key_memory_ptr, setup.key_len()); + let _res = host_env::tx_delete( + &mut tx_env, + setup.key_memory_ptr, + setup.key_len(), + ); } proptest! { @@ -697,16 +705,16 @@ mod tests { // dbg!(&setup); let mut test_env = TestTxEnv::default(); - let tx_env = setup_host_env(&setup, &mut test_env); + let mut tx_env = setup_host_env(&setup, &mut test_env); // Can fail, but must not panic let _res = host_env::tx_iter_prefix( - &tx_env, + &mut tx_env, setup.key_memory_ptr, setup.key_len(), ); let _res = host_env::tx_iter_next( - &tx_env, + &mut tx_env, // This field is not used for anything else in this test setup.val_memory_ptr, ); @@ -751,7 +759,7 @@ mod tests { batched_tx, } = test_env; - let tx_env = vm::host_env::testing::tx_env_with_wasm_memory( + let mut tx_env = vm::host_env::testing::tx_env_with_wasm_memory( state, iterators, verifiers, diff --git a/crates/tests/src/vm_host_env/vp.rs b/crates/tests/src/vm_host_env/vp.rs index 4444310a39..10a7bda496 100644 --- a/crates/tests/src/vm_host_env/vp.rs +++ b/crates/tests/src/vm_host_env/vp.rs @@ -267,7 +267,7 @@ mod native_vp_host_env { vp_cache_dir: _, }: &mut TestVpEnv| { - let env = vm::host_env::testing::vp_env( + let mut env = vm::host_env::testing::vp_env( addr, state, iterators, @@ -285,7 +285,7 @@ mod native_vp_host_env { // Call the `host_env` function and unwrap any // runtime errors - $fn( &env, $($arg),* ).unwrap() + $fn( &mut env, $($arg),* ).unwrap() }) } }); @@ -312,7 +312,7 @@ mod native_vp_host_env { vp_cache_dir: _, }: &mut TestVpEnv| { - let env = vm::host_env::testing::vp_env( + let mut env = vm::host_env::testing::vp_env( addr, state, iterators, @@ -330,7 +330,7 @@ mod native_vp_host_env { // Call the `host_env` function and unwrap any // runtime errors - $fn( &env, $($arg),* ).unwrap() + $fn( &mut env, $($arg),* ).unwrap() }) } }); diff --git a/crates/token/Cargo.toml b/crates/token/Cargo.toml index b06ab6086d..d944683801 100644 --- a/crates/token/Cargo.toml +++ b/crates/token/Cargo.toml @@ -15,14 +15,21 @@ version.workspace = true [features] default = [] multicore = ["namada_shielded_token/multicore"] -testing = ["namada_core/testing"] +testing = ["namada_core/testing", "proptest"] [dependencies] namada_core = { path = "../core" } namada_events = { path = "../events", default-features = false } +namada_macros = { path = "../macros" } namada_shielded_token = { path = "../shielded_token" } namada_storage = { path = "../storage" } namada_trans_token = { path = "../trans_token" } +borsh.workspace = true +proptest = { workspace = true, optional = true } +serde.workspace = true + [dev-dependencies] namada_core = { path = "../core", features = ["testing"] } + +proptest.workspace = true diff --git a/crates/token/src/lib.rs b/crates/token/src/lib.rs index 2ce15898a5..c14d93f430 100644 --- a/crates/token/src/lib.rs +++ b/crates/token/src/lib.rs @@ -18,8 +18,12 @@ clippy::print_stderr )] +use namada_core::borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; +use namada_core::hash::Hash; +use namada_macros::BorshDeserializer; pub use namada_shielded_token::*; pub use namada_trans_token::*; +use serde::{Deserialize, Serialize}; /// Token storage keys pub mod storage_key { @@ -28,8 +32,6 @@ pub mod storage_key { } use namada_core::address::Address; -#[cfg(any(test, feature = "testing"))] -pub use namada_core::token::testing; use namada_events::EmitEvents; use namada_storage::{Result, StorageRead, StorageWrite}; @@ -54,13 +56,144 @@ where pub fn finalize_block( storage: &mut S, _events: &mut impl EmitEvents, - is_new_epoch: bool, + is_new_masp_epoch: bool, ) -> Result<()> where S: StorageWrite + StorageRead + WithConversionState, { - if is_new_epoch { + if is_new_masp_epoch { conversion::update_allowed_conversions(storage)?; } Ok(()) } + +/// Arguments for a transparent token transfer +#[derive( + Debug, + Clone, + PartialEq, + BorshSerialize, + BorshDeserialize, + BorshDeserializer, + BorshSchema, + Hash, + Eq, + PartialOrd, + Serialize, + Deserialize, +)] +pub struct TransparentTransfer { + /// Source address will spend the tokens + pub source: Address, + /// Target address will receive the tokens + pub target: Address, + /// Token's address + pub token: Address, + /// The amount of tokens + pub amount: DenominatedAmount, +} + +/// Arguments for a shielded token transfer +#[derive( + Debug, + Clone, + PartialEq, + BorshSerialize, + BorshDeserialize, + BorshDeserializer, + BorshSchema, + Hash, + Eq, + PartialOrd, + Serialize, + Deserialize, +)] +pub struct ShieldedTransfer { + /// Hash of tx section that contains the MASP transaction + pub section_hash: Hash, +} + +/// Arguments for a shielding transfer (from a transparent token to a shielded +/// token) +#[derive( + Debug, + Clone, + PartialEq, + BorshSerialize, + BorshDeserialize, + BorshDeserializer, + BorshSchema, + Hash, + Eq, + PartialOrd, + Serialize, + Deserialize, +)] +pub struct ShieldingTransfer { + /// Source address will spend the tokens + pub source: Address, + /// Token's address + pub token: Address, + /// The amount of tokens + pub amount: DenominatedAmount, + /// Hash of tx section that contains the MASP transaction + pub shielded_section_hash: Hash, +} + +/// Arguments for an unshielding transfer (from a shielded token to a +/// transparent token) +#[derive( + Debug, + Clone, + PartialEq, + BorshSerialize, + BorshDeserialize, + BorshDeserializer, + BorshSchema, + Hash, + Eq, + PartialOrd, + Serialize, + Deserialize, +)] +pub struct UnshieldingTransfer { + /// Target address will receive the tokens + pub target: Address, + /// Token's address + pub token: Address, + /// The amount of tokens + pub amount: DenominatedAmount, + /// Hash of tx section that contains the MASP transaction + pub shielded_section_hash: Hash, +} + +#[cfg(any(test, feature = "testing"))] +/// Testing helpers and strategies for tokens +pub mod testing { + use namada_core::address::testing::{ + arb_established_address, arb_non_internal_address, + }; + use namada_core::address::Address; + pub use namada_core::token::*; + pub use namada_trans_token::testing::*; + use proptest::prelude::*; + + use super::TransparentTransfer; + + prop_compose! { + /// Generate a transparent transfer + pub fn arb_transparent_transfer()( + source in arb_non_internal_address(), + target in arb_non_internal_address(), + token in arb_established_address().prop_map(Address::Established), + amount in arb_denominated_amount(), + ) -> TransparentTransfer { + TransparentTransfer { + source, + target, + token, + amount, + } + } + } +} diff --git a/crates/trans_token/src/storage_key.rs b/crates/trans_token/src/storage_key.rs index c282696750..79200d9890 100644 --- a/crates/trans_token/src/storage_key.rs +++ b/crates/trans_token/src/storage_key.rs @@ -73,6 +73,14 @@ pub fn minted_balance_key(token_addr: &Address) -> storage::Key { .expect("Cannot obtain a storage key") } +/// Check if a key is part of the multitoken vp sub storage +pub fn is_multitoken_key(key: &storage::Key) -> bool { + match key.fst_address() { + Some(addr) => addr.eq(&Address::Internal(InternalAddress::Multitoken)), + None => false, + } +} + /// Check if the given storage key is a balance key for the given token. If it /// is, return the owner. For minted balances, use /// [`is_any_minted_balance_key()`]. diff --git a/crates/tx/src/action.rs b/crates/tx/src/action.rs index c61575305f..6748e181aa 100644 --- a/crates/tx/src/action.rs +++ b/crates/tx/src/action.rs @@ -8,6 +8,7 @@ use std::fmt; use namada_core::address::Address; use namada_core::borsh::{BorshDeserialize, BorshSerialize}; +use namada_core::hash::Hash; use namada_core::storage::KeySeg; use namada_core::{address, storage}; @@ -25,6 +26,7 @@ pub enum Action { Pos(PosAction), Gov(GovAction), Pgf(PgfAction), + Masp(MaspAction), } /// PoS tx actions. @@ -61,6 +63,13 @@ pub enum PgfAction { UpdateStewardCommission(Address), } +/// MASP tx action. +#[derive(Clone, Debug, BorshDeserialize, BorshSerialize)] +pub struct MaspAction { + /// The hash of the masp [`crate::types::Section`] + pub masp_section_ref: Hash, +} + /// Read actions from temporary storage pub trait Read { /// Storage access errors @@ -108,3 +117,19 @@ fn storage_key() -> storage::Key { .push(&TX_ACTIONS_KEY.to_owned()) .expect("Cannot obtain a storage key") } + +/// Helper function to get the optional masp section reference from the +/// [`Actions`]. If more than one [`MaspAction`] has been found we return the +/// first one +pub fn get_masp_section_ref( + reader: &T, +) -> Result, ::Err> { + Ok(reader.read_actions()?.into_iter().find_map(|action| { + // In case of multiple masp actions we get the first one + if let Action::Masp(MaspAction { masp_section_ref }) = action { + Some(masp_section_ref) + } else { + None + } + })) +} diff --git a/crates/tx/src/data/mod.rs b/crates/tx/src/data/mod.rs index 24dc596c80..20c4019fc2 100644 --- a/crates/tx/src/data/mod.rs +++ b/crates/tx/src/data/mod.rs @@ -21,6 +21,7 @@ use namada_core::borsh::{ BorshDeserialize, BorshSchema, BorshSerialize, BorshSerializeExt, }; use namada_core::hash::Hash; +use namada_core::masp::MaspTxRefs; use namada_core::storage; use namada_events::Event; use namada_gas::{Gas, VpsGas}; @@ -238,6 +239,24 @@ impl<'de, T: Deserialize<'de>> serde::Deserialize<'de> for BatchResults { } } +/// The extended transaction result, containing the references to masp +/// sections (if any) +pub struct ExtendedTxResult { + /// The transaction result + pub tx_result: TxResult, + /// The optional references to masp sections + pub masp_tx_refs: MaspTxRefs, +} + +impl Default for ExtendedTxResult { + fn default() -> Self { + Self { + tx_result: Default::default(), + masp_tx_refs: Default::default(), + } + } +} + /// Transaction application result // TODO derive BorshSchema after #[derive( @@ -279,6 +298,17 @@ impl TxResult { batch_results: BatchResults(batch_results), } } + + /// Converts this result to [`ExtendedTxResult`] + pub fn to_extended_result( + self, + masp_tx_refs: Option, + ) -> ExtendedTxResult { + ExtendedTxResult { + tx_result: self, + masp_tx_refs: masp_tx_refs.unwrap_or_default(), + } + } } #[cfg(feature = "migrations")] diff --git a/crates/tx/src/data/protocol.rs b/crates/tx/src/data/protocol.rs index 33995d8a81..fd994cb47c 100644 --- a/crates/tx/src/data/protocol.rs +++ b/crates/tx/src/data/protocol.rs @@ -56,6 +56,7 @@ impl ProtocolTx { } #[derive( + Copy, Clone, Debug, BorshSerialize, @@ -66,7 +67,6 @@ impl ProtocolTx { Deserialize, PartialEq, )] -#[allow(clippy::large_enum_variant)] /// Types of protocol messages to be sent pub enum ProtocolTxType { /// Ethereum events contained in vote extensions that diff --git a/crates/tx/src/types.rs b/crates/tx/src/types.rs index c1fe7e99ab..3156b584d5 100644 --- a/crates/tx/src/types.rs +++ b/crates/tx/src/types.rs @@ -1730,9 +1730,8 @@ impl<'tx> Tx { } } -/// Represents the pointers of an indexed tx, which are the block height, the -/// index inside that block and the commitment inside the tx bundle (if inner -/// tx) +/// Represents the pointers to a indexed tx, which are the block height and the +/// index inside that block #[derive( Debug, Clone, @@ -1750,8 +1749,6 @@ pub struct IndexedTx { pub height: BlockHeight, /// The index in the block of the tx pub index: TxIndex, - /// This is a pointer to the inner tx inside the batch - pub inner_tx: TxCommitments, } impl Default for IndexedTx { @@ -1759,7 +1756,6 @@ impl Default for IndexedTx { Self { height: BlockHeight::first(), index: TxIndex(0), - inner_tx: TxCommitments::default(), } } } diff --git a/crates/tx_prelude/Cargo.toml b/crates/tx_prelude/Cargo.toml index 58c57ba5bf..83f5423f69 100644 --- a/crates/tx_prelude/Cargo.toml +++ b/crates/tx_prelude/Cargo.toml @@ -33,8 +33,6 @@ namada_vm_env = { path = "../vm_env" } borsh.workspace = true masp_primitives.workspace = true -sha2.workspace = true -thiserror.workspace = true [dev-dependencies] namada_token = { path = "../token", features = ["testing"] } diff --git a/crates/tx_prelude/src/ibc.rs b/crates/tx_prelude/src/ibc.rs index a52f10038e..678e27ccf8 100644 --- a/crates/tx_prelude/src/ibc.rs +++ b/crates/tx_prelude/src/ibc.rs @@ -6,10 +6,10 @@ use std::rc::Rc; use namada_core::address::Address; use namada_core::token::Amount; -use namada_events::EventTypeBuilder; pub use namada_ibc::event::{IbcEvent, IbcEventType}; pub use namada_ibc::storage::{ - burn_tokens, ibc_token, is_ibc_key, mint_tokens, + burn_tokens, ibc_token, is_ibc_key, mint_limit_key, mint_tokens, + throughput_limit_key, }; pub use namada_ibc::{ IbcActions, IbcCommonContext, IbcStorageContext, NftTransferModule, @@ -42,20 +42,6 @@ impl IbcStorageContext for Ctx { ::emit_event(self, event) } - fn get_ibc_events( - &self, - event_type: impl AsRef, - ) -> Result, Error> { - let event_type = EventTypeBuilder::new_of::() - .with_segment(event_type.as_ref()) - .build(); - - Ok(::get_events(self, &event_type)? - .into_iter() - .filter_map(|event| IbcEvent::try_from(event).ok()) - .collect()) - } - fn transfer_token( &mut self, src: &Address, diff --git a/crates/tx_prelude/src/lib.rs b/crates/tx_prelude/src/lib.rs index eb0f6a3be9..3b737c8157 100644 --- a/crates/tx_prelude/src/lib.rs +++ b/crates/tx_prelude/src/lib.rs @@ -37,7 +37,7 @@ use namada_core::storage::TxIndex; pub use namada_core::storage::{ self, BlockHash, BlockHeight, Epoch, Header, BLOCK_HASH_LENGTH, }; -pub use namada_core::{encode, eth_bridge_pool, *}; +pub use namada_core::{address, encode, eth_bridge_pool, *}; use namada_events::{EmitEvents, Event, EventToEmit, EventType}; pub use namada_governance::storage as gov_storage; pub use namada_macros::transaction; diff --git a/crates/tx_prelude/src/token.rs b/crates/tx_prelude/src/token.rs index b30954aa1c..ab9ecaf571 100644 --- a/crates/tx_prelude/src/token.rs +++ b/crates/tx_prelude/src/token.rs @@ -5,13 +5,14 @@ use namada_events::{EmitEvents, EventLevel}; #[cfg(any(test, feature = "testing"))] pub use namada_token::testing; pub use namada_token::{ - storage_key, utils, Amount, DenominatedAmount, Transfer, + storage_key, utils, Amount, DenominatedAmount, ShieldedTransfer, + ShieldingTransfer, TransparentTransfer, UnshieldingTransfer, }; use namada_tx_env::TxEnv; use crate::{Ctx, TxResult}; -/// A token transfer that can be used in a transaction. +/// A transparent token transfer that can be used in a transaction. pub fn transfer( ctx: &mut Ctx, src: &Address, diff --git a/crates/vp_env/Cargo.toml b/crates/vp_env/Cargo.toml index 29045213aa..e21b44ab11 100644 --- a/crates/vp_env/Cargo.toml +++ b/crates/vp_env/Cargo.toml @@ -22,4 +22,3 @@ namada_ibc = { path = "../ibc" } derivative.workspace = true masp_primitives.workspace = true smooth-operator.workspace = true -thiserror.workspace = true diff --git a/crates/vp_env/src/lib.rs b/crates/vp_env/src/lib.rs index 0ab1815e9b..9ef6144bbe 100644 --- a/crates/vp_env/src/lib.rs +++ b/crates/vp_env/src/lib.rs @@ -20,12 +20,10 @@ pub mod collection_validation; -use masp_primitives::transaction::Transaction; use namada_core::address::Address; use namada_core::borsh::BorshDeserialize; use namada_core::hash::Hash; use namada_core::storage::{BlockHeight, Epoch, Epochs, Header, Key, TxIndex}; -use namada_core::token::Transfer; use namada_events::{Event, EventType}; use namada_ibc::{decode_message, IbcMessage}; use namada_storage::{OptionExt, StorageRead}; @@ -126,40 +124,12 @@ where fn get_shielded_action( &self, batched_tx: &BatchedTxRef<'_>, - ) -> Result<(Transaction, Vec), namada_storage::Error> { + ) -> Result, namada_storage::Error> { let data = batched_tx .tx .data(batched_tx.cmt) .ok_or_err_msg("No transaction data")?; - let mut msgs = vec![]; - let transfer = match Transfer::try_from_slice(&data) { - Ok(transfer) => Some(transfer), - Err(_) => { - let msg = decode_message(&data).map_err(|_| { - namada_storage::Error::new_const("Unknown IBC message") - })?; - msgs.push(msg.clone()); - match msg { - IbcMessage::Transfer(msg) => msg.transfer, - IbcMessage::NftTransfer(msg) => msg.transfer, - IbcMessage::RecvPacket(msg) => msg.transfer, - IbcMessage::AckPacket(msg) => msg.transfer, - IbcMessage::Timeout(msg) => msg.transfer, - IbcMessage::Envelope(_) => None, - } - } - }; - - let shielded_hash = transfer - .ok_or_err_msg("Missing transfer")? - .shielded - .ok_or_err_msg("unable to find shielded hash")?; - let masp_tx = batched_tx - .tx - .get_section(&shielded_hash) - .and_then(|x| x.as_ref().masp_tx()) - .ok_or_err_msg("unable to find shielded section")?; - Ok((masp_tx, msgs)) + Ok(decode_message(&data).into_iter().collect()) } /// Charge the provided gas for the current vp diff --git a/crates/vp_prelude/Cargo.toml b/crates/vp_prelude/Cargo.toml index a06c529d6a..e1275442c7 100644 --- a/crates/vp_prelude/Cargo.toml +++ b/crates/vp_prelude/Cargo.toml @@ -32,4 +32,3 @@ namada_vp_env = { path = "../vp_env" } borsh.workspace = true sha2.workspace = true -thiserror.workspace = true diff --git a/examples/Cargo.toml b/examples/Cargo.toml index a95700f17a..1720015a94 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -28,6 +28,7 @@ path = "make-db-migration.rs" namada-eth-bridge = ["namada_sdk/namada-eth-bridge"] [dev-dependencies] +masp_primitives = { workspace = true, features = ["transparent-inputs"] } masp_proofs = { workspace = true, default-features = false, features = ["local-prover", "download-params"] } namada_apps_lib = {path = "../crates/apps_lib", features = ["migrations"]} namada_macros = {path = "../crates/macros"} @@ -42,6 +43,3 @@ data-encoding.workspace = true proptest.workspace = true serde_json.workspace = true tokio = {workspace = true, default-features = false} - -[dependencies] -regex.workspace = true diff --git a/examples/tx_schema.rs b/examples/tx_schema.rs index e3d678eefe..1fcf24e162 100644 --- a/examples/tx_schema.rs +++ b/examples/tx_schema.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use std::error::Error; +use masp_primitives::transaction::components::sapling::builder::StoredBuildParams; use namada_sdk::borsh::BorshSchema; use namada_sdk::tx::Tx; @@ -12,6 +13,7 @@ fn main() -> Result<(), Box> { } let mut definitions = BTreeMap::new(); Tx::add_definitions_recursively(&mut definitions); + StoredBuildParams::add_definitions_recursively(&mut definitions); std::fs::write(&args[1], format!("{:#?}", definitions)) .expect("unable to save schema"); Ok(()) diff --git a/genesis/localnet/parameters.toml b/genesis/localnet/parameters.toml index e9d6d83de1..bef2c1ae2d 100644 --- a/genesis/localnet/parameters.toml +++ b/genesis/localnet/parameters.toml @@ -18,6 +18,8 @@ tx_allowlist = [] implicit_vp = "vp_implicit" # Expected number of epochs per year (also sets the min duration of an epoch in seconds) epochs_per_year = 31_536_000 +# The multiplier for masp epochs +masp_epoch_multiplier = 2 # Maximum number of signature per transaction max_signatures_per_transaction = 15 # Max gas for block diff --git a/genesis/starter/parameters.toml b/genesis/starter/parameters.toml index 200c1c8fbe..dfb01522d6 100644 --- a/genesis/starter/parameters.toml +++ b/genesis/starter/parameters.toml @@ -18,6 +18,8 @@ tx_allowlist = [] implicit_vp = "vp_implicit" # Expected number of epochs per year (also sets the min duration of an epoch in seconds) epochs_per_year = 31_536_000 +# The multiplier for masp epochs +masp_epoch_multiplier = 2 # Maximum number of signature per transaction max_signatures_per_transaction = 15 # Max gas for block diff --git a/scripts/get_hermes.sh b/scripts/get_hermes.sh index 54c0a5a183..70ac00bf0a 100755 --- a/scripts/get_hermes.sh +++ b/scripts/get_hermes.sh @@ -2,9 +2,9 @@ set -Eo pipefail -HERMES_MAJORMINOR="1.7" -HERMES_PATCH="4" -HERMES_SUFFIX="-namada-beta7" +HERMES_MAJORMINOR="1.8" +HERMES_PATCH="2" +HERMES_SUFFIX="-namada-beta11-rc2" HERMES_REPO="https://github.com/heliaxdev/hermes" diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index 7b8d4ebacf..268cf628e2 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -43,7 +43,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cipher", "cpufeatures", ] @@ -54,7 +54,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "once_cell", "version_check", ] @@ -301,10 +301,10 @@ checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", - "object 0.32.1", + "object", "rustc-demangle", ] @@ -484,7 +484,7 @@ dependencies = [ "arrayref", "arrayvec", "cc", - "cfg-if 1.0.0", + "cfg-if", "constant_time_eq", ] @@ -661,6 +661,15 @@ dependencies = [ "serde", ] +[[package]] +name = "bytesize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" +dependencies = [ + "serde", +] + [[package]] name = "camino" version = "1.1.6" @@ -711,12 +720,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -735,7 +738,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cipher", "cpufeatures", ] @@ -854,13 +857,19 @@ dependencies = [ "syn 2.0.52", ] +[[package]] +name = "const-default" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" + [[package]] name = "const-hex" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5104de16b218eddf8e34ffe2f86f74bfa4e61e95a1b89732fccf6325efd0557" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "hex", "proptest", @@ -908,7 +917,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80128832c58ea9cbd041d2a759ec449224487b2c1e400453d99d244eead87a8e" dependencies = [ "autocfg", - "cfg-if 1.0.0", + "cfg-if", "libc", "scopeguard", "windows-sys 0.33.0", @@ -994,56 +1003,74 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.82.3" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38faa2a16616c8e78a18d37b4726b98bfd2de192f2fdc8a39ddf568a408a0f75" +checksum = "2a2ab4512dfd3a6f4be184403a195f76e81a8a9f9e6c898e19d2dc3ce20e0115" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.82.3" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26f192472a3ba23860afd07d2b0217dc628f21fcc72617aa1336d98e1671f33b" +checksum = "98b022ed2a5913a38839dfbafe6cf135342661293b08049843362df4301261dc" dependencies = [ + "arrayvec", + "bumpalo", "cranelift-bforest", "cranelift-codegen-meta", "cranelift-codegen-shared", + "cranelift-egraph", "cranelift-entity", + "cranelift-isle", "gimli 0.26.2", "log", - "regalloc", + "regalloc2", "smallvec", "target-lexicon", ] [[package]] name = "cranelift-codegen-meta" -version = "0.82.3" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32ddb89e9b89d3d9b36a5b7d7ea3261c98235a76ac95ba46826b8ec40b1a24" +checksum = "639307b45434ad112a98f8300c0f0ab085cbefcd767efcdef9ef19d4c0756e74" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.82.3" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01fd0d9f288cc1b42d9333b7a776b17e278fc888c28e6a0f09b5573d45a150bc" +checksum = "278e52e29c53fcf32431ef08406c295699a70306d05a0715c5b1bf50e33a9ab7" + +[[package]] +name = "cranelift-egraph" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624b54323b06e675293939311943ba82d323bb340468ce1889be5da7932c8d73" +dependencies = [ + "cranelift-entity", + "fxhash", + "hashbrown 0.12.3", + "indexmap 1.9.3", + "log", + "smallvec", +] [[package]] name = "cranelift-entity" -version = "0.82.3" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3bfe172b83167604601faf9dc60453e0d0a93415b57a9c4d1a7ae6849185cf" +checksum = "9a59bcbca89c3f1b70b93ab3cbba5e5e0cbf3e63dadb23c7525cb142e21a9d4c" [[package]] name = "cranelift-frontend" -version = "0.82.3" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a006e3e32d80ce0e4ba7f1f9ddf66066d052a8c884a110b91d05404d6ce26dce" +checksum = "0d70abacb8cfef3dc8ff7e8836e9c1d70f7967dfdac824a4cd5e30223415aca6" dependencies = [ "cranelift-codegen", "log", @@ -1051,13 +1078,19 @@ dependencies = [ "target-lexicon", ] +[[package]] +name = "cranelift-isle" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "393bc73c451830ff8dbb3a07f61843d6cb41a084f9996319917c0b291ed785bb" + [[package]] name = "crc32fast" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1066,7 +1099,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] @@ -1078,12 +1111,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", - "memoffset 0.9.0", + "memoffset", "scopeguard", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.19" @@ -1180,14 +1222,38 @@ dependencies = [ "serde", ] +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + [[package]] name = "darling" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.3", + "darling_macro 0.20.3", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", ] [[package]] @@ -1203,17 +1269,41 @@ dependencies = [ "syn 2.0.52", ] +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", +] + [[package]] name = "darling_macro" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ - "darling_core", + "darling_core 0.20.3", "quote", "syn 2.0.52", ] +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.3", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "data-encoding" version = "2.5.0" @@ -1256,6 +1346,37 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling 0.14.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -1319,6 +1440,15 @@ dependencies = [ "syn 2.0.52", ] +[[package]] +name = "document-features" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95" +dependencies = [ + "litrs", +] + [[package]] name = "dunce" version = "1.0.4" @@ -1368,7 +1498,7 @@ checksum = "64fba5a42bd76a17cad4bfa00de168ee1cbfa06a5e8ce992ae880218c05641a9" dependencies = [ "byteorder", "dynasm", - "memmap2", + "memmap2 0.5.10", ] [[package]] @@ -1458,7 +1588,7 @@ version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1514,7 +1644,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" dependencies = [ - "darling", + "darling 0.20.3", "proc-macro2", "quote", "syn 2.0.52", @@ -1877,7 +2007,7 @@ version = "3.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "rustix", "windows-sys 0.48.0", ] @@ -1899,7 +2029,7 @@ version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", "windows-sys 0.52.0", @@ -2118,7 +2248,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "wasi 0.9.0+wasi-snapshot-preview1", @@ -2127,11 +2257,11 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -2211,7 +2341,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.11", - "indexmap 2.1.0", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -2219,13 +2349,10 @@ dependencies = [ ] [[package]] -name = "hashbrown" -version = "0.11.2" +name = "half" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash", -] +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "hashbrown" @@ -3087,20 +3214,21 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +version = "2.2.4" +source = "git+https://github.com/heliaxdev/indexmap?tag=2.2.4-heliax-1#b5b5b547bd6ab04bbb16e060326a50ddaeb6c909" dependencies = [ + "borsh 1.4.0", "equivalent", "hashbrown 0.14.3", + "serde", ] [[package]] name = "indexmap" -version = "2.2.4" -source = "git+https://github.com/heliaxdev/indexmap?tag=2.2.4-heliax-1#b5b5b547bd6ab04bbb16e060326a50ddaeb6c909" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ - "borsh 1.4.0", "equivalent", "hashbrown 0.14.3", "serde", @@ -3141,7 +3269,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -3226,7 +3354,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "ecdsa", "elliptic-curve", "once_cell", @@ -3282,16 +3410,6 @@ version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if 1.0.0", - "winapi", -] - [[package]] name = "libm" version = "0.2.8" @@ -3335,6 +3453,12 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + [[package]] name = "lock_api" version = "0.4.11" @@ -3351,27 +3475,6 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" -[[package]] -name = "loupe" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6a72dfa44fe15b5e76b94307eeb2ff995a8c5b283b55008940c02e0c5b634d" -dependencies = [ - "indexmap 1.9.3", - "loupe-derive", - "rustversion", -] - -[[package]] -name = "loupe-derive" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fbfc88337168279f2e9ae06e157cfed4efd3316e14dc96ed074d4f2e6c5952" -dependencies = [ - "quote", - "syn 1.0.109", -] - [[package]] name = "mach" version = "0.3.2" @@ -3384,7 +3487,7 @@ dependencies = [ [[package]] name = "masp_note_encryption" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=3aacc707c5948e7423589ac617305448bead9842#3aacc707c5948e7423589ac617305448bead9842" +source = "git+https://github.com/anoma/masp?rev=4ede1c42d76d6348af8224bc8bfac4404321fe82#4ede1c42d76d6348af8224bc8bfac4404321fe82" dependencies = [ "borsh 1.4.0", "chacha20", @@ -3397,7 +3500,7 @@ dependencies = [ [[package]] name = "masp_primitives" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=3aacc707c5948e7423589ac617305448bead9842#3aacc707c5948e7423589ac617305448bead9842" +source = "git+https://github.com/anoma/masp?rev=4ede1c42d76d6348af8224bc8bfac4404321fe82#4ede1c42d76d6348af8224bc8bfac4404321fe82" dependencies = [ "aes", "bip0039", @@ -3429,13 +3532,13 @@ dependencies = [ [[package]] name = "masp_proofs" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=3aacc707c5948e7423589ac617305448bead9842#3aacc707c5948e7423589ac617305448bead9842" +source = "git+https://github.com/anoma/masp?rev=4ede1c42d76d6348af8224bc8bfac4404321fe82#4ede1c42d76d6348af8224bc8bfac4404321fe82" dependencies = [ "bellman", "blake2b_simd", "bls12_381", "directories", - "getrandom 0.2.11", + "getrandom 0.2.15", "group", "itertools 0.11.0", "jubjub", @@ -3478,12 +3581,12 @@ dependencies = [ ] [[package]] -name = "memoffset" -version = "0.6.5" +name = "memmap2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +checksum = "6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872" dependencies = [ - "autocfg", + "libc", ] [[package]] @@ -3495,12 +3598,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "memory_units" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" - [[package]] name = "memuse" version = "0.2.1" @@ -3566,25 +3663,16 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "namada" -version = "0.37.0" +version = "0.39.0" dependencies = [ "async-trait", - "bimap", "borsh 1.4.0", "borsh-ext", - "circular-queue", "clru", - "data-encoding", - "derivation-path", - "derivative", - "ethbridge-bridge-contract", "ethers", "eyre", - "futures", "itertools 0.12.1", - "konst", "linkme", - "loupe", "masp_primitives", "masp_proofs", "namada_account", @@ -3594,7 +3682,6 @@ dependencies = [ "namada_gas", "namada_governance", "namada_ibc", - "namada_macros", "namada_migrations", "namada_parameters", "namada_proof_of_stake", @@ -3606,48 +3693,33 @@ dependencies = [ "namada_tx_env", "namada_vote_ext", "namada_vp_env", - "num-traits 0.2.17", - "num256", - "orion", - "owo-colors", "parity-wasm", - "paste", "proptest", "prost", "rand 0.8.5", - "rand_core 0.6.4", "rayon", - "regex", "ripemd", - "serde", "serde_json", "sha2 0.9.9", - "slip10_ed25519", "smooth-operator", "tempfile", "thiserror", "tiny-bip39", - "tiny-hderive", "tokio", - "toml 0.5.11", "tracing", "uint", "wasm-instrument", "wasmer", "wasmer-cache", "wasmer-compiler-singlepass", - "wasmer-engine-dylib", - "wasmer-engine-universal", "wasmer-vm", "wasmparser 0.107.0", "wasmtimer", - "wat", - "zeroize", ] [[package]] name = "namada_account" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.4.0", "linkme", @@ -3661,7 +3733,7 @@ dependencies = [ [[package]] name = "namada_controller" -version = "0.37.0" +version = "0.39.0" dependencies = [ "namada_core", "smooth-operator", @@ -3670,7 +3742,7 @@ dependencies = [ [[package]] name = "namada_core" -version = "0.37.0" +version = "0.39.0" dependencies = [ "bech32 0.8.1", "borsh 1.4.0", @@ -3718,10 +3790,9 @@ dependencies = [ [[package]] name = "namada_ethereum_bridge" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.4.0", - "ethabi", "ethers", "eyre", "itertools 0.12.1", @@ -3739,18 +3810,14 @@ dependencies = [ "namada_trans_token", "namada_tx", "namada_vote_ext", - "rand 0.8.5", "serde", - "serde_json", - "tendermint 0.36.0", - "tendermint-proto 0.36.0", "thiserror", "tracing", ] [[package]] name = "namada_events" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.4.0", "linkme", @@ -3765,7 +3832,7 @@ dependencies = [ [[package]] name = "namada_gas" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.4.0", "linkme", @@ -3779,7 +3846,7 @@ dependencies = [ [[package]] name = "namada_governance" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.4.0", "itertools 0.12.1", @@ -3802,7 +3869,7 @@ dependencies = [ [[package]] name = "namada_ibc" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.4.0", "ibc", @@ -3813,14 +3880,12 @@ dependencies = [ "masp_primitives", "namada_core", "namada_events", - "namada_gas", "namada_governance", "namada_macros", "namada_parameters", "namada_state", "namada_storage", "namada_token", - "namada_tx", "primitive-types", "proptest", "prost", @@ -3833,7 +3898,7 @@ dependencies = [ [[package]] name = "namada_macros" -version = "0.37.0" +version = "0.39.0" dependencies = [ "data-encoding", "proc-macro2", @@ -3844,7 +3909,7 @@ dependencies = [ [[package]] name = "namada_merkle_tree" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.4.0", "eyre", @@ -3858,7 +3923,7 @@ dependencies = [ [[package]] name = "namada_migrations" -version = "0.37.0" +version = "0.39.0" dependencies = [ "lazy_static", "linkme", @@ -3867,9 +3932,8 @@ dependencies = [ [[package]] name = "namada_parameters" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "borsh 1.4.0", "namada_core", "namada_macros", "namada_storage", @@ -3878,10 +3942,9 @@ dependencies = [ [[package]] name = "namada_proof_of_stake" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.4.0", - "data-encoding", "konst", "linkme", "namada_account", @@ -3894,7 +3957,6 @@ dependencies = [ "namada_parameters", "namada_storage", "namada_trans_token", - "num-traits 0.2.17", "once_cell", "proptest", "serde", @@ -3905,14 +3967,14 @@ dependencies = [ [[package]] name = "namada_replay_protection" -version = "0.37.0" +version = "0.39.0" dependencies = [ "namada_core", ] [[package]] name = "namada_sdk" -version = "0.37.0" +version = "0.39.0" dependencies = [ "async-trait", "bimap", @@ -3966,7 +4028,6 @@ dependencies = [ "sha2 0.9.9", "slip10_ed25519", "smooth-operator", - "tendermint-config", "tendermint-rpc", "thiserror", "tiny-bip39", @@ -3980,7 +4041,7 @@ dependencies = [ [[package]] name = "namada_shielded_token" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.4.0", "masp_primitives", @@ -3989,7 +4050,6 @@ dependencies = [ "namada_parameters", "namada_storage", "namada_trans_token", - "namada_tx", "serde", "smooth-operator", "tracing", @@ -3997,10 +4057,9 @@ dependencies = [ [[package]] name = "namada_state" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.4.0", - "ics23", "itertools 0.12.1", "linkme", "namada_core", @@ -4015,17 +4074,14 @@ dependencies = [ "namada_tx", "patricia_tree", "proptest", - "sha2 0.9.9", "smooth-operator", - "sparse-merkle-tree", "thiserror", - "tiny-keccak", "tracing", ] [[package]] name = "namada_storage" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.4.0", "itertools 0.12.1", @@ -4044,7 +4100,7 @@ dependencies = [ [[package]] name = "namada_test_utils" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.4.0", "namada_core", @@ -4053,53 +4109,49 @@ dependencies = [ [[package]] name = "namada_tests" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "async-trait", - "chrono", "concat-idents", "derivative", - "flate2", "hyper", "ibc-testkit", "ics23", "itertools 0.12.1", - "lazy_static", "namada", "namada_core", "namada_sdk", "namada_test_utils", "namada_tx_prelude", "namada_vp_prelude", - "num-traits 0.2.17", "proptest", "prost", "regex", "serde", "serde_json", "sha2 0.9.9", - "tar", "tempfile", "test-log", "tokio", - "tracing", - "tracing-subscriber", ] [[package]] name = "namada_token" -version = "0.37.0" +version = "0.39.0" dependencies = [ + "borsh 1.4.0", "namada_core", "namada_events", + "namada_macros", "namada_shielded_token", "namada_storage", "namada_trans_token", + "proptest", + "serde", ] [[package]] name = "namada_trans_token" -version = "0.37.0" +version = "0.39.0" dependencies = [ "konst", "namada_core", @@ -4109,7 +4161,7 @@ dependencies = [ [[package]] name = "namada_tx" -version = "0.37.0" +version = "0.39.0" dependencies = [ "ark-bls12-381", "bitflags 2.5.0", @@ -4137,7 +4189,7 @@ dependencies = [ [[package]] name = "namada_tx_env" -version = "0.37.0" +version = "0.39.0" dependencies = [ "namada_core", "namada_events", @@ -4146,7 +4198,7 @@ dependencies = [ [[package]] name = "namada_tx_prelude" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.4.0", "masp_primitives", @@ -4163,13 +4215,11 @@ dependencies = [ "namada_tx", "namada_tx_env", "namada_vm_env", - "sha2 0.9.9", - "thiserror", ] [[package]] name = "namada_vm_env" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.4.0", "masp_primitives", @@ -4178,7 +4228,7 @@ dependencies = [ [[package]] name = "namada_vote_ext" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.4.0", "linkme", @@ -4191,7 +4241,7 @@ dependencies = [ [[package]] name = "namada_vp_env" -version = "0.37.0" +version = "0.39.0" dependencies = [ "derivative", "masp_primitives", @@ -4201,12 +4251,11 @@ dependencies = [ "namada_storage", "namada_tx", "smooth-operator", - "thiserror", ] [[package]] name = "namada_vp_prelude" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.4.0", "namada_account", @@ -4223,7 +4272,6 @@ dependencies = [ "namada_vm_env", "namada_vp_env", "sha2 0.9.9", - "thiserror", ] [[package]] @@ -4384,18 +4432,6 @@ dependencies = [ "syn 2.0.52", ] -[[package]] -name = "object" -version = "0.28.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" -dependencies = [ - "crc32fast", - "hashbrown 0.11.2", - "indexmap 1.9.3", - "memchr", -] - [[package]] name = "object" version = "0.32.1" @@ -4449,7 +4485,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6624905ddd92e460ff0685567539ed1ac985b2dee4c92c7edcd64fce905b00c" dependencies = [ "ct-codecs", - "getrandom 0.2.11", + "getrandom 0.2.15", "subtle", "zeroize", ] @@ -4517,7 +4553,7 @@ version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", "smallvec", @@ -4652,7 +4688,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.1.0", + "indexmap 2.2.6", ] [[package]] @@ -4998,7 +5034,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", ] [[package]] @@ -5087,19 +5123,20 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "libredox", "thiserror", ] [[package]] -name = "regalloc" -version = "0.0.34" +name = "regalloc2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62446b1d3ebf980bdc68837700af1d77b37bc430e524bf95319c6eada2a4cc02" +checksum = "300d4fbfb40c1c66a78ba3ddd41c1110247cf52f97b87d0f2fc9209bd49b030c" dependencies = [ + "fxhash", "log", - "rustc-hash", + "slice-group-by", "smallvec", ] @@ -5235,7 +5272,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", - "getrandom 0.2.11", + "getrandom 0.2.15", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -5260,6 +5297,7 @@ dependencies = [ "bitvec", "bytecheck", "hashbrown 0.12.3", + "indexmap 1.9.3", "ptr_meta", "rend", "rkyv_derive", @@ -5301,6 +5339,18 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "rlsf" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222fb240c3286247ecdee6fa5341e7cdad0ffdf8e7e401d9937f2d58482a20bf" +dependencies = [ + "cfg-if", + "const-default", + "libc", + "svgbobdoc", +] + [[package]] name = "rust_decimal" version = "1.35.0" @@ -5430,7 +5480,7 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "derive_more", "parity-scale-codec", "scale-info-derive", @@ -5458,6 +5508,7 @@ dependencies = [ "schemars_derive", "serde", "serde_json", + "url", ] [[package]] @@ -5521,6 +5572,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "self_cell" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" + [[package]] name = "semver" version = "0.11.0" @@ -5562,9 +5619,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] @@ -5587,6 +5644,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_bytes" version = "0.11.12" @@ -5596,11 +5664,21 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", @@ -5661,6 +5739,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.2.6", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "serdect" version = "0.2.0" @@ -5678,7 +5769,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.9.0", "opaque-debug", @@ -5690,7 +5781,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.10.7", ] @@ -5714,6 +5805,16 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shared-buffer" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16" +dependencies = [ + "bytes", + "memmap2 0.6.2", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -5766,6 +5867,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "slice-group-by" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" + [[package]] name = "slip10_ed25519" version = "0.1.3" @@ -5783,16 +5890,16 @@ checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "smooth-operator" -version = "0.6.0" -source = "git+https://github.com/heliaxdev/smooth-operator?tag=v0.6.0#1e9e2382dd6c053f54418db836f7f03143fcd2f3" +version = "0.7.0" +source = "git+https://github.com/heliaxdev/smooth-operator?tag=v0.7.0#0e182707f5e5bb9c6e0efa2d235dc9efd715d0a1" dependencies = [ "smooth-operator-impl", ] [[package]] name = "smooth-operator-impl" -version = "0.6.0" -source = "git+https://github.com/heliaxdev/smooth-operator?tag=v0.6.0#1e9e2382dd6c053f54418db836f7f03143fcd2f3" +version = "0.7.0" +source = "git+https://github.com/heliaxdev/smooth-operator?tag=v0.7.0#0e182707f5e5bb9c6e0efa2d235dc9efd715d0a1" dependencies = [ "proc-macro2", "quote", @@ -5825,7 +5932,7 @@ version = "0.3.1-pre" source = "git+https://github.com/heliaxdev/sparse-merkle-tree?rev=bab8cb96872db22cc9a139b2d3dfc4e00521d097#bab8cb96872db22cc9a139b2d3dfc4e00521d097" dependencies = [ "borsh 1.4.0", - "cfg-if 1.0.0", + "cfg-if", "ics23", "itertools 0.12.1", "sha2 0.9.9", @@ -5865,6 +5972,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "strum" version = "0.24.1" @@ -5930,6 +6043,19 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" +[[package]] +name = "svgbobdoc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2c04b93fc15d79b39c63218f15e3fdffaa4c227830686e3b7c5f41244eb3e50" +dependencies = [ + "base64 0.13.1", + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-width", +] + [[package]] name = "syn" version = "1.0.109" @@ -6020,7 +6146,7 @@ version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand", "redox_syscall", "rustix", @@ -6155,7 +6281,7 @@ dependencies = [ "async-trait", "bytes", "flex-error", - "getrandom 0.2.11", + "getrandom 0.2.15", "peg", "pin-project", "rand 0.8.5", @@ -6238,7 +6364,7 @@ version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", ] @@ -6399,6 +6525,18 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.19.15", +] + [[package]] name = "toml" version = "0.8.2" @@ -6426,7 +6564,9 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.6", + "serde", + "serde_spanned", "toml_datetime", "winnow 0.5.25", ] @@ -6437,7 +6577,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", @@ -6450,7 +6590,7 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.6", "toml_datetime", "winnow 0.5.25", ] @@ -6533,7 +6673,6 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -6592,240 +6731,267 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "tx_become_validator" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_tx_prelude", - "wee_alloc", + "rlsf", ] [[package]] name = "tx_bond" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada", "namada_test_utils", "namada_tests", "namada_tx_prelude", "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "tx_bridge_pool" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_tx_prelude", - "wee_alloc", + "rlsf", ] [[package]] name = "tx_change_consensus_key" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_tx_prelude", - "wee_alloc", + "rlsf", ] [[package]] name = "tx_change_validator_commission" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada", "namada_test_utils", "namada_tests", "namada_tx_prelude", "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "tx_change_validator_metadata" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_tx_prelude", - "wee_alloc", + "rlsf", ] [[package]] name = "tx_claim_rewards" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_tx_prelude", - "wee_alloc", + "rlsf", ] [[package]] name = "tx_deactivate_validator" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_tx_prelude", - "wee_alloc", + "rlsf", ] [[package]] name = "tx_ibc" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_tx_prelude", - "wee_alloc", + "rlsf", ] [[package]] name = "tx_init_account" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_tx_prelude", - "wee_alloc", + "rlsf", ] [[package]] name = "tx_init_proposal" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_tx_prelude", - "wee_alloc", + "rlsf", ] [[package]] name = "tx_reactivate_validator" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_tx_prelude", - "wee_alloc", + "rlsf", ] [[package]] name = "tx_redelegate" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada", "namada_test_utils", "namada_tests", "namada_tx_prelude", "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "tx_resign_steward" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_tx_prelude", - "wee_alloc", + "rlsf", ] [[package]] name = "tx_reveal_pk" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_tx_prelude", - "wee_alloc", + "rlsf", ] [[package]] -name = "tx_transfer" -version = "0.37.0" +name = "tx_shielded_transfer" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_tx_prelude", - "wee_alloc", + "rlsf", +] + +[[package]] +name = "tx_shielding_transfer" +version = "0.39.0" +dependencies = [ + "getrandom 0.2.15", + "namada_tx_prelude", + "rlsf", +] + +[[package]] +name = "tx_transparent_transfer" +version = "0.39.0" +dependencies = [ + "getrandom 0.2.15", + "namada_tx_prelude", + "rlsf", ] [[package]] name = "tx_unbond" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada", "namada_test_utils", "namada_tests", "namada_tx_prelude", "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "tx_unjail_validator" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_tx_prelude", - "wee_alloc", + "rlsf", +] + +[[package]] +name = "tx_unshielding_transfer" +version = "0.39.0" +dependencies = [ + "getrandom 0.2.15", + "namada_tx_prelude", + "rlsf", ] [[package]] name = "tx_update_account" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_tx_prelude", - "wee_alloc", + "rlsf", ] [[package]] name = "tx_update_steward_commission" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_tx_prelude", - "wee_alloc", + "rlsf", ] [[package]] name = "tx_vote_proposal" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_tx_prelude", - "wee_alloc", + "rlsf", ] [[package]] name = "tx_withdraw" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada", "namada_test_utils", "namada_tests", "namada_tx_prelude", "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] @@ -6936,6 +7102,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.7.1" @@ -6957,6 +7129,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -6965,7 +7138,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "serde", ] @@ -6983,36 +7156,36 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vp_implicit" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada", "namada_test_utils", "namada_tests", "namada_tx_prelude", "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "vp_user" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada", "namada_test_utils", "namada_tests", "namada_tx_prelude", "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] @@ -7061,7 +7234,7 @@ version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] @@ -7086,7 +7259,7 @@ version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -7141,46 +7314,38 @@ dependencies = [ [[package]] name = "wasmer" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce4a267a570e121c9375136adefa2c48810273907de9c6817bc19db4d6144bc" dependencies = [ - "cfg-if 1.0.0", + "bytes", + "cfg-if", + "derivative", "indexmap 1.9.3", "js-sys", - "loupe", "more-asserts", + "rustc-demangle", + "serde", + "serde-wasm-bindgen", + "shared-buffer", "target-lexicon", "thiserror", + "tracing", "wasm-bindgen", - "wasmer-artifact", "wasmer-compiler", "wasmer-compiler-cranelift", "wasmer-derive", - "wasmer-engine", - "wasmer-engine-dylib", - "wasmer-engine-universal", "wasmer-types", "wasmer-vm", "wat", "winapi", ] -[[package]] -name = "wasmer-artifact" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" -dependencies = [ - "enumset", - "loupe", - "thiserror", - "wasmer-compiler", - "wasmer-types", -] - [[package]] name = "wasmer-cache" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a40804bcc2567f112003182fc5edc29584da5199c4a1f5a8d6a6e4b65feff0" dependencies = [ "blake3", "hex", @@ -7190,31 +7355,42 @@ dependencies = [ [[package]] name = "wasmer-compiler" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9c23098e86ef1038155684fe50f0c1079a0e2a2e70f115b789df17e6ba98d20" dependencies = [ + "backtrace", + "bytes", + "cfg-if", + "enum-iterator", "enumset", - "loupe", + "lazy_static", + "leb128", + "memmap2 0.5.10", + "more-asserts", + "region", "rkyv", - "serde", - "serde_bytes", + "self_cell", + "shared-buffer", "smallvec", - "target-lexicon", "thiserror", "wasmer-types", - "wasmparser 0.83.0", + "wasmer-vm", + "wasmparser 0.121.2", + "winapi", + "xxhash-rust", ] [[package]] name = "wasmer-compiler-cranelift" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95287b79973ad5f485215733ef9f0d4bb951a6b7e655585d2bd3d4a4ba1253c9" dependencies = [ "cranelift-codegen", "cranelift-entity", "cranelift-frontend", "gimli 0.26.2", - "loupe", "more-asserts", "rayon", "smallvec", @@ -7222,185 +7398,128 @@ dependencies = [ "tracing", "wasmer-compiler", "wasmer-types", - "wasmer-vm", ] [[package]] name = "wasmer-compiler-singlepass" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00d78d59be3ce78ad859e176b88f0d5bec0120ece0684922d7c5da1289e251b1" dependencies = [ "byteorder", "dynasm", "dynasmrt", + "enumset", "gimli 0.26.2", "lazy_static", - "loupe", "more-asserts", "rayon", "smallvec", "wasmer-compiler", "wasmer-types", - "wasmer-vm", -] - -[[package]] -name = "wasmer-derive" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", ] [[package]] -name = "wasmer-engine" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" -dependencies = [ - "backtrace", - "enumset", - "lazy_static", - "loupe", - "memmap2", - "more-asserts", - "rustc-demangle", - "serde", - "serde_bytes", - "target-lexicon", - "thiserror", - "wasmer-artifact", - "wasmer-compiler", - "wasmer-types", - "wasmer-vm", -] - -[[package]] -name = "wasmer-engine-dylib" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +name = "wasmer-config" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a0f70c177b1c5062cfe0f5308c3317751796fef9403c22a0cd7b4cacd4ccd8" dependencies = [ - "cfg-if 1.0.0", - "enum-iterator", - "enumset", - "leb128", - "libloading", - "loupe", - "object 0.28.4", - "rkyv", + "anyhow", + "bytesize", + "derive_builder", + "hex", + "indexmap 2.2.6", + "schemars", + "semver 1.0.20", "serde", - "tempfile", - "tracing", - "wasmer-artifact", - "wasmer-compiler", - "wasmer-engine", - "wasmer-object", - "wasmer-types", - "wasmer-vm", - "which", -] - -[[package]] -name = "wasmer-engine-universal" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" -dependencies = [ - "cfg-if 1.0.0", - "enumset", - "leb128", - "loupe", - "region", - "rkyv", - "wasmer-compiler", - "wasmer-engine", - "wasmer-engine-universal-artifact", - "wasmer-types", - "wasmer-vm", - "winapi", -] - -[[package]] -name = "wasmer-engine-universal-artifact" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" -dependencies = [ - "enum-iterator", - "enumset", - "loupe", - "rkyv", + "serde_cbor", + "serde_json", + "serde_yaml", "thiserror", - "wasmer-artifact", - "wasmer-compiler", - "wasmer-types", + "toml 0.8.2", + "url", ] [[package]] -name = "wasmer-object" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +name = "wasmer-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48f36aeeecb655f15fdd358bdf6e4cec27df181468fa4226084157e8462bd5e" dependencies = [ - "object 0.28.4", - "thiserror", - "wasmer-compiler", - "wasmer-types", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] name = "wasmer-types" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83cb97b6b20084757a2a8d548dc0d4179c3fe9e2d711740423a1e6aa3f8b9091" dependencies = [ - "backtrace", + "bytecheck", "enum-iterator", + "enumset", + "getrandom 0.2.15", + "hex", "indexmap 1.9.3", - "loupe", + "more-asserts", "rkyv", - "serde", + "sha2 0.10.8", + "target-lexicon", "thiserror", + "webc", + "xxhash-rust", ] [[package]] name = "wasmer-vm" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc1e19d986844b17b927ec8b0c7f3da6a7a2c2cb3b0f8ca5d4cb1a1f71bfb124" dependencies = [ "backtrace", "cc", - "cfg-if 1.0.0", + "cfg-if", "corosensei", + "crossbeam-queue", + "dashmap", + "derivative", "enum-iterator", + "fnv", "indexmap 1.9.3", "lazy_static", "libc", - "loupe", "mach", - "memoffset 0.6.5", + "memoffset", "more-asserts", "region", - "rkyv", "scopeguard", - "serde", "thiserror", - "wasmer-artifact", "wasmer-types", "winapi", ] [[package]] name = "wasmparser" -version = "0.83.0" +version = "0.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a" +checksum = "29e3ac9b780c7dda0cac7a52a5d6d2d6707cc6e3451c9db209b6c758f40d7acb" +dependencies = [ + "indexmap 1.9.3", + "semver 1.0.20", +] [[package]] name = "wasmparser" -version = "0.107.0" +version = "0.121.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29e3ac9b780c7dda0cac7a52a5d6d2d6707cc6e3451c9db209b6c758f40d7acb" +checksum = "9dbe55c8f9d0dbd25d9447a5a889ff90c0cc3feaa7395310d3d826b2c703eaab" dependencies = [ - "indexmap 1.9.3", + "bitflags 2.5.0", + "indexmap 2.2.6", "semver 1.0.20", ] @@ -7450,23 +7569,40 @@ dependencies = [ ] [[package]] -name = "webpki-roots" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" - -[[package]] -name = "wee_alloc" -version = "0.4.5" +name = "webc" +version = "6.0.0-rc1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" +checksum = "c1fc686c7b43c9bc630a499f6ae1f0a4c4bd656576a53ae8a147b0cc9bc983ad" dependencies = [ - "cfg-if 0.1.10", + "anyhow", + "base64 0.21.7", + "bytes", + "cfg-if", + "document-features", + "flate2", + "indexmap 1.9.3", "libc", - "memory_units", - "winapi", + "once_cell", + "semver 1.0.20", + "serde", + "serde_cbor", + "serde_json", + "sha2 0.10.8", + "shared-buffer", + "tar", + "tempfile", + "thiserror", + "toml 0.7.8", + "url", + "wasmer-config", ] +[[package]] +name = "webpki-roots" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" + [[package]] name = "which" version = "4.4.2" @@ -7718,7 +7854,7 @@ version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "windows-sys 0.48.0", ] @@ -7761,6 +7897,12 @@ dependencies = [ "rustix", ] +[[package]] +name = "xxhash-rust" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927da81e25be1e1a2901d59b81b37dd2efd1fc9c9345a55007f09bf5a2d3ee03" + [[package]] name = "zcash_encoding" version = "0.2.0" diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index 890a3b6c61..b0212b5def 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -16,12 +16,15 @@ members = [ "tx_reactivate_validator", "tx_redelegate", "tx_resign_steward", - "tx_transfer", + "tx_reveal_pk", + "tx_shielded_transfer", + "tx_shielding_transfer", + "tx_transparent_transfer", "tx_unbond", + "tx_unjail_validator", + "tx_unshielding_transfer", "tx_update_account", - "tx_reveal_pk", "tx_update_steward_commission", - "tx_unjail_validator", "tx_vote_proposal", "tx_withdraw", "vp_implicit", @@ -32,15 +35,15 @@ members = [ authors = ["Heliax AG "] edition = "2021" license = "GPL-3.0" -version = "0.37.0" +version = "0.39.0" [workspace.dependencies] namada_tx_prelude = { path = "../crates/tx_prelude" } namada_vp_prelude = { path = "../crates/vp_prelude" } once_cell = { version = "1.8.0" } -wee_alloc = "0.4.5" -getrandom = { version = "0.2", features = ["custom"] } +rlsf = "0.2.1" +getrandom = { version = "0.2.15", features = ["custom"] } [profile.release] # smaller and faster wasm (https://rustwasm.github.io/book/reference/code-size.html#compiling-with-link-time-optimizations-lto) diff --git a/wasm/checksums.json b/wasm/checksums.json index af7ed1e305..0b4f16240e 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,26 +1,30 @@ { - "tx_become_validator.wasm": "tx_become_validator.120563617e8f5cacfb4d6e62b87c2fe800545a0de7ec648457f499503ab43441.wasm", - "tx_bond.wasm": "tx_bond.3e7bfd88145c04337bed2b94ee33532bd85641b5311a48d177163dea4f358bab.wasm", - "tx_bridge_pool.wasm": "tx_bridge_pool.09e12de9ba9faf0b4e79c2d58b78d7a8d308f00a9c284f9995c1b1cb4f0f5f81.wasm", - "tx_change_consensus_key.wasm": "tx_change_consensus_key.2ed6abf06cc472ef2713d9679488591c0183d383cad34093055b8e0a5c7ae538.wasm", - "tx_change_validator_commission.wasm": "tx_change_validator_commission.2f9e67db1dc811bea9cedc4322664cb682a09cb81097af60dd87fcace029410f.wasm", - "tx_change_validator_metadata.wasm": "tx_change_validator_metadata.ff460c34ebaf828f7027d59175aa5c245d5b64c16b4d6b13230c93bf1321d48a.wasm", - "tx_claim_rewards.wasm": "tx_claim_rewards.1fd9f3a2c4c8c3443534d652e59edca768c62d0bddc5d2b5b1ab12e0e8af3b25.wasm", - "tx_deactivate_validator.wasm": "tx_deactivate_validator.4e2286f741de4ec50932ca079f513bb40c1d106e2f36297025bafe79f447e640.wasm", - "tx_ibc.wasm": "tx_ibc.cb1972468e22acd1aee392d7917046e5f2f74378d9c2b1f6c7058dac98df6df3.wasm", - "tx_init_account.wasm": "tx_init_account.5df2c6444016af2243d040039ee2cbfcfe743b8ba4b7a0a5fcd99bc7057a6b18.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.2d2010d9091ad8900aa443b0cb498a88611335ffcf7cee691e5875ece092305b.wasm", - "tx_reactivate_validator.wasm": "tx_reactivate_validator.234a06e499658498dd785f1c66519f17839c83299f882a59b696e6f2fadd4c54.wasm", - "tx_redelegate.wasm": "tx_redelegate.8232fd4abd3a222327acd32d0b1d4fa861dd6cfedb4c0fbfbe699b39094b1b15.wasm", - "tx_resign_steward.wasm": "tx_resign_steward.c7dda40b09fdc29c9367657c378ac4415351d688fc2b69bfdf84a06835eb71ae.wasm", - "tx_reveal_pk.wasm": "tx_reveal_pk.28fd22f041f38da21796fde50cb76d35f4661bcd569e0e49e9f8ca49c57d9dd8.wasm", + "tx_become_validator.wasm": "tx_become_validator.7f9c617b95c896a2bca2254c243462e97448b4497be10c7dc9b82c2eca466ab7.wasm", + "tx_bond.wasm": "tx_bond.3f092cd6f6eb933e472c26a3a8e9a8557bf753ed9052a6b853c358e6ae625aaf.wasm", + "tx_bridge_pool.wasm": "tx_bridge_pool.f94abdd2e3c3214d57948df678f8faffba2e57221dffeab8e13f2307d59e3625.wasm", + "tx_change_consensus_key.wasm": "tx_change_consensus_key.a122f6063f420fba60707bd3b73d413fb1f0ab102640abcdf3c964d30ee4c4d3.wasm", + "tx_change_validator_commission.wasm": "tx_change_validator_commission.149d3c6698aba20593195705286e31cfbb6efd58a471d1275aa0d4aa8941cb2d.wasm", + "tx_change_validator_metadata.wasm": "tx_change_validator_metadata.3d27a92fffe0c0fecaf75bd72caa8e75e44fed7694722cb1685b0284865b7a75.wasm", + "tx_claim_rewards.wasm": "tx_claim_rewards.f5d4b55665f6d93e04269ba13cb8948cbd8f2467a9c4f5ee87bfff19474ee331.wasm", + "tx_deactivate_validator.wasm": "tx_deactivate_validator.fed18f611ef760148b3b520e39d2be652636a8ef71e230451b55410310c1746b.wasm", + "tx_ibc.wasm": "tx_ibc.8d22e398c6733a7ad5ae790a4700eaa3fd258bf1c0eb42501d0c3db4f3d44493.wasm", + "tx_init_account.wasm": "tx_init_account.8bb6fc6385760c1a6b418485faafacf145ab24ecceb4dde5f3f0ec2dd0eded86.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.4eae3c7b76ad3f21183f59049d2298d8e2de708e52ce45aed3497b2e666f5552.wasm", + "tx_reactivate_validator.wasm": "tx_reactivate_validator.415a5877d9facde274d143b297bf0cfbfcf145f376ea0c7d29e7ac3c4f25358a.wasm", + "tx_redelegate.wasm": "tx_redelegate.a118a4ea3115db74fff25e4465f166c2fec685ce550392ecf248a81bc2ad8485.wasm", + "tx_resign_steward.wasm": "tx_resign_steward.069ed9ba68456be9869dbd513988e661a10034b7c043bfeebbd55d6d978486c1.wasm", + "tx_reveal_pk.wasm": "tx_reveal_pk.ef24fb7148b362eb8955f80b42b273bea32efcc4d6d29af3a0db72e6483f1193.wasm", + "tx_shielded_transfer.wasm": "tx_shielded_transfer.655649ca38b7059b7cdd71c051ba2f31d30ebfdb52aff1e8ebac838b1c325f7e.wasm", + "tx_shielding_transfer.wasm": "tx_shielding_transfer.21d05af93c3a6f85ac4e7e26f24d4cb115dd507abeea2e2794227c55fcf12ece.wasm", "tx_transfer.wasm": "tx_transfer.466af88a669f8474cbef15bcea910c4a6ec9d7ac84617f8cf808e29b9cf0b013.wasm", - "tx_unbond.wasm": "tx_unbond.64d5051e458cd70c659aa78175c9a319240585245946eed651134f6ff3721f53.wasm", - "tx_unjail_validator.wasm": "tx_unjail_validator.c4de22ad413eb84f907a37ade57b1b2f5c782e9588b2bed23f792fabc9839d45.wasm", - "tx_update_account.wasm": "tx_update_account.bc0bd503056c7cca31a10ff4c67db4b87a82656e24c586fb8f12566df8d62875.wasm", - "tx_update_steward_commission.wasm": "tx_update_steward_commission.553e76cab200d0f872de7e33d9dac0fd2696db7e00406eb15f890ec98311232b.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.98d2698516c7d7f598174c1fd7cb3742b9dbd44a41a0e12157e1d9c483b063de.wasm", - "tx_withdraw.wasm": "tx_withdraw.793ce3fc2586807d433d14e4c5ba6955a569cb5be2bb836bddd467c23ee8299b.wasm", - "vp_implicit.wasm": "vp_implicit.4307e550eca544cd8d224378d1ab97fbc84477176ebf18a5cb5e387aadff1564.wasm", - "vp_user.wasm": "vp_user.cca2ca1add22bd25ae05fa35d5c4a4ed627b95a403f1e6466a9779574a220b00.wasm" + "tx_transparent_transfer.wasm": "tx_transparent_transfer.a73bf788b11908b1e862d5034878cc80796b81ebbb7ad59d67d87cbc6f9fb476.wasm", + "tx_unbond.wasm": "tx_unbond.fc91d2aa4741521e7c0365ecf2eef314ef1366702e674c464bbe12536a5fe834.wasm", + "tx_unjail_validator.wasm": "tx_unjail_validator.80c9c530748a04bb912c7b4372efe50023f14a320916e1050accb7984e2adffb.wasm", + "tx_unshielding_transfer.wasm": "tx_unshielding_transfer.0f3f31e2246833d70c3d1dfc9f2f3a2921b436ef9650177faca7150d34b9f6af.wasm", + "tx_update_account.wasm": "tx_update_account.d5c6e491d392d1d43c7c3eb1e3933230bc2116a50711439ce669415720bd2ac6.wasm", + "tx_update_steward_commission.wasm": "tx_update_steward_commission.78c557501f9a491a435aabfe360ada78efbf2d422649beb33cff29f3e47b203f.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.31101166d6143104b17317016226d0d80620784bb4f225ecad93043798684015.wasm", + "tx_withdraw.wasm": "tx_withdraw.0bedcf46c3861475a087a32167f1a7e9b2dad2e9de24d7cde3892e8471da2ba8.wasm", + "vp_implicit.wasm": "vp_implicit.2198580b272e8bacdd318ad8101c1dc1b54856a8df612e7a0b61e6452dc214e1.wasm", + "vp_user.wasm": "vp_user.de83f50342ef3ad78218e675a4f3c94e375ec11e2b2718a4d003b4e5991e3889.wasm" } \ No newline at end of file diff --git a/wasm/tx_become_validator/Cargo.toml b/wasm/tx_become_validator/Cargo.toml index 85a5e33050..f689d3130d 100644 --- a/wasm/tx_become_validator/Cargo.toml +++ b/wasm/tx_become_validator/Cargo.toml @@ -10,7 +10,8 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [lib] diff --git a/wasm/tx_bond/Cargo.toml b/wasm/tx_bond/Cargo.toml index 7c4a73c733..50e0aaaa62 100644 --- a/wasm/tx_bond/Cargo.toml +++ b/wasm/tx_bond/Cargo.toml @@ -10,11 +10,12 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] -namada = {path = "../../crates/namada"} +namada = {path = "../../crates/namada", default-features = false} namada_tests = {path = "../../crates/tests"} namada_test_utils = {path = "../../crates/test_utils"} namada_tx_prelude = { workspace = true, features = ["testing"] } diff --git a/wasm/tx_change_bridge_pool/Cargo.toml b/wasm/tx_change_bridge_pool/Cargo.toml index ae19b620cc..44d945a594 100644 --- a/wasm/tx_change_bridge_pool/Cargo.toml +++ b/wasm/tx_change_bridge_pool/Cargo.toml @@ -10,7 +10,8 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [lib] diff --git a/wasm/tx_change_consensus_key/Cargo.toml b/wasm/tx_change_consensus_key/Cargo.toml index 86d5163c9f..433afb31eb 100644 --- a/wasm/tx_change_consensus_key/Cargo.toml +++ b/wasm/tx_change_consensus_key/Cargo.toml @@ -10,7 +10,8 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [lib] diff --git a/wasm/tx_change_validator_commission/Cargo.toml b/wasm/tx_change_validator_commission/Cargo.toml index d2905316ff..5a6fae6f2e 100644 --- a/wasm/tx_change_validator_commission/Cargo.toml +++ b/wasm/tx_change_validator_commission/Cargo.toml @@ -10,11 +10,12 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] -namada = {path = "../../crates/namada"} +namada = {path = "../../crates/namada", default-features = false} namada_tests = {path = "../../crates/tests"} namada_test_utils = {path = "../../crates/test_utils"} namada_vp_prelude = {path = "../../crates/vp_prelude"} diff --git a/wasm/tx_change_validator_metadata/Cargo.toml b/wasm/tx_change_validator_metadata/Cargo.toml index b085cdbc1d..da54690889 100644 --- a/wasm/tx_change_validator_metadata/Cargo.toml +++ b/wasm/tx_change_validator_metadata/Cargo.toml @@ -10,7 +10,8 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [lib] diff --git a/wasm/tx_claim_rewards/Cargo.toml b/wasm/tx_claim_rewards/Cargo.toml index cc92bd43d5..c98d3c0736 100644 --- a/wasm/tx_claim_rewards/Cargo.toml +++ b/wasm/tx_claim_rewards/Cargo.toml @@ -10,7 +10,8 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [lib] diff --git a/wasm/tx_deactivate_validator/Cargo.toml b/wasm/tx_deactivate_validator/Cargo.toml index 883ddd8467..da71e833a9 100644 --- a/wasm/tx_deactivate_validator/Cargo.toml +++ b/wasm/tx_deactivate_validator/Cargo.toml @@ -10,7 +10,8 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [lib] diff --git a/wasm/tx_ibc/Cargo.toml b/wasm/tx_ibc/Cargo.toml index 08f6d5b623..83888cc394 100644 --- a/wasm/tx_ibc/Cargo.toml +++ b/wasm/tx_ibc/Cargo.toml @@ -10,7 +10,8 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [lib] diff --git a/wasm/tx_ibc/src/lib.rs b/wasm/tx_ibc/src/lib.rs index 96f07dbe69..e131a90c9a 100644 --- a/wasm/tx_ibc/src/lib.rs +++ b/wasm/tx_ibc/src/lib.rs @@ -3,6 +3,7 @@ //! tx_data. This tx uses an IBC message wrapped inside //! `key::ed25519::SignedTxData` as its input as declared in `ibc` crate. +use namada_tx_prelude::action::{Action, MaspAction, Write}; use namada_tx_prelude::*; #[transaction] @@ -11,26 +12,25 @@ fn apply_tx(ctx: &mut Ctx, tx_data: BatchedTx) -> TxResult { let transfer = ibc::ibc_actions(ctx).execute(&data).into_storage_result()?; - if let Some(transfer) = transfer { - let shielded = transfer - .shielded - .as_ref() - .map(|hash| { - tx_data - .tx - .get_section(hash) - .and_then(|x| x.as_ref().masp_tx()) - .ok_or_err_msg("unable to find shielded section") - .map_err(|err| { - ctx.set_commitment_sentinel(); - err - }) - }) - .transpose()?; - if let Some(shielded) = shielded { - token::utils::handle_masp_tx(ctx, &shielded)?; - update_masp_note_commitment_tree(&shielded)?; - } + if let Some(masp_section_ref) = + transfer.map(|transfer| transfer.shielded_section_hash) + { + let shielded = tx_data + .tx + .get_section(&masp_section_ref) + .and_then(|x| x.as_ref().masp_tx()) + .ok_or_err_msg( + "Unable to find required shielded section in tx data", + ) + .map_err(|err| { + ctx.set_commitment_sentinel(); + err + })?; + token::utils::handle_masp_tx(ctx, &shielded) + .wrap_err("Encountered error while handling MASP transaction")?; + update_masp_note_commitment_tree(&shielded) + .wrap_err("Failed to update the MASP commitment tree")?; + ctx.push_action(Action::Masp(MaspAction { masp_section_ref }))?; } Ok(()) diff --git a/wasm/tx_init_account/Cargo.toml b/wasm/tx_init_account/Cargo.toml index 47ccf05716..fa6443996c 100644 --- a/wasm/tx_init_account/Cargo.toml +++ b/wasm/tx_init_account/Cargo.toml @@ -10,7 +10,8 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [lib] diff --git a/wasm/tx_init_proposal/Cargo.toml b/wasm/tx_init_proposal/Cargo.toml index ae6577d412..8f44e0fbc3 100644 --- a/wasm/tx_init_proposal/Cargo.toml +++ b/wasm/tx_init_proposal/Cargo.toml @@ -10,7 +10,8 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [lib] diff --git a/wasm/tx_reactivate_validator/Cargo.toml b/wasm/tx_reactivate_validator/Cargo.toml index b9d45f36e1..f1bb294aec 100644 --- a/wasm/tx_reactivate_validator/Cargo.toml +++ b/wasm/tx_reactivate_validator/Cargo.toml @@ -10,7 +10,8 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [lib] diff --git a/wasm/tx_redelegate/Cargo.toml b/wasm/tx_redelegate/Cargo.toml index cd3e662f75..8d9a2c1d76 100644 --- a/wasm/tx_redelegate/Cargo.toml +++ b/wasm/tx_redelegate/Cargo.toml @@ -10,11 +10,12 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] -namada = {path = "../../crates/namada"} +namada = {path = "../../crates/namada", default-features = false} namada_tests = {path = "../../crates/tests"} namada_test_utils = {path = "../../crates/test_utils"} namada_tx_prelude = { workspace = true, features = ["testing"] } diff --git a/wasm/tx_resign_steward/Cargo.toml b/wasm/tx_resign_steward/Cargo.toml index 6d88743b2b..5b9a13903c 100644 --- a/wasm/tx_resign_steward/Cargo.toml +++ b/wasm/tx_resign_steward/Cargo.toml @@ -10,7 +10,8 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [lib] diff --git a/wasm/tx_reveal_pk/Cargo.toml b/wasm/tx_reveal_pk/Cargo.toml index 236862f2c3..25759e0825 100644 --- a/wasm/tx_reveal_pk/Cargo.toml +++ b/wasm/tx_reveal_pk/Cargo.toml @@ -10,7 +10,8 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [lib] diff --git a/wasm/tx_transfer/Cargo.toml b/wasm/tx_shielded_transfer/Cargo.toml similarity index 87% rename from wasm/tx_transfer/Cargo.toml rename to wasm/tx_shielded_transfer/Cargo.toml index 8d664f48f3..8398b69750 100644 --- a/wasm/tx_transfer/Cargo.toml +++ b/wasm/tx_shielded_transfer/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "tx_transfer" +name = "tx_shielded_transfer" description = "WASM transaction to transfer tokens" authors.workspace = true edition.workspace = true @@ -10,7 +10,8 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [lib] diff --git a/wasm/tx_shielded_transfer/src/lib.rs b/wasm/tx_shielded_transfer/src/lib.rs new file mode 100644 index 0000000000..cc9e70a638 --- /dev/null +++ b/wasm/tx_shielded_transfer/src/lib.rs @@ -0,0 +1,29 @@ +//! A tx for shielded token transfer. + +use namada_tx_prelude::action::{Action, MaspAction, Write}; +use namada_tx_prelude::*; + +#[transaction] +fn apply_tx(ctx: &mut Ctx, tx_data: BatchedTx) -> TxResult { + let data = ctx.get_tx_data(&tx_data)?; + let transfer = token::ShieldedTransfer::try_from_slice(&data[..]) + .wrap_err("Failed to decode token::ShieldedTransfer tx data")?; + debug_log!("apply_tx called with transfer: {:#?}", transfer); + + let masp_section_ref = transfer.section_hash; + let shielded = tx_data + .tx + .get_section(&masp_section_ref) + .and_then(|x| x.as_ref().masp_tx()) + .ok_or_err_msg("Unable to find required shielded section in tx data") + .map_err(|err| { + ctx.set_commitment_sentinel(); + err + })?; + token::utils::handle_masp_tx(ctx, &shielded) + .wrap_err("Encountered error while handling MASP transaction")?; + update_masp_note_commitment_tree(&shielded) + .wrap_err("Failed to update the MASP commitment tree")?; + ctx.push_action(Action::Masp(MaspAction { masp_section_ref }))?; + Ok(()) +} diff --git a/wasm/tx_shielding_transfer/Cargo.toml b/wasm/tx_shielding_transfer/Cargo.toml new file mode 100644 index 0000000000..54dca625ec --- /dev/null +++ b/wasm/tx_shielding_transfer/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "tx_shielding_transfer" +description = "WASM transaction to transfer tokens" +authors.workspace = true +edition.workspace = true +license.workspace = true +version.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +namada_tx_prelude.workspace = true + +rlsf.workspace = true +getrandom.workspace = true + +[lib] +crate-type = ["cdylib"] diff --git a/wasm/tx_shielding_transfer/src/lib.rs b/wasm/tx_shielding_transfer/src/lib.rs new file mode 100644 index 0000000000..389942686b --- /dev/null +++ b/wasm/tx_shielding_transfer/src/lib.rs @@ -0,0 +1,39 @@ +//! A tx for shielding token transfer. + +use namada_tx_prelude::action::{Action, MaspAction, Write}; +use namada_tx_prelude::*; + +#[transaction] +fn apply_tx(ctx: &mut Ctx, tx_data: BatchedTx) -> TxResult { + let data = ctx.get_tx_data(&tx_data)?; + let transfer = token::ShieldingTransfer::try_from_slice(&data[..]) + .wrap_err("Failed to decode token::ShieldingTransfer tx data")?; + debug_log!("apply_tx called with transfer: {:#?}", transfer); + + token::transfer( + ctx, + &transfer.source, + &address::MASP, + &transfer.token, + transfer.amount.amount(), + ) + .wrap_err("Token transfer failed")?; + + let masp_section_ref = transfer.shielded_section_hash; + let shielded = tx_data + .tx + .get_section(&masp_section_ref) + .and_then(|x| x.as_ref().masp_tx()) + .ok_or_err_msg("Unable to find required shielded section in tx data") + .map_err(|err| { + ctx.set_commitment_sentinel(); + err + })?; + token::utils::handle_masp_tx(ctx, &shielded) + .wrap_err("Encountered error while handling MASP transaction")?; + update_masp_note_commitment_tree(&shielded) + .wrap_err("Failed to update the MASP commitment tree")?; + ctx.push_action(Action::Masp(MaspAction { masp_section_ref }))?; + + Ok(()) +} diff --git a/wasm/tx_transfer/src/lib.rs b/wasm/tx_transfer/src/lib.rs deleted file mode 100644 index b08b40eba2..0000000000 --- a/wasm/tx_transfer/src/lib.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! A tx for token transfer. -//! This tx uses `token::Transfer` wrapped inside `SignedTxData` -//! as its input as declared in `namada` crate. - -use namada_tx_prelude::*; - -#[transaction] -fn apply_tx(ctx: &mut Ctx, tx_data: BatchedTx) -> TxResult { - let data = ctx.get_tx_data(&tx_data)?; - let transfer = token::Transfer::try_from_slice(&data[..]) - .wrap_err("Failed to decode token::Transfer tx data")?; - debug_log!("apply_tx called with transfer: {:#?}", transfer); - - token::transfer( - ctx, - &transfer.source, - &transfer.target, - &transfer.token, - transfer.amount.amount(), - ) - .wrap_err("Token transfer failed")?; - - let shielded = transfer - .shielded - .as_ref() - .map(|hash| { - tx_data - .tx - .get_section(hash) - .and_then(|x| x.as_ref().masp_tx()) - .ok_or_err_msg( - "Unable to find required shielded section in tx data", - ) - .map_err(|err| { - ctx.set_commitment_sentinel(); - err - }) - }) - .transpose()?; - if let Some(shielded) = shielded { - token::utils::handle_masp_tx(ctx, &shielded) - .wrap_err("Encountered error while handling MASP transaction")?; - update_masp_note_commitment_tree(&shielded) - .wrap_err("Failed to update the MASP commitment tree")?; - } - Ok(()) -} diff --git a/wasm/tx_transparent_transfer/Cargo.toml b/wasm/tx_transparent_transfer/Cargo.toml new file mode 100644 index 0000000000..7408b86688 --- /dev/null +++ b/wasm/tx_transparent_transfer/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "tx_transparent_transfer" +description = "WASM transaction to transfer tokens" +authors.workspace = true +edition.workspace = true +license.workspace = true +version.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +namada_tx_prelude.workspace = true + +rlsf.workspace = true +getrandom.workspace = true + +[lib] +crate-type = ["cdylib"] diff --git a/wasm/tx_transparent_transfer/src/lib.rs b/wasm/tx_transparent_transfer/src/lib.rs new file mode 100644 index 0000000000..76aacc3891 --- /dev/null +++ b/wasm/tx_transparent_transfer/src/lib.rs @@ -0,0 +1,22 @@ +//! A tx for transparent token transfer. +//! This tx uses `token::TransparentTransfer` wrapped inside `SignedTxData` +//! as its input as declared in `namada` crate. + +use namada_tx_prelude::*; + +#[transaction] +fn apply_tx(ctx: &mut Ctx, tx_data: BatchedTx) -> TxResult { + let data = ctx.get_tx_data(&tx_data)?; + let transfer = token::TransparentTransfer::try_from_slice(&data[..]) + .wrap_err("Failed to decode token::TransparentTransfer tx data")?; + debug_log!("apply_tx called with transfer: {:#?}", transfer); + + token::transfer( + ctx, + &transfer.source, + &transfer.target, + &transfer.token, + transfer.amount.amount(), + ) + .wrap_err("Token transfer failed") +} diff --git a/wasm/tx_unbond/Cargo.toml b/wasm/tx_unbond/Cargo.toml index 75cc46c9f8..8184294d4b 100644 --- a/wasm/tx_unbond/Cargo.toml +++ b/wasm/tx_unbond/Cargo.toml @@ -10,11 +10,12 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] -namada = {path = "../../crates/namada"} +namada = {path = "../../crates/namada", default-features = false} namada_tests = {path = "../../crates/tests"} namada_test_utils = {path = "../../crates/test_utils"} namada_tx_prelude = { workspace = true, features = ["testing"] } diff --git a/wasm/tx_unjail_validator/Cargo.toml b/wasm/tx_unjail_validator/Cargo.toml index 04f7db2af1..d07cbd7910 100644 --- a/wasm/tx_unjail_validator/Cargo.toml +++ b/wasm/tx_unjail_validator/Cargo.toml @@ -10,7 +10,8 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [lib] diff --git a/wasm/tx_unshielding_transfer/Cargo.toml b/wasm/tx_unshielding_transfer/Cargo.toml new file mode 100644 index 0000000000..03d9aa125d --- /dev/null +++ b/wasm/tx_unshielding_transfer/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "tx_unshielding_transfer" +description = "WASM transaction to transfer tokens" +authors.workspace = true +edition.workspace = true +license.workspace = true +version.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +namada_tx_prelude.workspace = true + +rlsf.workspace = true +getrandom.workspace = true + +[lib] +crate-type = ["cdylib"] diff --git a/wasm/tx_unshielding_transfer/src/lib.rs b/wasm/tx_unshielding_transfer/src/lib.rs new file mode 100644 index 0000000000..79bdac0757 --- /dev/null +++ b/wasm/tx_unshielding_transfer/src/lib.rs @@ -0,0 +1,39 @@ +//! A tx for unshielding token transfer. + +use namada_tx_prelude::action::{Action, MaspAction, Write}; +use namada_tx_prelude::*; + +#[transaction] +fn apply_tx(ctx: &mut Ctx, tx_data: BatchedTx) -> TxResult { + let data = ctx.get_tx_data(&tx_data)?; + let transfer = token::UnshieldingTransfer::try_from_slice(&data[..]) + .wrap_err("Failed to decode token::UnshieldingTransfer tx data")?; + debug_log!("apply_tx called with transfer: {:#?}", transfer); + + token::transfer( + ctx, + &address::MASP, + &transfer.target, + &transfer.token, + transfer.amount.amount(), + ) + .wrap_err("Token transfer failed")?; + + let masp_section_ref = transfer.shielded_section_hash; + let shielded = tx_data + .tx + .get_section(&masp_section_ref) + .and_then(|x| x.as_ref().masp_tx()) + .ok_or_err_msg("Unable to find required shielded section in tx data") + .map_err(|err| { + ctx.set_commitment_sentinel(); + err + })?; + token::utils::handle_masp_tx(ctx, &shielded) + .wrap_err("Encountered error while handling MASP transaction")?; + update_masp_note_commitment_tree(&shielded) + .wrap_err("Failed to update the MASP commitment tree")?; + ctx.push_action(Action::Masp(MaspAction { masp_section_ref }))?; + + Ok(()) +} diff --git a/wasm/tx_update_account/Cargo.toml b/wasm/tx_update_account/Cargo.toml index 8908a7901b..c014ccf201 100644 --- a/wasm/tx_update_account/Cargo.toml +++ b/wasm/tx_update_account/Cargo.toml @@ -10,7 +10,8 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [lib] diff --git a/wasm/tx_update_steward_commission/Cargo.toml b/wasm/tx_update_steward_commission/Cargo.toml index 7ac597a244..d6d26ababf 100644 --- a/wasm/tx_update_steward_commission/Cargo.toml +++ b/wasm/tx_update_steward_commission/Cargo.toml @@ -10,7 +10,8 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [lib] diff --git a/wasm/tx_vote_proposal/Cargo.toml b/wasm/tx_vote_proposal/Cargo.toml index f98ee55d2f..be6e0dc40c 100644 --- a/wasm/tx_vote_proposal/Cargo.toml +++ b/wasm/tx_vote_proposal/Cargo.toml @@ -10,7 +10,8 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [lib] diff --git a/wasm/tx_withdraw/Cargo.toml b/wasm/tx_withdraw/Cargo.toml index f447b81cc0..ac84510764 100644 --- a/wasm/tx_withdraw/Cargo.toml +++ b/wasm/tx_withdraw/Cargo.toml @@ -10,11 +10,12 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] -namada = {path = "../../crates/namada"} +namada = {path = "../../crates/namada", default-features = false} namada_tests = {path = "../../crates/tests"} namada_test_utils = {path = "../../crates/test_utils"} namada_tx_prelude = { workspace = true, features = ["testing"] } diff --git a/wasm/vp_implicit/Cargo.toml b/wasm/vp_implicit/Cargo.toml index 6a3487b74d..e46c65496c 100644 --- a/wasm/vp_implicit/Cargo.toml +++ b/wasm/vp_implicit/Cargo.toml @@ -11,11 +11,12 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true namada_vp_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] -namada = {path = "../../crates/namada"} +namada = {path = "../../crates/namada", default-features = false} namada_tests = {path = "../../crates/tests"} namada_test_utils = {path = "../../crates/test_utils"} namada_vp_prelude = {path = "../../crates/vp_prelude"} diff --git a/wasm/vp_implicit/src/lib.rs b/wasm/vp_implicit/src/lib.rs index 991e682551..db89216caf 100644 --- a/wasm/vp_implicit/src/lib.rs +++ b/wasm/vp_implicit/src/lib.rs @@ -101,6 +101,7 @@ fn validate_tx( &tx, &addr, )?, + Action::Masp(_) => (), } } diff --git a/wasm/vp_user/Cargo.toml b/wasm/vp_user/Cargo.toml index fdcc100666..8b2a8e642f 100644 --- a/wasm/vp_user/Cargo.toml +++ b/wasm/vp_user/Cargo.toml @@ -11,11 +11,12 @@ version.workspace = true [dependencies] namada_tx_prelude.workspace = true namada_vp_prelude.workspace = true -wee_alloc.workspace = true + +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] -namada = {path = "../../crates/namada"} +namada = {path = "../../crates/namada", default-features = false} namada_tests = {path = "../../crates/tests"} namada_test_utils = {path = "../../crates/test_utils"} namada_vp_prelude = {path = "../../crates/vp_prelude"} diff --git a/wasm/vp_user/src/lib.rs b/wasm/vp_user/src/lib.rs index 1bf41684fb..4071c6fdc5 100644 --- a/wasm/vp_user/src/lib.rs +++ b/wasm/vp_user/src/lib.rs @@ -101,6 +101,7 @@ fn validate_tx( &tx, &addr, )?, + Action::Masp(_) => (), } } diff --git a/wasm_for_tests/Cargo.lock b/wasm_for_tests/Cargo.lock index 159c1bb94a..b6bfa699cc 100644 --- a/wasm_for_tests/Cargo.lock +++ b/wasm_for_tests/Cargo.lock @@ -43,7 +43,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cipher", "cpufeatures", ] @@ -54,7 +54,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "once_cell", "version_check", ] @@ -83,6 +83,55 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "anyhow" version = "1.0.75" @@ -301,10 +350,10 @@ checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", - "cfg-if 1.0.0", + "cfg-if", "libc", "miniz_oxide", - "object 0.32.1", + "object", "rustc-demangle", ] @@ -484,7 +533,7 @@ dependencies = [ "arrayref", "arrayvec", "cc", - "cfg-if 1.0.0", + "cfg-if", "constant_time_eq", ] @@ -661,6 +710,15 @@ dependencies = [ "serde", ] +[[package]] +name = "bytesize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" +dependencies = [ + "serde", +] + [[package]] name = "camino" version = "1.1.6" @@ -711,12 +769,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -735,7 +787,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cipher", "cpufeatures", ] @@ -787,6 +839,46 @@ dependencies = [ "version_check", ] +[[package]] +name = "clap" +version = "4.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.65", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + [[package]] name = "clru" version = "0.5.0" @@ -844,6 +936,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + [[package]] name = "concat-idents" version = "1.1.5" @@ -854,13 +952,19 @@ dependencies = [ "syn 2.0.65", ] +[[package]] +name = "const-default" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" + [[package]] name = "const-hex" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5104de16b218eddf8e34ffe2f86f74bfa4e61e95a1b89732fccf6325efd0557" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "hex", "proptest", @@ -908,7 +1012,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80128832c58ea9cbd041d2a759ec449224487b2c1e400453d99d244eead87a8e" dependencies = [ "autocfg", - "cfg-if 1.0.0", + "cfg-if", "libc", "scopeguard", "windows-sys 0.33.0", @@ -994,56 +1098,74 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.82.3" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38faa2a16616c8e78a18d37b4726b98bfd2de192f2fdc8a39ddf568a408a0f75" +checksum = "2a2ab4512dfd3a6f4be184403a195f76e81a8a9f9e6c898e19d2dc3ce20e0115" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.82.3" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26f192472a3ba23860afd07d2b0217dc628f21fcc72617aa1336d98e1671f33b" +checksum = "98b022ed2a5913a38839dfbafe6cf135342661293b08049843362df4301261dc" dependencies = [ + "arrayvec", + "bumpalo", "cranelift-bforest", "cranelift-codegen-meta", "cranelift-codegen-shared", + "cranelift-egraph", "cranelift-entity", + "cranelift-isle", "gimli 0.26.2", "log", - "regalloc", + "regalloc2", "smallvec", "target-lexicon", ] [[package]] name = "cranelift-codegen-meta" -version = "0.82.3" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f32ddb89e9b89d3d9b36a5b7d7ea3261c98235a76ac95ba46826b8ec40b1a24" +checksum = "639307b45434ad112a98f8300c0f0ab085cbefcd767efcdef9ef19d4c0756e74" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.82.3" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01fd0d9f288cc1b42d9333b7a776b17e278fc888c28e6a0f09b5573d45a150bc" +checksum = "278e52e29c53fcf32431ef08406c295699a70306d05a0715c5b1bf50e33a9ab7" + +[[package]] +name = "cranelift-egraph" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624b54323b06e675293939311943ba82d323bb340468ce1889be5da7932c8d73" +dependencies = [ + "cranelift-entity", + "fxhash", + "hashbrown 0.12.3", + "indexmap 1.9.3", + "log", + "smallvec", +] [[package]] name = "cranelift-entity" -version = "0.82.3" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3bfe172b83167604601faf9dc60453e0d0a93415b57a9c4d1a7ae6849185cf" +checksum = "9a59bcbca89c3f1b70b93ab3cbba5e5e0cbf3e63dadb23c7525cb142e21a9d4c" [[package]] name = "cranelift-frontend" -version = "0.82.3" +version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a006e3e32d80ce0e4ba7f1f9ddf66066d052a8c884a110b91d05404d6ce26dce" +checksum = "0d70abacb8cfef3dc8ff7e8836e9c1d70f7967dfdac824a4cd5e30223415aca6" dependencies = [ "cranelift-codegen", "log", @@ -1051,13 +1173,19 @@ dependencies = [ "target-lexicon", ] +[[package]] +name = "cranelift-isle" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "393bc73c451830ff8dbb3a07f61843d6cb41a084f9996319917c0b291ed785bb" + [[package]] name = "crc32fast" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1066,7 +1194,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] @@ -1078,12 +1206,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", - "memoffset 0.9.0", + "memoffset", "scopeguard", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.19" @@ -1180,14 +1317,38 @@ dependencies = [ "serde", ] +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + [[package]] name = "darling" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.3", + "darling_macro 0.20.3", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", ] [[package]] @@ -1203,17 +1364,41 @@ dependencies = [ "syn 2.0.65", ] +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", +] + [[package]] name = "darling_macro" version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ - "darling_core", + "darling_core 0.20.3", "quote", "syn 2.0.65", ] +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.3", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "data-encoding" version = "2.5.0" @@ -1256,6 +1441,37 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling 0.14.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -1319,6 +1535,15 @@ dependencies = [ "syn 2.0.65", ] +[[package]] +name = "document-features" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95" +dependencies = [ + "litrs", +] + [[package]] name = "dunce" version = "1.0.4" @@ -1368,7 +1593,7 @@ checksum = "64fba5a42bd76a17cad4bfa00de168ee1cbfa06a5e8ce992ae880218c05641a9" dependencies = [ "byteorder", "dynasm", - "memmap2", + "memmap2 0.5.10", ] [[package]] @@ -1458,7 +1683,7 @@ version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1514,7 +1739,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" dependencies = [ - "darling", + "darling 0.20.3", "proc-macro2", "quote", "syn 2.0.65", @@ -1877,7 +2102,7 @@ version = "3.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "rustix", "windows-sys 0.48.0", ] @@ -1899,7 +2124,7 @@ version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", "windows-sys 0.52.0", @@ -2118,7 +2343,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "wasi 0.9.0+wasi-snapshot-preview1", @@ -2127,11 +2352,11 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -2211,7 +2436,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.11", - "indexmap 2.1.0", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -2219,13 +2444,10 @@ dependencies = [ ] [[package]] -name = "hashbrown" -version = "0.11.2" +name = "half" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash", -] +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" [[package]] name = "hashbrown" @@ -3087,20 +3309,21 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +version = "2.2.4" +source = "git+https://github.com/heliaxdev/indexmap?tag=2.2.4-heliax-1#b5b5b547bd6ab04bbb16e060326a50ddaeb6c909" dependencies = [ + "borsh 1.2.1", "equivalent", "hashbrown 0.14.3", + "serde", ] [[package]] name = "indexmap" -version = "2.2.4" -source = "git+https://github.com/heliaxdev/indexmap?tag=2.2.4-heliax-1#b5b5b547bd6ab04bbb16e060326a50ddaeb6c909" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ - "borsh 1.2.1", "equivalent", "hashbrown 0.14.3", "serde", @@ -3141,7 +3364,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -3159,6 +3382,12 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "itertools" version = "0.11.0" @@ -3226,7 +3455,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "ecdsa", "elliptic-curve", "once_cell", @@ -3282,16 +3511,6 @@ version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if 1.0.0", - "winapi", -] - [[package]] name = "libm" version = "0.2.8" @@ -3315,6 +3534,12 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + [[package]] name = "lock_api" version = "0.4.11" @@ -3331,27 +3556,6 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" -[[package]] -name = "loupe" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6a72dfa44fe15b5e76b94307eeb2ff995a8c5b283b55008940c02e0c5b634d" -dependencies = [ - "indexmap 1.9.3", - "loupe-derive", - "rustversion", -] - -[[package]] -name = "loupe-derive" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fbfc88337168279f2e9ae06e157cfed4efd3316e14dc96ed074d4f2e6c5952" -dependencies = [ - "quote", - "syn 1.0.109", -] - [[package]] name = "mach" version = "0.3.2" @@ -3364,7 +3568,7 @@ dependencies = [ [[package]] name = "masp_note_encryption" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=3aacc707c5948e7423589ac617305448bead9842#3aacc707c5948e7423589ac617305448bead9842" +source = "git+https://github.com/anoma/masp?rev=4ede1c42d76d6348af8224bc8bfac4404321fe82#4ede1c42d76d6348af8224bc8bfac4404321fe82" dependencies = [ "borsh 1.2.1", "chacha20", @@ -3377,7 +3581,7 @@ dependencies = [ [[package]] name = "masp_primitives" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=3aacc707c5948e7423589ac617305448bead9842#3aacc707c5948e7423589ac617305448bead9842" +source = "git+https://github.com/anoma/masp?rev=4ede1c42d76d6348af8224bc8bfac4404321fe82#4ede1c42d76d6348af8224bc8bfac4404321fe82" dependencies = [ "aes", "bip0039", @@ -3409,13 +3613,13 @@ dependencies = [ [[package]] name = "masp_proofs" version = "1.0.0" -source = "git+https://github.com/anoma/masp?rev=3aacc707c5948e7423589ac617305448bead9842#3aacc707c5948e7423589ac617305448bead9842" +source = "git+https://github.com/anoma/masp?rev=4ede1c42d76d6348af8224bc8bfac4404321fe82#4ede1c42d76d6348af8224bc8bfac4404321fe82" dependencies = [ "bellman", "blake2b_simd", "bls12_381", "directories", - "getrandom 0.2.11", + "getrandom 0.2.15", "group", "itertools 0.11.0", "jubjub", @@ -3458,12 +3662,12 @@ dependencies = [ ] [[package]] -name = "memoffset" -version = "0.6.5" +name = "memmap2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +checksum = "6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872" dependencies = [ - "autocfg", + "libc", ] [[package]] @@ -3475,12 +3679,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "memory_units" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" - [[package]] name = "memuse" version = "0.2.1" @@ -3546,24 +3744,15 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "namada" -version = "0.37.0" +version = "0.39.0" dependencies = [ "async-trait", - "bimap", "borsh 1.2.1", "borsh-ext", - "circular-queue", "clru", - "data-encoding", - "derivation-path", - "derivative", - "ethbridge-bridge-contract", "ethers", "eyre", - "futures", "itertools 0.12.1", - "konst", - "loupe", "masp_primitives", "masp_proofs", "namada_account", @@ -3573,7 +3762,6 @@ dependencies = [ "namada_gas", "namada_governance", "namada_ibc", - "namada_macros", "namada_parameters", "namada_proof_of_stake", "namada_replay_protection", @@ -3584,48 +3772,33 @@ dependencies = [ "namada_tx_env", "namada_vote_ext", "namada_vp_env", - "num-traits 0.2.17", - "num256", - "orion", - "owo-colors", "parity-wasm", - "paste", "proptest", "prost", "rand 0.8.5", - "rand_core 0.6.4", "rayon", - "regex", "ripemd", - "serde", "serde_json", "sha2 0.9.9", - "slip10_ed25519", "smooth-operator", "tempfile", "thiserror", "tiny-bip39", - "tiny-hderive", "tokio", - "toml 0.5.11", "tracing", "uint", "wasm-instrument", "wasmer", "wasmer-cache", "wasmer-compiler-singlepass", - "wasmer-engine-dylib", - "wasmer-engine-universal", "wasmer-vm", "wasmparser 0.107.0", "wasmtimer", - "wat", - "zeroize", ] [[package]] name = "namada_account" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "namada_core", @@ -3637,7 +3810,7 @@ dependencies = [ [[package]] name = "namada_controller" -version = "0.37.0" +version = "0.39.0" dependencies = [ "namada_core", "smooth-operator", @@ -3646,7 +3819,7 @@ dependencies = [ [[package]] name = "namada_core" -version = "0.37.0" +version = "0.39.0" dependencies = [ "bech32 0.8.1", "borsh 1.2.1", @@ -3692,10 +3865,9 @@ dependencies = [ [[package]] name = "namada_ethereum_bridge" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", - "ethabi", "ethers", "eyre", "itertools 0.12.1", @@ -3711,18 +3883,14 @@ dependencies = [ "namada_trans_token", "namada_tx", "namada_vote_ext", - "rand 0.8.5", "serde", - "serde_json", - "tendermint 0.36.0", - "tendermint-proto 0.36.0", "thiserror", "tracing", ] [[package]] name = "namada_events" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "namada_core", @@ -3735,7 +3903,7 @@ dependencies = [ [[package]] name = "namada_gas" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "namada_core", @@ -3747,7 +3915,7 @@ dependencies = [ [[package]] name = "namada_governance" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "itertools 0.12.1", @@ -3768,7 +3936,7 @@ dependencies = [ [[package]] name = "namada_ibc" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "ibc", @@ -3779,14 +3947,12 @@ dependencies = [ "masp_primitives", "namada_core", "namada_events", - "namada_gas", "namada_governance", "namada_macros", "namada_parameters", "namada_state", "namada_storage", "namada_token", - "namada_tx", "primitive-types", "proptest", "prost", @@ -3799,7 +3965,7 @@ dependencies = [ [[package]] name = "namada_macros" -version = "0.37.0" +version = "0.39.0" dependencies = [ "data-encoding", "proc-macro2", @@ -3810,7 +3976,7 @@ dependencies = [ [[package]] name = "namada_merkle_tree" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "eyre", @@ -3824,9 +3990,8 @@ dependencies = [ [[package]] name = "namada_parameters" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "borsh 1.2.1", "namada_core", "namada_macros", "namada_storage", @@ -3835,10 +4000,9 @@ dependencies = [ [[package]] name = "namada_proof_of_stake" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", - "data-encoding", "konst", "namada_account", "namada_controller", @@ -3849,7 +4013,6 @@ dependencies = [ "namada_parameters", "namada_storage", "namada_trans_token", - "num-traits 0.2.17", "once_cell", "proptest", "serde", @@ -3860,14 +4023,14 @@ dependencies = [ [[package]] name = "namada_replay_protection" -version = "0.37.0" +version = "0.39.0" dependencies = [ "namada_core", ] [[package]] name = "namada_sdk" -version = "0.37.0" +version = "0.39.0" dependencies = [ "async-trait", "bimap", @@ -3919,7 +4082,6 @@ dependencies = [ "sha2 0.9.9", "slip10_ed25519", "smooth-operator", - "tendermint-config", "tendermint-rpc", "thiserror", "tiny-bip39", @@ -3933,7 +4095,7 @@ dependencies = [ [[package]] name = "namada_shielded_token" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "masp_primitives", @@ -3942,7 +4104,6 @@ dependencies = [ "namada_parameters", "namada_storage", "namada_trans_token", - "namada_tx", "serde", "smooth-operator", "tracing", @@ -3950,10 +4111,9 @@ dependencies = [ [[package]] name = "namada_state" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", - "ics23", "itertools 0.12.1", "namada_core", "namada_events", @@ -3966,17 +4126,14 @@ dependencies = [ "namada_tx", "patricia_tree", "proptest", - "sha2 0.9.9", "smooth-operator", - "sparse-merkle-tree", "thiserror", - "tiny-keccak", "tracing", ] [[package]] name = "namada_storage" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "itertools 0.12.1", @@ -3993,7 +4150,7 @@ dependencies = [ [[package]] name = "namada_test_utils" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "namada_core", @@ -4002,53 +4159,49 @@ dependencies = [ [[package]] name = "namada_tests" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "async-trait", - "chrono", "concat-idents", "derivative", - "flate2", "hyper", "ibc-testkit", "ics23", "itertools 0.12.1", - "lazy_static", "namada", "namada_core", "namada_sdk", "namada_test_utils", "namada_tx_prelude", "namada_vp_prelude", - "num-traits 0.2.17", "proptest", "prost", "regex", "serde", "serde_json", "sha2 0.9.9", - "tar", "tempfile", "test-log", "tokio", - "tracing", - "tracing-subscriber", ] [[package]] name = "namada_token" -version = "0.37.0" +version = "0.39.0" dependencies = [ + "borsh 1.2.1", "namada_core", "namada_events", + "namada_macros", "namada_shielded_token", "namada_storage", "namada_trans_token", + "proptest", + "serde", ] [[package]] name = "namada_trans_token" -version = "0.37.0" +version = "0.39.0" dependencies = [ "konst", "namada_core", @@ -4058,7 +4211,7 @@ dependencies = [ [[package]] name = "namada_tx" -version = "0.37.0" +version = "0.39.0" dependencies = [ "ark-bls12-381", "bitflags 2.5.0", @@ -4084,7 +4237,7 @@ dependencies = [ [[package]] name = "namada_tx_env" -version = "0.37.0" +version = "0.39.0" dependencies = [ "namada_core", "namada_events", @@ -4093,7 +4246,7 @@ dependencies = [ [[package]] name = "namada_tx_prelude" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "masp_primitives", @@ -4110,13 +4263,11 @@ dependencies = [ "namada_tx", "namada_tx_env", "namada_vm_env", - "sha2 0.9.9", - "thiserror", ] [[package]] name = "namada_vm_env" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "masp_primitives", @@ -4125,7 +4276,7 @@ dependencies = [ [[package]] name = "namada_vote_ext" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "namada_core", @@ -4136,7 +4287,7 @@ dependencies = [ [[package]] name = "namada_vp_env" -version = "0.37.0" +version = "0.39.0" dependencies = [ "derivative", "masp_primitives", @@ -4146,12 +4297,11 @@ dependencies = [ "namada_storage", "namada_tx", "smooth-operator", - "thiserror", ] [[package]] name = "namada_vp_prelude" -version = "0.37.0" +version = "0.39.0" dependencies = [ "borsh 1.2.1", "namada_account", @@ -4168,7 +4318,6 @@ dependencies = [ "namada_vm_env", "namada_vp_env", "sha2 0.9.9", - "thiserror", ] [[package]] @@ -4329,18 +4478,6 @@ dependencies = [ "syn 2.0.65", ] -[[package]] -name = "object" -version = "0.28.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" -dependencies = [ - "crc32fast", - "hashbrown 0.11.2", - "indexmap 1.9.3", - "memchr", -] - [[package]] name = "object" version = "0.32.1" @@ -4394,7 +4531,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6624905ddd92e460ff0685567539ed1ac985b2dee4c92c7edcd64fce905b00c" dependencies = [ "ct-codecs", - "getrandom 0.2.11", + "getrandom 0.2.15", "subtle", "zeroize", ] @@ -4462,7 +4599,7 @@ version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", "smallvec", @@ -4597,7 +4734,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.1.0", + "indexmap 2.2.6", ] [[package]] @@ -4935,7 +5072,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", ] [[package]] @@ -5024,19 +5161,20 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "libredox", "thiserror", ] [[package]] -name = "regalloc" -version = "0.0.34" +name = "regalloc2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62446b1d3ebf980bdc68837700af1d77b37bc430e524bf95319c6eada2a4cc02" +checksum = "300d4fbfb40c1c66a78ba3ddd41c1110247cf52f97b87d0f2fc9209bd49b030c" dependencies = [ + "fxhash", "log", - "rustc-hash", + "slice-group-by", "smallvec", ] @@ -5172,7 +5310,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" dependencies = [ "cc", - "getrandom 0.2.11", + "getrandom 0.2.15", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -5197,6 +5335,7 @@ dependencies = [ "bitvec", "bytecheck", "hashbrown 0.12.3", + "indexmap 1.9.3", "ptr_meta", "rend", "rkyv_derive", @@ -5238,6 +5377,18 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "rlsf" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222fb240c3286247ecdee6fa5341e7cdad0ffdf8e7e401d9937f2d58482a20bf" +dependencies = [ + "cfg-if", + "const-default", + "libc", + "svgbobdoc", +] + [[package]] name = "rust_decimal" version = "1.35.0" @@ -5367,7 +5518,7 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "derive_more", "parity-scale-codec", "scale-info-derive", @@ -5395,6 +5546,7 @@ dependencies = [ "schemars_derive", "serde", "serde_json", + "url", ] [[package]] @@ -5458,6 +5610,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "self_cell" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" + [[package]] name = "semver" version = "0.11.0" @@ -5499,9 +5657,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" dependencies = [ "serde_derive", ] @@ -5524,6 +5682,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_bytes" version = "0.11.12" @@ -5533,11 +5702,21 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" dependencies = [ "proc-macro2", "quote", @@ -5598,6 +5777,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.2.6", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "serdect" version = "0.2.0" @@ -5615,7 +5807,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.9.0", "opaque-debug", @@ -5627,7 +5819,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.10.7", ] @@ -5651,6 +5843,16 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shared-buffer" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16" +dependencies = [ + "bytes", + "memmap2 0.6.2", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -5703,6 +5905,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "slice-group-by" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" + [[package]] name = "slip10_ed25519" version = "0.1.3" @@ -5720,16 +5928,16 @@ checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "smooth-operator" -version = "0.6.0" -source = "git+https://github.com/heliaxdev/smooth-operator?tag=v0.6.0#1e9e2382dd6c053f54418db836f7f03143fcd2f3" +version = "0.7.0" +source = "git+https://github.com/heliaxdev/smooth-operator?tag=v0.7.0#0e182707f5e5bb9c6e0efa2d235dc9efd715d0a1" dependencies = [ "smooth-operator-impl", ] [[package]] name = "smooth-operator-impl" -version = "0.6.0" -source = "git+https://github.com/heliaxdev/smooth-operator?tag=v0.6.0#1e9e2382dd6c053f54418db836f7f03143fcd2f3" +version = "0.7.0" +source = "git+https://github.com/heliaxdev/smooth-operator?tag=v0.7.0#0e182707f5e5bb9c6e0efa2d235dc9efd715d0a1" dependencies = [ "proc-macro2", "quote", @@ -5762,7 +5970,7 @@ version = "0.3.1-pre" source = "git+https://github.com/heliaxdev/sparse-merkle-tree?rev=bab8cb96872db22cc9a139b2d3dfc4e00521d097#bab8cb96872db22cc9a139b2d3dfc4e00521d097" dependencies = [ "borsh 1.2.1", - "cfg-if 1.0.0", + "cfg-if", "ics23", "itertools 0.12.1", "sha2 0.9.9", @@ -5802,6 +6010,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "strum" version = "0.24.1" @@ -5867,6 +6081,19 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" +[[package]] +name = "svgbobdoc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2c04b93fc15d79b39c63218f15e3fdffaa4c227830686e3b7c5f41244eb3e50" +dependencies = [ + "base64 0.13.1", + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-width", +] + [[package]] name = "syn" version = "1.0.109" @@ -5957,7 +6184,7 @@ version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand", "redox_syscall", "rustix", @@ -6092,7 +6319,7 @@ dependencies = [ "async-trait", "bytes", "flex-error", - "getrandom 0.2.11", + "getrandom 0.2.15", "peg", "pin-project", "rand 0.8.5", @@ -6175,7 +6402,7 @@ version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", ] @@ -6336,6 +6563,18 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.19.15", +] + [[package]] name = "toml" version = "0.8.2" @@ -6363,7 +6602,9 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.6", + "serde", + "serde_spanned", "toml_datetime", "winnow 0.5.25", ] @@ -6374,7 +6615,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", @@ -6459,7 +6700,6 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -6518,178 +6758,158 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "tx_fail" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", - "namada_test_utils", + "getrandom 0.2.15", "namada_tests", "namada_tx_prelude", - "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "tx_infinite_guest_gas" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", - "namada_test_utils", + "getrandom 0.2.15", "namada_tests", "namada_tx_prelude", - "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "tx_infinite_host_gas" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", - "namada_test_utils", + "getrandom 0.2.15", "namada_tests", "namada_tx_prelude", - "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "tx_invalid_data" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", - "namada_test_utils", + "getrandom 0.2.15", "namada_tests", "namada_tx_prelude", - "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "tx_memory_limit" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", - "namada_test_utils", + "getrandom 0.2.15", "namada_tests", "namada_tx_prelude", - "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "tx_no_op" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", - "namada_test_utils", + "getrandom 0.2.15", "namada_tests", "namada_tx_prelude", - "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "tx_proposal_code" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", - "namada_test_utils", + "getrandom 0.2.15", + "namada_proof_of_stake", "namada_tests", "namada_tx_prelude", - "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "tx_proposal_ibc_token_inflation" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", - "namada_test_utils", + "getrandom 0.2.15", "namada_tests", "namada_tx_prelude", - "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "tx_proposal_masp_reward" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", - "namada_test_utils", + "getrandom 0.2.15", "namada_tests", "namada_tx_prelude", - "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "tx_read_storage_key" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", - "namada_test_utils", + "getrandom 0.2.15", "namada_tests", "namada_tx_prelude", - "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "tx_write" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "namada_test_utils", "namada_tests", "namada_tx_prelude", - "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] @@ -6800,6 +7020,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.7.1" @@ -6821,15 +7047,22 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "uuid" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom 0.2.11", + "getrandom 0.2.15", "serde", ] @@ -6847,114 +7080,102 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vp_always_false" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", - "namada_test_utils", + "getrandom 0.2.15", "namada_tests", - "namada_tx_prelude", "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "vp_always_true" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", - "namada_test_utils", + "getrandom 0.2.15", "namada_tests", - "namada_tx_prelude", "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "vp_eval" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", - "namada_test_utils", + "getrandom 0.2.15", "namada_tests", "namada_tx_prelude", "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "vp_infinite_guest_gas" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", - "namada_test_utils", + "getrandom 0.2.15", "namada_tests", - "namada_tx_prelude", "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "vp_infinite_host_gas" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", - "namada_test_utils", + "getrandom 0.2.15", "namada_tests", "namada_tx_prelude", "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "vp_memory_limit" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", - "namada_test_utils", + "getrandom 0.2.15", "namada_tests", - "namada_tx_prelude", "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] name = "vp_read_storage_key" -version = "0.37.0" +version = "0.39.0" dependencies = [ - "getrandom 0.2.11", - "namada_test_utils", + "getrandom 0.2.15", "namada_tests", - "namada_tx_prelude", "namada_vp_prelude", "proptest", + "rlsf", "test-log", "tracing", "tracing-subscriber", - "wee_alloc", ] [[package]] @@ -7003,7 +7224,7 @@ version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] @@ -7028,7 +7249,7 @@ version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -7083,46 +7304,38 @@ dependencies = [ [[package]] name = "wasmer" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce4a267a570e121c9375136adefa2c48810273907de9c6817bc19db4d6144bc" dependencies = [ - "cfg-if 1.0.0", + "bytes", + "cfg-if", + "derivative", "indexmap 1.9.3", "js-sys", - "loupe", "more-asserts", + "rustc-demangle", + "serde", + "serde-wasm-bindgen", + "shared-buffer", "target-lexicon", "thiserror", + "tracing", "wasm-bindgen", - "wasmer-artifact", "wasmer-compiler", "wasmer-compiler-cranelift", "wasmer-derive", - "wasmer-engine", - "wasmer-engine-dylib", - "wasmer-engine-universal", "wasmer-types", "wasmer-vm", "wat", "winapi", ] -[[package]] -name = "wasmer-artifact" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" -dependencies = [ - "enumset", - "loupe", - "thiserror", - "wasmer-compiler", - "wasmer-types", -] - [[package]] name = "wasmer-cache" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a40804bcc2567f112003182fc5edc29584da5199c4a1f5a8d6a6e4b65feff0" dependencies = [ "blake3", "hex", @@ -7132,31 +7345,42 @@ dependencies = [ [[package]] name = "wasmer-compiler" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9c23098e86ef1038155684fe50f0c1079a0e2a2e70f115b789df17e6ba98d20" dependencies = [ + "backtrace", + "bytes", + "cfg-if", + "enum-iterator", "enumset", - "loupe", + "lazy_static", + "leb128", + "memmap2 0.5.10", + "more-asserts", + "region", "rkyv", - "serde", - "serde_bytes", + "self_cell", + "shared-buffer", "smallvec", - "target-lexicon", "thiserror", "wasmer-types", - "wasmparser 0.83.0", + "wasmer-vm", + "wasmparser 0.121.2", + "winapi", + "xxhash-rust", ] [[package]] name = "wasmer-compiler-cranelift" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95287b79973ad5f485215733ef9f0d4bb951a6b7e655585d2bd3d4a4ba1253c9" dependencies = [ "cranelift-codegen", "cranelift-entity", "cranelift-frontend", "gimli 0.26.2", - "loupe", "more-asserts", "rayon", "smallvec", @@ -7164,185 +7388,128 @@ dependencies = [ "tracing", "wasmer-compiler", "wasmer-types", - "wasmer-vm", ] [[package]] name = "wasmer-compiler-singlepass" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00d78d59be3ce78ad859e176b88f0d5bec0120ece0684922d7c5da1289e251b1" dependencies = [ "byteorder", "dynasm", "dynasmrt", + "enumset", "gimli 0.26.2", "lazy_static", - "loupe", "more-asserts", "rayon", "smallvec", "wasmer-compiler", "wasmer-types", - "wasmer-vm", ] [[package]] -name = "wasmer-derive" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "wasmer-engine" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" -dependencies = [ - "backtrace", - "enumset", - "lazy_static", - "loupe", - "memmap2", - "more-asserts", - "rustc-demangle", - "serde", - "serde_bytes", - "target-lexicon", - "thiserror", - "wasmer-artifact", - "wasmer-compiler", - "wasmer-types", - "wasmer-vm", -] - -[[package]] -name = "wasmer-engine-dylib" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +name = "wasmer-config" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a0f70c177b1c5062cfe0f5308c3317751796fef9403c22a0cd7b4cacd4ccd8" dependencies = [ - "cfg-if 1.0.0", - "enum-iterator", - "enumset", - "leb128", - "libloading", - "loupe", - "object 0.28.4", - "rkyv", + "anyhow", + "bytesize", + "derive_builder", + "hex", + "indexmap 2.2.6", + "schemars", + "semver 1.0.20", "serde", - "tempfile", - "tracing", - "wasmer-artifact", - "wasmer-compiler", - "wasmer-engine", - "wasmer-object", - "wasmer-types", - "wasmer-vm", - "which", -] - -[[package]] -name = "wasmer-engine-universal" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" -dependencies = [ - "cfg-if 1.0.0", - "enumset", - "leb128", - "loupe", - "region", - "rkyv", - "wasmer-compiler", - "wasmer-engine", - "wasmer-engine-universal-artifact", - "wasmer-types", - "wasmer-vm", - "winapi", -] - -[[package]] -name = "wasmer-engine-universal-artifact" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" -dependencies = [ - "enum-iterator", - "enumset", - "loupe", - "rkyv", + "serde_cbor", + "serde_json", + "serde_yaml", "thiserror", - "wasmer-artifact", - "wasmer-compiler", - "wasmer-types", + "toml 0.8.2", + "url", ] [[package]] -name = "wasmer-object" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +name = "wasmer-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48f36aeeecb655f15fdd358bdf6e4cec27df181468fa4226084157e8462bd5e" dependencies = [ - "object 0.28.4", - "thiserror", - "wasmer-compiler", - "wasmer-types", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] name = "wasmer-types" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83cb97b6b20084757a2a8d548dc0d4179c3fe9e2d711740423a1e6aa3f8b9091" dependencies = [ - "backtrace", + "bytecheck", "enum-iterator", + "enumset", + "getrandom 0.2.15", + "hex", "indexmap 1.9.3", - "loupe", + "more-asserts", "rkyv", - "serde", + "sha2 0.10.8", + "target-lexicon", "thiserror", + "webc", + "xxhash-rust", ] [[package]] name = "wasmer-vm" -version = "2.3.0" -source = "git+https://github.com/heliaxdev/wasmer?rev=255054f7f58b7b4a525f2fee6b9b86422d1ca15b#255054f7f58b7b4a525f2fee6b9b86422d1ca15b" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc1e19d986844b17b927ec8b0c7f3da6a7a2c2cb3b0f8ca5d4cb1a1f71bfb124" dependencies = [ "backtrace", "cc", - "cfg-if 1.0.0", + "cfg-if", "corosensei", + "crossbeam-queue", + "dashmap", + "derivative", "enum-iterator", + "fnv", "indexmap 1.9.3", "lazy_static", "libc", - "loupe", "mach", - "memoffset 0.6.5", + "memoffset", "more-asserts", "region", - "rkyv", "scopeguard", - "serde", "thiserror", - "wasmer-artifact", "wasmer-types", "winapi", ] [[package]] name = "wasmparser" -version = "0.83.0" +version = "0.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a" +checksum = "29e3ac9b780c7dda0cac7a52a5d6d2d6707cc6e3451c9db209b6c758f40d7acb" +dependencies = [ + "indexmap 1.9.3", + "semver 1.0.20", +] [[package]] name = "wasmparser" -version = "0.107.0" +version = "0.121.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29e3ac9b780c7dda0cac7a52a5d6d2d6707cc6e3451c9db209b6c758f40d7acb" +checksum = "9dbe55c8f9d0dbd25d9447a5a889ff90c0cc3feaa7395310d3d826b2c703eaab" dependencies = [ - "indexmap 1.9.3", + "bitflags 2.5.0", + "indexmap 2.2.6", "semver 1.0.20", ] @@ -7392,23 +7559,41 @@ dependencies = [ ] [[package]] -name = "webpki-roots" -version = "0.25.3" +name = "webc" +version = "6.0.0-alpha9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" - -[[package]] -name = "wee_alloc" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" +checksum = "9e1b4e8dd987046eede4348d660404ff990412631b7d493f9e547adcf2862cd5" dependencies = [ - "cfg-if 0.1.10", + "anyhow", + "base64 0.21.7", + "bytes", + "cfg-if", + "clap", + "document-features", + "flate2", + "indexmap 1.9.3", "libc", - "memory_units", - "winapi", + "once_cell", + "semver 1.0.20", + "serde", + "serde_cbor", + "serde_json", + "sha2 0.10.8", + "shared-buffer", + "tar", + "tempfile", + "thiserror", + "toml 0.7.8", + "url", + "wasmer-config", ] +[[package]] +name = "webpki-roots" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" + [[package]] name = "which" version = "4.4.2" @@ -7660,7 +7845,7 @@ version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "windows-sys 0.48.0", ] @@ -7703,6 +7888,12 @@ dependencies = [ "rustix", ] +[[package]] +name = "xxhash-rust" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927da81e25be1e1a2901d59b81b37dd2efd1fc9c9345a55007f09bf5a2d3ee03" + [[package]] name = "zcash_encoding" version = "0.2.0" diff --git a/wasm_for_tests/Cargo.toml b/wasm_for_tests/Cargo.toml index 4aa5b90290..5378370874 100644 --- a/wasm_for_tests/Cargo.toml +++ b/wasm_for_tests/Cargo.toml @@ -26,14 +26,15 @@ members = [ authors = ["Heliax AG "] edition = "2021" license = "GPL-3.0" -version = "0.37.0" +version = "0.39.0" [workspace.dependencies] namada_test_utils = { path = "../crates/test_utils" } namada_tx_prelude = { path = "../crates/tx_prelude" } namada_vp_prelude = { path = "../crates/vp_prelude" } -wee_alloc = "0.4.5" -getrandom = { version = "0.2", features = ["custom"] } +namada_proof_of_stake = { path = "../crates/proof_of_stake" } +rlsf = "0.2.1" +getrandom = { version = "0.2.15", features = ["custom"] } [profile.release] # smaller and faster wasm (https://rustwasm.github.io/book/reference/code-size.html#compiling-with-link-time-optimizations-lto) diff --git a/wasm_for_tests/tx_fail.wasm b/wasm_for_tests/tx_fail.wasm index 117d3d75a9..f145bea35f 100755 Binary files a/wasm_for_tests/tx_fail.wasm and b/wasm_for_tests/tx_fail.wasm differ diff --git a/wasm_for_tests/tx_fail/Cargo.toml b/wasm_for_tests/tx_fail/Cargo.toml index 1662428c00..7ad61b1390 100644 --- a/wasm_for_tests/tx_fail/Cargo.toml +++ b/wasm_for_tests/tx_fail/Cargo.toml @@ -9,10 +9,8 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -namada_test_utils.workspace = true namada_tx_prelude.workspace = true -namada_vp_prelude.workspace = true -wee_alloc.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/tx_infinite_guest_gas.wasm b/wasm_for_tests/tx_infinite_guest_gas.wasm index 125a29f508..7116f5fdaf 100755 Binary files a/wasm_for_tests/tx_infinite_guest_gas.wasm and b/wasm_for_tests/tx_infinite_guest_gas.wasm differ diff --git a/wasm_for_tests/tx_infinite_guest_gas/Cargo.toml b/wasm_for_tests/tx_infinite_guest_gas/Cargo.toml index 18bc81e956..4ae786610a 100644 --- a/wasm_for_tests/tx_infinite_guest_gas/Cargo.toml +++ b/wasm_for_tests/tx_infinite_guest_gas/Cargo.toml @@ -9,10 +9,8 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -namada_test_utils.workspace = true namada_tx_prelude.workspace = true -namada_vp_prelude.workspace = true -wee_alloc.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/tx_infinite_host_gas.wasm b/wasm_for_tests/tx_infinite_host_gas.wasm index f64a16841a..b75e3b3264 100755 Binary files a/wasm_for_tests/tx_infinite_host_gas.wasm and b/wasm_for_tests/tx_infinite_host_gas.wasm differ diff --git a/wasm_for_tests/tx_infinite_host_gas/Cargo.toml b/wasm_for_tests/tx_infinite_host_gas/Cargo.toml index dd78ce23f2..f6173d018d 100644 --- a/wasm_for_tests/tx_infinite_host_gas/Cargo.toml +++ b/wasm_for_tests/tx_infinite_host_gas/Cargo.toml @@ -9,10 +9,8 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -namada_test_utils.workspace = true namada_tx_prelude.workspace = true -namada_vp_prelude.workspace = true -wee_alloc.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/tx_invalid_data.wasm b/wasm_for_tests/tx_invalid_data.wasm index 4fd63135dc..8285dcf297 100755 Binary files a/wasm_for_tests/tx_invalid_data.wasm and b/wasm_for_tests/tx_invalid_data.wasm differ diff --git a/wasm_for_tests/tx_invalid_data/Cargo.toml b/wasm_for_tests/tx_invalid_data/Cargo.toml index a228c741be..08ede9f085 100644 --- a/wasm_for_tests/tx_invalid_data/Cargo.toml +++ b/wasm_for_tests/tx_invalid_data/Cargo.toml @@ -9,10 +9,8 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -namada_test_utils.workspace = true namada_tx_prelude.workspace = true -namada_vp_prelude.workspace = true -wee_alloc.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/tx_memory_limit.wasm b/wasm_for_tests/tx_memory_limit.wasm index 5e283dfe21..4c871537c5 100755 Binary files a/wasm_for_tests/tx_memory_limit.wasm and b/wasm_for_tests/tx_memory_limit.wasm differ diff --git a/wasm_for_tests/tx_memory_limit/Cargo.toml b/wasm_for_tests/tx_memory_limit/Cargo.toml index 9e7206bdaf..c7d9599462 100644 --- a/wasm_for_tests/tx_memory_limit/Cargo.toml +++ b/wasm_for_tests/tx_memory_limit/Cargo.toml @@ -9,10 +9,8 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -namada_test_utils.workspace = true namada_tx_prelude.workspace = true -namada_vp_prelude.workspace = true -wee_alloc.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/tx_no_op.wasm b/wasm_for_tests/tx_no_op.wasm index cbdb61cad9..8d6c8b50ad 100755 Binary files a/wasm_for_tests/tx_no_op.wasm and b/wasm_for_tests/tx_no_op.wasm differ diff --git a/wasm_for_tests/tx_no_op/Cargo.toml b/wasm_for_tests/tx_no_op/Cargo.toml index 1edd8f9513..6a7d841196 100644 --- a/wasm_for_tests/tx_no_op/Cargo.toml +++ b/wasm_for_tests/tx_no_op/Cargo.toml @@ -9,10 +9,8 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -namada_test_utils.workspace = true namada_tx_prelude.workspace = true -namada_vp_prelude.workspace = true -wee_alloc.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/tx_proposal_code.wasm b/wasm_for_tests/tx_proposal_code.wasm index b5caf73670..e62c32e8e4 100755 Binary files a/wasm_for_tests/tx_proposal_code.wasm and b/wasm_for_tests/tx_proposal_code.wasm differ diff --git a/wasm_for_tests/tx_proposal_code/Cargo.toml b/wasm_for_tests/tx_proposal_code/Cargo.toml index 9fb447f057..871734a09d 100644 --- a/wasm_for_tests/tx_proposal_code/Cargo.toml +++ b/wasm_for_tests/tx_proposal_code/Cargo.toml @@ -9,10 +9,9 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -namada_test_utils.workspace = true namada_tx_prelude.workspace = true -namada_vp_prelude.workspace = true -wee_alloc.workspace = true +namada_proof_of_stake.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/tx_proposal_code/src/lib.rs b/wasm_for_tests/tx_proposal_code/src/lib.rs index 0080302bfa..d05e8c32ca 100644 --- a/wasm_for_tests/tx_proposal_code/src/lib.rs +++ b/wasm_for_tests/tx_proposal_code/src/lib.rs @@ -1,4 +1,10 @@ -use namada_tx_prelude::{hash::Hash, storage::Key, *}; +use std::str::FromStr; + +use dec::Dec; +use namada_proof_of_stake::storage::{read_pos_params, write_pos_params}; +use namada_tx_prelude::hash::Hash; +use namada_tx_prelude::storage::Key; +use namada_tx_prelude::*; #[transaction] fn apply_tx(ctx: &mut Ctx, _tx_data: BatchedTx) -> TxResult { @@ -10,6 +16,7 @@ fn apply_tx(ctx: &mut Ctx, _tx_data: BatchedTx) -> TxResult { let target_key = parameters_storage::get_vp_allowlist_storage_key(); ctx.write(&target_key, vec!["hash"])?; + // add tx let wasm_code_hash = Hash::sha256("test"); let wasm_code_name = "test".to_string(); @@ -25,5 +32,29 @@ fn apply_tx(ctx: &mut Ctx, _tx_data: BatchedTx) -> TxResult { let wasm_hash_key = Key::wasm_hash("test"); ctx.write_bytes(&wasm_hash_key, wasm_code_name)?; + // change pgf parameter + let pgf_inflation_key = + governance::pgf::storage::keys::get_pgf_inflation_rate_key(); + let pgf_inflation_rate = Dec::from_str("0.025").unwrap(); + ctx.write(&pgf_inflation_key, pgf_inflation_rate)?; + + // change pos parameter + let mut pos_params = read_pos_params(ctx)?.owned; + pos_params.max_inflation_rate = Dec::from_str("0.15").unwrap(); + pos_params.target_staked_ratio = Dec::from_str("0.33").unwrap(); + pos_params.rewards_gain_p = Dec::from_str("1.5").unwrap(); + pos_params.rewards_gain_d = Dec::from_str("3.5").unwrap(); + write_pos_params(ctx, &pos_params)?; + + // change ibc parameter + let ibc_denom = "transfer/channel-0/some_token_address".to_string(); + let token_address = ibc::ibc_token(ibc_denom); + + let mint_limit_token_key = ibc::mint_limit_key(&token_address); + ctx.write(&mint_limit_token_key, token::Amount::from_u64(100))?; + + let throughput_limit_token_key = ibc::throughput_limit_key(&token_address); + ctx.write(&throughput_limit_token_key, token::Amount::from_u64(100))?; + Ok(()) } diff --git a/wasm_for_tests/tx_proposal_ibc_token_inflation.wasm b/wasm_for_tests/tx_proposal_ibc_token_inflation.wasm index 5681f5ccd1..1c3eb52607 100755 Binary files a/wasm_for_tests/tx_proposal_ibc_token_inflation.wasm and b/wasm_for_tests/tx_proposal_ibc_token_inflation.wasm differ diff --git a/wasm_for_tests/tx_proposal_ibc_token_inflation/Cargo.toml b/wasm_for_tests/tx_proposal_ibc_token_inflation/Cargo.toml index 8116c055d6..e5caefcfb0 100644 --- a/wasm_for_tests/tx_proposal_ibc_token_inflation/Cargo.toml +++ b/wasm_for_tests/tx_proposal_ibc_token_inflation/Cargo.toml @@ -9,10 +9,8 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -namada_test_utils.workspace = true namada_tx_prelude.workspace = true -namada_vp_prelude.workspace = true -wee_alloc.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/tx_proposal_masp_reward.wasm b/wasm_for_tests/tx_proposal_masp_reward.wasm index 35a5748604..d31af36dbe 100755 Binary files a/wasm_for_tests/tx_proposal_masp_reward.wasm and b/wasm_for_tests/tx_proposal_masp_reward.wasm differ diff --git a/wasm_for_tests/tx_proposal_masp_reward/Cargo.toml b/wasm_for_tests/tx_proposal_masp_reward/Cargo.toml index ba52a8b614..361d8eaeef 100644 --- a/wasm_for_tests/tx_proposal_masp_reward/Cargo.toml +++ b/wasm_for_tests/tx_proposal_masp_reward/Cargo.toml @@ -9,10 +9,8 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -namada_test_utils.workspace = true namada_tx_prelude.workspace = true -namada_vp_prelude.workspace = true -wee_alloc.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/tx_read_storage_key.wasm b/wasm_for_tests/tx_read_storage_key.wasm index ff32c6c6e6..d356522709 100755 Binary files a/wasm_for_tests/tx_read_storage_key.wasm and b/wasm_for_tests/tx_read_storage_key.wasm differ diff --git a/wasm_for_tests/tx_read_storage_key/Cargo.toml b/wasm_for_tests/tx_read_storage_key/Cargo.toml index 195c76f3e8..4a4f1aef2a 100644 --- a/wasm_for_tests/tx_read_storage_key/Cargo.toml +++ b/wasm_for_tests/tx_read_storage_key/Cargo.toml @@ -9,10 +9,8 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -namada_test_utils.workspace = true namada_tx_prelude.workspace = true -namada_vp_prelude.workspace = true -wee_alloc.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/tx_write.wasm b/wasm_for_tests/tx_write.wasm index 7204ab109e..79b38f2ede 100755 Binary files a/wasm_for_tests/tx_write.wasm and b/wasm_for_tests/tx_write.wasm differ diff --git a/wasm_for_tests/tx_write/Cargo.toml b/wasm_for_tests/tx_write/Cargo.toml index d26ec28930..52ef2c7b91 100644 --- a/wasm_for_tests/tx_write/Cargo.toml +++ b/wasm_for_tests/tx_write/Cargo.toml @@ -11,8 +11,7 @@ version.workspace = true [dependencies] namada_test_utils.workspace = true namada_tx_prelude.workspace = true -namada_vp_prelude.workspace = true -wee_alloc.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/vp_always_false.wasm b/wasm_for_tests/vp_always_false.wasm index ae65b36c57..db86b0ce3b 100755 Binary files a/wasm_for_tests/vp_always_false.wasm and b/wasm_for_tests/vp_always_false.wasm differ diff --git a/wasm_for_tests/vp_always_false/Cargo.toml b/wasm_for_tests/vp_always_false/Cargo.toml index 65b36fb190..dfb265329d 100644 --- a/wasm_for_tests/vp_always_false/Cargo.toml +++ b/wasm_for_tests/vp_always_false/Cargo.toml @@ -9,10 +9,8 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -namada_test_utils.workspace = true -namada_tx_prelude.workspace = true namada_vp_prelude.workspace = true -wee_alloc.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/vp_always_true.wasm b/wasm_for_tests/vp_always_true.wasm index fdbbb26525..763161ed7f 100755 Binary files a/wasm_for_tests/vp_always_true.wasm and b/wasm_for_tests/vp_always_true.wasm differ diff --git a/wasm_for_tests/vp_always_true/Cargo.toml b/wasm_for_tests/vp_always_true/Cargo.toml index 6ba4a1a14c..9ad6a8621c 100644 --- a/wasm_for_tests/vp_always_true/Cargo.toml +++ b/wasm_for_tests/vp_always_true/Cargo.toml @@ -9,10 +9,8 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -namada_test_utils.workspace = true -namada_tx_prelude.workspace = true namada_vp_prelude.workspace = true -wee_alloc.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/vp_evail.wasm b/wasm_for_tests/vp_evail.wasm new file mode 100755 index 0000000000..8c30db6ee0 Binary files /dev/null and b/wasm_for_tests/vp_evail.wasm differ diff --git a/wasm_for_tests/vp_eval.wasm b/wasm_for_tests/vp_eval.wasm index 9edfc4a5ae..ccdfade5a7 100755 Binary files a/wasm_for_tests/vp_eval.wasm and b/wasm_for_tests/vp_eval.wasm differ diff --git a/wasm_for_tests/vp_eval/Cargo.toml b/wasm_for_tests/vp_eval/Cargo.toml index 77d5ae8f66..d6c7d13215 100644 --- a/wasm_for_tests/vp_eval/Cargo.toml +++ b/wasm_for_tests/vp_eval/Cargo.toml @@ -9,10 +9,9 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -namada_test_utils.workspace = true namada_tx_prelude.workspace = true namada_vp_prelude.workspace = true -wee_alloc.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/vp_infinite_guest_gas.wasm b/wasm_for_tests/vp_infinite_guest_gas.wasm index cc5d961568..4708b7e0d4 100755 Binary files a/wasm_for_tests/vp_infinite_guest_gas.wasm and b/wasm_for_tests/vp_infinite_guest_gas.wasm differ diff --git a/wasm_for_tests/vp_infinite_guest_gas/Cargo.toml b/wasm_for_tests/vp_infinite_guest_gas/Cargo.toml index 674646e6c0..3243cae45a 100644 --- a/wasm_for_tests/vp_infinite_guest_gas/Cargo.toml +++ b/wasm_for_tests/vp_infinite_guest_gas/Cargo.toml @@ -9,10 +9,8 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -namada_test_utils.workspace = true -namada_tx_prelude.workspace = true namada_vp_prelude.workspace = true -wee_alloc.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/vp_infinite_host_gas.wasm b/wasm_for_tests/vp_infinite_host_gas.wasm index e2c5e07d0f..233b8e33df 100755 Binary files a/wasm_for_tests/vp_infinite_host_gas.wasm and b/wasm_for_tests/vp_infinite_host_gas.wasm differ diff --git a/wasm_for_tests/vp_infinite_host_gas/Cargo.toml b/wasm_for_tests/vp_infinite_host_gas/Cargo.toml index bec1ef23ee..5f2ee8d60b 100644 --- a/wasm_for_tests/vp_infinite_host_gas/Cargo.toml +++ b/wasm_for_tests/vp_infinite_host_gas/Cargo.toml @@ -9,10 +9,9 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -namada_test_utils.workspace = true namada_tx_prelude.workspace = true namada_vp_prelude.workspace = true -wee_alloc.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/vp_memory_limit.wasm b/wasm_for_tests/vp_memory_limit.wasm index 6306d6fce8..c2562a1294 100755 Binary files a/wasm_for_tests/vp_memory_limit.wasm and b/wasm_for_tests/vp_memory_limit.wasm differ diff --git a/wasm_for_tests/vp_memory_limit/Cargo.toml b/wasm_for_tests/vp_memory_limit/Cargo.toml index ed9c0894b9..67d8d97e6a 100644 --- a/wasm_for_tests/vp_memory_limit/Cargo.toml +++ b/wasm_for_tests/vp_memory_limit/Cargo.toml @@ -9,10 +9,8 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -namada_test_utils.workspace = true -namada_tx_prelude.workspace = true namada_vp_prelude.workspace = true -wee_alloc.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/vp_read_storage_key.wasm b/wasm_for_tests/vp_read_storage_key.wasm index e0e4b18d2c..7105852723 100755 Binary files a/wasm_for_tests/vp_read_storage_key.wasm and b/wasm_for_tests/vp_read_storage_key.wasm differ diff --git a/wasm_for_tests/vp_read_storage_key/Cargo.toml b/wasm_for_tests/vp_read_storage_key/Cargo.toml index 6ba5fc315e..094c40c7b4 100644 --- a/wasm_for_tests/vp_read_storage_key/Cargo.toml +++ b/wasm_for_tests/vp_read_storage_key/Cargo.toml @@ -9,10 +9,8 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -namada_test_utils.workspace = true -namada_tx_prelude.workspace = true namada_vp_prelude.workspace = true -wee_alloc.workspace = true +rlsf.workspace = true getrandom.workspace = true [dev-dependencies] diff --git a/wasm_for_tests/wasm_source/Cargo.toml b/wasm_for_tests/wasm_source/Cargo.toml deleted file mode 100644 index 85bc53973d..0000000000 --- a/wasm_for_tests/wasm_source/Cargo.toml +++ /dev/null @@ -1,48 +0,0 @@ -[package] -authors = ["Heliax AG "] -edition = "2021" -license = "GPL-3.0" -name = "namada_wasm_for_tests" -resolver = "2" -version = "0.32.1" - -[lib] -crate-type = ["cdylib"] - -# The features should be used individually to build the selected wasm. -# Newly added wasms should also be added into the Makefile `$(wasms)` list. -[features] -tx_fail = [] -tx_infinite_guest_gas = [] -tx_infinite_host_gas = [] -tx_invalid_data = [] -tx_memory_limit = [] -tx_no_op = [] -tx_proposal_code = [] -tx_proposal_ibc_token_inflation = [] -tx_proposal_masp_reward = [] -tx_read_storage_key = [] -tx_write = [] -vp_always_false = [] -vp_always_true = [] -vp_eval = [] -vp_infinite_guest_gas = [] -vp_infinite_host_gas = [] -vp_memory_limit = [] -vp_read_storage_key = [] - -[dependencies] -namada_test_utils = {path = "../../crates/test_utils"} -namada_tx_prelude = {path = "../../crates/tx_prelude"} -namada_vp_prelude = {path = "../../crates/vp_prelude"} -wee_alloc = "0.4.5" -getrandom = { version = "0.2", features = ["custom"] } - -[dev-dependencies] -namada_tests = {path = "../../crates/tests", default-features = false, features = ["wasm-runtime"]} - -[profile.release] -# smaller and faster wasm https://rustwasm.github.io/book/reference/code-size.html#compiling-with-link-time-optimizations-lto -lto = true -# simply terminate on panics, no unwinding -panic = "abort"