diff --git a/.changelog/unreleased/SDK/2225-remove-sdk-lifetimes.md b/.changelog/unreleased/SDK/2225-remove-sdk-lifetimes.md new file mode 100644 index 0000000000..e02e6f8880 --- /dev/null +++ b/.changelog/unreleased/SDK/2225-remove-sdk-lifetimes.md @@ -0,0 +1,2 @@ +- Removed uses of lifetimes in the SDKs Namada trait and implementation + ([\#2225](https://github.com/anoma/namada/pull/2225)) \ No newline at end of file diff --git a/.changelog/unreleased/SDK/2235-with-async.md b/.changelog/unreleased/SDK/2235-with-async.md new file mode 100644 index 0000000000..1ce8c610db --- /dev/null +++ b/.changelog/unreleased/SDK/2235-with-async.md @@ -0,0 +1,2 @@ +- Added Send trait support to the SDK to allow its use in more multithreaded + contexts. ([\#2235](https://github.com/anoma/namada/pull/2235)) \ No newline at end of file diff --git a/.changelog/unreleased/bug-fixes/1993-fst-epoch-start-height.md b/.changelog/unreleased/bug-fixes/1993-fst-epoch-start-height.md new file mode 100644 index 0000000000..856a1508ce --- /dev/null +++ b/.changelog/unreleased/bug-fixes/1993-fst-epoch-start-height.md @@ -0,0 +1,2 @@ +- Fix the start block height of the first epoch. + ([\#1993](https://github.com/anoma/namada/pull/1993)) \ No newline at end of file diff --git a/.changelog/unreleased/bug-fixes/2035-outdated-eth-nonces.md b/.changelog/unreleased/bug-fixes/2035-outdated-eth-nonces.md new file mode 100644 index 0000000000..b0d728eaaf --- /dev/null +++ b/.changelog/unreleased/bug-fixes/2035-outdated-eth-nonces.md @@ -0,0 +1,2 @@ +- Fix Ethereum event validation/state updates when more than one validator is + running the chain ([\#2035](https://github.com/anoma/namada/pull/2035)) \ No newline at end of file diff --git a/.changelog/unreleased/bug-fixes/2230-masp-rewards.md b/.changelog/unreleased/bug-fixes/2230-masp-rewards.md new file mode 100644 index 0000000000..b50a828064 --- /dev/null +++ b/.changelog/unreleased/bug-fixes/2230-masp-rewards.md @@ -0,0 +1,2 @@ +- Fix possible underflow in MASP rewards calculation. + ([\#2230](https://github.com/anoma/namada/pull/2230)) \ No newline at end of file diff --git a/.changelog/unreleased/improvements/1764-halt-oracle-from-ledger.md b/.changelog/unreleased/improvements/1764-halt-oracle-from-ledger.md new file mode 100644 index 0000000000..8921ac4529 --- /dev/null +++ b/.changelog/unreleased/improvements/1764-halt-oracle-from-ledger.md @@ -0,0 +1,5 @@ +Allow the ethereum oracle to be activated / deactivated via config +updates sent from ledger. This allows governance to shut down the +ledger without restarts. Otherwise, disconnecting from Ethereum will +result in the ledger crashing. +([\#1764](https://github.com/anoma/namada/pull/1764)) diff --git a/.changelog/unreleased/improvements/2110-prune-bp-merkle-tree.md b/.changelog/unreleased/improvements/2110-prune-bp-merkle-tree.md new file mode 100644 index 0000000000..4abce31ec0 --- /dev/null +++ b/.changelog/unreleased/improvements/2110-prune-bp-merkle-tree.md @@ -0,0 +1,2 @@ +- Prune merkle tree of bridge pool + ([\#2110](https://github.com/anoma/namada/issues/2110)) \ No newline at end of file diff --git a/.changelog/unreleased/improvements/2153-revert-chain-id-format.md b/.changelog/unreleased/improvements/2153-revert-chain-id-format.md new file mode 100644 index 0000000000..d3ca2c0a15 --- /dev/null +++ b/.changelog/unreleased/improvements/2153-revert-chain-id-format.md @@ -0,0 +1,2 @@ +- Revert the chain ID format by upgrading ibc-rs to 0.48.1 + ([\#2153](https://github.com/anoma/namada/issues/2153)) \ No newline at end of file diff --git a/.changelog/unreleased/improvements/2202-combine-user-validator-vp.md b/.changelog/unreleased/improvements/2202-combine-user-validator-vp.md new file mode 100644 index 0000000000..030af2ca17 --- /dev/null +++ b/.changelog/unreleased/improvements/2202-combine-user-validator-vp.md @@ -0,0 +1,2 @@ +- Combined the user and the validator VP into one. + ([\#2202](https://github.com/anoma/namada/pull/2202)) \ No newline at end of file diff --git a/.changelog/unreleased/improvements/2205-network-gas.md b/.changelog/unreleased/improvements/2205-network-gas.md new file mode 100644 index 0000000000..77891ac403 --- /dev/null +++ b/.changelog/unreleased/improvements/2205-network-gas.md @@ -0,0 +1,2 @@ +- Charge gas for network usage. + ([\#2205](https://github.com/anoma/namada/pull/2205)) \ No newline at end of file diff --git a/.changelog/unreleased/improvements/2208-init-validator-wo-account.md b/.changelog/unreleased/improvements/2208-init-validator-wo-account.md new file mode 100644 index 0000000000..f12ec7704f --- /dev/null +++ b/.changelog/unreleased/improvements/2208-init-validator-wo-account.md @@ -0,0 +1,9 @@ +- A new `tx_become_validator` replaces `tx_init_validator`. This tx doesn't + initialize a new account and instead it modifies an existing established + address to become a validator. This currently requires that there are no + delegations on the source account before it can become a validator (if there + are some, they have to be unbonded, but they don't have to be withdrawn). + A new client command `become-validator` is added that requires an `--address`. + The client command `init-validator` is kept for convenience and updated to + send `tx_init_account` tx before `tx_become_validator`. + ([\#2208](https://github.com/anoma/namada/pull/2208)) \ No newline at end of file diff --git a/.changelog/unreleased/improvements/2209-cli-public-keys.md b/.changelog/unreleased/improvements/2209-cli-public-keys.md new file mode 100644 index 0000000000..33486a7c1d --- /dev/null +++ b/.changelog/unreleased/improvements/2209-cli-public-keys.md @@ -0,0 +1,2 @@ +- Increase hardware wallet support in the CLI + ([\#2209](https://github.com/anoma/namada/pull/2209)) \ No newline at end of file diff --git a/.changelog/unreleased/improvements/2215-vp-less-permissive.md b/.changelog/unreleased/improvements/2215-vp-less-permissive.md new file mode 100644 index 0000000000..57faf65be7 --- /dev/null +++ b/.changelog/unreleased/improvements/2215-vp-less-permissive.md @@ -0,0 +1,2 @@ +- Handle errors on loading WASMs from file-system compilation cache. + ([\#2215](https://github.com/anoma/namada/pull/2215)) \ No newline at end of file diff --git a/.changelog/unreleased/improvements/2217-upgrade-pos-rewards.md b/.changelog/unreleased/improvements/2217-upgrade-pos-rewards.md new file mode 100644 index 0000000000..b198a23962 --- /dev/null +++ b/.changelog/unreleased/improvements/2217-upgrade-pos-rewards.md @@ -0,0 +1,3 @@ +- Implement a CLI query for available rewards from a bond, + and improve the bond amount for rewards computation + ([\#2217](https://github.com/anoma/namada/pull/2217)) \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index a760f39701..e3495610b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -500,7 +500,7 @@ dependencies = [ "hmac 0.12.1", "pbkdf2 0.10.1", "rand 0.8.5", - "sha2 0.10.6", + "sha2 0.10.8", "unicode-normalization", "zeroize", ] @@ -597,7 +597,7 @@ dependencies = [ "cc", "cfg-if 1.0.0", "constant_time_eq", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -762,9 +762,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" dependencies = [ "serde 1.0.190", ] @@ -1000,13 +1000,13 @@ dependencies = [ "bincode", "bs58", "coins-core", - "digest 0.10.6", + "digest 0.10.7", "getrandom 0.2.10", "hmac 0.12.1", "k256", "lazy_static", "serde 1.0.190", - "sha2 0.10.6", + "sha2 0.10.8", "thiserror", ] @@ -1023,7 +1023,7 @@ dependencies = [ "once_cell", "pbkdf2 0.12.1", "rand 0.8.5", - "sha2 0.10.6", + "sha2 0.10.8", "thiserror", ] @@ -1036,13 +1036,13 @@ dependencies = [ "base64 0.21.0", "bech32 0.7.3", "bs58", - "digest 0.10.6", + "digest 0.10.7", "generic-array 0.14.7", "hex", "ripemd", "serde 1.0.190", "serde_derive", - "sha2 0.10.6", + "sha2 0.10.8", "sha3", "thiserror", ] @@ -1424,17 +1424,32 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] name = "curve25519-dalek" -version = "3.2.0" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", + "cfg-if 1.0.0", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "platforms", + "rustc_version 0.4.0", "subtle 2.4.1", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "curve25519-dalek-ng" version = "4.1.1" @@ -1559,9 +1574,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", "const-oid", @@ -1651,23 +1666,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" dependencies = [ "der", - "digest 0.10.6", + "digest 0.10.7", "elliptic-curve", "rfc6979", "serdect", - "signature 2.1.0", + "signature", "spki", ] -[[package]] -name = "ed25519" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" -dependencies = [ - "signature 1.6.4", -] - [[package]] name = "ed25519" version = "2.2.2" @@ -1675,7 +1681,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d" dependencies = [ "pkcs8", - "signature 2.1.0", + "signature", ] [[package]] @@ -1708,15 +1714,15 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "1.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" dependencies = [ "curve25519-dalek", - "ed25519 1.5.3", - "rand 0.7.3", + "ed25519", "serde 1.0.190", - "sha2 0.9.9", + "sha2 0.10.8", + "subtle 2.4.1", "zeroize", ] @@ -1734,7 +1740,7 @@ checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" dependencies = [ "base16ct", "crypto-bigint", - "digest 0.10.6", + "digest 0.10.7", "ff", "generic-array 0.14.7", "group", @@ -1861,7 +1867,7 @@ checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" dependencies = [ "aes", "ctr", - "digest 0.10.6", + "digest 0.10.7", "hex", "hmac 0.12.1", "pbkdf2 0.11.0", @@ -1869,7 +1875,7 @@ dependencies = [ "scrypt", "serde 1.0.190", "serde_json", - "sha2 0.10.6", + "sha2 0.10.8", "sha3", "thiserror", "uuid 0.8.2", @@ -2169,7 +2175,7 @@ dependencies = [ "ethers-core", "hex", "rand 0.8.5", - "sha2 0.10.6", + "sha2 0.10.8", "thiserror", "tracing", ] @@ -2239,6 +2245,12 @@ dependencies = [ "subtle 2.4.1", ] +[[package]] +name = "fiat-crypto" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" + [[package]] name = "filetime" version = "0.2.21" @@ -2749,7 +2761,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -2891,40 +2903,389 @@ dependencies = [ [[package]] name = "ibc" -version = "0.47.0" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "429b6aca6624a9364878e28c90311438c2621a8270942d80732b2651ac38ac74" +dependencies = [ + "ibc-apps", + "ibc-clients", + "ibc-core", + "ibc-core-host-cosmos", + "ibc-derive", + "ibc-primitives", +] + +[[package]] +name = "ibc-app-transfer" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b177b343385d9654d99be4709b5ed1574d41f91dfa4044b2d26d688be4179d7c" +dependencies = [ + "ibc-app-transfer-types", + "ibc-core", + "serde-json-wasm", +] + +[[package]] +name = "ibc-app-transfer-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95f92a3eda225e5c86e7bb6501c95986583ac541c4369d3c528349d81390f947" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core", + "ibc-proto", + "primitive-types", + "serde 1.0.190", + "uint", +] + +[[package]] +name = "ibc-apps" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4be40d55ed2dea9f2d05b902a3586f20850c723e4bdbfc4fb0ebe7a66ca5e40" +dependencies = [ + "ibc-app-transfer", +] + +[[package]] +name = "ibc-client-tendermint" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119aa5873214228bf69bded3f20022b9ae1bc35b6841d295afcd73e53db05ccf" +dependencies = [ + "ibc-client-tendermint-types", + "ibc-core-client", + "ibc-core-commitment-types", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-primitives", + "prost 0.12.1", + "serde 1.0.190", + "tendermint", + "tendermint-light-client-verifier", +] + +[[package]] +name = "ibc-client-tendermint-types" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "184eb22140cb4143bbcf7ddc8fdfeb9cc058ef73a6066f8ea78162e69d3565d1" +checksum = "6f21679016931b332b295a761e65cc122dc6fbfb98444148b681ad3aaa474665" dependencies = [ "bytes", + "displaydoc", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde 1.0.190", + "tendermint", + "tendermint-light-client-verifier", + "tendermint-proto", +] + +[[package]] +name = "ibc-clients" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c660323e93107a136aa3dbc412b7fa2eafd315c2fe71184096a43800f8ca5" +dependencies = [ + "ibc-client-tendermint", +] + +[[package]] +name = "ibc-core" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "100d9d0aa67432c5078a8a1c818e3fc990a193be6d35ed0abeda5b340d16c1da" +dependencies = [ + "ibc-core-channel", + "ibc-core-client", + "ibc-core-commitment-types", + "ibc-core-connection", + "ibc-core-handler", + "ibc-core-host", + "ibc-core-router", + "ibc-primitives", +] + +[[package]] +name = "ibc-core-channel" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebaa37629ac029f914dfe552ab5dad01ddb240ec885ed0ae68221cbea4e9bfc" +dependencies = [ + "ibc-core-channel-types", + "ibc-core-client", + "ibc-core-commitment-types", + "ibc-core-connection", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-core-router", + "ibc-primitives", + "prost 0.12.1", +] + +[[package]] +name = "ibc-core-channel-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2ba72c56c411b1e0ce6dc3f5e1fa1de9e6c84891f425b7be8a9e1705964378" +dependencies = [ "derive_more", "displaydoc", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-connection-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde 1.0.190", + "sha2 0.10.8", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-client" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c4fac8e05201795073dee8c93d5afe9dfeac9aec2412b4a2b0c5f0d1e1d725" +dependencies = [ + "ibc-core-client-context", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-primitives", + "prost 0.12.1", +] + +[[package]] +name = "ibc-core-client-context" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b82abd9489021730d59ab2d00e9438d3711e8e78ecba4d083b64f833301682b" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-handler-types", + "ibc-core-host-types", "ibc-derive", + "ibc-primitives", + "prost 0.12.1", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-client-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bafdbf6db5dab4c8ad610b6940e23b4f8abd0a6ac5e8e2801415a95defd4a583" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-commitment-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde 1.0.190", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-commitment-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed4256b0216fc49024bac7e01c61b9bb055e31914ffe9ce6f468d7ce496a9357" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-primitives", + "ibc-proto", + "ics23", + "prost 0.12.1", + "serde 1.0.190", + "subtle-encoding", +] + +[[package]] +name = "ibc-core-connection" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e237b70b9ba0177a4e59ac9048fffac2ac44c334703cc0ae403ad221450850" +dependencies = [ + "ibc-core-client", + "ibc-core-connection-types", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-primitives", + "prost 0.12.1", +] + +[[package]] +name = "ibc-core-connection-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca841416fa29626423917099092f3698ae2735074cb3fe42936ddf6b2ccbf2f7" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde 1.0.190", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-handler" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47e5e5a006aa0fc87ec3f5fb1e0ef6dd5aeea5079fa927d799d526c44329987" +dependencies = [ + "ibc-core-channel", + "ibc-core-client", + "ibc-core-commitment-types", + "ibc-core-connection", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-core-router", + "ibc-primitives", +] + +[[package]] +name = "ibc-core-handler-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3d59a8a5eb2069530c42783b4fef63472a89e0e9242334351df1bb58aaf542" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-channel-types", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-connection-types", + "ibc-core-host-types", + "ibc-core-router-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde 1.0.190", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-host" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aa63c895c0e5a75e42fe859b8fd4250c12bfa8b9c6b114f94c927ecfad38a03" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-channel-types", + "ibc-core-client-context", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-connection-types", + "ibc-core-handler-types", + "ibc-core-host-types", + "ibc-primitives", + "prost 0.12.1", + "subtle-encoding", +] + +[[package]] +name = "ibc-core-host-cosmos" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a325862af6c20b0df3d27c072a2d802a7232dc1666214d738cdfbd9a9c99720" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-app-transfer-types", + "ibc-client-tendermint", + "ibc-core-client-context", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-connection-types", + "ibc-core-handler-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde 1.0.190", + "sha2 0.10.8", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-host-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616955da310febbe93c0569a2feebd9f57cafed3eee5a56b0c3bb953a75f6089" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-primitives", + "serde 1.0.190", +] + +[[package]] +name = "ibc-core-router" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31fe115da73e0616bdb44400fa6b11ca251648d070c4ff419d58e27804d30243" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router-types", + "ibc-primitives", + "prost 0.12.1", + "subtle-encoding", +] + +[[package]] +name = "ibc-core-router-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d1fbb0bbbdeafa7ac989ba1693ed46d22e0e3eb0bdae478544e31157a4fdba6" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-host-types", + "ibc-primitives", "ibc-proto", "ics23", - "num-traits 0.2.15", - "parking_lot", - "primitive-types", "prost 0.12.1", "serde 1.0.190", - "serde-json-wasm", - "serde_derive", - "sha2 0.10.6", "subtle-encoding", "tendermint", - "tendermint-light-client-verifier", - "tendermint-proto", - "tendermint-testgen", - "time", - "tracing", - "typed-builder", - "uint", ] [[package]] name = "ibc-derive" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92f1528535e9ca495badb76c143bdd4763c1c9d987f59d1f8b47963ba0c11674" +checksum = "df07bf5bc1e65e291506b7497633e07967e49b36a8db10cda77a8fd686eb4548" dependencies = [ "darling", "proc-macro2", @@ -2932,11 +3293,26 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "ibc-primitives" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5edea4685267fd68514c87e7aa3a62712340c4cff6903f088a9ab571428a08a" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-proto", + "prost 0.12.1", + "serde 1.0.190", + "tendermint", + "time", +] + [[package]] name = "ibc-proto" -version = "0.37.1" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63042806bb2f662ca1c68026231900cfe13361136ddfd0dd09bcb315056a22b8" +checksum = "93cbf4cbe9e5113cc7c70f3208a7029b2205c629502cbb2ae7ea0a09a97d3005" dependencies = [ "base64 0.21.0", "bytes", @@ -2948,6 +3324,27 @@ dependencies = [ "tendermint-proto", ] +[[package]] +name = "ibc-testkit" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f550c91648f3db6474880e18cd2bd294096a99b30621aa01a9059b71e3612d98" +dependencies = [ + "bytes", + "derive_more", + "displaydoc", + "ibc", + "ibc-proto", + "parking_lot", + "primitive-types", + "prost 0.12.1", + "subtle-encoding", + "tendermint", + "tendermint-testgen", + "tracing", + "typed-builder", +] + [[package]] name = "ics23" version = "0.11.0" @@ -2961,7 +3358,7 @@ dependencies = [ "prost 0.12.1", "ripemd", "serde 1.0.190", - "sha2 0.10.6", + "sha2 0.10.8", "sha3", ] @@ -3208,8 +3605,8 @@ dependencies = [ "elliptic-curve", "once_cell", "serdect", - "sha2 0.10.6", - "signature 2.1.0", + "sha2 0.10.8", + "signature", ] [[package]] @@ -3253,7 +3650,7 @@ dependencies = [ [[package]] name = "ledger-namada-rs" version = "0.0.1" -source = "git+https://github.com/heliaxdev/ledger-namada?rev=7e861c440de0fdabaf51e30d97f5c8736be348f3#7e861c440de0fdabaf51e30d97f5c8736be348f3" +source = "git+https://github.com/Zondax/ledger-namada?tag=v0.0.12#3e7c30bec1d1e135b94c80b48b194aa7341519a4" dependencies = [ "bincode", "byteorder", @@ -3263,7 +3660,7 @@ dependencies = [ "ledger-zondax-generic", "prost 0.11.9", "prost-types 0.11.9", - "sha2 0.10.6", + "sha2 0.10.8", "thiserror", ] @@ -3532,7 +3929,7 @@ dependencies = [ "num-traits 0.2.15", "rand 0.8.5", "rand_core 0.6.4", - "sha2 0.10.6", + "sha2 0.10.8", "subtle 2.4.1", "zcash_encoding", ] @@ -3749,6 +4146,7 @@ dependencies = [ "eyre", "fd-lock", "futures", + "ibc-testkit", "itertools 0.10.5", "k256", "loupe", @@ -3923,7 +4321,7 @@ dependencies = [ "eyre", "ibc", "ibc-derive", - "ibc-proto", + "ibc-testkit", "ics23", "impl-num-traits", "index-set", @@ -4105,6 +4503,8 @@ dependencies = [ "eyre", "fs_extra", "hyper", + "ibc-testkit", + "ics23", "itertools 0.10.5", "lazy_static", "namada", @@ -4724,7 +5124,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "password-hash", ] @@ -4734,7 +5134,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -4743,7 +5143,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0ca0b5a68607598bf3bad68f32227a8164f6254833f84eafaac409cd6746c31" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "hmac 0.12.1", ] @@ -4864,6 +5264,12 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "platforms" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" + [[package]] name = "plotters" version = "0.3.5" @@ -4968,9 +5374,9 @@ dependencies = [ [[package]] name = "primitive-types" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", "impl-codec", @@ -5510,7 +5916,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -5812,7 +6218,7 @@ dependencies = [ "hmac 0.12.1", "pbkdf2 0.11.0", "salsa20", - "sha2 0.10.6", + "sha2 0.10.8", ] [[package]] @@ -6047,7 +6453,7 @@ checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -6077,13 +6483,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -6092,7 +6498,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "keccak", ] @@ -6130,19 +6536,13 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" - [[package]] name = "signature" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "rand_core 0.6.4", ] @@ -6433,8 +6833,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc2294fa667c8b548ee27a9ba59115472d0a09c2ba255771092a7f1dcf03a789" dependencies = [ "bytes", - "digest 0.10.6", - "ed25519 2.2.2", + "digest 0.10.7", + "ed25519", "ed25519-consensus 2.1.0", "flex-error", "futures", @@ -6448,8 +6848,8 @@ dependencies = [ "serde_bytes", "serde_json", "serde_repr", - "sha2 0.10.6", - "signature 2.1.0", + "sha2 0.10.8", + "signature", "subtle 2.4.1", "subtle-encoding", "tendermint-proto", @@ -6989,11 +7389,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if 1.0.0", "log", "pin-project-lite", "tracing-attributes", @@ -7013,9 +7412,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.24" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", @@ -7024,9 +7423,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", @@ -7120,18 +7519,18 @@ dependencies = [ [[package]] name = "typed-builder" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c6a006a6d3d6a6f143fda41cf4d1ad35110080687628c9f2117bd3cc7924f3" +checksum = "e47c0496149861b7c95198088cbf36645016b1a0734cf350c50e2a38e070f38a" dependencies = [ "typed-builder-macro", ] [[package]] name = "typed-builder-macro" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fa054ee5e2346187d631d2f1d1fd3b33676772d6d03a2d84e1c5213b31674ee" +checksum = "982ee4197351b5c9782847ef5ec1fdcaf50503fb19d68f9771adae314e72b492" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index c1fa8f6d03..fd6c152151 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,12 +81,15 @@ flate2 = "1.0.22" fs_extra = "1.2.0" futures = "0.3" git2 = "0.13.25" +ibc = {version = "0.48.1", default-features = false, features = ["serde"]} +ibc-derive = "0.4.0" +ibc-testkit = {version = "0.48.1", default-features = false} ics23 = "0.11.0" index-set = {git = "https://github.com/heliaxdev/index-set", tag = "v0.8.0", features = ["serialize-borsh", "serialize-serde"]} itertools = "0.10.0" k256 = { version = "0.13.0", default-features = false, features = ["ecdsa", "pkcs8", "precomputed-tables", "serde", "std"]} lazy_static = "1.4.0" -ledger-namada-rs = { git = "https://github.com/heliaxdev/ledger-namada", rev = "7e861c440de0fdabaf51e30d97f5c8736be348f3" } +ledger-namada-rs = { git = "https://github.com/Zondax/ledger-namada", tag = "v0.0.12" } ledger-transport-hid = "0.10.0" libc = "0.2.97" libloading = "0.7.2" diff --git a/apps/src/bin/namada-client/main.rs b/apps/src/bin/namada-client/main.rs index 770dcf5367..9fdea9c51d 100644 --- a/apps/src/bin/namada-client/main.rs +++ b/apps/src/bin/namada-client/main.rs @@ -16,7 +16,7 @@ async fn main() -> Result<()> { CliApi::handle_client_command::( None, cli::namada_client_cli()?, - &CliIo, + CliIo, ) .await } diff --git a/apps/src/bin/namada-relayer/main.rs b/apps/src/bin/namada-relayer/main.rs index f9d98a2a4e..1eb2679e28 100644 --- a/apps/src/bin/namada-relayer/main.rs +++ b/apps/src/bin/namada-relayer/main.rs @@ -14,5 +14,5 @@ async fn main() -> Result<()> { let cmd = cli::namada_relayer_cli()?; // run the CLI - CliApi::handle_relayer_command::(None, cmd, &CliIo).await + CliApi::handle_relayer_command::(None, cmd, CliIo).await } diff --git a/apps/src/lib/bench_utils.rs b/apps/src/lib/bench_utils.rs index 551bf49abd..1863ea9bf4 100644 --- a/apps/src/lib/bench_utils.rs +++ b/apps/src/lib/bench_utils.rs @@ -19,39 +19,39 @@ use namada::core::types::address::{self, Address}; use namada::core::types::key::common::SecretKey; use namada::core::types::storage::Key; use namada::core::types::token::{Amount, Transfer}; -use namada::ibc::applications::transfer::msgs::transfer::MsgTransfer; -use namada::ibc::applications::transfer::packet::PacketData; -use namada::ibc::applications::transfer::PrefixedCoin; -use namada::ibc::clients::ics07_tendermint::client_state::{ - AllowUpdate, ClientState, +use namada::ibc::apps::transfer::types::msgs::transfer::MsgTransfer; +use namada::ibc::apps::transfer::types::packet::PacketData; +use namada::ibc::apps::transfer::types::PrefixedCoin; +use namada::ibc::clients::tendermint::client_state::ClientState; +use namada::ibc::clients::tendermint::consensus_state::ConsensusState; +use namada::ibc::clients::tendermint::types::{ + AllowUpdate, ClientState as ClientStateType, + ConsensusState as ConsensusStateType, TrustThreshold, }; -use namada::ibc::clients::ics07_tendermint::consensus_state::ConsensusState; -use namada::ibc::clients::ics07_tendermint::trust_threshold::TrustThreshold; -use namada::ibc::core::ics02_client::client_type::ClientType; -use namada::ibc::core::ics03_connection::connection::{ - ConnectionEnd, Counterparty, State as ConnectionState, -}; -use namada::ibc::core::ics03_connection::version::Version; -use namada::ibc::core::ics04_channel::channel::{ +use namada::ibc::core::channel::types::channel::{ ChannelEnd, Counterparty as ChannelCounterparty, Order, State, }; -use namada::ibc::core::ics04_channel::timeout::TimeoutHeight; -use namada::ibc::core::ics04_channel::Version as ChannelVersion; -use namada::ibc::core::ics23_commitment::commitment::{ +use namada::ibc::core::channel::types::timeout::TimeoutHeight; +use namada::ibc::core::channel::types::Version as ChannelVersion; +use namada::ibc::core::client::types::Height as IbcHeight; +use namada::ibc::core::commitment_types::commitment::{ CommitmentPrefix, CommitmentRoot, }; -use namada::ibc::core::ics23_commitment::specs::ProofSpecs; -use namada::ibc::core::ics24_host::identifier::{ +use namada::ibc::core::commitment_types::specs::ProofSpecs; +use namada::ibc::core::connection::types::version::Version; +use namada::ibc::core::connection::types::{ + ConnectionEnd, Counterparty, State as ConnectionState, +}; +use namada::ibc::core::host::types::identifiers::{ ChainId as IbcChainId, ChannelId as NamadaChannelId, ChannelId, ClientId, - ConnectionId, ConnectionId as NamadaConnectionId, PortId as NamadaPortId, - PortId, + ClientType, ConnectionId, ConnectionId as NamadaConnectionId, + PortId as NamadaPortId, PortId, +}; +use namada::ibc::core::host::types::path::{ + ClientConsensusStatePath, ClientStatePath, Path as IbcPath, }; -use namada::ibc::core::ics24_host::path::Path as IbcPath; -use namada::ibc::core::timestamp::Timestamp as IbcTimestamp; -use namada::ibc::core::Msg; -use namada::ibc::Height as IbcHeight; -use namada::ibc_proto::google::protobuf::Any; -use namada::ibc_proto::protobuf::Protobuf; +use namada::ibc::primitives::proto::{Any, Protobuf}; +use namada::ibc::primitives::{Msg, Timestamp as IbcTimestamp}; use namada::ledger::dry_run_tx; use namada::ledger::gas::TxGasMeter; use namada::ledger::ibc::storage::{channel_key, connection_key}; @@ -80,20 +80,20 @@ use namada_sdk::masp::{ self, ShieldedContext, ShieldedTransfer, ShieldedUtils, }; pub use namada_sdk::tx::{ - TX_BOND_WASM, TX_BRIDGE_POOL_WASM, + TX_BECOME_VALIDATOR_WASM, TX_BOND_WASM, TX_BRIDGE_POOL_WASM, TX_CHANGE_COMMISSION_WASM as TX_CHANGE_VALIDATOR_COMMISSION_WASM, TX_CHANGE_CONSENSUS_KEY_WASM, TX_CHANGE_METADATA_WASM as TX_CHANGE_VALIDATOR_METADATA_WASM, TX_CLAIM_REWARDS_WASM, TX_DEACTIVATE_VALIDATOR_WASM, TX_IBC_WASM, TX_INIT_ACCOUNT_WASM, TX_INIT_PROPOSAL as TX_INIT_PROPOSAL_WASM, - TX_INIT_VALIDATOR_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_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, VP_VALIDATOR_WASM, + TX_WITHDRAW_WASM, VP_USER_WASM, }; use namada_sdk::wallet::Wallet; -use namada_sdk::NamadaImpl; +use namada_sdk::{Namada, NamadaImpl}; use namada_test_utils::tx_data::TxWriteData; use rand_core::OsRng; use sha2::{Digest, Sha256}; @@ -424,15 +424,11 @@ impl BenchShell { ClientId::new(ClientType::new("01-tendermint").unwrap(), 1) .unwrap(); let client_state_key = addr_key.join(&Key::from( - IbcPath::ClientState( - namada::ibc::core::ics24_host::path::ClientStatePath( - client_id.clone(), - ), - ) - .to_string() - .to_db_key(), + IbcPath::ClientState(ClientStatePath(client_id.clone())) + .to_string() + .to_db_key(), )); - let client_state = ClientState::new( + let client_state = ClientStateType::new( IbcChainId::from_str(&ChainId::default().to_string()).unwrap(), TrustThreshold::ONE_THIRD, std::time::Duration::new(100, 0), @@ -446,8 +442,9 @@ impl BenchShell { after_misbehaviour: true, }, ) - .unwrap(); - let bytes = >::encode_vec(&client_state); + .unwrap() + .into(); + let bytes = >::encode_vec(client_state); self.wl_storage .storage .write(&client_state_key, bytes) @@ -457,25 +454,24 @@ impl BenchShell { let now: namada::tendermint::Time = DateTimeUtc::now().try_into().unwrap(); let consensus_key = addr_key.join(&Key::from( - IbcPath::ClientConsensusState( - namada::ibc::core::ics24_host::path::ClientConsensusStatePath { - client_id: client_id.clone(), - epoch: 0, - height: 1, - }, - ) + IbcPath::ClientConsensusState(ClientConsensusStatePath { + client_id: client_id.clone(), + revision_number: 0, + revision_height: 1, + }) .to_string() .to_db_key(), )); - let consensus_state = ConsensusState { + let consensus_state = ConsensusStateType { timestamp: now, root: CommitmentRoot::from_bytes(&[]), next_validators_hash: Hash::Sha256([0u8; 32]), - }; + } + .into(); let bytes = - >::encode_vec(&consensus_state); + >::encode_vec(consensus_state); self.wl_storage .storage .write(&consensus_key, bytes) @@ -819,11 +815,11 @@ impl Default for BenchShieldedCtx { impl BenchShieldedCtx { pub fn generate_masp_tx( - &mut self, + mut self, amount: Amount, source: TransferSource, target: TransferTarget, - ) -> Tx { + ) -> (Self, Tx) { let denominated_amount = DenominatedAmount { amount, denom: 0.into(), @@ -840,12 +836,13 @@ impl BenchShieldedCtx { &[], )) .unwrap(); + let native_token = self.shell.wl_storage.storage.native_token.clone(); let namada = NamadaImpl::native_new( - &self.shell, - &mut self.wallet, - &mut self.shielded, - &StdIo, - self.shell.wl_storage.storage.native_token.clone(), + self.shell, + self.wallet, + self.shielded, + StdIo, + native_token, ); let shielded = async_runtime .block_on( @@ -877,7 +874,7 @@ impl BenchShieldedCtx { ) }); - self.shell.generate_tx( + let tx = namada.client().generate_tx( TX_TRANSFER_WASM, Transfer { source: source.effective_address(), @@ -890,6 +887,18 @@ impl BenchShieldedCtx { shielded, None, vec![&defaults::albert_keypair()], - ) + ); + let NamadaImpl { + client, + wallet, + shielded, + .. + } = namada; + let ctx = Self { + shielded: shielded.into_inner(), + shell: client, + wallet: wallet.into_inner(), + }; + (ctx, tx) } } diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs index 3bb7f5c7ad..3c2a5fa66b 100644 --- a/apps/src/lib/cli.rs +++ b/apps/src/lib/cli.rs @@ -223,6 +223,7 @@ pub mod cmds { .subcommand(TxInitProposal::def().display_order(1)) .subcommand(TxVoteProposal::def().display_order(1)) // PoS transactions + .subcommand(TxBecomeValidator::def().display_order(2)) .subcommand(TxInitValidator::def().display_order(2)) .subcommand(TxUnjailValidator::def().display_order(2)) .subcommand(TxDeactivateValidator::def().display_order(2)) @@ -260,6 +261,7 @@ pub mod cmds { .subcommand(QueryPgf::def().display_order(5)) .subcommand(QueryValidatorState::def().display_order(5)) .subcommand(QueryCommissionRate::def().display_order(5)) + .subcommand(QueryRewards::def().display_order(5)) .subcommand(QueryMetaData::def().display_order(5)) // Actions .subcommand(SignTx::def().display_order(6)) @@ -276,6 +278,8 @@ pub mod cmds { let tx_update_account = Self::parse_with_ctx(matches, TxUpdateAccount); let tx_init_account = Self::parse_with_ctx(matches, TxInitAccount); + let tx_become_validator = + Self::parse_with_ctx(matches, TxBecomeValidator); let tx_init_validator = Self::parse_with_ctx(matches, TxInitValidator); let tx_unjail_validator = @@ -315,6 +319,7 @@ pub mod cmds { let query_bonded_stake = Self::parse_with_ctx(matches, QueryBondedStake); let query_slashes = Self::parse_with_ctx(matches, QuerySlashes); + let query_rewards = Self::parse_with_ctx(matches, QueryRewards); let query_delegations = Self::parse_with_ctx(matches, QueryDelegations); let query_find_validator = @@ -346,6 +351,7 @@ pub mod cmds { .or(tx_reveal_pk) .or(tx_init_proposal) .or(tx_vote_proposal) + .or(tx_become_validator) .or(tx_init_validator) .or(tx_commission_rate_change) .or(tx_change_consensus_key) @@ -369,6 +375,7 @@ pub mod cmds { .or(query_bonds) .or(query_bonded_stake) .or(query_slashes) + .or(query_rewards) .or(query_delegations) .or(query_find_validator) .or(query_result) @@ -426,6 +433,7 @@ pub mod cmds { QueryResult(QueryResult), TxUpdateAccount(TxUpdateAccount), TxInitAccount(TxInitAccount), + TxBecomeValidator(TxBecomeValidator), TxInitValidator(TxInitValidator), TxCommissionRateChange(TxCommissionRateChange), TxChangeConsensusKey(TxChangeConsensusKey), @@ -463,6 +471,7 @@ pub mod cmds { QueryProtocolParameters(QueryProtocolParameters), QueryPgf(QueryPgf), QueryValidatorState(QueryValidatorState), + QueryRewards(QueryRewards), SignTx(SignTx), GenIbcShieldedTransafer(GenIbcShieldedTransafer), } @@ -1395,6 +1404,25 @@ pub mod cmds { } } + #[derive(Clone, Debug)] + pub struct TxBecomeValidator(pub args::TxBecomeValidator); + + impl SubCmd for TxBecomeValidator { + const CMD: &'static str = "become-validator"; + + fn parse(matches: &ArgMatches) -> Option { + matches.subcommand_matches(Self::CMD).map(|matches| { + TxBecomeValidator(args::TxBecomeValidator::parse(matches)) + }) + } + + fn def() -> App { + App::new(Self::CMD) + .about("Send a signed transaction to become a validator.") + .add_args::>() + } + } + #[derive(Clone, Debug)] pub struct TxInitValidator(pub args::TxInitValidator); @@ -1410,8 +1438,8 @@ pub mod cmds { fn def() -> App { App::new(Self::CMD) .about( - "Send a signed transaction to create a new validator \ - account.", + "Send a signed transaction to create an established \ + account and then become a validator.", ) .add_args::>() } @@ -1844,6 +1872,28 @@ pub mod cmds { } } + #[derive(Clone, Debug)] + pub struct QueryRewards(pub args::QueryRewards); + + impl SubCmd for QueryRewards { + const CMD: &'static str = "rewards"; + + fn parse(matches: &ArgMatches) -> Option { + matches + .subcommand_matches(Self::CMD) + .map(|matches| QueryRewards(args::QueryRewards::parse(matches))) + } + + fn def() -> App { + App::new(Self::CMD) + .about( + "Query the latest rewards available to claim for a given \ + delegation (or self-bond).", + ) + .add_args::>() + } + } + #[derive(Clone, Debug)] pub struct QueryDelegations(pub args::QueryDelegations); @@ -2818,7 +2868,7 @@ pub mod args { use std::path::PathBuf; use std::str::FromStr; - use namada::ibc::core::ics24_host::identifier::{ChannelId, PortId}; + use namada::ibc::core::host::types::identifiers::{ChannelId, PortId}; use namada::types::address::Address; use namada::types::chain::{ChainId, ChainIdPrefix}; use namada::types::dec::Dec; @@ -2833,12 +2883,12 @@ pub mod args { use namada::types::transaction::GasLimit; pub use namada_sdk::args::*; pub use namada_sdk::tx::{ - 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_INIT_VALIDATOR_WASM, - TX_REACTIVATE_VALIDATOR_WASM, TX_REDELEGATE_WASM, TX_RESIGN_STEWARD, - TX_REVEAL_PK, TX_TRANSFER_WASM, TX_UNBOND_WASM, + 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_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL, TX_WITHDRAW_WASM, VP_USER_WASM, @@ -2935,7 +2985,7 @@ pub mod args { arg_opt("gas-spending-key"); pub const FEE_AMOUNT_OPT: ArgOpt = arg_opt("gas-price"); - pub const FEE_PAYER_OPT: ArgOpt = arg_opt("gas-payer"); + pub const FEE_PAYER_OPT: ArgOpt = arg_opt("gas-payer"); pub const FORCE: ArgFlag = flag("force"); pub const GAS_LIMIT: ArgDefault = arg_default("gas-limit", DefaultFn(|| GasLimit::from(25_000))); @@ -3020,9 +3070,8 @@ pub mod args { arg("self-bond-amount"); pub const SENDER: Arg = arg("sender"); pub const SIGNER: ArgOpt = arg_opt("signer"); - pub const SIGNING_KEY_OPT: ArgOpt = SIGNING_KEY.opt(); - pub const SIGNING_KEY: Arg = arg("signing-key"); - pub const SIGNING_KEYS: ArgMulti = arg_multi("signing-keys"); + pub const SIGNING_KEYS: ArgMulti = + arg_multi("signing-keys"); pub const SIGNATURES: ArgMulti = arg_multi("signatures"); pub const SOURCE: Arg = arg("source"); pub const SOURCE_OPT: ArgOpt = SOURCE.opt(); @@ -3041,7 +3090,7 @@ pub mod args { pub const TRANSFER_SOURCE: Arg = arg("source"); pub const TRANSFER_TARGET: Arg = arg("target"); pub const TX_HASH: Arg = arg("tx-hash"); - pub const THRESOLD: ArgOpt = arg_opt("threshold"); + pub const THRESHOLD: ArgOpt = arg_opt("threshold"); pub const UNSAFE_DONT_ENCRYPT: ArgFlag = flag("unsafe-dont-encrypt"); pub const UNSAFE_SHOW_SECRET: ArgFlag = flag("unsafe-show-secret"); pub const USE_DEVICE: ArgFlag = flag("use-device"); @@ -3051,17 +3100,15 @@ pub mod args { arg_opt("account-key"); pub const VALIDATOR_ACCOUNT_KEYS: ArgMulti = arg_multi("account-keys"); - pub const VALIDATOR_CONSENSUS_KEY: ArgOpt = + pub const VALIDATOR_CONSENSUS_KEY: ArgOpt = arg_opt("consensus-key"); pub const VALIDATOR_CODE_PATH: ArgOpt = arg_opt("validator-code-path"); - pub const VALIDATOR_ETH_COLD_KEY: ArgOpt = + pub const VALIDATOR_ETH_COLD_KEY: ArgOpt = arg_opt("eth-cold-key"); - pub const VALIDATOR_ETH_HOT_KEY: ArgOpt = + pub const VALIDATOR_ETH_HOT_KEY: ArgOpt = arg_opt("eth-hot-key"); pub const VALUE: ArgOpt = arg_opt("value"); - pub const VERIFICATION_KEY: ArgOpt = - arg_opt("verification-key"); pub const VIEWING_KEY: Arg = arg("key"); pub const WALLET_ALIAS_FORCE: ArgFlag = flag("wallet-alias-force"); pub const WASM_CHECKSUMS_PATH: Arg = arg("wasm-checksums-path"); @@ -3990,7 +4037,7 @@ pub mod args { .unwrap_or_else(|| PathBuf::from(VP_USER_WASM)); let tx_code_path = PathBuf::from(TX_INIT_ACCOUNT_WASM); let public_keys = PUBLIC_KEYS.parse(matches); - let threshold = THRESOLD.parse(matches); + let threshold = THRESHOLD.parse(matches); Self { tx, vp_code_path, @@ -4011,7 +4058,7 @@ pub mod args { "A list public keys to be associated with the new account \ in hexadecimal encoding.", )) - .arg(THRESOLD.def().help( + .arg(THRESHOLD.def().help( "The minimum number of signature to be provided for \ authorization. Must be less then the maximum number of \ public keys provided.", @@ -4019,6 +4066,122 @@ pub mod args { } } + impl CliToSdk> for TxBecomeValidator { + fn to_sdk(self, ctx: &mut Context) -> TxBecomeValidator { + let tx = self.tx.to_sdk(ctx); + let chain_ctx = ctx.borrow_mut_chain_or_exit(); + TxBecomeValidator:: { + tx, + scheme: self.scheme, + address: chain_ctx.get(&self.address), + consensus_key: self.consensus_key.map(|x| chain_ctx.get(&x)), + eth_cold_key: self.eth_cold_key.map(|x| chain_ctx.get(&x)), + eth_hot_key: self.eth_hot_key.map(|x| chain_ctx.get(&x)), + protocol_key: self.protocol_key.map(|x| chain_ctx.get(&x)), + commission_rate: self.commission_rate, + max_commission_rate_change: self.max_commission_rate_change, + email: self.email, + description: self.description, + website: self.website, + discord_handle: self.discord_handle, + unsafe_dont_encrypt: self.unsafe_dont_encrypt, + tx_code_path: self.tx_code_path.to_path_buf(), + } + } + } + + impl Args for TxBecomeValidator { + fn parse(matches: &ArgMatches) -> Self { + let tx = Tx::parse(matches); + let address = ADDRESS.parse(matches); + let scheme = SCHEME.parse(matches); + let consensus_key = VALIDATOR_CONSENSUS_KEY.parse(matches); + let eth_cold_key = VALIDATOR_ETH_COLD_KEY.parse(matches); + let eth_hot_key = VALIDATOR_ETH_HOT_KEY.parse(matches); + let protocol_key = PROTOCOL_KEY.parse(matches); + let commission_rate = COMMISSION_RATE.parse(matches); + let max_commission_rate_change = + MAX_COMMISSION_RATE_CHANGE.parse(matches); + let email = EMAIL.parse(matches); + let description = DESCRIPTION_OPT.parse(matches); + let website = WEBSITE_OPT.parse(matches); + let discord_handle = DISCORD_OPT.parse(matches); + let unsafe_dont_encrypt = UNSAFE_DONT_ENCRYPT.parse(matches); + let tx_code_path = PathBuf::from(TX_BECOME_VALIDATOR_WASM); + Self { + tx, + address, + scheme, + consensus_key, + eth_cold_key, + eth_hot_key, + protocol_key, + commission_rate, + max_commission_rate_change, + email, + description, + website, + discord_handle, + unsafe_dont_encrypt, + tx_code_path, + } + } + + fn def(app: App) -> App { + app.add_args::>() + .arg(ADDRESS.def().help( + "Address of an account that will become a validator.", + )) + .arg(SCHEME.def().help( + "The key scheme/type used for the validator keys. \ + Currently supports ed25519 and secp256k1.", + )) + .arg(VALIDATOR_CONSENSUS_KEY.def().help( + "A consensus key for the validator account. A new one \ + will be generated if none given. Note that this must be \ + ed25519.", + )) + .arg(VALIDATOR_ETH_COLD_KEY.def().help( + "An Eth cold key for the validator account. A new one \ + will be generated if none given. Note that this must be \ + secp256k1.", + )) + .arg(VALIDATOR_ETH_HOT_KEY.def().help( + "An Eth hot key for the validator account. A new one will \ + be generated if none given. Note that this must be \ + secp256k1.", + )) + .arg(PROTOCOL_KEY.def().help( + "A public key for signing protocol transactions. A new \ + one will be generated if none given.", + )) + .arg(COMMISSION_RATE.def().help( + "The commission rate charged by the validator for \ + delegation rewards. Expressed as a decimal between 0 and \ + 1. This is a required parameter.", + )) + .arg(MAX_COMMISSION_RATE_CHANGE.def().help( + "The maximum change per epoch in the commission rate \ + charged by the validator for delegation rewards. \ + Expressed as a decimal between 0 and 1. This is a \ + required parameter.", + )) + .arg(EMAIL.def().help("The validator's email.")) + .arg(DESCRIPTION_OPT.def().help("The validator's description.")) + .arg(WEBSITE_OPT.def().help("The validator's website.")) + .arg(DISCORD_OPT.def().help("The validator's discord handle.")) + .arg(VALIDATOR_CODE_PATH.def().help( + "The path to the validity predicate WASM code to be used \ + for the validator account. Uses the default validator VP \ + if none specified.", + )) + .arg(UNSAFE_DONT_ENCRYPT.def().help( + "UNSAFE: Do not encrypt the generated keypairs. Do not \ + use this for keys used in a live network.", + )) + } + } + impl CliToSdk> for TxInitValidator { fn to_sdk(self, ctx: &mut Context) -> TxInitValidator { let tx = self.tx.to_sdk(ctx); @@ -4032,13 +4195,9 @@ pub mod args { .map(|x| chain_ctx.get(x)) .collect(), threshold: self.threshold, - consensus_key: self - .consensus_key - .map(|x| chain_ctx.get_cached(&x)), - eth_cold_key: self - .eth_cold_key - .map(|x| chain_ctx.get_cached(&x)), - eth_hot_key: self.eth_hot_key.map(|x| chain_ctx.get_cached(&x)), + consensus_key: self.consensus_key.map(|x| chain_ctx.get(&x)), + eth_cold_key: self.eth_cold_key.map(|x| chain_ctx.get(&x)), + eth_hot_key: self.eth_hot_key.map(|x| chain_ctx.get(&x)), protocol_key: self.protocol_key.map(|x| chain_ctx.get(&x)), commission_rate: self.commission_rate, max_commission_rate_change: self.max_commission_rate_change, @@ -4050,7 +4209,12 @@ pub mod args { .validator_vp_code_path .to_path_buf(), unsafe_dont_encrypt: self.unsafe_dont_encrypt, - tx_code_path: self.tx_code_path.to_path_buf(), + tx_init_account_code_path: self + .tx_init_account_code_path + .to_path_buf(), + tx_become_validator_code_path: self + .tx_become_validator_code_path + .to_path_buf(), } } } @@ -4075,8 +4239,10 @@ pub mod args { .parse(matches) .unwrap_or_else(|| PathBuf::from(VP_USER_WASM)); let unsafe_dont_encrypt = UNSAFE_DONT_ENCRYPT.parse(matches); - let tx_code_path = PathBuf::from(TX_INIT_VALIDATOR_WASM); - let threshold = THRESOLD.parse(matches); + let tx_init_account_code_path = PathBuf::from(TX_INIT_ACCOUNT_WASM); + let tx_become_validator_code_path = + PathBuf::from(TX_BECOME_VALIDATOR_WASM); + let threshold = THRESHOLD.parse(matches); Self { tx, scheme, @@ -4094,7 +4260,8 @@ pub mod args { discord_handle, validator_vp_code_path, unsafe_dont_encrypt, - tx_code_path, + tx_init_account_code_path, + tx_become_validator_code_path, } } @@ -4139,24 +4306,10 @@ pub mod args { Expressed as a decimal between 0 and 1. This is a \ required parameter.", )) - .arg(EMAIL_OPT.def().help( - "The desired new validator email. To remove the existing \ - email, pass an empty string to this argument.", - )) - .arg(DESCRIPTION_OPT.def().help( - "The desired new validator description. To remove the \ - existing description, pass an empty string to this \ - argument.", - )) - .arg(WEBSITE_OPT.def().help( - "The desired new validator website. To remove the \ - existing website, pass an empty string to this argument.", - )) - .arg(DISCORD_OPT.def().help( - "The desired new validator discord handle. To remove the \ - existing discord handle, pass an empty string to this \ - argument.", - )) + .arg(EMAIL.def().help("The validator's email.")) + .arg(DESCRIPTION_OPT.def().help("The validator's description.")) + .arg(WEBSITE_OPT.def().help("The validator's website.")) + .arg(DISCORD_OPT.def().help("The validator's discord handle.")) .arg(VALIDATOR_CODE_PATH.def().help( "The path to the validity predicate WASM code to be used \ for the validator account. Uses the default validator VP \ @@ -4166,7 +4319,7 @@ pub mod args { "UNSAFE: Do not encrypt the generated keypairs. Do not \ use this for keys used in a live network.", )) - .arg(THRESOLD.def().help( + .arg(THRESHOLD.def().help( "The minimum number of signature to be provided for \ authorization. Must be less then the maximum number of \ public keys provided.", @@ -4200,7 +4353,7 @@ pub mod args { let addr = ADDRESS.parse(matches); let tx_code_path = PathBuf::from(TX_UPDATE_ACCOUNT_WASM); let public_keys = PUBLIC_KEYS.parse(matches); - let threshold = THRESOLD.parse(matches); + let threshold = THRESHOLD.parse(matches); Self { tx, vp_code_path, @@ -4226,7 +4379,7 @@ pub mod args { "A list public keys to be associated with the new account \ in hexadecimal encoding.", )) - .arg(THRESOLD.def().help( + .arg(THRESHOLD.def().help( "The minimum number of signature to be provided for \ authorization. Must be less then the maximum number of \ public keys provided.", @@ -4826,8 +4979,8 @@ pub mod args { .arg(VALIDATOR.def().help("Validator address.")) .arg(SOURCE_OPT.def().help( "Source address for withdrawing from delegations. For \ - withdrawing from self-bonds, the validator is also the \ - source.", + withdrawing from self-bonds, this arg does not need to \ + be supplied.", )) } } @@ -5172,9 +5325,7 @@ pub mod args { ConsensusKeyChange:: { tx, validator: chain_ctx.get(&self.validator), - consensus_key: self - .consensus_key - .map(|x| chain_ctx.get_cached(&x)), + consensus_key: self.consensus_key.map(|x| chain_ctx.get(&x)), tx_code_path: self.tx_code_path.to_path_buf(), } } @@ -5552,6 +5703,42 @@ pub mod args { } } + impl CliToSdk> for QueryRewards { + fn to_sdk(self, ctx: &mut Context) -> QueryRewards { + QueryRewards:: { + query: self.query.to_sdk(ctx), + validator: ctx.borrow_chain_or_exit().get(&self.validator), + source: self.source.map(|x| ctx.borrow_chain_or_exit().get(&x)), + } + } + } + + impl Args for QueryRewards { + fn parse(matches: &ArgMatches) -> Self { + let query = Query::parse(matches); + let source = SOURCE_OPT.parse(matches); + let validator = VALIDATOR.parse(matches); + Self { + query, + source, + validator, + } + } + + fn def(app: App) -> App { + app.add_args::>() + .arg(SOURCE_OPT.def().help( + "Source address for the rewards query. For self-bonds, \ + this arg does not need to be supplied.", + )) + .arg( + VALIDATOR + .def() + .help("Validator address for the rewards query."), + ) + } + } + impl Args for QueryDelegations { fn parse(matches: &ArgMatches) -> Self { let query = Query::parse(matches); @@ -5665,16 +5852,13 @@ pub mod args { signing_keys: self .signing_keys .iter() - .map(|key| ctx.get_cached(key)) + .map(|key| ctx.get(key)) .collect(), signatures: self .signatures .iter() .map(|path| std::fs::read(path).unwrap()) .collect(), - verification_key: self - .verification_key - .map(|public_key| ctx.get(&public_key)), disposable_signing_key: self.disposable_signing_key, tx_reveal_code_path: self.tx_reveal_code_path, password: self.password, @@ -5682,9 +5866,7 @@ pub mod args { chain_id: self .chain_id .or_else(|| Some(ctx.config.ledger.chain_id.clone())), - wrapper_fee_payer: self - .wrapper_fee_payer - .map(|x| ctx.get_cached(&x)), + wrapper_fee_payer: self.wrapper_fee_payer.map(|x| ctx.get(&x)), use_device: self.use_device, } } @@ -5768,10 +5950,7 @@ pub mod args { public key, public key hash or alias from your \ wallet.", ) - .conflicts_with_all([ - SIGNATURES.name, - VERIFICATION_KEY.name, - ]), + .conflicts_with_all([SIGNATURES.name]), ) .arg( SIGNATURES @@ -5781,25 +5960,12 @@ pub mod args { to be attached to a transaction. Requires to provide \ a gas payer.", ) - .conflicts_with_all([ - SIGNING_KEYS.name, - VERIFICATION_KEY.name, - ]) + .conflicts_with_all([SIGNING_KEYS.name]) .requires(FEE_PAYER_OPT.name), ) .arg(OUTPUT_FOLDER_PATH.def().help( "The output folder path where the artifact will be stored.", )) - .arg( - VERIFICATION_KEY - .def() - .help( - "Sign the transaction with the key for the given \ - public key, public key hash or alias from your \ - wallet.", - ) - .conflicts_with_all([SIGNING_KEYS.name, SIGNATURES.name]), - ) .arg(CHAIN_ID_OPT.def().help("The chain ID.")) .arg( FEE_PAYER_OPT @@ -5836,7 +6002,6 @@ pub mod args { let disposable_signing_key = DISPOSABLE_SIGNING_KEY.parse(matches); let signing_keys = SIGNING_KEYS.parse(matches); let signatures = SIGNATURES.parse(matches); - let verification_key = VERIFICATION_KEY.parse(matches); let tx_reveal_code_path = PathBuf::from(TX_REVEAL_PK); let chain_id = CHAIN_ID_OPT.parse(matches); let password = None; @@ -5860,7 +6025,6 @@ pub mod args { disposable_signing_key, signing_keys, signatures, - verification_key, tx_reveal_code_path, password, chain_id, diff --git a/apps/src/lib/cli/client.rs b/apps/src/lib/cli/client.rs index d4f81483fb..2ed5ba456b 100644 --- a/apps/src/lib/cli/client.rs +++ b/apps/src/lib/cli/client.rs @@ -12,7 +12,7 @@ impl CliApi { pub async fn handle_client_command( client: Option, cmd: cli::NamadaClient, - io: &IO, + io: IO, ) -> Result<()> where C: CliClient, @@ -29,9 +29,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); let dry_run = args.tx.dry_run || args.tx.dry_run_wrapper; tx::submit_custom(&namada, args).await?; @@ -42,7 +42,7 @@ impl CliApi { .save() .unwrap_or_else(|err| eprintln!("{}", err)); } else { - io.println( + namada.io().println( "Transaction dry run. No addresses have been \ saved.", ) @@ -54,9 +54,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_transfer(&namada, args).await?; } Sub::TxIbcTransfer(TxIbcTransfer(mut args)) => { @@ -65,9 +65,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_ibc_transfer(&namada, args).await?; } Sub::TxUpdateAccount(TxUpdateAccount(mut args)) => { @@ -76,9 +76,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_update_account(&namada, args).await?; } Sub::TxInitAccount(TxInitAccount(mut args)) => { @@ -87,9 +87,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); let dry_run = args.tx.dry_run || args.tx.dry_run_wrapper; tx::submit_init_account(&namada, args).await?; @@ -100,30 +100,54 @@ impl CliApi { .save() .unwrap_or_else(|err| eprintln!("{}", err)); } else { - io.println( + namada.io().println( "Transaction dry run. No addresses have been \ saved.", ) } } + Sub::TxBecomeValidator(TxBecomeValidator(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.tx.ledger_address, + ) + }); + client.wait_until_node_is_synced(&io).await?; + let args = args.to_sdk(&mut ctx); + let cli::context::ChainContext { + wallet, + mut config, + shielded, + native_token, + } = ctx.take_chain_or_exit(); + let namada = NamadaImpl::native_new( + client, + wallet, + shielded, + io, + native_token, + ); + tx::submit_become_validator(&namada, &mut config, args) + .await?; + } Sub::TxInitValidator(TxInitValidator(mut args)) => { let client = client.unwrap_or_else(|| { C::from_tendermint_address( &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); let cli::context::ChainContext { - mut wallet, + wallet, mut config, - mut shielded, + shielded, native_token, } = ctx.take_chain_or_exit(); let namada = NamadaImpl::native_new( - &client, - &mut wallet, - &mut shielded, + client, + wallet, + shielded, io, native_token, ); @@ -136,9 +160,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_init_proposal(&namada, args).await?; } Sub::TxVoteProposal(TxVoteProposal(mut args)) => { @@ -147,9 +171,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_vote_proposal(&namada, args).await?; } Sub::TxRevealPk(TxRevealPk(mut args)) => { @@ -158,9 +182,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_reveal_pk(&namada, args).await?; } Sub::Bond(Bond(mut args)) => { @@ -169,9 +193,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_bond(&namada, args).await?; } Sub::Unbond(Unbond(mut args)) => { @@ -180,9 +204,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_unbond(&namada, args).await?; } Sub::Withdraw(Withdraw(mut args)) => { @@ -191,9 +215,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_withdraw(&namada, args).await?; } Sub::ClaimRewards(ClaimRewards(mut args)) => { @@ -202,9 +226,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_claim_rewards(&namada, args).await?; } Sub::Redelegate(Redelegate(mut args)) => { @@ -213,9 +237,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_redelegate(&namada, args).await?; } Sub::TxCommissionRateChange(TxCommissionRateChange( @@ -226,9 +250,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_validator_commission_change(&namada, args) .await?; } @@ -240,18 +264,18 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); let cli::context::ChainContext { - mut wallet, + wallet, mut config, - mut shielded, + shielded, native_token, } = ctx.take_chain_or_exit(); let namada = NamadaImpl::native_new( - &client, - &mut wallet, - &mut shielded, + client, + wallet, + shielded, io, native_token, ); @@ -268,9 +292,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_validator_metadata_change(&namada, args) .await?; } @@ -282,9 +306,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_bridge_pool_tx(&namada, args).await?; } Sub::TxUnjailValidator(TxUnjailValidator(mut args)) => { @@ -293,9 +317,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_unjail_validator(&namada, args).await?; } Sub::TxDeactivateValidator(TxDeactivateValidator( @@ -306,9 +330,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_deactivate_validator(&namada, args).await?; } Sub::TxReactivateValidator(TxReactivateValidator( @@ -319,9 +343,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_reactivate_validator(&namada, args).await?; } Sub::TxUpdateStewardCommission( @@ -332,9 +356,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_update_steward_commission(&namada, args) .await?; } @@ -344,9 +368,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::submit_resign_steward(&namada, args).await?; } // Ledger queries @@ -354,8 +378,8 @@ impl CliApi { let client = client.unwrap_or_else(|| { C::from_tendermint_address(&mut args.ledger_address) }); - client.wait_until_node_is_synced(io).await?; - let namada = ctx.to_sdk(&client, io); + client.wait_until_node_is_synced(&io).await?; + let namada = ctx.to_sdk(client, io); rpc::query_and_print_epoch(&namada).await; } Sub::QueryValidatorState(QueryValidatorState(mut args)) => { @@ -364,9 +388,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_and_print_validator_state(&namada, args) .await; } @@ -376,9 +400,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_transfers(&namada, args).await; } Sub::QueryConversions(QueryConversions(mut args)) => { @@ -387,17 +411,17 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_conversions(&namada, args).await; } Sub::QueryBlock(QueryBlock(mut args)) => { let client = client.unwrap_or_else(|| { C::from_tendermint_address(&mut args.ledger_address) }); - client.wait_until_node_is_synced(io).await?; - let namada = ctx.to_sdk(&client, io); + client.wait_until_node_is_synced(&io).await?; + let namada = ctx.to_sdk(client, io); rpc::query_block(&namada).await; } Sub::QueryBalance(QueryBalance(mut args)) => { @@ -406,9 +430,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_balance(&namada, args).await; } Sub::QueryBonds(QueryBonds(mut args)) => { @@ -417,9 +441,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_bonds(&namada, args) .await .expect("expected successful query of bonds"); @@ -430,9 +454,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_bonded_stake(&namada, args).await; } Sub::QueryCommissionRate(QueryCommissionRate(mut args)) => { @@ -441,9 +465,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_and_print_commission_rate(&namada, args) .await; } @@ -453,9 +477,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_and_print_metadata(&namada, args).await; } Sub::QuerySlashes(QuerySlashes(mut args)) => { @@ -464,20 +488,31 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_slashes(&namada, args).await; } + Sub::QueryRewards(QueryRewards(mut args)) => { + let client = client.unwrap_or_else(|| { + C::from_tendermint_address( + &mut args.query.ledger_address, + ) + }); + client.wait_until_node_is_synced(&io).await?; + let args = args.to_sdk(&mut ctx); + let namada = ctx.to_sdk(client, io); + rpc::query_and_print_rewards(&namada, args).await; + } Sub::QueryDelegations(QueryDelegations(mut args)) => { let client = client.unwrap_or_else(|| { C::from_tendermint_address( &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_delegations(&namada, args).await; } Sub::QueryFindValidator(QueryFindValidator(mut args)) => { @@ -486,9 +521,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_find_validator(&namada, args).await; } Sub::QueryResult(QueryResult(mut args)) => { @@ -497,9 +532,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_result(&namada, args).await; } Sub::QueryRawBytes(QueryRawBytes(mut args)) => { @@ -508,9 +543,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_raw_bytes(&namada, args).await; } Sub::QueryProposal(QueryProposal(mut args)) => { @@ -519,9 +554,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_proposal(&namada, args).await; } Sub::QueryProposalResult(QueryProposalResult(mut args)) => { @@ -530,9 +565,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_proposal_result(&namada, args).await; } Sub::QueryProtocolParameters(QueryProtocolParameters( @@ -543,9 +578,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_protocol_parameters(&namada, args).await; } Sub::QueryPgf(QueryPgf(mut args)) => { @@ -554,9 +589,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_pgf(&namada, args).await; } Sub::QueryAccount(QueryAccount(mut args)) => { @@ -565,9 +600,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::query_account(&namada, args).await; } Sub::SignTx(SignTx(mut args)) => { @@ -576,9 +611,9 @@ impl CliApi { &mut args.tx.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::sign_tx(&namada, args).await?; } Sub::GenIbcShieldedTransafer(GenIbcShieldedTransafer( @@ -589,9 +624,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); tx::gen_ibc_shielded_transfer(&namada, args).await?; } } @@ -625,9 +660,9 @@ impl CliApi { let mut ledger_address = args.ledger_address.clone(); let client = C::from_tendermint_address(&mut ledger_address); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); rpc::epoch_sleep(&namada, args).await; } Utils::ValidateGenesisTemplates(ValidateGenesisTemplates( diff --git a/apps/src/lib/cli/context.rs b/apps/src/lib/cli/context.rs index 51c8ba4eac..92a1d2eaa1 100644 --- a/apps/src/lib/cli/context.rs +++ b/apps/src/lib/cli/context.rs @@ -165,22 +165,18 @@ impl Context { } /// Make an implementation of Namada from this object and parameters. - pub fn to_sdk<'a, C, IO>( - &'a mut self, - client: &'a C, - io: &'a IO, - ) -> impl Namada + pub fn to_sdk(self, client: C, io: IO) -> impl Namada where C: namada::ledger::queries::Client + Sync, IO: Io, { - let chain_ctx = self.borrow_mut_chain_or_exit(); + let chain_ctx = self.take_chain_or_exit(); NamadaImpl::native_new( client, - &mut chain_ctx.wallet, - &mut chain_ctx.shielded, + chain_ctx.wallet, + chain_ctx.shielded, io, - chain_ctx.native_token.clone(), + chain_ctx.native_token, ) } } diff --git a/apps/src/lib/cli/relayer.rs b/apps/src/lib/cli/relayer.rs index 1dee9b784e..7dc360db4f 100644 --- a/apps/src/lib/cli/relayer.rs +++ b/apps/src/lib/cli/relayer.rs @@ -12,7 +12,7 @@ impl CliApi { pub async fn handle_relayer_command( client: Option, cmd: cli::NamadaRelayer, - io: &impl Io, + io: impl Io, ) -> Result<()> where C: CliClient, @@ -29,9 +29,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk(&mut ctx); - let namada = ctx.to_sdk(&client, io); + let namada = ctx.to_sdk(client, io); bridge_pool::recommend_batch(&namada, args).await?; } } @@ -45,9 +45,9 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk_ctxless(); - bridge_pool::construct_proof(&client, io, args).await?; + bridge_pool::construct_proof(&client, &io, args).await?; } EthBridgePoolWithoutCtx::RelayProof(RelayProof(mut args)) => { let client = client.unwrap_or_else(|| { @@ -55,12 +55,12 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let eth_client = get_eth_rpc_client(&args.eth_rpc_endpoint).await; let args = args.to_sdk_ctxless(); bridge_pool::relay_bridge_pool_proof( - eth_client, &client, io, args, + eth_client, &client, &io, args, ) .await?; } @@ -70,8 +70,8 @@ impl CliApi { let client = client.unwrap_or_else(|| { C::from_tendermint_address(&mut query.ledger_address) }); - client.wait_until_node_is_synced(io).await?; - bridge_pool::query_bridge_pool(&client, io).await?; + client.wait_until_node_is_synced(&io).await?; + bridge_pool::query_bridge_pool(&client, &io).await?; } EthBridgePoolWithoutCtx::QuerySigned( QuerySignedBridgePool(mut query), @@ -79,8 +79,8 @@ impl CliApi { let client = client.unwrap_or_else(|| { C::from_tendermint_address(&mut query.ledger_address) }); - client.wait_until_node_is_synced(io).await?; - bridge_pool::query_signed_bridge_pool(&client, io).await?; + client.wait_until_node_is_synced(&io).await?; + bridge_pool::query_signed_bridge_pool(&client, &io).await?; } EthBridgePoolWithoutCtx::QueryRelays(QueryRelayProgress( mut query, @@ -88,8 +88,8 @@ impl CliApi { let client = client.unwrap_or_else(|| { C::from_tendermint_address(&mut query.ledger_address) }); - client.wait_until_node_is_synced(io).await?; - bridge_pool::query_relay_progress(&client, io).await?; + client.wait_until_node_is_synced(&io).await?; + bridge_pool::query_relay_progress(&client, &io).await?; } }, cli::NamadaRelayer::ValidatorSet(sub) => match sub { @@ -101,10 +101,10 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk_ctxless(); validator_set::query_bridge_validator_set( - &client, io, args, + &client, &io, args, ) .await?; } @@ -116,10 +116,10 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk_ctxless(); validator_set::query_governnace_validator_set( - &client, io, args, + &client, &io, args, ) .await?; } @@ -131,10 +131,10 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let args = args.to_sdk_ctxless(); validator_set::query_validator_set_update_proof( - &client, io, args, + &client, &io, args, ) .await?; } @@ -146,12 +146,12 @@ impl CliApi { &mut args.query.ledger_address, ) }); - client.wait_until_node_is_synced(io).await?; + client.wait_until_node_is_synced(&io).await?; let eth_client = get_eth_rpc_client(&args.eth_rpc_endpoint).await; let args = args.to_sdk_ctxless(); validator_set::relay_validator_set_update( - eth_client, &client, io, args, + eth_client, &client, &io, args, ) .await?; } diff --git a/apps/src/lib/cli/wallet.rs b/apps/src/lib/cli/wallet.rs index 4d22365f80..c0dcecd751 100644 --- a/apps/src/lib/cli/wallet.rs +++ b/apps/src/lib/cli/wallet.rs @@ -135,7 +135,7 @@ fn address_key_find( Ok(spending_key) => { display_line!(io, "Spending key: {}", spending_key) } - Err(FindKeyError::KeyNotFound) => {} + Err(FindKeyError::KeyNotFound(_)) => {} Err(err) => edisplay_line!(io, "{}", err), } } diff --git a/apps/src/lib/client/rpc.rs b/apps/src/lib/client/rpc.rs index f696a0602b..43acdc9302 100644 --- a/apps/src/lib/client/rpc.rs +++ b/apps/src/lib/client/rpc.rs @@ -65,8 +65,8 @@ use crate::facade::tendermint_rpc::error::Error as TError; /// /// If a response is not delivered until `deadline`, we exit the cli with an /// error. -pub async fn query_tx_status<'a>( - namada: &impl Namada<'a>, +pub async fn query_tx_status( + namada: &impl Namada, status: namada_sdk::rpc::TxEventQuery<'_>, deadline: Instant, ) -> Event { @@ -76,14 +76,14 @@ pub async fn query_tx_status<'a>( } /// Query and print the epoch of the last committed block -pub async fn query_and_print_epoch<'a>(context: &impl Namada<'a>) -> Epoch { +pub async fn query_and_print_epoch(context: &impl Namada) -> Epoch { let epoch = rpc::query_epoch(context.client()).await.unwrap(); display_line!(context.io(), "Last committed epoch: {}", epoch); epoch } /// Query the last committed block -pub async fn query_block<'a>(context: &impl Namada<'a>) { +pub async fn query_block(context: &impl Namada) { let block = namada_sdk::rpc::query_block(context.client()) .await .unwrap(); @@ -114,8 +114,8 @@ pub async fn query_results( } /// Query the specified accepted transfers from the ledger -pub async fn query_transfers<'a>( - context: &impl Namada<'a>, +pub async fn query_transfers( + context: &impl Namada, args: args::QueryTransfers, ) { let query_token = args.token; @@ -250,7 +250,7 @@ pub async fn query_transfers<'a>( } /// Query the raw bytes of given storage key -pub async fn query_raw_bytes<'a, N: Namada<'a>>( +pub async fn query_raw_bytes( context: &N, args: args::QueryRawBytes, ) { @@ -281,10 +281,7 @@ pub async fn query_raw_bytes<'a, N: Namada<'a>>( } /// Query token balance(s) -pub async fn query_balance<'a>( - context: &impl Namada<'a>, - args: args::QueryBalance, -) { +pub async fn query_balance(context: &impl Namada, args: args::QueryBalance) { // Query the balances of shielded or transparent account types depending on // the CLI arguments match &args.owner { @@ -309,8 +306,8 @@ pub async fn query_balance<'a>( } /// Query token balance(s) -pub async fn query_transparent_balance<'a>( - context: &impl Namada<'a>, +pub async fn query_transparent_balance( + context: &impl Namada, args: args::QueryBalance, ) { let prefix = Key::from( @@ -386,8 +383,8 @@ pub async fn query_transparent_balance<'a>( } /// Query the token pinned balance(s) -pub async fn query_pinned_balance<'a>( - context: &impl Namada<'a>, +pub async fn query_pinned_balance( + context: &impl Namada, args: args::QueryBalance, ) { // Map addresses to token names @@ -549,8 +546,8 @@ pub async fn query_pinned_balance<'a>( } } -async fn print_balances<'a>( - context: &impl Namada<'a>, +async fn print_balances( + context: &impl Namada, balances: impl Iterator, token: Option<&Address>, target: Option<&Address>, @@ -629,8 +626,8 @@ async fn print_balances<'a>( } } -async fn lookup_token_alias<'a>( - context: &impl Namada<'a>, +async fn lookup_token_alias( + context: &impl Namada, token: &Address, owner: &Address, ) -> String { @@ -649,8 +646,8 @@ async fn lookup_token_alias<'a>( } /// Returns pairs of token alias and token address -async fn query_tokens<'a>( - context: &impl Namada<'a>, +async fn query_tokens( + context: &impl Namada, base_token: Option<&Address>, owner: Option<&Address>, ) -> BTreeMap { @@ -708,8 +705,8 @@ async fn query_tokens<'a>( tokens } -async fn get_ibc_denom_alias<'a>( - context: &impl Namada<'a>, +async fn get_ibc_denom_alias( + context: &impl Namada, ibc_denom: impl AsRef, ) -> String { let wallet = context.wallet().await; @@ -729,10 +726,7 @@ async fn get_ibc_denom_alias<'a>( } /// Query Proposals -pub async fn query_proposal<'a>( - context: &impl Namada<'a>, - args: args::QueryProposal, -) { +pub async fn query_proposal(context: &impl Namada, args: args::QueryProposal) { let current_epoch = query_and_print_epoch(context).await; if let Some(id) = args.proposal_id { @@ -781,8 +775,8 @@ pub async fn query_proposal_by_id( } /// Query token shielded balance(s) -pub async fn query_shielded_balance<'a>( - context: &impl Namada<'a>, +pub async fn query_shielded_balance( + context: &impl Namada, args: args::QueryBalance, ) { // Used to control whether balances for all keys or a specific key are @@ -1050,8 +1044,8 @@ pub async fn query_shielded_balance<'a>( } } -pub async fn print_decoded_balance<'a>( - context: &impl Namada<'a>, +pub async fn print_decoded_balance( + context: &impl Namada, decoded_balance: MaspAmount, epoch: Epoch, ) { @@ -1072,8 +1066,8 @@ pub async fn print_decoded_balance<'a>( } } -pub async fn print_decoded_balance_with_epoch<'a>( - context: &impl Namada<'a>, +pub async fn print_decoded_balance_with_epoch( + context: &impl Namada, decoded_balance: MaspAmount, ) { let tokens = context @@ -1110,8 +1104,8 @@ pub async fn get_token_balance( .unwrap() } -pub async fn query_proposal_result<'a>( - context: &impl Namada<'a>, +pub async fn query_proposal_result( + context: &impl Namada, args: args::QueryProposalResult, ) { if args.proposal_id.is_some() { @@ -1250,10 +1244,7 @@ pub async fn query_proposal_result<'a>( } } -pub async fn query_account<'a>( - context: &impl Namada<'a>, - args: args::QueryAccount, -) { +pub async fn query_account(context: &impl Namada, args: args::QueryAccount) { let account = rpc::get_account_info(context.client(), &args.owner) .await .unwrap(); @@ -1269,7 +1260,7 @@ pub async fn query_account<'a>( } } -pub async fn query_pgf<'a>(context: &impl Namada<'a>, _args: args::QueryPgf) { +pub async fn query_pgf(context: &impl Namada, _args: args::QueryPgf) { let stewards = query_pgf_stewards(context.client()).await; let fundings = query_pgf_fundings(context.client()).await; @@ -1320,8 +1311,8 @@ pub async fn query_pgf<'a>(context: &impl Namada<'a>, _args: args::QueryPgf) { } } -pub async fn query_protocol_parameters<'a>( - context: &impl Namada<'a>, +pub async fn query_protocol_parameters( + context: &impl Namada, _args: args::QueryProtocolParameters, ) { let governance_parameters = @@ -1578,8 +1569,8 @@ pub async fn query_pgf_parameters( unwrap_client_response::(RPC.vp().pgf().parameters(client).await) } -pub async fn query_and_print_unbonds<'a>( - context: &impl Namada<'a>, +pub async fn query_and_print_unbonds( + context: &impl Namada, source: &Address, validator: &Address, ) { @@ -1634,8 +1625,8 @@ pub async fn query_withdrawable_tokens< } /// Query PoS bond(s) and unbond(s) -pub async fn query_bonds<'a>( - context: &impl Namada<'a>, +pub async fn query_bonds( + context: &impl Namada, args: args::QueryBonds, ) -> std::io::Result<()> { let epoch = query_and_print_epoch(context).await; @@ -1758,7 +1749,7 @@ pub async fn query_bonds<'a>( } /// Query PoS bonded stake -pub async fn query_bonded_stake<'a, N: Namada<'a>>( +pub async fn query_bonded_stake( context: &N, args: args::QueryBondedStake, ) { @@ -1895,9 +1886,20 @@ pub async fn query_validator_state< ) } +/// Query and return the available reward tokens corresponding to the bond +pub async fn query_rewards( + client: &C, + source: &Option
, + validator: &Address, +) -> token::Amount { + unwrap_client_response::( + RPC.vp().pos().rewards(client, validator, source).await, + ) +} + /// Query a validator's state information -pub async fn query_and_print_validator_state<'a>( - context: &impl Namada<'a>, +pub async fn query_and_print_validator_state( + context: &impl Namada, args: args::QueryValidatorState, ) { let validator = args.validator; @@ -1941,8 +1943,8 @@ pub async fn query_and_print_validator_state<'a>( } /// Query PoS validator's commission rate information -pub async fn query_and_print_commission_rate<'a>( - context: &impl Namada<'a>, +pub async fn query_and_print_commission_rate( + context: &impl Namada, args: args::QueryCommissionRate, ) { let validator = args.validator; @@ -1974,8 +1976,8 @@ pub async fn query_and_print_commission_rate<'a>( } /// Query PoS validator's metadata -pub async fn query_and_print_metadata<'a>( - context: &impl Namada<'a>, +pub async fn query_and_print_metadata( + context: &impl Namada, args: args::QueryMetaData, ) { let validator = args.validator; @@ -2051,10 +2053,7 @@ pub async fn query_and_print_metadata<'a>( } /// Query PoS slashes -pub async fn query_slashes<'a, N: Namada<'a>>( - context: &N, - args: args::QuerySlashes, -) { +pub async fn query_slashes(context: &N, args: args::QuerySlashes) { match args.validator { Some(validator) => { let validator = validator; @@ -2206,7 +2205,21 @@ pub async fn query_slashes<'a, N: Namada<'a>>( } } -pub async fn query_delegations<'a, N: Namada<'a>>( +pub async fn query_and_print_rewards( + context: &N, + args: args::QueryRewards, +) { + let (source, validator) = (args.source, args.validator); + + let rewards = query_rewards(context.client(), &source, &validator).await; + display_line!( + context.io(), + "Current rewards available for claim: {} NAM", + rewards.to_string_native() + ); +} + +pub async fn query_delegations( context: &N, args: args::QueryDelegations, ) { @@ -2227,7 +2240,7 @@ pub async fn query_delegations<'a, N: Namada<'a>>( } } -pub async fn query_find_validator<'a, N: Namada<'a>>( +pub async fn query_find_validator( context: &N, args: args::QueryFindValidator, ) { @@ -2264,7 +2277,7 @@ pub async fn query_find_validator<'a, N: Namada<'a>>( } /// Dry run a transaction -pub async fn dry_run_tx<'a, N: Namada<'a>>( +pub async fn dry_run_tx( context: &N, tx_bytes: Vec, ) -> Result<(), error::Error> @@ -2288,7 +2301,7 @@ pub async fn get_public_key( rpc::get_public_key_at(client, address, index).await } -/// Check if the given address is a known validator. +/// Check if the given address has any bonds. pub async fn is_validator( client: &C, address: &Address, @@ -2318,6 +2331,14 @@ pub async fn is_delegator_at( .unwrap() } +/// Check if the given address has any bonds. +pub async fn has_bonds( + client: &C, + address: &Address, +) -> bool { + namada_sdk::rpc::has_bonds(client, address).await.unwrap() +} + /// Check if the address exists on chain. Established address exists if it has a /// stored validity predicate. Implicit and internal addresses always return /// true. @@ -2331,8 +2352,8 @@ pub async fn known_address( } /// Query for all conversions. -pub async fn query_conversions<'a>( - context: &impl Namada<'a>, +pub async fn query_conversions( + context: &impl Namada, args: args::QueryConversions, ) { // The chosen token type of the conversions @@ -2408,8 +2429,8 @@ pub async fn query_conversion( } /// Query a wasm code hash -pub async fn query_wasm_code_hash<'a>( - context: &impl Namada<'a>, +pub async fn query_wasm_code_hash( + context: &impl Namada, code_path: impl AsRef, ) -> Result { rpc::query_wasm_code_hash(context, code_path).await @@ -2443,8 +2464,8 @@ pub async fn query_storage_value_bytes< /// Query a range of storage values with a matching prefix and decode them with /// [`BorshDeserialize`]. Returns an iterator of the storage keys paired with /// their associated values. -pub async fn query_storage_prefix<'a, 'b, T>( - context: &'b impl Namada<'a>, +pub async fn query_storage_prefix<'b, T>( + context: &'b impl Namada, key: &storage::Key, ) -> Option> where @@ -2488,10 +2509,7 @@ pub async fn query_tx_response( /// Lookup the results of applying the specified transaction to the /// blockchain. -pub async fn query_result<'a>( - context: &impl Namada<'a>, - args: args::QueryResult, -) { +pub async fn query_result(context: &impl Namada, args: args::QueryResult) { // First try looking up application event pertaining to given hash. let tx_response = query_tx_response( context.client(), @@ -2529,7 +2547,7 @@ pub async fn query_result<'a>( } } -pub async fn epoch_sleep<'a>(context: &impl Namada<'a>, _args: args::Query) { +pub async fn epoch_sleep(context: &impl Namada, _args: args::Query) { let start_epoch = query_and_print_epoch(context).await; loop { tokio::time::sleep(core::time::Duration::from_secs(1)).await; @@ -2628,14 +2646,14 @@ pub async fn query_governance_parameters< fn unwrap_client_response( response: Result, ) -> T { - response.unwrap_or_else(|_err| { - eprintln!("Error in the query"); + response.unwrap_or_else(|err| { + eprintln!("Error in the query: {:?}", err); cli::safe_exit(1) }) } -pub async fn compute_offline_proposal_votes<'a>( - context: &impl Namada<'a>, +pub async fn compute_offline_proposal_votes( + context: &impl Namada, proposal: &OfflineSignedProposal, votes: Vec, ) -> ProposalVotes { diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs index 0317ec43f3..583a7ee937 100644 --- a/apps/src/lib/client/tx.rs +++ b/apps/src/lib/client/tx.rs @@ -13,13 +13,13 @@ use namada::core::ledger::governance::cli::offline::{ use namada::core::ledger::governance::cli::onchain::{ DefaultProposal, PgfFundingProposal, PgfStewardProposal, ProposalVote, }; -use namada::ibc::applications::transfer::Memo; +use namada::ibc::apps::transfer::types::Memo; use namada::proto::{CompressedSignature, Section, Signer, Tx}; use namada::types::address::{Address, ImplicitAddress}; use namada::types::dec::Dec; use namada::types::io::Io; use namada::types::key::{self, *}; -use namada::types::transaction::pos::{ConsensusKeyChange, InitValidator}; +use namada::types::transaction::pos::{BecomeValidator, ConsensusKeyChange}; use namada_sdk::rpc::{TxBroadcastData, TxResponse}; use namada_sdk::wallet::alias::validator_consensus_key; use namada_sdk::{display_line, edisplay_line, error, signing, tx, Namada}; @@ -39,8 +39,8 @@ use crate::wallet::{gen_validator_keys, read_and_confirm_encryption_password}; /// Wrapper around `signing::aux_signing_data` that stores the optional /// disposable address to the wallet -pub async fn aux_signing_data<'a>( - context: &impl Namada<'a>, +pub async fn aux_signing_data( + context: &impl Namada, args: &args::Tx, owner: Option
, default_signer: Option
, @@ -69,8 +69,8 @@ pub async fn aux_signing_data<'a>( } // Sign the given transaction using a hardware wallet as a backup -pub async fn sign<'a>( - context: &impl Namada<'a>, +pub async fn sign( + context: &impl Namada, tx: &mut Tx, args: &args::Tx, signing_data: SigningTxData, @@ -134,9 +134,12 @@ pub async fn sign<'a>( response_pubkey, pubkey, ))); } + // Remove unnecessary detail for Ledger signing + let mut compressed_tx = tx.clone(); + compressed_tx.wallet_filter(); // Get the Ledger to sign using our obtained derivation path let response = app - .sign(&path, &tx.serialize_to_vec()) + .sign(&path, &compressed_tx.serialize_to_vec()) .await .map_err(|err| error::Error::Other(err.to_string()))?; // Sign the raw header if that is requested @@ -200,8 +203,8 @@ pub async fn sign<'a>( } // Build a transaction to reveal the signer of the given transaction. -pub async fn submit_reveal_aux<'a>( - context: &impl Namada<'a>, +pub async fn submit_reveal_aux( + context: &impl Namada, args: args::Tx, address: &Address, ) -> Result<(), error::Error> { @@ -239,7 +242,7 @@ pub async fn submit_reveal_aux<'a>( Ok(()) } -pub async fn submit_bridge_pool_tx<'a, N: Namada<'a>>( +pub async fn submit_bridge_pool_tx( namada: &N, args: args::EthereumBridgePool, ) -> Result<(), error::Error> { @@ -263,7 +266,7 @@ pub async fn submit_bridge_pool_tx<'a, N: Namada<'a>>( Ok(()) } -pub async fn submit_custom<'a, N: Namada<'a>>( +pub async fn submit_custom( namada: &N, args: args::TxCustom, ) -> Result<(), error::Error> @@ -289,7 +292,7 @@ where Ok(()) } -pub async fn submit_update_account<'a, N: Namada<'a>>( +pub async fn submit_update_account( namada: &N, args: args::TxUpdateAccount, ) -> Result<(), error::Error> @@ -313,10 +316,10 @@ where Ok(()) } -pub async fn submit_init_account<'a, N: Namada<'a>>( +pub async fn submit_init_account( namada: &N, args: args::TxInitAccount, -) -> Result<(), error::Error> +) -> Result, error::Error> where ::Error: std::fmt::Display, { @@ -332,14 +335,17 @@ where signing::generate_test_vector(namada, &tx).await?; - namada.submit(tx, &args.tx).await?; + let result = namada.submit(tx, &args.tx).await?; + if let ProcessTxResponse::Applied(response) = result { + return Ok(response.initialized_accounts.first().cloned()); + } } - Ok(()) + Ok(None) } -pub async fn submit_change_consensus_key<'a>( - namada: &impl Namada<'a>, +pub async fn submit_change_consensus_key( + namada: &impl Namada, config: &mut crate::config::Config, args::ConsensusKeyChange { tx: tx_args, @@ -380,8 +386,8 @@ pub async fn submit_change_consensus_key<'a>( let mut wallet = namada.wallet_mut().await; let consensus_key = consensus_key .map(|key| match key { - common::SecretKey::Ed25519(_) => key, - common::SecretKey::Secp256k1(_) => { + common::PublicKey::Ed25519(_) => key, + common::PublicKey::Secp256k1(_) => { edisplay_line!( namada.io(), "Consensus key can only be ed25519" @@ -403,6 +409,7 @@ pub async fn submit_change_consensus_key<'a>( ) .expect("Key generation should not fail.") .1 + .ref_to() }); // To avoid wallet deadlocks in following operations drop(wallet); @@ -410,7 +417,7 @@ pub async fn submit_change_consensus_key<'a>( // Check that the new consensus key is unique let consensus_keys = rpc::query_consensus_keys(namada.client()).await; - let new_ck = consensus_key.ref_to(); + let new_ck = consensus_key; if consensus_keys.contains(&new_ck) { edisplay_line!(namada.io(), "Consensus key can only be ed25519"); safe_exit(1) @@ -482,14 +489,13 @@ pub async fn submit_change_consensus_key<'a>( Ok(()) } -pub async fn submit_init_validator<'a>( - namada: &impl Namada<'a>, +pub async fn submit_become_validator( + namada: &impl Namada, config: &mut crate::config::Config, - args::TxInitValidator { + args::TxBecomeValidator { tx: tx_args, + address, scheme, - account_keys, - threshold, consensus_key, eth_cold_key, eth_hot_key, @@ -500,10 +506,9 @@ pub async fn submit_init_validator<'a>( website, description, discord_handle, - validator_vp_code_path, unsafe_dont_encrypt, - tx_code_path: _, - }: args::TxInitValidator, + tx_code_path, + }: args::TxBecomeValidator, ) -> Result<(), error::Error> { let tx_args = args::Tx { chain_id: tx_args @@ -512,6 +517,79 @@ pub async fn submit_init_validator<'a>( .or_else(|| Some(config.ledger.chain_id.clone())), ..tx_args.clone() }; + + // Check that the address is established + if !address.is_established() { + edisplay_line!( + namada.io(), + "The given address {address} is not established. Only an \ + established address can become a validator.", + ); + if !tx_args.force { + safe_exit(1) + } + }; + + // Check that the address is not already a validator + if rpc::is_validator(namada.client(), &address).await { + edisplay_line!( + namada.io(), + "The given address {address} is already a validator", + ); + if !tx_args.force { + safe_exit(1) + } + }; + + // If the address is not yet a validator, it cannot have self-bonds, but it + // may have delegations. It has to unbond those before it can become a + // validator. + if rpc::has_bonds(namada.client(), &address).await { + edisplay_line!( + namada.io(), + "The given address {address} has delegations and therefore cannot \ + become a validator. To become a validator, you have to unbond \ + your delegations first.", + ); + if !tx_args.force { + safe_exit(1) + } + } + + // Validate the commission rate data + if commission_rate > Dec::one() || commission_rate < Dec::zero() { + edisplay_line!( + namada.io(), + "The validator commission rate must not exceed 1.0 or 100%, and \ + it must be 0 or positive." + ); + if !tx_args.force { + safe_exit(1) + } + } + if max_commission_rate_change > Dec::one() + || max_commission_rate_change < Dec::zero() + { + edisplay_line!( + namada.io(), + "The validator maximum change in commission rate per epoch must \ + not exceed 1.0 or 100%, and it must be 0 or positive." + ); + if !tx_args.force { + safe_exit(1) + } + } + // Validate the email + if email.is_empty() { + edisplay_line!( + namada.io(), + "The validator email must not be an empty string." + ); + if !tx_args.force { + safe_exit(1) + } + } + let alias = tx_args .initialized_account_alias .as_ref() @@ -521,25 +599,14 @@ pub async fn submit_init_validator<'a>( let validator_key_alias = format!("{}-key", alias); let consensus_key_alias = validator_consensus_key(&alias.clone().into()); let protocol_key_alias = format!("{}-protocol-key", alias); - - let threshold = match threshold { - Some(threshold) => threshold, - None => { - if account_keys.len() == 1 { - 1u8 - } else { - safe_exit(1) - } - } - }; let eth_hot_key_alias = format!("{}-eth-hot-key", alias); let eth_cold_key_alias = format!("{}-eth-cold-key", alias); let mut wallet = namada.wallet_mut().await; let consensus_key = consensus_key .map(|key| match key { - common::SecretKey::Ed25519(_) => key, - common::SecretKey::Secp256k1(_) => { + common::PublicKey::Ed25519(_) => key, + common::PublicKey::Secp256k1(_) => { edisplay_line!( namada.io(), "Consensus key can only be ed25519" @@ -562,12 +629,13 @@ pub async fn submit_init_validator<'a>( ) .expect("Key generation should not fail.") .1 + .ref_to() }); let eth_cold_pk = eth_cold_key .map(|key| match key { - common::SecretKey::Secp256k1(_) => key.ref_to(), - common::SecretKey::Ed25519(_) => { + common::PublicKey::Secp256k1(_) => key, + common::PublicKey::Ed25519(_) => { edisplay_line!( namada.io(), "Eth cold key can only be secp256k1" @@ -595,8 +663,8 @@ pub async fn submit_init_validator<'a>( let eth_hot_pk = eth_hot_key .map(|key| match key { - common::SecretKey::Secp256k1(_) => key.ref_to(), - common::SecretKey::Ed25519(_) => { + common::PublicKey::Secp256k1(_) => key, + common::PublicKey::Ed25519(_) => { edisplay_line!( namada.io(), "Eth hot key can only be secp256k1" @@ -629,7 +697,7 @@ pub async fn submit_init_validator<'a>( } // Generate the validator keys let validator_keys = gen_validator_keys( - *namada.wallet_mut().await, + &mut *namada.wallet_mut().await, Some(eth_hot_pk.clone()), protocol_key, scheme, @@ -655,61 +723,16 @@ pub async fn submit_init_validator<'a>( ) .map_err(|err| error::Error::Other(err.to_string()))?; - let validator_vp_code_hash = - query_wasm_code_hash(namada, validator_vp_code_path.to_str().unwrap()) - .await - .unwrap(); - - // Validate the commission rate data - if commission_rate > Dec::one() || commission_rate < Dec::zero() { - edisplay_line!( - namada.io(), - "The validator commission rate must not exceed 1.0 or 100%, and \ - it must be 0 or positive" - ); - if !tx_args.force { - safe_exit(1) - } - } - if max_commission_rate_change > Dec::one() - || max_commission_rate_change < Dec::zero() - { - edisplay_line!( - namada.io(), - "The validator maximum change in commission rate per epoch must \ - not exceed 1.0 or 100%" - ); - if !tx_args.force { - safe_exit(1) - } - } - // Validate the email - if email.is_empty() { - edisplay_line!( - namada.io(), - "The validator email must not be an empty string" - ); - if !tx_args.force { - safe_exit(1) - } - } - let tx_code_hash = - query_wasm_code_hash(namada, args::TX_INIT_VALIDATOR_WASM) + query_wasm_code_hash(namada, tx_code_path.to_string_lossy()) .await .unwrap(); let chain_id = tx_args.chain_id.clone().unwrap(); let mut tx = Tx::new(chain_id, tx_args.expiration); - let extra_section_hash = tx.add_extra_section_from_hash( - validator_vp_code_hash, - Some(validator_vp_code_path.to_string_lossy().into_owned()), - ); - - let data = InitValidator { - account_keys, - threshold, - consensus_key: consensus_key.ref_to(), + let data = BecomeValidator { + address: address.clone(), + consensus_key: consensus_key.clone(), eth_cold_key: key::secp256k1::PublicKey::try_from_pk(ð_cold_pk) .unwrap(), eth_hot_key: key::secp256k1::PublicKey::try_from_pk(ð_hot_pk) @@ -721,19 +744,28 @@ pub async fn submit_init_validator<'a>( description, website, discord_handle, - validator_vp_code_hash: extra_section_hash, }; // Put together all the PKs that we have to sign with to verify ownership - let mut all_pks = data.account_keys.clone(); - all_pks.push(consensus_key.to_public()); + let account = namada_sdk::rpc::get_account_info(namada.client(), &address) + .await? + .unwrap_or_else(|| { + edisplay_line!( + namada.io(), + "Unable to query account keys for address {address}." + ); + safe_exit(1) + }); + let mut all_pks: Vec<_> = + account.public_keys_map.pk_to_idx.into_keys().collect(); + all_pks.push(consensus_key.clone()); all_pks.push(eth_cold_pk); all_pks.push(eth_hot_pk); all_pks.push(data.protocol_key.clone()); tx.add_code_from_hash( tx_code_hash, - Some(args::TX_INIT_VALIDATOR_WASM.to_string()), + Some(args::TX_BECOME_VALIDATOR_WASM.to_string()), ) .add_data(data); @@ -758,49 +790,25 @@ pub async fn submit_init_validator<'a>( signing::generate_test_vector(namada, &tx).await?; - let result = namada.submit(tx, &tx_args).await?.initialized_accounts(); + namada.submit(tx, &tx_args).await?.initialized_accounts(); if !tx_args.dry_run { - let (validator_address_alias, validator_address) = match &result[..] - { - // There should be 1 account for the validator itself - [validator_address] => { - if let Some(alias) = - namada.wallet().await.find_alias(validator_address) - { - (alias.clone(), validator_address.clone()) - } else { - edisplay_line!( - namada.io(), - "Expected one account to be created" - ); - safe_exit(1) - } - } - _ => { - edisplay_line!( - namada.io(), - "Expected one account to be created" - ); - safe_exit(1) - } - }; // add validator address and keys to the wallet - namada - .wallet_mut() - .await - .add_validator_data(validator_address, validator_keys); - namada - .wallet_mut() - .await + let mut wallet = namada.wallet_mut().await; + wallet.add_validator_data(address.clone(), validator_keys); + wallet .save() .unwrap_or_else(|err| edisplay_line!(namada.io(), "{}", err)); let tendermint_home = config.ledger.cometbft_dir(); tendermint_node::write_validator_key( &tendermint_home, - &consensus_key, + &wallet + .find_key_by_pk(&consensus_key, None) + .expect("unable to find consensus key pair in the wallet"), ); + // To avoid wallet deadlocks in following operations + drop(wallet); tendermint_node::write_validator_state(tendermint_home); // Write Namada config stuff or figure out how to do the above @@ -819,12 +827,7 @@ pub async fn submit_init_validator<'a>( display_line!(namada.io(), ""); display_line!( namada.io(), - "The validator's addresses and keys were stored in the wallet:" - ); - display_line!( - namada.io(), - " Validator address \"{}\"", - validator_address_alias + "The keys for validator \"{alias}\" were stored in the wallet:" ); display_line!( namada.io(), @@ -857,8 +860,84 @@ pub async fn submit_init_validator<'a>( Ok(()) } -pub async fn submit_transfer<'a>( - namada: &impl Namada<'a>, +pub async fn submit_init_validator( + namada: &impl Namada, + config: &mut crate::config::Config, + args::TxInitValidator { + tx: tx_args, + scheme, + account_keys, + threshold, + consensus_key, + eth_cold_key, + eth_hot_key, + protocol_key, + commission_rate, + max_commission_rate_change, + email, + website, + description, + discord_handle, + validator_vp_code_path, + unsafe_dont_encrypt, + tx_init_account_code_path, + tx_become_validator_code_path, + }: args::TxInitValidator, +) -> Result<(), error::Error> { + let address = submit_init_account( + namada, + args::TxInitAccount { + tx: tx_args.clone(), + vp_code_path: validator_vp_code_path, + tx_code_path: tx_init_account_code_path, + public_keys: account_keys, + threshold, + }, + ) + .await?; + + if tx_args.dry_run { + eprintln!( + "Cannot proceed to become validator in dry-run as no account has \ + been created" + ); + safe_exit(1); + } + let address = address.unwrap_or_else(|| { + eprintln!( + "Something went wrong with transaction to initialize an account \ + as no address has been created. Cannot proceed to become \ + validator." + ); + safe_exit(1); + }); + + submit_become_validator( + namada, + config, + args::TxBecomeValidator { + tx: tx_args, + address, + scheme, + consensus_key, + eth_cold_key, + eth_hot_key, + protocol_key, + commission_rate, + max_commission_rate_change, + email, + description, + website, + discord_handle, + tx_code_path: tx_become_validator_code_path, + unsafe_dont_encrypt, + }, + ) + .await +} + +pub async fn submit_transfer( + namada: &impl Namada, args: args::TxTransfer, ) -> Result<(), error::Error> { for _ in 0..2 { @@ -911,7 +990,7 @@ pub async fn submit_transfer<'a>( Ok(()) } -pub async fn submit_ibc_transfer<'a, N: Namada<'a>>( +pub async fn submit_ibc_transfer( namada: &N, args: args::TxIbcTransfer, ) -> Result<(), error::Error> @@ -935,7 +1014,7 @@ where Ok(()) } -pub async fn submit_init_proposal<'a, N: Namada<'a>>( +pub async fn submit_init_proposal( namada: &N, args: args::InitProposal, ) -> Result<(), error::Error> @@ -965,8 +1044,14 @@ where ) .await?; + let mut wallet = namada.wallet_mut().await; let signed_offline_proposal = proposal.sign( - args.tx.signing_keys, + args.tx + .signing_keys + .iter() + .map(|pk| wallet.find_key_by_pk(pk, None)) + .collect::>() + .expect("secret keys corresponding to public keys not found"), &signing_data.account_public_keys_map.unwrap(), ); let output_file_path = signed_offline_proposal @@ -1064,7 +1149,7 @@ where Ok(()) } -pub async fn submit_vote_proposal<'a, N: Namada<'a>>( +pub async fn submit_vote_proposal( namada: &N, args: args::VoteProposal, ) -> Result<(), error::Error> @@ -1112,8 +1197,14 @@ where delegations, ); + let mut wallet = namada.wallet_mut().await; let offline_signed_vote = offline_vote.sign( - args.tx.signing_keys, + args.tx + .signing_keys + .iter() + .map(|pk| wallet.find_key_by_pk(pk, None)) + .collect::>() + .expect("secret keys corresponding to public keys not found"), &signing_data.account_public_keys_map.unwrap(), ); let output_file_path = offline_signed_vote @@ -1144,7 +1235,7 @@ where Ok(()) } -pub async fn sign_tx<'a, N: Namada<'a>>( +pub async fn sign_tx( namada: &N, args::SignTx { tx: tx_args, @@ -1225,7 +1316,7 @@ where Ok(()) } -pub async fn submit_reveal_pk<'a, N: Namada<'a>>( +pub async fn submit_reveal_pk( namada: &N, args: args::RevealPk, ) -> Result<(), error::Error> @@ -1237,7 +1328,7 @@ where Ok(()) } -pub async fn submit_bond<'a, N: Namada<'a>>( +pub async fn submit_bond( namada: &N, args: args::Bond, ) -> Result<(), error::Error> @@ -1264,7 +1355,7 @@ where Ok(()) } -pub async fn submit_unbond<'a, N: Namada<'a>>( +pub async fn submit_unbond( namada: &N, args: args::Unbond, ) -> Result<(), error::Error> @@ -1290,7 +1381,7 @@ where Ok(()) } -pub async fn submit_withdraw<'a, N: Namada<'a>>( +pub async fn submit_withdraw( namada: &N, args: args::Withdraw, ) -> Result<(), error::Error> @@ -1314,7 +1405,7 @@ where Ok(()) } -pub async fn submit_claim_rewards<'a, N: Namada<'a>>( +pub async fn submit_claim_rewards( namada: &N, args: args::ClaimRewards, ) -> Result<(), error::Error> @@ -1338,7 +1429,7 @@ where Ok(()) } -pub async fn submit_redelegate<'a, N: Namada<'a>>( +pub async fn submit_redelegate( namada: &N, args: args::Redelegate, ) -> Result<(), error::Error> @@ -1361,7 +1452,7 @@ where Ok(()) } -pub async fn submit_validator_commission_change<'a, N: Namada<'a>>( +pub async fn submit_validator_commission_change( namada: &N, args: args::CommissionRateChange, ) -> Result<(), error::Error> @@ -1385,7 +1476,7 @@ where Ok(()) } -pub async fn submit_validator_metadata_change<'a, N: Namada<'a>>( +pub async fn submit_validator_metadata_change( namada: &N, args: args::MetaDataChange, ) -> Result<(), error::Error> @@ -1409,7 +1500,7 @@ where Ok(()) } -// pub async fn submit_change_consensus_key<'a, N: Namada<'a>>( +// pub async fn submit_change_consensus_key( // namada: &N, // args: args::ConsensusKeyChange, // ) -> Result<(), error::Error> @@ -1431,7 +1522,7 @@ where // Ok(()) // } -pub async fn submit_unjail_validator<'a, N: Namada<'a>>( +pub async fn submit_unjail_validator( namada: &N, args: args::TxUnjailValidator, ) -> Result<(), error::Error> @@ -1455,7 +1546,7 @@ where Ok(()) } -pub async fn submit_deactivate_validator<'a, N: Namada<'a>>( +pub async fn submit_deactivate_validator( namada: &N, args: args::TxDeactivateValidator, ) -> Result<(), error::Error> @@ -1479,7 +1570,7 @@ where Ok(()) } -pub async fn submit_reactivate_validator<'a, N: Namada<'a>>( +pub async fn submit_reactivate_validator( namada: &N, args: args::TxReactivateValidator, ) -> Result<(), error::Error> @@ -1503,7 +1594,7 @@ where Ok(()) } -pub async fn submit_update_steward_commission<'a, N: Namada<'a>>( +pub async fn submit_update_steward_commission( namada: &N, args: args::UpdateStewardCommission, ) -> Result<(), error::Error> @@ -1528,7 +1619,7 @@ where Ok(()) } -pub async fn submit_resign_steward<'a, N: Namada<'a>>( +pub async fn submit_resign_steward( namada: &N, args: args::ResignSteward, ) -> Result<(), error::Error> @@ -1553,8 +1644,8 @@ where } /// Save accounts initialized from a tx into the wallet, if any. -pub async fn save_initialized_accounts<'a>( - namada: &impl Namada<'a>, +pub async fn save_initialized_accounts( + namada: &impl Namada, args: &args::Tx, initialized_accounts: Vec
, ) { @@ -1565,8 +1656,8 @@ pub async fn save_initialized_accounts<'a>( /// the tx has been successfully included into the mempool of a validator /// /// In the case of errors in any of those stages, an error message is returned -pub async fn broadcast_tx<'a>( - namada: &impl Namada<'a>, +pub async fn broadcast_tx( + namada: &impl Namada, to_broadcast: &TxBroadcastData, ) -> Result { tx::broadcast_tx(namada, to_broadcast).await @@ -1580,15 +1671,15 @@ pub async fn broadcast_tx<'a>( /// 3. The decrypted payload of the tx has been included on the blockchain. /// /// In the case of errors in any of those stages, an error message is returned -pub async fn submit_tx<'a>( - namada: &impl Namada<'a>, +pub async fn submit_tx( + namada: &impl Namada, to_broadcast: TxBroadcastData, ) -> Result { tx::submit_tx(namada, to_broadcast).await } -pub async fn gen_ibc_shielded_transfer<'a>( - context: &impl Namada<'a>, +pub async fn gen_ibc_shielded_transfer( + context: &impl Namada, args: args::GenIbcShieldedTransafer, ) -> Result<(), error::Error> { if let Some(shielded_transfer) = diff --git a/apps/src/lib/config/genesis.rs b/apps/src/lib/config/genesis.rs index b1fac85e81..32d2fcf3ae 100644 --- a/apps/src/lib/config/genesis.rs +++ b/apps/src/lib/config/genesis.rs @@ -380,7 +380,7 @@ pub fn make_dev_genesis( address, tx: transactions::ValidatorAccountTx { alias: alias.clone(), - vp: "vp_validator".to_string(), + vp: "vp_user".to_string(), commission_rate: Dec::new(5, 2).expect("This can't fail"), max_commission_rate_change: Dec::new(1, 2) .expect("This can't fail"), diff --git a/apps/src/lib/config/genesis/transactions.rs b/apps/src/lib/config/genesis/transactions.rs index d457ef87f5..432335d263 100644 --- a/apps/src/lib/config/genesis/transactions.rs +++ b/apps/src/lib/config/genesis/transactions.rs @@ -153,7 +153,7 @@ pub fn init_validator( validator_wallet.eth_cold_key.ref_to(), ), // No custom validator VPs yet - vp: "vp_validator".to_string(), + vp: "vp_user".to_string(), commission_rate, max_commission_rate_change, email, @@ -345,7 +345,7 @@ pub fn sign_delegation_bond_tx( }; let source_key = match found_key { Ok(key) => key, - Err(FindKeyError::KeyNotFound) => { + Err(FindKeyError::KeyNotFound(_)) => { // If it's not in the wallet, it must be an established account // so we need to look-up its public key first let pk = established_accounts diff --git a/apps/src/lib/node/ledger/ethereum_oracle/mod.rs b/apps/src/lib/node/ledger/ethereum_oracle/mod.rs index 64a05b64ff..796563a27d 100644 --- a/apps/src/lib/node/ledger/ethereum_oracle/mod.rs +++ b/apps/src/lib/node/ledger/ethereum_oracle/mod.rs @@ -252,6 +252,18 @@ impl Oracle { _ => None, } } + + /// If the bridge has been deactivated, block here until a new + /// config is passed that reactivates the bridge + async fn wait_on_reactivation(&mut self) -> Config { + loop { + if let Some(Command::UpdateConfig(c)) = self.control.recv().await { + if c.active { + return c; + } + } + } + } } /// Block until an initial configuration is received via the command channel. @@ -438,6 +450,9 @@ async fn run_oracle_aux(mut oracle: Oracle) { if let Some(new_config) = oracle.update_config() { config = new_config; } + if !config.active { + config = oracle.wait_on_reactivation().await; + } next_block_to_process += 1.into(); } } @@ -1009,6 +1024,105 @@ mod test_oracle { oracle.await.expect("Test failed"); } + /// Test that Ethereum oracle can be deactivate and reactivated + /// via config updates. + /// NOTE: This test can flake due to async channel race + /// conditions. + #[tokio::test] + async fn test_oracle_reactivation() { + let TestPackage { + oracle, + eth_recv, + controller, + mut blocks_processed_recv, + mut control_sender, + } = setup(); + let config = Config::default(); + let oracle = start_with_default_config( + oracle, + &mut control_sender, + config.clone(), + ) + .await; + + // set the height of the chain such that there are some blocks deep + // enough to be considered confirmed by the oracle + let confirmed_block_height = 9; // all blocks up to and including this block will have enough confirmations + let min_confirmations = u64::from(config.min_confirmations); + controller.apply_cmd(TestCmd::NewHeight(Uint256::from( + min_confirmations + confirmed_block_height - 5, + ))); + + // check that the oracle indeed processes the expected blocks + for height in 0u64..(confirmed_block_height - 4) { + let block_processed = timeout( + std::time::Duration::from_secs(3), + blocks_processed_recv.recv(), + ) + .await + .expect("Timed out waiting for block to be checked") + .unwrap(); + assert_eq!(block_processed, Uint256::from(height)); + } + + // Deactivate the bridge before all confirmed events are confirmed and + // processed There is a very fine needle to thread here. A block + // must be processed **after** this config is sent in order for + // the updated config to be received. However, this test can + // flake due to channel race conditions. + control_sender + .try_send(Command::UpdateConfig(Config { + active: false, + ..Default::default() + })) + .expect("Test failed"); + std::thread::sleep(Duration::from_secs(1)); + controller.apply_cmd(TestCmd::NewHeight(Uint256::from( + min_confirmations + confirmed_block_height - 4, + ))); + + let block_processed = timeout( + std::time::Duration::from_secs(3), + blocks_processed_recv.recv(), + ) + .await + .expect("Timed out waiting for block to be checked") + .unwrap(); + assert_eq!(block_processed, Uint256::from(confirmed_block_height - 4)); + + // check that the oracle hasn't yet checked any further blocks + // TODO: check this in a deterministic way rather than just waiting a + // bit + let res = timeout( + std::time::Duration::from_secs(3), + blocks_processed_recv.recv(), + ) + .await; + assert!(res.is_err()); + + // reactivate the bridge and check that the oracle + // processed the rest of the confirmed blocks + control_sender + .try_send(Command::UpdateConfig(Default::default())) + .expect("Test failed"); + + controller.apply_cmd(TestCmd::NewHeight(Uint256::from( + min_confirmations + confirmed_block_height, + ))); + for height in (confirmed_block_height - 3)..=confirmed_block_height { + let block_processed = timeout( + std::time::Duration::from_secs(3), + blocks_processed_recv.recv(), + ) + .await + .expect("Timed out waiting for block to be checked") + .unwrap(); + assert_eq!(block_processed, Uint256::from(height)); + } + drop(eth_recv); + oracle.await.expect("Test failed"); + } + /// Test that if the Ethereum RPC endpoint returns a latest block that is /// more than one block later than the previous latest block we received, we /// still check all the blocks in between diff --git a/apps/src/lib/node/ledger/shell/finalize_block.rs b/apps/src/lib/node/ledger/shell/finalize_block.rs index 257b766a03..49a1c5222c 100644 --- a/apps/src/lib/node/ledger/shell/finalize_block.rs +++ b/apps/src/lib/node/ledger/shell/finalize_block.rs @@ -198,6 +198,7 @@ where // Tracks the accepted transactions self.wl_storage.storage.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 @@ -411,7 +412,7 @@ where ) .map_err(Error::TxApply) { - Ok(result) => { + Ok(ref mut result) => { if result.is_accepted() { if let EventType::Accepted = tx_event.event_type { // Wrapper transaction @@ -430,6 +431,7 @@ where tx_event["hash"], result ); + changed_keys.append(&mut result.changed_keys); stats.increment_successful_txs(); if let Some(wrapper) = embedding_wrapper { self.commit_inner_tx_hash(wrapper); @@ -561,7 +563,7 @@ where self.update_epoch(&mut response); // send the latest oracle configs. These may have changed due to // governance. - self.update_eth_oracle(); + self.update_eth_oracle(&changed_keys); } write_last_block_proposer_address( @@ -694,11 +696,8 @@ where .pred_epochs .first_block_heights[last_epoch.0 as usize] .0; - let num_blocks_in_last_epoch = if first_block_of_last_epoch == 0 { - self.wl_storage.storage.block.height.0 - 1 - } else { - self.wl_storage.storage.block.height.0 - first_block_of_last_epoch - }; + let num_blocks_in_last_epoch = + self.wl_storage.storage.block.height.0 - first_block_of_last_epoch; let staking_token = staking_token_address(&self.wl_storage); @@ -1662,7 +1661,7 @@ mod test_finalize_block { transfer }; let ethereum_event = EthereumEvent::TransfersToEthereum { - nonce: 0u64.into(), + nonce: 1u64.into(), transfers: vec![transfer], relayer: bertha, }; @@ -2176,7 +2175,7 @@ mod test_finalize_block { assert!(rp3 > rp4); } - /// A unit test for PoS inflationary rewards claiming + /// A unit test for PoS inflationary rewards claiming and querying #[test] fn test_claim_rewards() { let (mut shell, _recv, _, _) = setup_with_cfg(SetupCfg { @@ -2252,6 +2251,15 @@ mod test_finalize_block { advance_epoch(&mut shell, &pkh1, &votes, None); total_rewards += inflation; + // Query the available rewards + let query_rewards = namada_proof_of_stake::query_reward_tokens( + &shell.wl_storage, + None, + &validator.address, + current_epoch, + ) + .unwrap(); + // Claim the rewards from the initial epoch let reward_1 = namada_proof_of_stake::claim_reward_tokens( &mut shell.wl_storage, @@ -2261,8 +2269,20 @@ mod test_finalize_block { ) .unwrap(); total_claimed += reward_1; + assert_eq!(reward_1, query_rewards); assert!(is_reward_equal_enough(total_rewards, total_claimed, 1)); + // Query the available rewards again and check that it is 0 now after + // the claim + let query_rewards = namada_proof_of_stake::query_reward_tokens( + &shell.wl_storage, + None, + &validator.address, + current_epoch, + ) + .unwrap(); + assert_eq!(query_rewards, token::Amount::zero()); + // Try a claim the next block and ensure we get 0 tokens back next_block_for_inflation( &mut shell, @@ -2297,6 +2317,15 @@ mod test_finalize_block { .unwrap(); assert_eq!(unbond_res.sum, unbond_amount); + // Query the available rewards + let query_rewards = namada_proof_of_stake::query_reward_tokens( + &shell.wl_storage, + None, + &validator.address, + current_epoch, + ) + .unwrap(); + let rew = namada_proof_of_stake::claim_reward_tokens( &mut shell.wl_storage, None, @@ -2306,6 +2335,7 @@ mod test_finalize_block { .unwrap(); total_claimed += rew; assert!(is_reward_equal_enough(total_rewards, total_claimed, 3)); + assert_eq!(query_rewards, rew); // Check the bond amounts for rewards up thru the withdrawable epoch let withdraw_epoch = current_epoch + params.withdrawable_epoch_offset(); @@ -2365,6 +2395,15 @@ mod test_finalize_block { .unwrap(); assert_eq!(withdraw_amount, unbond_amount); + // Query the available rewards + let query_rewards = namada_proof_of_stake::query_reward_tokens( + &shell.wl_storage, + None, + &validator.address, + current_epoch, + ) + .unwrap(); + // Claim tokens let reward_2 = namada_proof_of_stake::claim_reward_tokens( &mut shell.wl_storage, @@ -2374,6 +2413,7 @@ mod test_finalize_block { ) .unwrap(); total_claimed += reward_2; + assert_eq!(query_rewards, reward_2); // The total rewards claimed should be approximately equal to the total // minted inflation, minus (unbond_amount / initial_stake) * rewards @@ -2384,6 +2424,16 @@ mod test_finalize_block { let token_uncertainty = uncertainty * lost_rewards; let token_diff = total_claimed + lost_rewards - total_rewards; assert!(token_diff < token_uncertainty); + + // Query the available rewards to check that they are 0 + let query_rewards = namada_proof_of_stake::query_reward_tokens( + &shell.wl_storage, + None, + &validator.address, + current_epoch, + ) + .unwrap(); + assert_eq!(query_rewards, token::Amount::zero()); } /// A unit test for PoS inflationary rewards claiming diff --git a/apps/src/lib/node/ledger/shell/init_chain.rs b/apps/src/lib/node/ledger/shell/init_chain.rs index aad1fcc362..c252a8a61f 100644 --- a/apps/src/lib/node/ledger/shell/init_chain.rs +++ b/apps/src/lib/node/ledger/shell/init_chain.rs @@ -111,7 +111,7 @@ where if let Some(config) = genesis.get_eth_bridge_params() { tracing::debug!("Initializing Ethereum bridge storage."); config.init_storage(&mut self.wl_storage); - self.update_eth_oracle(); + self.update_eth_oracle(&Default::default()); } else { self.wl_storage .write_bytes( @@ -159,7 +159,7 @@ where pos::namada_proof_of_stake::compute_and_store_total_consensus_stake( &mut self.wl_storage, - Default::default(), + current_epoch, ) .expect("Could not compute total consensus stake at genesis"); // This has to be done after `apply_genesis_txs_validator_account` @@ -448,8 +448,8 @@ where // TODO: replace pos::init_genesis validators arg with // init_genesis_validator from here if let Err(err) = pos::namada_proof_of_stake::become_validator( + &mut self.wl_storage, BecomeValidator { - storage: &mut self.wl_storage, params, address, consensus_key: &consensus_key.pk.raw, diff --git a/apps/src/lib/node/ledger/shell/mod.rs b/apps/src/lib/node/ledger/shell/mod.rs index 861fc4e727..8e33bf87bb 100644 --- a/apps/src/lib/node/ledger/shell/mod.rs +++ b/apps/src/lib/node/ledger/shell/mod.rs @@ -254,18 +254,32 @@ impl EthereumReceiver { } } - /// Pull messages from the channel and add to queue - /// Since vote extensions require ordering of ethereum - /// events, we do that here. We also de-duplicate events - pub fn fill_queue(&mut self) { + /// Pull Ethereum events from the oracle and queue them to + /// be voted on. + /// + /// Since vote extensions require ordering of Ethereum + /// events, we do that here. We also de-duplicate events. + /// Events may be filtered out of the queue with a provided + /// predicate. + pub fn fill_queue(&mut self, mut keep_event: F) + where + F: FnMut(&EthereumEvent) -> bool, + { let mut new_events = 0; + let mut filtered_events = 0; while let Ok(eth_event) = self.channel.try_recv() { - if self.queue.insert(eth_event) { + if keep_event(ð_event) && self.queue.insert(eth_event) { new_events += 1; - }; + } else { + filtered_events += 1; + } } - if new_events > 0 { - tracing::info!(n = new_events, "received Ethereum events"); + if new_events + filtered_events > 0 { + tracing::info!( + new_events, + filtered_events, + "received Ethereum events" + ); } } @@ -569,8 +583,7 @@ where // TODO: config event log params event_log: EventLog::default(), }; - - shell.update_eth_oracle(); + shell.update_eth_oracle(&Default::default()); shell } @@ -982,14 +995,18 @@ where } /// If a handle to an Ethereum oracle was provided to the [`Shell`], attempt - /// to send it an updated configuration, using an initial configuration + /// to send it an updated configuration, using a configuration /// based on Ethereum bridge parameters in blockchain storage. /// /// This method must be safe to call even before ABCI `InitChain` has been /// called (i.e. when storage is empty), as we may want to do this check /// every time the shell starts up (including the first time ever at which /// time storage will be empty). - fn update_eth_oracle(&mut self) { + /// + /// This method is also called during `FinalizeBlock` to update the oracle + /// if relevant storage changes have occurred. This includes deactivating + /// and reactivating the bridge. + fn update_eth_oracle(&mut self, changed_keys: &BTreeSet) { if let ShellMode::Validator { eth_oracle: Some(EthereumOracleChannels { control_sender, .. }), .. @@ -1015,16 +1032,30 @@ where ); return; } - if !self.wl_storage.ethbridge_queries().is_bridge_active() { - tracing::info!( - "Not starting oracle as the Ethereum bridge is disabled" - ); + let Some(config) = EthereumOracleConfig::read(&self.wl_storage) else { + tracing::info!("Not starting oracle as the Ethereum bridge config couldn't be found in storage"); return; - } - let config = EthereumOracleConfig::read(&self.wl_storage).expect( - "The oracle config must be present in storage, since the \ - bridge is enabled", - ); + }; + let active = + if !self.wl_storage.ethbridge_queries().is_bridge_active() { + if !changed_keys + .contains(ð_bridge::storage::active_key()) + { + tracing::info!( + "Not starting oracle as the Ethereum bridge is \ + disabled" + ); + return; + } else { + tracing::info!( + "Disabling oracle as the bridge has been disabled" + ); + false + } + } else { + true + }; + let start_block = self .wl_storage .storage @@ -1040,6 +1071,7 @@ where min_confirmations: config.min_confirmations.into(), bridge_contract: config.contracts.bridge.address, start_block, + active, }; tracing::info!( ?config, @@ -2362,6 +2394,81 @@ mod shell_tests { ); } + /// Test that Ethereum events with outdated nonces are + /// not validated by `CheckTx`. + #[test] + fn test_outdated_nonce_mempool_validate() { + use namada::types::storage::InnerEthEventsQueue; + + const LAST_HEIGHT: BlockHeight = BlockHeight(3); + + let (mut shell, _recv, _, _) = test_utils::setup_at_height(LAST_HEIGHT); + shell + .wl_storage + .storage + .eth_events_queue + // sent transfers to namada nonce to 5 + .transfers_to_namada = InnerEthEventsQueue::new_at(5.into()); + + let (protocol_key, _) = wallet::defaults::validator_keys(); + + // only bad events + { + let ethereum_event = EthereumEvent::TransfersToNamada { + nonce: 3u64.into(), + transfers: vec![], + }; + let ext = { + let ext = ethereum_events::Vext { + validator_addr: wallet::defaults::validator_address(), + block_height: LAST_HEIGHT, + ethereum_events: vec![ethereum_event], + } + .sign(&protocol_key); + assert!(ext.verify(&protocol_key.ref_to()).is_ok()); + ext + }; + let tx = EthereumTxData::EthEventsVext(ext) + .sign(&protocol_key, shell.chain_id.clone()) + .to_bytes(); + let rsp = shell.mempool_validate(&tx, Default::default()); + assert!( + rsp.code != ErrorCodes::Ok.into(), + "Validation should have failed" + ); + } + + // at least one good event + { + let e1 = EthereumEvent::TransfersToNamada { + nonce: 3u64.into(), + transfers: vec![], + }; + let e2 = EthereumEvent::TransfersToNamada { + nonce: 5u64.into(), + transfers: vec![], + }; + let ext = { + let ext = ethereum_events::Vext { + validator_addr: wallet::defaults::validator_address(), + block_height: LAST_HEIGHT, + ethereum_events: vec![e1, e2], + } + .sign(&protocol_key); + assert!(ext.verify(&protocol_key.ref_to()).is_ok()); + ext + }; + let tx = EthereumTxData::EthEventsVext(ext) + .sign(&protocol_key, shell.chain_id.clone()) + .to_bytes(); + let rsp = shell.mempool_validate(&tx, Default::default()); + assert!( + rsp.code == ErrorCodes::Ok.into(), + "Validation should have passed" + ); + } + } + /// Test that we do not include protocol txs in the mempool, /// voting on ethereum events or signing bridge pool roots /// and nonces if the bridge is inactive. diff --git a/apps/src/lib/node/ledger/shell/prepare_proposal.rs b/apps/src/lib/node/ledger/shell/prepare_proposal.rs index baf77012d8..6a4ca7ab2d 100644 --- a/apps/src/lib/node/ledger/shell/prepare_proposal.rs +++ b/apps/src/lib/node/ledger/shell/prepare_proposal.rs @@ -391,10 +391,12 @@ mod test_prepare_proposal { use namada::types::address::{self, Address}; use namada::types::ethereum_events::EthereumEvent; use namada::types::key::RefTo; - use namada::types::storage::BlockHeight; + use namada::types::storage::{BlockHeight, InnerEthEventsQueue}; use namada::types::token; use namada::types::token::Amount; - use namada::types::transaction::protocol::EthereumTxData; + use namada::types::transaction::protocol::{ + ethereum_tx_data_variants, EthereumTxData, + }; use namada::types::transaction::{Fee, TxType, WrapperTx}; use namada::types::vote_extensions::ethereum_events; @@ -1376,4 +1378,115 @@ mod test_prepare_proposal { eprintln!("Proposal: {:?}", result.txs); assert!(result.txs.is_empty()); } + + /// Test that Ethereum events with outdated nonces are + /// not proposed during `PrepareProposal`. + #[test] + fn test_outdated_nonce_proposal() { + const LAST_HEIGHT: BlockHeight = BlockHeight(3); + + let (mut shell, _recv, _, _) = test_utils::setup_at_height(LAST_HEIGHT); + shell + .wl_storage + .storage + .eth_events_queue + // sent transfers to namada nonce to 5 + .transfers_to_namada = InnerEthEventsQueue::new_at(5.into()); + + let (protocol_key, _) = wallet::defaults::validator_keys(); + let validator_addr = wallet::defaults::validator_address(); + + // test an extension containing solely events with + // bad nonces + { + let ethereum_event = EthereumEvent::TransfersToNamada { + // outdated nonce (3 < 5) + nonce: 3u64.into(), + transfers: vec![], + }; + let ext = { + let ext = ethereum_events::Vext { + validator_addr: validator_addr.clone(), + block_height: LAST_HEIGHT, + ethereum_events: vec![ethereum_event], + } + .sign(&protocol_key); + assert!(ext.verify(&protocol_key.ref_to()).is_ok()); + ext + }; + let tx = EthereumTxData::EthEventsVext(ext) + .sign(&protocol_key, shell.chain_id.clone()) + .to_bytes(); + let req = RequestPrepareProposal { + txs: vec![tx.into()], + ..Default::default() + }; + let proposed_txs = + shell.prepare_proposal(req).txs.into_iter().map(|tx_bytes| { + Tx::try_from(tx_bytes.as_ref()).expect("Test failed") + }); + // since no events with valid nonces are contained in the vote + // extension, we drop it from the proposal + for tx in proposed_txs { + if ethereum_tx_data_variants::EthEventsVext::try_from(&tx) + .is_ok() + { + panic!( + "No ethereum events should have been found in the \ + proposal" + ); + } + } + } + + // test an extension containing at least one event + // with a good nonce + { + let event1 = EthereumEvent::TransfersToNamada { + // outdated nonce (3 < 5) + nonce: 3u64.into(), + transfers: vec![], + }; + let event2 = EthereumEvent::TransfersToNamada { + // outdated nonce (10 >= 5) + nonce: 10u64.into(), + transfers: vec![], + }; + let ext = { + let ext = ethereum_events::Vext { + validator_addr, + block_height: LAST_HEIGHT, + ethereum_events: vec![event1, event2.clone()], + } + .sign(&protocol_key); + assert!(ext.verify(&protocol_key.ref_to()).is_ok()); + ext + }; + let tx = EthereumTxData::EthEventsVext(ext) + .sign(&protocol_key, shell.chain_id.clone()) + .to_bytes(); + let req = RequestPrepareProposal { + txs: vec![tx.into()], + ..Default::default() + }; + let proposed_txs = + shell.prepare_proposal(req).txs.into_iter().map(|tx_bytes| { + Tx::try_from(tx_bytes.as_ref()).expect("Test failed") + }); + // find the event with the good nonce + let mut ext = 'ext: { + for tx in proposed_txs { + if let Ok(ext) = + ethereum_tx_data_variants::EthEventsVext::try_from(&tx) + { + break 'ext ext; + } + } + panic!("No ethereum events found in proposal"); + }; + assert_eq!(ext.data.ethereum_events.len(), 2); + let found_event = ext.data.ethereum_events.remove(1); + assert_eq!(found_event, event2); + } + } } diff --git a/apps/src/lib/node/ledger/shell/process_proposal.rs b/apps/src/lib/node/ledger/shell/process_proposal.rs index 9f19cf2d66..7fad385eda 100644 --- a/apps/src/lib/node/ledger/shell/process_proposal.rs +++ b/apps/src/lib/node/ledger/shell/process_proposal.rs @@ -2119,4 +2119,76 @@ mod test_process_proposal { } } } + + /// Test that Ethereum events with outdated nonces are + /// not validated by `ProcessProposal`. + #[test] + fn test_outdated_nonce_process_proposal() { + use namada::types::storage::InnerEthEventsQueue; + + const LAST_HEIGHT: BlockHeight = BlockHeight(3); + + let (mut shell, _recv, _, _) = test_utils::setup_at_height(LAST_HEIGHT); + shell + .wl_storage + .storage + .eth_events_queue + // sent transfers to namada nonce to 5 + .transfers_to_namada = InnerEthEventsQueue::new_at(5.into()); + + let (protocol_key, _) = wallet::defaults::validator_keys(); + + // only bad events + { + let ethereum_event = EthereumEvent::TransfersToNamada { + // outdated nonce (3 < 5) + nonce: 3u64.into(), + transfers: vec![], + }; + let ext = { + let ext = ethereum_events::Vext { + validator_addr: wallet::defaults::validator_address(), + block_height: LAST_HEIGHT, + ethereum_events: vec![ethereum_event], + } + .sign(&protocol_key); + assert!(ext.verify(&protocol_key.ref_to()).is_ok()); + ext + }; + let tx = EthereumTxData::EthEventsVext(ext) + .sign(&protocol_key, shell.chain_id.clone()) + .to_bytes(); + let req = ProcessProposal { txs: vec![tx] }; + let rsp = shell.process_proposal(req); + assert!(rsp.is_err()); + } + + // at least one good event + { + let e1 = EthereumEvent::TransfersToNamada { + nonce: 3u64.into(), + transfers: vec![], + }; + let e2 = EthereumEvent::TransfersToNamada { + nonce: 5u64.into(), + transfers: vec![], + }; + let ext = { + let ext = ethereum_events::Vext { + validator_addr: wallet::defaults::validator_address(), + block_height: LAST_HEIGHT, + ethereum_events: vec![e1, e2], + } + .sign(&protocol_key); + assert!(ext.verify(&protocol_key.ref_to()).is_ok()); + ext + }; + let tx = EthereumTxData::EthEventsVext(ext) + .sign(&protocol_key, shell.chain_id.clone()) + .to_bytes(); + let req = ProcessProposal { txs: vec![tx] }; + let rsp = shell.process_proposal(req); + assert!(rsp.is_ok()); + } + } } diff --git a/apps/src/lib/node/ledger/shell/testing/client.rs b/apps/src/lib/node/ledger/shell/testing/client.rs index 5e4c04b07f..4343cf6a7d 100644 --- a/apps/src/lib/node/ledger/shell/testing/client.rs +++ b/apps/src/lib/node/ledger/shell/testing/client.rs @@ -48,7 +48,7 @@ pub fn run( rt.block_on(CliApi::handle_client_command( Some(node), cmd, - &TestingIo, + TestingIo, )) } Bin::Wallet => { @@ -84,7 +84,7 @@ pub fn run( rt.block_on(CliApi::handle_relayer_command( Some(node), cmd, - &TestingIo, + TestingIo, )) } } diff --git a/apps/src/lib/node/ledger/shell/vote_extensions.rs b/apps/src/lib/node/ledger/shell/vote_extensions.rs index f0d2ad17a0..7d26f6195d 100644 --- a/apps/src/lib/node/ledger/shell/vote_extensions.rs +++ b/apps/src/lib/node/ledger/shell/vote_extensions.rs @@ -28,10 +28,8 @@ pub enum VoteExtensionError { ValsetUpdProofAvailable, #[error("The length of the transfers and their validity map differ")] TransfersLenMismatch, - #[error("The bridge pool nonce in the vote extension is invalid")] - InvalidBpNonce, - #[error("The transfer to Namada nonce in the vote extension is invalid")] - InvalidNamNonce, + #[error("The nonce in the Ethereum event is invalid")] + InvalidEthEventNonce, #[error("The vote extension was issued for an unexpected block height")] UnexpectedBlockHeight, #[error("The vote extension was issued for an unexpected epoch")] @@ -229,8 +227,20 @@ where } }; match (&tx).try_into().ok()? { - EthereumTxData::EthEventsVext(_) - | EthereumTxData::BridgePoolVext(_) => Some(tx_bytes.clone()), + EthereumTxData::BridgePoolVext(_) => Some(tx_bytes.clone()), + EthereumTxData::EthEventsVext(ext) => { + // NB: only propose events with at least + // one valid nonce + ext.data + .ethereum_events + .iter() + .any(|event| { + self.wl_storage + .ethbridge_queries() + .validate_eth_event_nonce(event) + }) + .then(|| tx_bytes.clone()) + } EthereumTxData::ValSetUpdateVext(ext) => { // only include non-stale validator set updates // in block proposals. it might be sitting long diff --git a/apps/src/lib/node/ledger/shell/vote_extensions/bridge_pool_vext.rs b/apps/src/lib/node/ledger/shell/vote_extensions/bridge_pool_vext.rs index 2486d2d442..5e4f34ac2c 100644 --- a/apps/src/lib/node/ledger/shell/vote_extensions/bridge_pool_vext.rs +++ b/apps/src/lib/node/ledger/shell/vote_extensions/bridge_pool_vext.rs @@ -249,20 +249,22 @@ mod test_bp_vote_extensions { let hot_key = gen_secp256k1_keypair(); let cold_key = gen_secp256k1_keypair(); - become_validator(BecomeValidator { - storage: &mut shell.wl_storage, - params: ¶ms, - address: &bertha_address(), - consensus_key: &consensus_key.ref_to(), - protocol_key: &protocol_key.ref_to(), - eth_hot_key: &hot_key.ref_to(), - eth_cold_key: &cold_key.ref_to(), - current_epoch: 0.into(), - commission_rate: Default::default(), - max_commission_rate_change: Default::default(), - metadata: Default::default(), - offset_opt: None, - }) + become_validator( + &mut shell.wl_storage, + BecomeValidator { + params: ¶ms, + address: &bertha_address(), + consensus_key: &consensus_key.ref_to(), + protocol_key: &protocol_key.ref_to(), + eth_hot_key: &hot_key.ref_to(), + eth_cold_key: &cold_key.ref_to(), + current_epoch: 0.into(), + commission_rate: Default::default(), + max_commission_rate_change: Default::default(), + metadata: Default::default(), + offset_opt: None, + }, + ) .expect("Test failed"); // we advance forward to the next epoch diff --git a/apps/src/lib/node/ledger/shell/vote_extensions/eth_events.rs b/apps/src/lib/node/ledger/shell/vote_extensions/eth_events.rs index f3856312aa..127c4c4d0e 100644 --- a/apps/src/lib/node/ledger/shell/vote_extensions/eth_events.rs +++ b/apps/src/lib/node/ledger/shell/vote_extensions/eth_events.rs @@ -131,11 +131,8 @@ where /// an [`ethereum_events::Vext`]. /// /// The supplied Ethereum events must be ordered in - /// ascending ordering, and must not contain any dupes. - /// - /// A detailed description of the validation applied - /// to each event kind can be found in the docstring - /// of [`Shell::validate_eth_event`]. + /// ascending ordering, must not contain any dupes + /// and must have valid nonces. fn validate_eth_events( &self, ext: ðereum_events::Vext, @@ -157,84 +154,23 @@ where ); return Err(VoteExtensionError::HaveDupesOrNonSorted); } - ext.ethereum_events - .iter() - .try_for_each(|event| self.validate_eth_event(event)) - } - - /// Valdidate an [`EthereumEvent`] against the current state - /// of the ledger. - /// - /// # Event kinds - /// - /// In this section, we shall describe the checks perform for - /// each kind of relevant Ethereum event. - /// - /// ## Transfers to Ethereum - /// - /// We need to check if the nonce in the event corresponds to - /// the most recent bridge pool nonce. Unless the nonces match, - /// no state updates derived from the event should be applied. - /// In case the nonces are different, we reject the event, and - /// thus the inclusion of its container Ethereum events vote - /// extension. - /// - /// ## Transfers to Namada - /// - /// For a transfers to Namada event to be considered valid, - /// the nonce of this kind of event must not be lower than - /// the one stored in Namada. - fn validate_eth_event( - &self, - event: &EthereumEvent, - ) -> std::result::Result<(), VoteExtensionError> { - // TODO: on the transfer events, maybe perform additional checks: - // - some token asset is not whitelisted - // - do we have enough balance for the transfer - // in practice, some events may have a variable degree of garbage - // data in them; we can simply rely on quorum decisions to filter - // out such events, which will time out in storage - match event { - EthereumEvent::TransfersToEthereum { - nonce: ext_nonce, .. - } => { - let current_bp_nonce = - self.wl_storage.ethbridge_queries().get_bridge_pool_nonce(); - if ¤t_bp_nonce != ext_nonce { - tracing::debug!( - %current_bp_nonce, - %ext_nonce, - "The Ethereum events vote extension's BP nonce is \ - invalid" - ); - return Err(VoteExtensionError::InvalidBpNonce); - } - } - EthereumEvent::TransfersToNamada { - nonce: ext_nonce, .. - } => { - let next_nam_transfers_nonce = self - .wl_storage - .ethbridge_queries() - .get_next_nam_transfers_nonce(); - if &next_nam_transfers_nonce > ext_nonce { - tracing::debug!( - ?event, - %next_nam_transfers_nonce, - "Attempt to replay a transfer to Namada event" - ); - return Err(VoteExtensionError::InvalidNamNonce); - } - } - // consider other ethereum event kinds valid - _ => {} + // for the proposal to be valid, at least one of the + // event's nonces must be valid + if ext.ethereum_events.iter().any(|event| { + self.wl_storage + .ethbridge_queries() + .validate_eth_event_nonce(event) + }) { + Ok(()) + } else { + Err(VoteExtensionError::InvalidEthEventNonce) } - Ok(()) } /// Checks the channel from the Ethereum oracle monitoring /// the fullnode and retrieves all seen Ethereum events. pub fn new_ethereum_events(&mut self) -> Vec { + let queries = self.wl_storage.ethbridge_queries(); match &mut self.mode { ShellMode::Validator { eth_oracle: @@ -243,7 +179,9 @@ where }), .. } => { - ethereum_receiver.fill_queue(); + ethereum_receiver.fill_queue(|event| { + queries.validate_eth_event_nonce(event) + }); ethereum_receiver.get_events() } _ => vec![], @@ -359,6 +297,7 @@ mod test_vote_extensions { NestedSubKey, SubKey, }; use namada::eth_bridge::storage::bridge_pool; + use namada::ledger::eth_bridge::EthBridgeQueries; use namada::ledger::pos::PosQueries; use namada::proof_of_stake::types::WeightedValidator; use namada::proof_of_stake::{ @@ -401,55 +340,83 @@ mod test_vote_extensions { // eth transfers with the same nonce as the bp nonce in storage are // valid shell - .validate_eth_event(&EthereumEvent::TransfersToEthereum { + .wl_storage + .ethbridge_queries() + .validate_eth_event_nonce(&EthereumEvent::TransfersToEthereum { nonce, transfers: vec![], relayer: gen_established_address(), }) + .then_some(()) + .ok_or(()) .expect("Test failed"); // eth transfers with different nonces are invalid shell - .validate_eth_event(&EthereumEvent::TransfersToEthereum { + .wl_storage + .ethbridge_queries() + .validate_eth_event_nonce(&EthereumEvent::TransfersToEthereum { nonce: nonce + 1, transfers: vec![], relayer: gen_established_address(), }) + .then_some(()) + .ok_or(()) .expect_err("Test failed"); shell - .validate_eth_event(&EthereumEvent::TransfersToEthereum { + .wl_storage + .ethbridge_queries() + .validate_eth_event_nonce(&EthereumEvent::TransfersToEthereum { nonce: nonce - 1, transfers: vec![], relayer: gen_established_address(), }) + .then_some(()) + .ok_or(()) .expect_err("Test failed"); // nam transfers with nonces >= the nonce in storage are valid shell - .validate_eth_event(&EthereumEvent::TransfersToNamada { + .wl_storage + .ethbridge_queries() + .validate_eth_event_nonce(&EthereumEvent::TransfersToNamada { nonce, transfers: vec![], }) + .then_some(()) + .ok_or(()) .expect("Test failed"); shell - .validate_eth_event(&EthereumEvent::TransfersToNamada { + .wl_storage + .ethbridge_queries() + .validate_eth_event_nonce(&EthereumEvent::TransfersToNamada { nonce: nonce + 5, transfers: vec![], }) + .then_some(()) + .ok_or(()) .expect("Test failed"); // nam transfers with lower nonces are invalid shell - .validate_eth_event(&EthereumEvent::TransfersToNamada { + .wl_storage + .ethbridge_queries() + .validate_eth_event_nonce(&EthereumEvent::TransfersToNamada { nonce: nonce - 1, transfers: vec![], }) + .then_some(()) + .ok_or(()) .expect_err("Test failed"); shell - .validate_eth_event(&EthereumEvent::TransfersToNamada { + .wl_storage + .ethbridge_queries() + .validate_eth_event_nonce(&EthereumEvent::TransfersToNamada { nonce: nonce - 2, transfers: vec![], }) + .then_some(()) + .ok_or(()) .expect_err("Test failed"); } @@ -486,7 +453,12 @@ mod test_vote_extensions { nonce: 0.into(), transfers: vec![], }; + let event_4 = EthereumEvent::TransfersToNamada { + nonce: 1.into(), + transfers: vec![], + }; + // send valid events tokio_test::block_on(oracle.send(event_1.clone())) .expect("Test failed"); tokio_test::block_on(oracle.send(event_3.clone())) @@ -502,16 +474,22 @@ mod test_vote_extensions { .collect(); assert_eq!(expected_events, got_events); + // we cannot get two transfer to ethereum events within + // the same block height on ethereum. this is because we + // require a confirmation eth event on namada to increment + // the bridge pool nonce. this event should get ignored + tokio_test::block_on(oracle.send(event_2)).expect("Test failed"); + // check that we queue and de-duplicate events - tokio_test::block_on(oracle.send(event_2.clone())) - .expect("Test failed"); tokio_test::block_on(oracle.send(event_3.clone())) .expect("Test failed"); + tokio_test::block_on(oracle.send(event_4.clone())) + .expect("Test failed"); let got_events: [EthereumEvent; 3] = shell.new_ethereum_events().try_into().expect("Test failed"); let expected_events: Vec<_> = - std::collections::BTreeSet::from([event_1, event_2, event_3]) + std::collections::BTreeSet::from([event_1, event_3, event_4]) .into_iter() .collect(); assert_eq!(expected_events, got_events); diff --git a/apps/src/lib/node/ledger/storage/mod.rs b/apps/src/lib/node/ledger/storage/mod.rs index 52c10d4a17..edf539528c 100644 --- a/apps/src/lib/node/ledger/storage/mod.rs +++ b/apps/src/lib/node/ledger/storage/mod.rs @@ -55,6 +55,7 @@ mod tests { use itertools::Itertools; use namada::core::ledger::masp_conversions::update_allowed_conversions; + use namada::ledger::eth_bridge::storage::bridge_pool; use namada::ledger::gas::STORAGE_ACCESS_GAS_PER_BYTE; use namada::ledger::ibc::storage::ibc_key; use namada::ledger::parameters::{EpochDuration, Parameters}; @@ -62,6 +63,7 @@ mod tests { use namada::ledger::storage::{types, StoreType, WlStorage}; use namada::ledger::storage_api::{self, StorageWrite}; use namada::types::chain::ChainId; + use namada::types::ethereum_events::Uint; use namada::types::hash::Hash; use namada::types::storage::{BlockHash, BlockHeight, Key}; use namada::types::time::DurationSecs; @@ -487,13 +489,15 @@ mod tests { let value_bytes = types::encode(&storage.block.height); storage.write(&key, value_bytes)?; } + let key = bridge_pool::get_nonce_key(); + let bytes = types::encode(&Uint::default()); + storage.write(&key, bytes)?; // Update and commit let hash = BlockHash::default(); let height = BlockHeight(1); storage.begin_block(hash, height)?; - // Epoch 1 - storage.block.epoch = storage.block.epoch.next(); + // Epoch 0 storage.block.pred_epochs.new_epoch(height); let mut batch = PersistentStorage::batch(); for (height, key, write_type) in blocks_write_type.clone() { @@ -581,8 +585,14 @@ mod tests { None, Some(5), ); + let new_epoch_start = BlockHeight(1); + let bp_nonce_key = bridge_pool::get_nonce_key(); + let nonce = Uint::default(); + let bytes = types::encode(&nonce); + storage.write(&bp_nonce_key, bytes).unwrap(); + storage - .begin_block(BlockHash::default(), BlockHeight(1)) + .begin_block(BlockHash::default(), new_epoch_start) .expect("begin_block failed"); let key = ibc_key("key").unwrap(); @@ -591,13 +601,13 @@ mod tests { .write(&key, types::encode(&value)) .expect("write failed"); - storage.block.epoch = storage.block.epoch.next(); - storage.block.pred_epochs.new_epoch(BlockHeight(1)); + storage.block.pred_epochs.new_epoch(new_epoch_start); let batch = PersistentStorage::batch(); storage.commit_block(batch).expect("commit failed"); + let new_epoch_start = BlockHeight(6); storage - .begin_block(BlockHash::default(), BlockHeight(6)) + .begin_block(BlockHash::default(), new_epoch_start) .expect("begin_block failed"); let key = ibc_key("key2").unwrap(); @@ -606,19 +616,29 @@ mod tests { .write(&key, types::encode(&value)) .expect("write failed"); + let nonce = nonce + 1; + let bytes = types::encode(&nonce); + storage.write(&bp_nonce_key, bytes).unwrap(); + storage.block.epoch = storage.block.epoch.next(); - storage.block.pred_epochs.new_epoch(BlockHeight(6)); + storage.block.pred_epochs.new_epoch(new_epoch_start); let batch = PersistentStorage::batch(); storage.commit_block(batch).expect("commit failed"); let result = storage.get_merkle_tree(1.into(), Some(StoreType::Ibc)); assert!(result.is_ok(), "The tree at Height 1 should be restored"); + let new_epoch_start = BlockHeight(11); storage - .begin_block(BlockHash::default(), BlockHeight(11)) + .begin_block(BlockHash::default(), new_epoch_start) .expect("begin_block failed"); + + let nonce = nonce + 1; + let bytes = types::encode(&nonce); + storage.write(&bp_nonce_key, bytes).unwrap(); + storage.block.epoch = storage.block.epoch.next(); - storage.block.pred_epochs.new_epoch(BlockHeight(11)); + storage.block.pred_epochs.new_epoch(new_epoch_start); let batch = PersistentStorage::batch(); storage.commit_block(batch).expect("commit failed"); @@ -630,7 +650,30 @@ mod tests { "The tree at Height 5 shouldn't be able to be restored" ); let result = storage.get_merkle_tree(6.into(), Some(StoreType::Ibc)); - assert!(result.is_ok(), "The tree should be restored"); + assert!(result.is_ok(), "The ibc tree should be restored"); + let result = + storage.get_merkle_tree(6.into(), Some(StoreType::BridgePool)); + assert!(result.is_ok(), "The bridge pool tree should be restored"); + + storage + .begin_block(BlockHash::default(), BlockHeight(12)) + .expect("begin_block failed"); + + let nonce = nonce + 1; + let bytes = types::encode(&nonce); + storage.write(&bp_nonce_key, bytes).unwrap(); + storage.block.epoch = storage.block.epoch.next(); + storage.block.pred_epochs.new_epoch(BlockHeight(12)); + let batch = PersistentStorage::batch(); + storage.commit_block(batch).expect("commit failed"); + + // ibc tree should be able to be restored + let result = storage.get_merkle_tree(6.into(), Some(StoreType::Ibc)); + assert!(result.is_ok(), "The ibc tree should be restored"); + // bridge pool tree should be pruned because of the nonce + let result = + storage.get_merkle_tree(6.into(), Some(StoreType::BridgePool)); + assert!(result.is_err(), "The bridge pool tree should be pruned"); } /// Test the prefix iterator with RocksDB. diff --git a/apps/src/lib/wallet/mod.rs b/apps/src/lib/wallet/mod.rs index 140a85f69d..6c1034c994 100644 --- a/apps/src/lib/wallet/mod.rs +++ b/apps/src/lib/wallet/mod.rs @@ -223,12 +223,13 @@ where { maybe_pk .map(|pk| { + let pkh = PublicKeyHash::from(&pk); wallet // TODO: optionally encrypt validator keys - .find_key_by_pkh(&PublicKeyHash::from(&pk), None) + .find_key_by_pkh(&pkh, None) .ok() .or_else(|| wallet.get_validator_data().map(extract_key)) - .ok_or(FindKeyError::KeyNotFound) + .ok_or_else(|| FindKeyError::KeyNotFound(pkh.to_string())) }) .transpose() } diff --git a/benches/host_env.rs b/benches/host_env.rs index 3b096f11ec..289b0eb564 100644 --- a/benches/host_env.rs +++ b/benches/host_env.rs @@ -9,7 +9,7 @@ use namada::proto::Signature; use namada::vm::wasm::TxCache; use namada_apps::bench_utils::{ BenchShell, TX_INIT_PROPOSAL_WASM, TX_REVEAL_PK_WASM, TX_TRANSFER_WASM, - TX_UPDATE_ACCOUNT_WASM, VP_VALIDATOR_WASM, WASM_DIR, + TX_UPDATE_ACCOUNT_WASM, VP_USER_WASM, WASM_DIR, }; use namada_apps::wallet::defaults; use namada_apps::wasm_loader; @@ -68,7 +68,7 @@ fn compile_wasm(c: &mut Criterion) { TX_INIT_PROPOSAL_WASM, TX_REVEAL_PK_WASM, TX_UPDATE_ACCOUNT_WASM, - VP_VALIDATOR_WASM, + VP_USER_WASM, ] { let wasm_code = wasm_loader::read_wasm_or_exit(WASM_DIR, tx); txs.insert(tx, wasm_code); diff --git a/benches/native_vps.rs b/benches/native_vps.rs index fdaed5d1f9..7981216918 100644 --- a/benches/native_vps.rs +++ b/benches/native_vps.rs @@ -14,16 +14,15 @@ use namada::core::ledger::storage_api::{StorageRead, StorageWrite}; use namada::core::types::address::{self, Address}; use namada::core::types::token::{Amount, Transfer}; use namada::eth_bridge::storage::whitelist; -use namada::ibc::core::ics02_client::client_type::ClientType; -use namada::ibc::core::ics03_connection::connection::Counterparty; -use namada::ibc::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; -use namada::ibc::core::ics03_connection::version::Version; -use namada::ibc::core::ics04_channel::channel::Order; -use namada::ibc::core::ics04_channel::msgs::MsgChannelOpenInit; -use namada::ibc::core::ics04_channel::Version as ChannelVersion; -use namada::ibc::core::ics23_commitment::commitment::CommitmentPrefix; -use namada::ibc::core::ics24_host::identifier::{ - ClientId, ConnectionId, PortId, +use namada::ibc::core::channel::types::channel::Order; +use namada::ibc::core::channel::types::msgs::MsgChannelOpenInit; +use namada::ibc::core::channel::types::Version as ChannelVersion; +use namada::ibc::core::commitment_types::commitment::CommitmentPrefix; +use namada::ibc::core::connection::types::msgs::MsgConnectionOpenInit; +use namada::ibc::core::connection::types::version::Version; +use namada::ibc::core::connection::types::Counterparty; +use namada::ibc::core::host::types::identifiers::{ + ClientId, ClientType, ConnectionId, PortId, }; use namada::ledger::eth_bridge::read_native_erc20_address; use namada::ledger::gas::{TxGasMeter, VpGasMeter}; @@ -495,7 +494,7 @@ fn setup_storage_for_masp_verification( .to_owned(); // Shield some tokens for Albert - let shield_tx = shielded_ctx.generate_masp_tx( + let (mut shielded_ctx, shield_tx) = shielded_ctx.generate_masp_tx( amount, TransferSource::Address(defaults::albert_address()), TransferTarget::PaymentAddress(albert_payment_addr), @@ -504,7 +503,7 @@ fn setup_storage_for_masp_verification( shielded_ctx.shell.wl_storage.commit_tx(); shielded_ctx.shell.commit(); - let signed_tx = match bench_name { + let (mut shielded_ctx, signed_tx) = match bench_name { "shielding" => shielded_ctx.generate_masp_tx( amount, TransferSource::Address(defaults::albert_address()), diff --git a/benches/txs.rs b/benches/txs.rs index 02d6c9c22d..454b50f401 100644 --- a/benches/txs.rs +++ b/benches/txs.rs @@ -12,24 +12,23 @@ use namada::core::types::key::{ }; use namada::core::types::token::Amount; use namada::core::types::transaction::account::{InitAccount, UpdateAccount}; -use namada::core::types::transaction::pos::{InitValidator, MetaDataChange}; -use namada::ibc::core::ics02_client::client_type::ClientType; -use namada::ibc::core::ics03_connection::connection::Counterparty; -use namada::ibc::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; -use namada::ibc::core::ics03_connection::version::Version; -use namada::ibc::core::ics04_channel::channel::Order; -use namada::ibc::core::ics04_channel::msgs::MsgChannelOpenInit; -use namada::ibc::core::ics04_channel::Version as ChannelVersion; -use namada::ibc::core::ics23_commitment::commitment::CommitmentPrefix; -use namada::ibc::core::ics24_host::identifier::{ - ClientId, ConnectionId, PortId, +use namada::core::types::transaction::pos::{BecomeValidator, MetaDataChange}; +use namada::ibc::core::channel::types::channel::Order; +use namada::ibc::core::channel::types::msgs::MsgChannelOpenInit; +use namada::ibc::core::channel::types::Version as ChannelVersion; +use namada::ibc::core::commitment_types::commitment::CommitmentPrefix; +use namada::ibc::core::connection::types::msgs::MsgConnectionOpenInit; +use namada::ibc::core::connection::types::version::Version; +use namada::ibc::core::connection::types::Counterparty; +use namada::ibc::core::host::types::identifiers::{ + ClientId, ClientType, ConnectionId, PortId, }; use namada::ledger::eth_bridge::read_native_erc20_address; -use namada::ledger::storage_api::StorageRead; +use namada::ledger::storage_api::{StorageRead, StorageWrite}; use namada::proof_of_stake::types::SlashType; use namada::proof_of_stake::{self, read_pos_params, KeySeg}; use namada::proto::{Code, Section}; -use namada::types::address::Address; +use namada::types::address::{self, Address}; use namada::types::eth_bridge_pool::{GasFee, PendingTransfer}; use namada::types::hash::Hash; use namada::types::key::{ed25519, secp256k1, PublicKey, RefTo}; @@ -43,15 +42,15 @@ use namada::types::transaction::pos::{ }; use namada_apps::bench_utils::{ BenchShell, BenchShieldedCtx, ALBERT_PAYMENT_ADDRESS, ALBERT_SPENDING_KEY, - BERTHA_PAYMENT_ADDRESS, TX_BOND_WASM, TX_BRIDGE_POOL_WASM, - TX_CHANGE_CONSENSUS_KEY_WASM, TX_CHANGE_VALIDATOR_COMMISSION_WASM, - TX_CHANGE_VALIDATOR_METADATA_WASM, TX_CLAIM_REWARDS_WASM, - TX_DEACTIVATE_VALIDATOR_WASM, TX_IBC_WASM, TX_INIT_ACCOUNT_WASM, - TX_INIT_PROPOSAL_WASM, TX_INIT_VALIDATOR_WASM, - TX_REACTIVATE_VALIDATOR_WASM, TX_REDELEGATE_WASM, TX_RESIGN_STEWARD, - TX_REVEAL_PK_WASM, TX_UNBOND_WASM, TX_UNJAIL_VALIDATOR_WASM, - TX_UPDATE_ACCOUNT_WASM, TX_UPDATE_STEWARD_COMMISSION, - TX_VOTE_PROPOSAL_WASM, TX_WITHDRAW_WASM, VP_VALIDATOR_WASM, + BERTHA_PAYMENT_ADDRESS, TX_BECOME_VALIDATOR_WASM, TX_BOND_WASM, + TX_BRIDGE_POOL_WASM, TX_CHANGE_CONSENSUS_KEY_WASM, + TX_CHANGE_VALIDATOR_COMMISSION_WASM, TX_CHANGE_VALIDATOR_METADATA_WASM, + TX_CLAIM_REWARDS_WASM, TX_DEACTIVATE_VALIDATOR_WASM, TX_IBC_WASM, + TX_INIT_ACCOUNT_WASM, TX_INIT_PROPOSAL_WASM, TX_REACTIVATE_VALIDATOR_WASM, + TX_REDELEGATE_WASM, TX_RESIGN_STEWARD, TX_REVEAL_PK_WASM, TX_UNBOND_WASM, + TX_UNJAIL_VALIDATOR_WASM, TX_UPDATE_ACCOUNT_WASM, + TX_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL_WASM, TX_WITHDRAW_WASM, + VP_USER_WASM, }; use namada_apps::wallet::defaults; use sha2::Digest; @@ -83,16 +82,17 @@ fn transfer(c: &mut Criterion) { .to_owned(); // Shield some tokens for Albert - let shield_tx = shielded_ctx.generate_masp_tx( - amount, - TransferSource::Address(defaults::albert_address()), - TransferTarget::PaymentAddress(albert_payment_addr), - ); + let (mut shielded_ctx, shield_tx) = shielded_ctx + .generate_masp_tx( + amount, + TransferSource::Address(defaults::albert_address()), + TransferTarget::PaymentAddress(albert_payment_addr), + ); shielded_ctx.shell.execute_tx(&shield_tx); shielded_ctx.shell.wl_storage.commit_tx(); shielded_ctx.shell.commit(); - let signed_tx = match bench_name { + let (shielded_ctx, signed_tx) = match bench_name { "transparent" => shielded_ctx.generate_masp_tx( amount, TransferSource::Address(defaults::albert_address()), @@ -369,11 +369,11 @@ fn reveal_pk(c: &mut Criterion) { fn update_account(c: &mut Criterion) { let shell = BenchShell::default(); let vp_code_hash: Hash = shell - .read_storage_key(&Key::wasm_hash(VP_VALIDATOR_WASM)) + .read_storage_key(&Key::wasm_hash(VP_USER_WASM)) .unwrap(); let extra_section = Section::ExtraData(Code::from_hash( vp_code_hash, - Some(VP_VALIDATOR_WASM.to_string()), + Some(VP_USER_WASM.to_string()), )); let data = UpdateAccount { addr: defaults::albert_address(), @@ -412,11 +412,11 @@ fn init_account(c: &mut Criterion) { let shell = BenchShell::default(); let vp_code_hash: Hash = shell - .read_storage_key(&Key::wasm_hash(VP_VALIDATOR_WASM)) + .read_storage_key(&Key::wasm_hash(VP_USER_WASM)) .unwrap(); let extra_section = Section::ExtraData(Code::from_hash( vp_code_hash, - Some(VP_VALIDATOR_WASM.to_string()), + Some(VP_USER_WASM.to_string()), )); let extra_hash = Hash( extra_section @@ -586,8 +586,9 @@ fn vote_proposal(c: &mut Criterion) { group.finish(); } -fn init_validator(c: &mut Criterion) { +fn become_validator(c: &mut Criterion) { let mut csprng = rand::rngs::OsRng {}; + let address = address::testing::established_address_1(); let consensus_key_sk = ed25519::SigScheme::generate(&mut csprng) .try_to_sk::() .unwrap(); @@ -612,22 +613,8 @@ fn init_validator(c: &mut Criterion) { let protocol_key = protocol_key_sk.to_public(); let shell = BenchShell::default(); - let validator_vp_code_hash: Hash = shell - .read_storage_key(&Key::wasm_hash(VP_VALIDATOR_WASM)) - .unwrap(); - let extra_section = Section::ExtraData(Code::from_hash( - validator_vp_code_hash, - Some(VP_VALIDATOR_WASM.to_string()), - )); - let extra_hash = Hash( - extra_section - .hash(&mut sha2::Sha256::new()) - .finalize_reset() - .into(), - ); - let data = InitValidator { - account_keys: vec![defaults::albert_keypair().to_public()], - threshold: 1, + let data = BecomeValidator { + address: address.clone(), consensus_key, eth_cold_key, eth_hot_key, @@ -638,13 +625,12 @@ fn init_validator(c: &mut Criterion) { description: None, website: None, discord_handle: None, - validator_vp_code_hash: extra_hash, }; let tx = shell.generate_tx( - TX_INIT_VALIDATOR_WASM, + TX_BECOME_VALIDATOR_WASM, data, None, - Some(vec![extra_section]), + None, vec![ &defaults::albert_keypair(), &consensus_key_sk, @@ -654,9 +640,22 @@ fn init_validator(c: &mut Criterion) { ], ); - c.bench_function("init_validator", |b| { + c.bench_function("become_validator", |b| { b.iter_batched_ref( - BenchShell::default, + || { + let mut shell = BenchShell::default(); + // Initialize the account to be able to use it + shell + .wl_storage + .write_bytes( + &namada::types::storage::Key::validity_predicate( + &address, + ), + vec![], + ) + .unwrap(); + shell + }, |shell| shell.execute_tx(&tx), criterion::BatchSize::SmallInput, ) @@ -1089,7 +1088,7 @@ criterion_group!( init_account, init_proposal, vote_proposal, - init_validator, + become_validator, change_validator_commission, ibc, unjail_validator, diff --git a/benches/vps.rs b/benches/vps.rs index d101b2a4a9..366887d1fa 100644 --- a/benches/vps.rs +++ b/benches/vps.rs @@ -22,7 +22,7 @@ use namada_apps::bench_utils::{ generate_foreign_key_tx, BenchShell, TX_BOND_WASM, TX_CHANGE_VALIDATOR_COMMISSION_WASM, TX_REVEAL_PK_WASM, TX_TRANSFER_WASM, TX_UNBOND_WASM, TX_UPDATE_ACCOUNT_WASM, TX_VOTE_PROPOSAL_WASM, - VP_USER_WASM, VP_VALIDATOR_WASM, + VP_USER_WASM, }; use namada_apps::wallet::defaults; use sha2::Digest; @@ -70,11 +70,11 @@ fn vp_user(c: &mut Criterion) { ); let vp_validator_hash = shell - .read_storage_key(&Key::wasm_hash(VP_VALIDATOR_WASM)) + .read_storage_key(&Key::wasm_hash(VP_USER_WASM)) .unwrap(); let extra_section = Section::ExtraData(Code::from_hash( vp_validator_hash, - Some(VP_VALIDATOR_WASM.to_string()), + Some(VP_USER_WASM.to_string()), )); let data = UpdateAccount { addr: defaults::albert_address(), @@ -322,7 +322,7 @@ fn vp_implicit(c: &mut Criterion) { fn vp_validator(c: &mut Criterion) { let shell = BenchShell::default(); let vp_code_hash: Hash = shell - .read_storage_key(&Key::wasm_hash(VP_VALIDATOR_WASM)) + .read_storage_key(&Key::wasm_hash(VP_USER_WASM)) .unwrap(); let mut group = c.benchmark_group("vp_validator"); @@ -361,7 +361,7 @@ fn vp_validator(c: &mut Criterion) { let extra_section = Section::ExtraData(Code::from_hash( vp_code_hash, - Some(VP_VALIDATOR_WASM.to_string()), + Some(VP_USER_WASM.to_string()), )); let data = UpdateAccount { addr: defaults::validator_address(), diff --git a/core/Cargo.toml b/core/Cargo.toml index 53ee824077..143e4400e6 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -17,12 +17,12 @@ default = ["rand"] mainnet = [] wasm-runtime = ["rayon"] rand = ["dep:rand", "rand_core"] -ibc-mocks = ["ibc/mocks" ] ethers-derive = [ "ethbridge-structs/ethers-derive" ] # for integration tests and test utilies testing = [ + "ibc-testkit", "rand", "proptest", ] @@ -42,9 +42,9 @@ ed25519-consensus.workspace = true ethabi.workspace = true ethbridge-structs.workspace = true eyre.workspace = true -ibc = { version = "0.47.0", default-features = false, features = ["serde"]} -ibc-derive = { version = "0.3.0"} -ibc-proto = {version = "0.37.1", default-features = false} +ibc.workspace = true +ibc-derive.workspace = true +ibc-testkit = {workspace = true, optional = true} ics23.workspace = true impl-num-traits = "0.1.2" index-set.workspace = true @@ -80,6 +80,7 @@ pretty_assertions.workspace = true proptest.workspace = true rand.workspace = true rand_core.workspace = true +rayon = {version = "=1.5.3"} test-log.workspace = true toml.workspace = true tracing-subscriber.workspace = true diff --git a/core/src/ledger/gas.rs b/core/src/ledger/gas.rs index 092c0ba3b2..fc09636766 100644 --- a/core/src/ledger/gas.rs +++ b/core/src/ledger/gas.rs @@ -35,6 +35,8 @@ const STORAGE_OCCUPATION_GAS_PER_BYTE: u64 = // codebase. For these two reasons we just set an arbitrary value (based on // actual SSDs latency) per byte here const PHYSICAL_STORAGE_LATENCY_PER_BYTE: u64 = 75; +// This is based on the global avarage bandwidth +const NETWORK_TRANSMISSION_GAS_PER_BYTE: u64 = 13; /// The cost of accessing data from memory (both read and write mode), per byte pub const MEMORY_ACCESS_GAS_PER_BYTE: u64 = 2; @@ -273,13 +275,18 @@ impl TxGasMeter { /// Add the gas required by a wrapper transaction which is comprised of: /// - cost of validating the wrapper tx /// - space that the transaction requires in the block + /// - cost of downloading (as part of the block) the transaction bytes over + /// the network pub fn add_wrapper_gas(&mut self, tx_bytes: &[u8]) -> Result<()> { self.consume(WRAPPER_TX_VALIDATION_GAS)?; let bytes_len = tx_bytes.len() as u64; self.consume( bytes_len - .checked_mul(STORAGE_OCCUPATION_GAS_PER_BYTE) + .checked_mul( + STORAGE_OCCUPATION_GAS_PER_BYTE + + NETWORK_TRANSMISSION_GAS_PER_BYTE, + ) .ok_or(Error::GasOverflow)?, ) } diff --git a/core/src/ledger/ibc/context/client.rs b/core/src/ledger/ibc/context/client.rs index 5c771a0712..0000432c76 100644 --- a/core/src/ledger/ibc/context/client.rs +++ b/core/src/ledger/ibc/context/client.rs @@ -1,37 +1,35 @@ //! AnyClientState and AnyConsensusState for IBC context use ibc_derive::ConsensusState; +#[cfg(feature = "testing")] +use ibc_testkit::testapp::ibc::clients::mock::client_state::MockClientContext; +#[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 prost::Message; -use crate::ibc::clients::ics07_tendermint::client_state::ClientState as TmClientState; -use crate::ibc::clients::ics07_tendermint::consensus_state::ConsensusState as TmConsensusState; -use crate::ibc::clients::ics07_tendermint::{ +use crate::ibc::clients::tendermint::client_state::ClientState as TmClientState; +use crate::ibc::clients::tendermint::consensus_state::ConsensusState as TmConsensusState; +use crate::ibc::clients::tendermint::context::{ CommonContext, ExecutionContext as TmExecutionContext, ValidationContext as TmValidationContext, }; -use crate::ibc::core::ics02_client::client_state::{ - ClientStateCommon, ClientStateExecution, ClientStateValidation, Status, - UpdateKind, +use crate::ibc::core::client::context::client_state::{ + ClientStateCommon, ClientStateExecution, ClientStateValidation, }; -use crate::ibc::core::ics02_client::client_type::ClientType; -use crate::ibc::core::ics02_client::error::ClientError; -use crate::ibc::core::ics02_client::{ +use crate::ibc::core::client::context::{ ClientExecutionContext, ClientValidationContext, }; -use crate::ibc::core::ics23_commitment::commitment::{ +use crate::ibc::core::client::types::error::ClientError; +use crate::ibc::core::client::types::{Height, Status, UpdateKind}; +use crate::ibc::core::commitment_types::commitment::{ CommitmentPrefix, CommitmentProofBytes, CommitmentRoot, }; -use crate::ibc::core::ics24_host::identifier::ClientId; -use crate::ibc::core::ics24_host::path::Path; -use crate::ibc::core::ExecutionContext; -#[cfg(feature = "ibc-mocks")] -use crate::ibc::mock::client_state::MockClientContext; -#[cfg(feature = "ibc-mocks")] -use crate::ibc::mock::client_state::MockClientState; -#[cfg(feature = "ibc-mocks")] -use crate::ibc::mock::consensus_state::MockConsensusState; -use crate::ibc::Height; -use crate::ibc_proto::google::protobuf::Any; +use crate::ibc::core::host::types::identifiers::{ClientId, ClientType}; +use crate::ibc::core::host::types::path::Path; +use crate::ibc::core::host::ExecutionContext; +use crate::ibc::primitives::proto::Any; // TODO: #[derive(ClientState)] doesn't support contexts with contexts generic // for now @@ -41,7 +39,7 @@ pub enum AnyClientState { /// Tendermint client state Tendermint(TmClientState), - #[cfg(feature = "ibc-mocks")] + #[cfg(feature = "testing")] /// Mock client state for testing Mock(MockClientState), } @@ -52,7 +50,7 @@ impl From for AnyClientState { } } -#[cfg(feature = "ibc-mocks")] +#[cfg(feature = "testing")] impl From for AnyClientState { fn from(cs: MockClientState) -> Self { Self::Mock(cs) @@ -63,7 +61,7 @@ impl From for Any { fn from(client_state: AnyClientState) -> Self { match client_state { AnyClientState::Tendermint(cs) => cs.into(), - #[cfg(feature = "ibc-mocks")] + #[cfg(feature = "testing")] AnyClientState::Mock(cs) => cs.into(), } } @@ -73,7 +71,7 @@ impl TryFrom for AnyClientState { type Error = ClientError; fn try_from(client_state: Any) -> Result { - #[cfg(feature = "ibc-mocks")] + #[cfg(feature = "testing")] if let Ok(cs) = MockClientState::try_from(client_state.clone()) { return Ok(cs.into()); } @@ -93,7 +91,7 @@ pub enum AnyConsensusState { /// Tendermint consensus state Tendermint(TmConsensusState), - #[cfg(feature = "ibc-mocks")] + #[cfg(feature = "testing")] /// Mock consensus state for testing Mock(MockConsensusState), } @@ -104,7 +102,7 @@ impl From for AnyConsensusState { } } -#[cfg(feature = "ibc-mocks")] +#[cfg(feature = "testing")] impl From for AnyConsensusState { fn from(cs: MockConsensusState) -> Self { Self::Mock(cs) @@ -117,7 +115,7 @@ impl TryFrom for TmConsensusState { fn try_from(any: AnyConsensusState) -> Result { match any { AnyConsensusState::Tendermint(cs) => Ok(cs), - #[cfg(feature = "ibc-mocks")] + #[cfg(feature = "testing")] _ => Err(ClientError::UnknownConsensusStateType { consensus_state_type: "Only Tendermint client state type is \ supported" @@ -127,7 +125,7 @@ impl TryFrom for TmConsensusState { } } -#[cfg(feature = "ibc-mocks")] +#[cfg(feature = "testing")] impl TryFrom for MockConsensusState { type Error = ClientError; @@ -146,7 +144,7 @@ impl TryFrom for AnyConsensusState { type Error = ClientError; fn try_from(consensus_state: Any) -> Result { - #[cfg(feature = "ibc-mocks")] + #[cfg(feature = "testing")] if let Ok(cs) = MockConsensusState::try_from(consensus_state.clone()) { return Ok(cs.into()); } @@ -179,7 +177,7 @@ impl ClientStateCommon for AnyClientState { AnyClientState::Tendermint(cs) => { cs.verify_consensus_state(consensus_state) } - #[cfg(feature = "ibc-mocks")] + #[cfg(feature = "testing")] AnyClientState::Mock(cs) => { cs.verify_consensus_state(consensus_state) } @@ -189,7 +187,7 @@ impl ClientStateCommon for AnyClientState { fn client_type(&self) -> ClientType { match self { AnyClientState::Tendermint(cs) => cs.client_type(), - #[cfg(feature = "ibc-mocks")] + #[cfg(feature = "testing")] AnyClientState::Mock(cs) => cs.client_type(), } } @@ -197,7 +195,7 @@ impl ClientStateCommon for AnyClientState { fn latest_height(&self) -> Height { match self { AnyClientState::Tendermint(cs) => cs.latest_height(), - #[cfg(feature = "ibc-mocks")] + #[cfg(feature = "testing")] AnyClientState::Mock(cs) => cs.latest_height(), } } @@ -210,7 +208,7 @@ impl ClientStateCommon for AnyClientState { AnyClientState::Tendermint(cs) => { cs.validate_proof_height(proof_height) } - #[cfg(feature = "ibc-mocks")] + #[cfg(feature = "testing")] AnyClientState::Mock(cs) => cs.validate_proof_height(proof_height), } } @@ -231,7 +229,7 @@ impl ClientStateCommon for AnyClientState { proof_upgrade_consensus_state, root, ), - #[cfg(feature = "ibc-mocks")] + #[cfg(feature = "testing")] AnyClientState::Mock(cs) => cs.verify_upgrade_client( upgraded_client_state, upgraded_consensus_state, @@ -254,7 +252,7 @@ impl ClientStateCommon for AnyClientState { AnyClientState::Tendermint(cs) => { cs.verify_membership(prefix, proof, root, path, value) } - #[cfg(feature = "ibc-mocks")] + #[cfg(feature = "testing")] AnyClientState::Mock(cs) => { cs.verify_membership(prefix, proof, root, path, value) } @@ -272,7 +270,7 @@ impl ClientStateCommon for AnyClientState { AnyClientState::Tendermint(cs) => { cs.verify_non_membership(prefix, proof, root, path) } - #[cfg(feature = "ibc-mocks")] + #[cfg(feature = "testing")] AnyClientState::Mock(cs) => { cs.verify_non_membership(prefix, proof, root, path) } @@ -280,7 +278,7 @@ impl ClientStateCommon for AnyClientState { } } -#[cfg(not(feature = "ibc-mocks"))] +#[cfg(not(feature = "testing"))] impl ClientStateValidation for AnyClientState where V: ClientValidationContext + TmValidationContext, @@ -331,7 +329,7 @@ where } } -#[cfg(feature = "ibc-mocks")] +#[cfg(feature = "testing")] impl ClientStateValidation for AnyClientState where V: ClientValidationContext + TmValidationContext + MockClientContext, @@ -400,7 +398,7 @@ where } } -#[cfg(not(feature = "ibc-mocks"))] +#[cfg(not(feature = "testing"))] impl ClientStateExecution for AnyClientState where E: ExecutionContext + TmExecutionContext, @@ -468,7 +466,7 @@ where } } -#[cfg(feature = "ibc-mocks")] +#[cfg(feature = "testing")] impl ClientStateExecution for AnyClientState where E: ExecutionContext + TmExecutionContext + MockClientContext, diff --git a/core/src/ledger/ibc/context/common.rs b/core/src/ledger/ibc/context/common.rs index d823b005d7..e8245babdd 100644 --- a/core/src/ledger/ibc/context/common.rs +++ b/core/src/ledger/ibc/context/common.rs @@ -7,31 +7,30 @@ use sha2::Digest; use super::client::{AnyClientState, AnyConsensusState}; use super::storage::IbcStorageContext; -use crate::ibc::clients::ics07_tendermint::consensus_state::ConsensusState as TmConsensusState; -use crate::ibc::core::ics02_client::consensus_state::ConsensusState; -use crate::ibc::core::ics02_client::error::ClientError; -use crate::ibc::core::ics02_client::height::Height; -use crate::ibc::core::ics03_connection::connection::ConnectionEnd; -use crate::ibc::core::ics03_connection::error::ConnectionError; -use crate::ibc::core::ics04_channel::channel::ChannelEnd; -use crate::ibc::core::ics04_channel::commitment::{ +use crate::ibc::clients::tendermint::consensus_state::ConsensusState as TmConsensusState; +use crate::ibc::clients::tendermint::types::ConsensusState as TmConsensusStateType; +use crate::ibc::core::channel::types::channel::ChannelEnd; +use crate::ibc::core::channel::types::commitment::{ AcknowledgementCommitment, PacketCommitment, }; -use crate::ibc::core::ics04_channel::error::{ChannelError, PacketError}; -use crate::ibc::core::ics04_channel::packet::{Receipt, Sequence}; -use crate::ibc::core::ics04_channel::timeout::TimeoutHeight; -use crate::ibc::core::ics24_host::identifier::{ - ChannelId, ClientId, ConnectionId, PortId, +use crate::ibc::core::channel::types::error::{ChannelError, PacketError}; +use crate::ibc::core::channel::types::packet::Receipt; +use crate::ibc::core::channel::types::timeout::TimeoutHeight; +use crate::ibc::core::client::context::consensus_state::ConsensusState; +use crate::ibc::core::client::types::error::ClientError; +use crate::ibc::core::client::types::Height; +use crate::ibc::core::connection::types::error::ConnectionError; +use crate::ibc::core::connection::types::ConnectionEnd; +use crate::ibc::core::handler::types::error::ContextError; +use crate::ibc::core::host::types::identifiers::{ + ChannelId, ClientId, ConnectionId, PortId, Sequence, }; -use crate::ibc::core::timestamp::Timestamp; -use crate::ibc::core::ContextError; -use crate::ibc_proto::google::protobuf::Any; -use crate::ibc_proto::protobuf::Protobuf; +use crate::ibc::primitives::proto::{Any, Protobuf}; +use crate::ibc::primitives::Timestamp; use crate::ledger::ibc::storage; use crate::ledger::parameters::storage::get_max_expected_time_per_block_key; use crate::ledger::storage_api; use crate::tendermint::Time as TmTime; -use crate::tendermint_proto::Protobuf as TmProtobuf; use crate::types::storage::{BlockHeight, Key}; use crate::types::time::DurationSecs; @@ -292,8 +291,12 @@ pub trait IbcCommonContext: IbcStorageContext { .next_validators_hash .try_into() .expect("The hash should be converted"); - let consensus_state = - TmConsensusState::new(commitment_root, time, next_validators_hash); + let consensus_state: TmConsensusState = TmConsensusStateType::new( + commitment_root, + time, + next_validators_hash, + ) + .into(); Ok(consensus_state.into()) } diff --git a/core/src/ledger/ibc/context/execution.rs b/core/src/ledger/ibc/context/execution.rs index 893cd67702..bdebb242ef 100644 --- a/core/src/ledger/ibc/context/execution.rs +++ b/core/src/ledger/ibc/context/execution.rs @@ -3,23 +3,26 @@ use super::client::{AnyClientState, AnyConsensusState}; use super::common::IbcCommonContext; use super::IbcContext; -use crate::ibc::core::events::IbcEvent; -use crate::ibc::core::ics02_client::ClientExecutionContext; -use crate::ibc::core::ics03_connection::connection::ConnectionEnd; -use crate::ibc::core::ics04_channel::channel::ChannelEnd; -use crate::ibc::core::ics04_channel::commitment::{ +use crate::ibc::core::channel::types::channel::ChannelEnd; +use crate::ibc::core::channel::types::commitment::{ AcknowledgementCommitment, PacketCommitment, }; -use crate::ibc::core::ics04_channel::packet::{Receipt, Sequence}; -use crate::ibc::core::ics24_host::identifier::{ClientId, ConnectionId}; -use crate::ibc::core::ics24_host::path::{ +use crate::ibc::core::channel::types::packet::Receipt; +use crate::ibc::core::client::context::ClientExecutionContext; +use crate::ibc::core::client::types::Height; +use crate::ibc::core::connection::types::ConnectionEnd; +use crate::ibc::core::handler::types::error::ContextError; +use crate::ibc::core::handler::types::events::IbcEvent; +use crate::ibc::core::host::types::identifiers::{ + ClientId, ConnectionId, Sequence, +}; +use crate::ibc::core::host::types::path::{ AckPath, ChannelEndPath, ClientConnectionPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath, ConnectionPath, ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; -use crate::ibc::core::timestamp::Timestamp; -use crate::ibc::core::{ContextError, ExecutionContext}; -use crate::ibc::Height; +use crate::ibc::core::host::ExecutionContext; +use crate::ibc::primitives::Timestamp; use crate::ledger::ibc::storage; impl ClientExecutionContext for IbcContext @@ -47,8 +50,8 @@ where ) -> Result<(), ContextError> { let client_id = consensus_state_path.client_id; let height = Height::new( - consensus_state_path.epoch, - consensus_state_path.height, + consensus_state_path.revision_number, + consensus_state_path.revision_height, )?; self.inner.borrow_mut().store_consensus_state( &client_id, @@ -63,8 +66,8 @@ where ) -> Result<(), ContextError> { let client_id = consensus_state_path.client_id; let height = Height::new( - consensus_state_path.epoch, - consensus_state_path.height, + consensus_state_path.revision_number, + consensus_state_path.revision_height, )?; self.inner .borrow_mut() diff --git a/core/src/ledger/ibc/context/mod.rs b/core/src/ledger/ibc/context/mod.rs index b57819eec1..b661bf2f09 100644 --- a/core/src/ledger/ibc/context/mod.rs +++ b/core/src/ledger/ibc/context/mod.rs @@ -14,8 +14,8 @@ use std::fmt::Debug; use std::rc::Rc; use std::time::Duration; -use crate::ibc::core::ics23_commitment::specs::ProofSpecs; -use crate::ibc::core::ics24_host::identifier::ChainId as IbcChainId; +use crate::ibc::core::commitment_types::specs::ProofSpecs; +use crate::ibc::core::host::types::identifiers::ChainId as IbcChainId; /// IBC context to handle IBC-related data #[derive(Debug)] @@ -58,7 +58,7 @@ pub struct ValidationParams { impl Default for ValidationParams { fn default() -> Self { Self { - chain_id: IbcChainId::new("non-init-chain", 0) + chain_id: IbcChainId::new("non-init-chain") .expect("Convert the default chain ID shouldn't fail"), proof_specs: ProofSpecs::default(), unbonding_period: Duration::default(), diff --git a/core/src/ledger/ibc/context/router.rs b/core/src/ledger/ibc/context/router.rs index daba314a5d..cc9abca1fc 100644 --- a/core/src/ledger/ibc/context/router.rs +++ b/core/src/ledger/ibc/context/router.rs @@ -4,8 +4,10 @@ use std::collections::HashMap; use std::rc::Rc; use super::super::ModuleWrapper; -use crate::ibc::core::ics24_host::identifier::PortId; -use crate::ibc::core::router::{Module, ModuleId, Router}; +use crate::ibc::core::host::types::identifiers::PortId; +use crate::ibc::core::router::module::Module; +use crate::ibc::core::router::router::Router; +use crate::ibc::core::router::types::module::ModuleId; /// IBC router #[derive(Debug, Default)] diff --git a/core/src/ledger/ibc/context/token_transfer.rs b/core/src/ledger/ibc/context/token_transfer.rs index 4c41b8c956..c358049bc2 100644 --- a/core/src/ledger/ibc/context/token_transfer.rs +++ b/core/src/ledger/ibc/context/token_transfer.rs @@ -4,15 +4,14 @@ use std::cell::RefCell; use std::rc::Rc; use super::common::IbcCommonContext; -use crate::ibc::applications::transfer::coin::PrefixedCoin; -use crate::ibc::applications::transfer::context::{ +use crate::ibc::apps::transfer::context::{ TokenTransferExecutionContext, TokenTransferValidationContext, }; -use crate::ibc::applications::transfer::denom::PrefixedDenom; -use crate::ibc::applications::transfer::error::TokenTransferError; -use crate::ibc::core::ics04_channel::error::ChannelError; -use crate::ibc::core::ics24_host::identifier::{ChannelId, PortId}; -use crate::ibc::core::ContextError; +use crate::ibc::apps::transfer::types::error::TokenTransferError; +use crate::ibc::apps::transfer::types::{PrefixedCoin, PrefixedDenom}; +use crate::ibc::core::channel::types::error::ChannelError; +use crate::ibc::core::handler::types::error::ContextError; +use crate::ibc::core::host::types::identifiers::{ChannelId, PortId}; use crate::ledger::ibc::storage; use crate::ledger::storage_api::token::read_denom; use crate::types::address::{Address, InternalAddress}; diff --git a/core/src/ledger/ibc/context/transfer_mod.rs b/core/src/ledger/ibc/context/transfer_mod.rs index b3951e24de..5bc18b35c3 100644 --- a/core/src/ledger/ibc/context/transfer_mod.rs +++ b/core/src/ledger/ibc/context/transfer_mod.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use super::common::IbcCommonContext; use super::token_transfer::TokenTransferContext; -use crate::ibc::applications::transfer::context::{ +use crate::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, @@ -17,18 +17,19 @@ use crate::ibc::applications::transfer::context::{ on_recv_packet_execute, on_timeout_packet_execute, on_timeout_packet_validate, }; -use crate::ibc::applications::transfer::error::TokenTransferError; -use crate::ibc::applications::transfer::MODULE_ID_STR; -use crate::ibc::core::ics04_channel::acknowledgement::Acknowledgement; -use crate::ibc::core::ics04_channel::channel::{Counterparty, Order}; -use crate::ibc::core::ics04_channel::error::{ChannelError, PacketError}; -use crate::ibc::core::ics04_channel::packet::Packet; -use crate::ibc::core::ics04_channel::Version; -use crate::ibc::core::ics24_host::identifier::{ +use crate::ibc::apps::transfer::types::error::TokenTransferError; +use crate::ibc::apps::transfer::types::MODULE_ID_STR; +use crate::ibc::core::channel::types::acknowledgement::Acknowledgement; +use crate::ibc::core::channel::types::channel::{Counterparty, Order}; +use crate::ibc::core::channel::types::error::{ChannelError, PacketError}; +use crate::ibc::core::channel::types::packet::Packet; +use crate::ibc::core::channel::types::Version; +use crate::ibc::core::host::types::identifiers::{ ChannelId, ConnectionId, PortId, }; -use crate::ibc::core::router::{Module, ModuleExtras, ModuleId}; -use crate::ibc::Signer; +use crate::ibc::core::router::module::Module; +use crate::ibc::core::router::types::module::{ModuleExtras, ModuleId}; +use crate::ibc::primitives::Signer; /// IBC module wrapper for getting the reference of the module pub trait ModuleWrapper: Module { @@ -331,8 +332,8 @@ fn into_packet_error(error: TokenTransferError) -> PacketError { #[cfg(any(test, feature = "testing"))] pub mod testing { use super::*; - use crate::ibc::applications::transfer::ack_success_b64; - use crate::ibc::core::ics04_channel::acknowledgement::AcknowledgementStatus; + use crate::ibc::apps::transfer::types::ack_success_b64; + use crate::ibc::core::channel::types::acknowledgement::AcknowledgementStatus; /// Dummy IBC module for token transfer #[derive(Debug)] diff --git a/core/src/ledger/ibc/context/validation.rs b/core/src/ledger/ibc/context/validation.rs index ffc0585c8c..8ecd55fe0b 100644 --- a/core/src/ledger/ibc/context/validation.rs +++ b/core/src/ledger/ibc/context/validation.rs @@ -1,35 +1,37 @@ //! ValidationContext implementation for IBC +#[cfg(feature = "testing")] +use ibc_testkit::testapp::ibc::clients::mock::client_state::MockClientState; + use super::client::{AnyClientState, AnyConsensusState}; use super::common::IbcCommonContext; use super::IbcContext; -use crate::ibc::clients::ics07_tendermint::{ +use crate::ibc::clients::tendermint::context::{ CommonContext as TmCommonContext, ValidationContext as TmValidationContext, }; -use crate::ibc::core::ics02_client::error::ClientError; -use crate::ibc::core::ics02_client::ClientValidationContext; -use crate::ibc::core::ics03_connection::connection::ConnectionEnd; -use crate::ibc::core::ics04_channel::channel::ChannelEnd; -use crate::ibc::core::ics04_channel::commitment::{ +use crate::ibc::core::channel::types::channel::ChannelEnd; +use crate::ibc::core::channel::types::commitment::{ AcknowledgementCommitment, PacketCommitment, }; -use crate::ibc::core::ics04_channel::packet::{Receipt, Sequence}; -use crate::ibc::core::ics23_commitment::commitment::CommitmentPrefix; -use crate::ibc::core::ics23_commitment::specs::ProofSpecs; -use crate::ibc::core::ics24_host::identifier::{ - ChainId, ClientId, ConnectionId, +use crate::ibc::core::channel::types::packet::Receipt; +use crate::ibc::core::client::context::ClientValidationContext; +use crate::ibc::core::client::types::error::ClientError; +use crate::ibc::core::client::types::Height; +use crate::ibc::core::commitment_types::commitment::CommitmentPrefix; +use crate::ibc::core::commitment_types::specs::ProofSpecs; +use crate::ibc::core::connection::types::ConnectionEnd; +use crate::ibc::core::handler::types::error::ContextError; +use crate::ibc::core::host::types::identifiers::{ + ChainId, ClientId, ConnectionId, Sequence, }; -use crate::ibc::core::ics24_host::path::{ +use crate::ibc::core::host::types::path::{ AckPath, ChannelEndPath, ClientConsensusStatePath, CommitmentPath, ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, }; -use crate::ibc::core::timestamp::Timestamp; -use crate::ibc::core::{ContextError, ValidationContext}; -use crate::ibc::hosts::tendermint::ValidateSelfClientContext; -#[cfg(any(feature = "ibc-mocks-abcipp", feature = "ibc-mocks"))] -use crate::ibc::mock::client_state::MockClientState; -use crate::ibc::{Height, Signer}; -use crate::ibc_proto::google::protobuf::Any; +use crate::ibc::core::host::ValidationContext; +use crate::ibc::cosmos_host::ValidateSelfClientContext; +use crate::ibc::primitives::proto::Any; +use crate::ibc::primitives::{Signer, Timestamp}; use crate::ledger::ibc::storage; const COMMITMENT_PREFIX: &[u8] = b"ibc"; @@ -85,9 +87,9 @@ where } } -#[cfg(feature = "ibc-mocks")] -use crate::ibc::mock::client_state::MockClientContext; -#[cfg(feature = "ibc-mocks")] +#[cfg(feature = "testing")] +use ibc_testkit::testapp::ibc::clients::mock::client_state::MockClientContext; +#[cfg(feature = "testing")] impl MockClientContext for IbcContext where C: IbcCommonContext, @@ -164,8 +166,8 @@ where client_cons_state_path: &ClientConsensusStatePath, ) -> Result { let height = Height::new( - client_cons_state_path.epoch, - client_cons_state_path.height, + client_cons_state_path.revision_number, + client_cons_state_path.revision_height, )?; self.inner .borrow() @@ -205,7 +207,7 @@ where &self, counterparty_client_state: Any, ) -> Result<(), ContextError> { - #[cfg(any(feature = "ibc-mocks-abcipp", feature = "ibc-mocks"))] + #[cfg(feature = "testing")] { if MockClientState::try_from(counterparty_client_state.clone()) .is_ok() diff --git a/core/src/ledger/ibc/mod.rs b/core/src/ledger/ibc/mod.rs index 2a4919100e..1b01017d3f 100644 --- a/core/src/ledger/ibc/mod.rs +++ b/core/src/ledger/ibc/mod.rs @@ -18,19 +18,23 @@ pub use context::ValidationParams; use prost::Message; use thiserror::Error; -use crate::ibc::applications::transfer::error::TokenTransferError; -use crate::ibc::applications::transfer::msgs::transfer::MsgTransfer; -use crate::ibc::applications::transfer::{ - is_receiver_chain_source, send_transfer_execute, send_transfer_validate, - PrefixedDenom, TracePrefix, +use crate::ibc::apps::transfer::handler::{ + send_transfer_execute, send_transfer_validate, }; -use crate::ibc::core::ics04_channel::msgs::PacketMsg; -use crate::ibc::core::ics24_host::identifier::{ - ChannelId, IdentifierError, PortId, +use crate::ibc::apps::transfer::types::error::TokenTransferError; +use crate::ibc::apps::transfer::types::msgs::transfer::MsgTransfer; +use crate::ibc::apps::transfer::types::{ + is_receiver_chain_source, PrefixedDenom, TracePrefix, }; -use crate::ibc::core::router::ModuleId; -use crate::ibc::core::{execute, validate, MsgEnvelope, RouterError}; -use crate::ibc_proto::google::protobuf::Any; +use crate::ibc::core::channel::types::msgs::PacketMsg; +use crate::ibc::core::entrypoint::{execute, validate}; +use crate::ibc::core::handler::types::error::ContextError; +use crate::ibc::core::handler::types::msgs::MsgEnvelope; +use crate::ibc::core::host::types::error::IdentifierError; +use crate::ibc::core::host::types::identifiers::{ChannelId, PortId}; +use crate::ibc::core::router::types::error::RouterError; +use crate::ibc::core::router::types::module::ModuleId; +use crate::ibc::primitives::proto::Any; use crate::types::address::{Address, MASP}; use crate::types::ibc::{ get_shielded_transfer, is_ibc_denom, EVENT_TYPE_DENOM_TRACE, @@ -45,16 +49,10 @@ pub enum Error { DecodingData(prost::DecodeError), #[error("Decoding message error: {0}")] DecodingMessage(RouterError), - #[error("IBC storage error: {0}")] - IbcStorage(storage::Error), - #[error("IBC execution error: {0}")] - Execution(RouterError), + #[error("IBC context error: {0}")] + Context(Box), #[error("IBC token transfer error: {0}")] TokenTransfer(TokenTransferError), - #[error("IBC validation error: {0}")] - Validation(RouterError), - #[error("IBC module doesn't exist")] - NoModule, #[error("Denom error: {0}")] Denom(String), #[error("Invalid chain ID: {0}")] @@ -114,10 +112,10 @@ where .map_err(Error::TokenTransfer) } Err(_) => { - let envelope = - MsgEnvelope::try_from(any_msg).map_err(Error::Execution)?; + let envelope = MsgEnvelope::try_from(any_msg) + .map_err(Error::DecodingMessage)?; execute(&mut self.ctx, &mut self.router, envelope.clone()) - .map_err(Error::Execution)?; + .map_err(|e| Error::Context(Box::new(e)))?; // For receiving the token to a shielded address self.handle_masp_tx(&envelope)?; // the current ibc-rs execution doesn't store the denom for the @@ -230,9 +228,9 @@ where } Err(_) => { let envelope = MsgEnvelope::try_from(any_msg) - .map_err(Error::Validation)?; + .map_err(Error::DecodingMessage)?; validate(&self.ctx, &self.router, envelope) - .map_err(Error::Validation) + .map_err(|e| Error::Context(Box::new(e))) } } } diff --git a/core/src/ledger/ibc/storage.rs b/core/src/ledger/ibc/storage.rs index dae7d8d0d2..eeaecd2efa 100644 --- a/core/src/ledger/ibc/storage.rs +++ b/core/src/ledger/ibc/storage.rs @@ -5,12 +5,11 @@ use std::str::FromStr; use sha2::{Digest, Sha256}; use thiserror::Error; -use crate::ibc::core::ics02_client::height::Height; -use crate::ibc::core::ics04_channel::packet::Sequence; -use crate::ibc::core::ics24_host::identifier::{ - ChannelId, ClientId, ConnectionId, PortId, +use crate::ibc::core::client::types::Height; +use crate::ibc::core::host::types::identifiers::{ + ChannelId, ClientId, ConnectionId, PortId, Sequence, }; -use crate::ibc::core::ics24_host::path::{ +use crate::ibc::core::host::types::path::{ AckPath, ChannelEndPath, ClientConnectionPath, ClientConsensusStatePath, ClientStatePath, CommitmentPath, ConnectionPath, Path, PortPath, ReceiptPath, SeqAckPath, SeqRecvPath, SeqSendPath, @@ -81,8 +80,8 @@ pub fn client_state_key(client_id: &ClientId) -> Key { pub fn consensus_state_key(client_id: &ClientId, height: Height) -> Key { let path = Path::ClientConsensusState(ClientConsensusStatePath { client_id: client_id.clone(), - epoch: height.revision_number(), - height: height.revision_height(), + revision_number: height.revision_number(), + revision_height: height.revision_height(), }); ibc_key(path.to_string()) .expect("Creating a key for the consensus state shouldn't fail") @@ -92,8 +91,8 @@ pub fn consensus_state_key(client_id: &ClientId, height: Height) -> Key { pub fn consensus_state_prefix(client_id: &ClientId) -> Key { let path = Path::ClientConsensusState(ClientConsensusStatePath { client_id: client_id.clone(), - epoch: 0, - height: 0, + revision_number: 0, + revision_height: 0, }); let suffix = "/0-0".to_string(); let path = path.to_string(); diff --git a/core/src/ledger/masp_conversions.rs b/core/src/ledger/masp_conversions.rs index 371e8a5ec9..ab915c22e2 100644 --- a/core/src/ledger/masp_conversions.rs +++ b/core/src/ledger/masp_conversions.rs @@ -17,8 +17,7 @@ use crate::ledger::storage_api::{StorageRead, StorageWrite}; use crate::types::address::{Address, MASP}; use crate::types::dec::Dec; use crate::types::storage::Epoch; -use crate::types::token; -use crate::types::token::MaspDenom; +use crate::types::token::{self, DenominatedAmount, MaspDenom}; use crate::types::uint::Uint; /// A representation of the conversion state @@ -149,6 +148,17 @@ where 0u128 }) }; + let inflation_amount = token::Amount::from_uint( + (total_token_in_masp.raw_amount() / precision) + * Uint::from(noterized_inflation), + 0, + ) + .unwrap(); + let denom_amount = DenominatedAmount { + amount: inflation_amount, + denom: denomination, + }; + tracing::info!("MASP inflation for {addr} is {denom_amount}"); tracing::debug!( "Controller, call: total_in_masp {:?}, total_tokens {:?}, \ @@ -166,25 +176,19 @@ where kd_gain_nom, epochs_per_year, ); - tracing::debug!("Please give me: {:?}", addr); + tracing::debug!("Token address: {:?}", addr); tracing::debug!("Ratio {:?}", locked_ratio); tracing::debug!("inflation from the pd controller {:?}", inflation); tracing::debug!("total in the masp {:?}", total_token_in_masp); - tracing::debug!("Please give me inflation: {:?}", noterized_inflation); + tracing::debug!("precision {}", precision); + tracing::debug!("Noterized inflation: {}", noterized_inflation); // Is it fine to write the inflation rate, this is accurate, // but we should make sure the return value's ratio matches // this new inflation rate in 'update_allowed_conversions', // otherwise we will have an inaccurate view of inflation - wl_storage.write( - &token::masp_last_inflation_key(addr), - token::Amount::from_uint( - (total_token_in_masp.raw_amount() / precision) - * Uint::from(noterized_inflation), - 0, - ) - .unwrap(), - )?; + wl_storage + .write(&token::masp_last_inflation_key(addr), inflation_amount)?; wl_storage.write(&token::masp_last_locked_ratio_key(addr), locked_ratio)?; @@ -192,7 +196,7 @@ where } // This is only enabled when "wasm-runtime" is on, because we're using rayon -#[cfg(feature = "wasm-runtime")] +#[cfg(any(feature = "wasm-runtime", test))] /// Update the MASP's allowed conversions pub fn update_allowed_conversions( wl_storage: &mut WlStorage, @@ -340,7 +344,8 @@ where total_reward += (addr_bal * (new_normed_inflation, *normed_inflation)) .0 - - addr_bal; + .checked_sub(addr_bal) + .unwrap_or_default(); // Save the new normed inflation *normed_inflation = new_normed_inflation; } @@ -491,3 +496,129 @@ pub fn encode_asset_type( AssetType::new(new_asset_bytes.as_ref()) .expect("unable to derive asset identifier") } + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + use std::str::FromStr; + + use proptest::prelude::*; + use proptest::test_runner::Config; + use test_log::test; + + use super::*; + use crate::ledger::parameters::{EpochDuration, Parameters}; + use crate::ledger::storage::testing::TestWlStorage; + use crate::ledger::storage_api::token::write_denom; + use crate::types::address; + use crate::types::dec::testing::arb_non_negative_dec; + use crate::types::time::DurationSecs; + use crate::types::token::testing::arb_amount; + + proptest! { + #![proptest_config(Config { + cases: 10, + .. Config::default() + })] + #[test] + fn test_updated_allowed_conversions( + initial_balance in arb_amount(), + masp_locked_ratio in arb_non_negative_dec(), + ) { + test_updated_allowed_conversions_aux(initial_balance, masp_locked_ratio) + } + } + + fn test_updated_allowed_conversions_aux( + initial_balance: token::Amount, + masp_locked_ratio: Dec, + ) { + const ROUNDS: usize = 10; + + let mut s = TestWlStorage::default(); + let params = Parameters { + max_tx_bytes: 1024 * 1024, + epoch_duration: EpochDuration { + min_num_of_blocks: 1, + min_duration: DurationSecs(3600), + }, + max_expected_time_per_block: DurationSecs(3600), + max_proposal_bytes: Default::default(), + max_block_gas: 100, + vp_whitelist: vec![], + tx_whitelist: vec![], + implicit_vp_code_hash: Default::default(), + epochs_per_year: 365, + max_signatures_per_transaction: 10, + pos_gain_p: Default::default(), + pos_gain_d: Default::default(), + staked_ratio: Default::default(), + pos_inflation_amount: Default::default(), + fee_unshielding_gas_limit: 0, + fee_unshielding_descriptions_limit: 0, + minimum_gas_price: Default::default(), + }; + + // Initialize the state + { + // Parameters + params.init_storage(&mut s).unwrap(); + + // Tokens + let token_params = token::Parameters { + max_reward_rate: Dec::from_str("0.1").unwrap(), + kp_gain_nom: Dec::from_str("0.1").unwrap(), + kd_gain_nom: Dec::from_str("0.1").unwrap(), + locked_ratio_target: Dec::from_str("0.6667").unwrap(), + }; + + for (token_addr, (alias, denom)) in tokens() { + token_params.init_storage(&token_addr, &mut s); + + write_denom(&mut s, &token_addr, denom).unwrap(); + + // Write a minted token balance + let total_token_balance = initial_balance; + s.write( + &token::minted_balance_key(&token_addr), + total_token_balance, + ) + .unwrap(); + + // Put the locked ratio into MASP + s.write( + &token::balance_key(&token_addr, &address::MASP), + masp_locked_ratio * total_token_balance, + ) + .unwrap(); + + // Insert tokens into MASP conversion state + s.storage + .conversion_state + .tokens + .insert(alias.to_string(), token_addr.clone()); + } + } + + for i in 0..ROUNDS { + println!("Round {i}"); + update_allowed_conversions(&mut s).unwrap(); + println!(); + println!(); + } + } + + pub fn tokens() -> HashMap { + vec![ + (address::nam(), ("nam", 6.into())), + (address::btc(), ("btc", 8.into())), + (address::eth(), ("eth", 18.into())), + (address::dot(), ("dot", 10.into())), + (address::schnitzel(), ("schnitzel", 6.into())), + (address::apfel(), ("apfel", 6.into())), + (address::kartoffel(), ("kartoffel", 6.into())), + ] + .into_iter() + .collect() + } +} diff --git a/core/src/ledger/storage/mod.rs b/core/src/ledger/storage/mod.rs index b338b3518b..45802169dd 100644 --- a/core/src/ledger/storage/mod.rs +++ b/core/src/ledger/storage/mod.rs @@ -25,7 +25,9 @@ pub use wl_storage::{ }; use super::gas::MEMORY_ACCESS_GAS_PER_BYTE; -use crate::ledger::eth_bridge::storage::bridge_pool::is_pending_transfer_key; +use crate::ledger::eth_bridge::storage::bridge_pool::{ + self, is_pending_transfer_key, +}; use crate::ledger::gas::{ STORAGE_ACCESS_GAS_PER_BYTE, STORAGE_WRITE_GAS_PER_BYTE, }; @@ -39,6 +41,7 @@ use crate::ledger::storage::merkle_tree::{ use crate::tendermint::merkle::proof::ProofOps; use crate::types::address::{Address, EstablishedAddressGen, InternalAddress}; use crate::types::chain::{ChainId, CHAIN_ID_LENGTH}; +use crate::types::ethereum_events::Uint; use crate::types::ethereum_structs; use crate::types::hash::{Error as HashError, Hash}; use crate::types::internal::{ExpiredTxsQueue, TxQueue}; @@ -136,8 +139,8 @@ pub struct BlockStorage { pub hash: BlockHash, /// From the start of `FinalizeBlock` until the end of `Commit`, this is /// height of the block that is going to be committed. Otherwise, it is the - /// height of the most recently committed block, or `BlockHeight(0)` if no - /// block has been committed yet. + /// height of the most recently committed block, or `BlockHeight::sentinel` + /// (0) if no block has been committed yet. pub height: BlockHeight, /// From the start of `FinalizeBlock` until the end of `Commit`, this is /// height of the block that is going to be committed. Otherwise it is the @@ -1012,6 +1015,9 @@ where } = parameters.epoch_duration; self.next_epoch_min_start_height = initial_height + min_num_of_blocks; self.next_epoch_min_start_time = genesis_time + min_duration; + self.block.pred_epochs = Epochs { + first_block_heights: vec![initial_height], + }; self.update_epoch_in_merkle_tree() } @@ -1144,25 +1150,7 @@ where if self.block.epoch.0 == 0 { return Ok(()); } - if let Some(limit) = self.storage_read_past_height_limit { - if self.get_last_block_height().0 <= limit { - return Ok(()); - } - - let min_height = (self.get_last_block_height().0 - limit).into(); - if let Some(epoch) = self.block.pred_epochs.get_epoch(min_height) { - if epoch.0 == 0 { - return Ok(()); - } - // Remove stores at the previous epoch because the Merkle tree - // stores at the starting height of the epoch would be used to - // restore stores at a height (> min_height) in the epoch - for st in StoreType::iter_provable() { - self.db.prune_merkle_tree_store(batch, st, epoch.prev())?; - } - } - } - // remove non-provable stores at the previous epoch + // Prune non-provable stores at the previous epoch for st in StoreType::iter_non_provable() { self.db.prune_merkle_tree_store( batch, @@ -1170,6 +1158,32 @@ where self.block.epoch.prev(), )?; } + // Prune provable stores + let oldest_epoch = self.get_oldest_epoch(); + if oldest_epoch.0 > 0 { + // Remove stores at the previous epoch because the Merkle tree + // stores at the starting height of the epoch would be used to + // restore stores at a height (> oldest_height) in the epoch + for st in StoreType::iter_provable() { + self.db.prune_merkle_tree_store( + batch, + st, + oldest_epoch.prev(), + )?; + } + + // Prune the BridgePool subtree stores with invalid nonce + let mut epoch = self.get_oldest_epoch_with_valid_nonce()?; + while oldest_epoch < epoch { + epoch = epoch.prev(); + self.db.prune_merkle_tree_store( + batch, + &StoreType::BridgePool, + epoch, + )?; + } + } + Ok(()) } @@ -1182,6 +1196,52 @@ where .unwrap_or_default() } + /// Get the oldest epoch where we can read a value + pub fn get_oldest_epoch(&self) -> Epoch { + let oldest_height = match self.storage_read_past_height_limit { + Some(limit) if limit < self.get_last_block_height().0 => { + (self.get_last_block_height().0 - limit).into() + } + _ => BlockHeight(1), + }; + self.block + .pred_epochs + .get_epoch(oldest_height) + .unwrap_or_default() + } + + /// Get oldest epoch which has the valid signed nonce of the bridge pool + pub fn get_oldest_epoch_with_valid_nonce(&self) -> Result { + let nonce_key = bridge_pool::get_nonce_key(); + let (bytes, _) = self.read(&nonce_key)?; + let bytes = bytes.expect("Bridge pool nonce should exits"); + let current_nonce = + Uint::try_from_slice(&bytes).map_err(Error::BorshCodingError)?; + let (mut epoch, _) = self.get_last_epoch(); + // We don't need to check the older epochs because their Merkle tree + // snapshots have been already removed + let oldest_epoch = self.get_oldest_epoch(); + // Look up the last valid epoch which has the previous nonce of the + // current one. It has the previous nonce, but it was + // incremented during the epoch. + while 0 < epoch.0 && oldest_epoch <= epoch { + epoch = epoch.prev(); + let height = + match self.block.pred_epochs.get_start_height_of_epoch(epoch) { + Some(h) => h, + None => continue, + }; + let (bytes, _) = self.read_with_height(&nonce_key, height)?; + let bytes = bytes.expect("Bridge pool nonce should exits"); + let nonce = Uint::try_from_slice(&bytes) + .map_err(Error::BorshCodingError)?; + if nonce < current_nonce { + break; + } + } + Ok(epoch) + } + /// Check it the given transaction's hash is already present in storage pub fn has_replay_protection_entry(&self, hash: &Hash) -> Result { self.db.has_replay_protection_entry(hash) @@ -1394,6 +1454,12 @@ mod tests { minimum_gas_price: BTreeMap::default(), }; parameters.init_storage(&mut wl_storage).unwrap(); + // Initialize pred_epochs to the current height + wl_storage + .storage + .block + .pred_epochs + .new_epoch(wl_storage.storage.block.height); let epoch_before = wl_storage.storage.last_epoch; assert_eq!(epoch_before, wl_storage.storage.block.epoch); diff --git a/core/src/lib.rs b/core/src/lib.rs index a4db54712b..cbc9588201 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -12,7 +12,7 @@ pub mod ledger; pub mod proto; pub mod types; -pub use {ibc, ibc_proto, tendermint, tendermint_proto}; +pub use {ibc, tendermint, tendermint_proto}; // A handy macro for tests #[cfg(test)] diff --git a/core/src/proto/types.rs b/core/src/proto/types.rs index 97c16f1b1d..ba90b4936f 100644 --- a/core/src/proto/types.rs +++ b/core/src/proto/types.rs @@ -507,7 +507,7 @@ impl Signature { // vector instead of a map assert!( secret_keys.keys().cloned().eq(0..(secret_keys.len() as u8)), - "secret keys must be enumerateed when signer address is absent" + "secret keys must be enumerated when signer address is absent" ); Signer::PubKeys(secret_keys.values().map(RefTo::ref_to).collect()) }; @@ -1573,9 +1573,15 @@ impl Tx { let hashes = vec![self.raw_header_hash()]; self.protocol_filter(); + let secret_keys = if signer.is_some() { + account_public_keys_map.index_secret_keys(keypairs) + } else { + (0..).zip(keypairs.into_iter()).collect() + }; + self.add_section(Section::Signature(Signature::new( hashes, - account_public_keys_map.index_secret_keys(keypairs), + secret_keys, signer, ))); self diff --git a/core/src/types/address.rs b/core/src/types/address.rs index 2543fc7f54..73a03f8e3a 100644 --- a/core/src/types/address.rs +++ b/core/src/types/address.rs @@ -14,7 +14,7 @@ use data_encoding::HEXUPPER; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; -use crate::ibc::Signer; +use crate::ibc::primitives::Signer; use crate::impl_display_and_from_str_via_format; use crate::types::ethereum_events::EthAddress; use crate::types::ibc::IbcTokenHash; @@ -282,6 +282,16 @@ impl Address { } } } + + /// If the address established? + pub fn is_established(&self) -> bool { + matches!(self, Address::Established(_)) + } + + /// If the address implicit? + pub fn is_implicit(&self) -> bool { + matches!(self, Address::Implicit(_)) + } } impl string_encoding::Format for Address { diff --git a/core/src/types/chain.rs b/core/src/types/chain.rs index 2b22a13812..2c7c815a14 100644 --- a/core/src/types/chain.rs +++ b/core/src/types/chain.rs @@ -10,9 +10,8 @@ use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use thiserror::Error; -/// The length of the chain ID string. Tendermint's MAX_LENGTH is 50, and ibc-rs -/// would append a maximum of 21 characters. -pub const CHAIN_ID_LENGTH: usize = 29; +/// The length of the chain ID string +pub const CHAIN_ID_LENGTH: usize = 30; /// The maximum length of chain ID prefix pub const CHAIN_ID_PREFIX_MAX_LEN: usize = 19; /// Separator between chain ID prefix and the generated hash @@ -174,7 +173,7 @@ impl ProposalBytes { } /// Release default chain ID. Must be [`CHAIN_ID_LENGTH`] long. -pub const DEFAULT_CHAIN_ID: &str = "namada-internal.00000000000-0"; +pub const DEFAULT_CHAIN_ID: &str = "namada-internal.00000000000000"; /// Chain ID #[derive( @@ -208,10 +207,10 @@ impl ChainId { let mut hasher = Sha256::new(); hasher.update(genesis_bytes); // less `1` for chain ID prefix separator char - let width = CHAIN_ID_LENGTH - 3 - prefix.len(); + let width = CHAIN_ID_LENGTH - 1 - prefix.len(); // lowercase hex of the first `width` chars of the hash let hash = format!("{:.width$x}", hasher.finalize(), width = width,); - let raw = format!("{}{}{}-0", prefix, CHAIN_ID_PREFIX_SEP, hash); + let raw = format!("{}{}{}", prefix, CHAIN_ID_PREFIX_SEP, hash); ChainId(raw) } @@ -227,10 +226,10 @@ impl ChainId { let mut hasher = Sha256::new(); hasher.update(genesis_bytes); // less `1` for chain ID prefix separator char - let width = CHAIN_ID_LENGTH - 3 - prefix.len(); + let width = CHAIN_ID_LENGTH - 1 - prefix.len(); // lowercase hex of the first `width` chars of the hash let expected_hash = - format!("{:.width$x}-0", hasher.finalize(), width = width,); + format!("{:.width$x}", hasher.finalize(), width = width,); if hash != expected_hash { errors.push(ChainIdValidationError::InvalidHash( expected_hash, diff --git a/core/src/types/dec.rs b/core/src/types/dec.rs index 406144a0df..3a77b991e8 100644 --- a/core/src/types/dec.rs +++ b/core/src/types/dec.rs @@ -478,6 +478,21 @@ impl Debug for Dec { } } +/// Helpers for testing. +#[cfg(any(test, feature = "testing"))] +pub mod testing { + use proptest::prelude::*; + + use super::*; + + /// Generate an arbitrary non-negative `Dec` + pub fn arb_non_negative_dec() -> impl Strategy { + (any::(), 0_u8..POS_DECIMAL_PRECISION).prop_map( + |(mantissa, scale)| Dec::new(mantissa.into(), scale).unwrap(), + ) + } +} + #[cfg(test)] mod test_dec { use super::*; diff --git a/core/src/types/ibc.rs b/core/src/types/ibc.rs index 9490f1efdc..2f04e11709 100644 --- a/core/src/types/ibc.rs +++ b/core/src/types/ibc.rs @@ -11,8 +11,8 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; use super::address::HASH_LEN; -use crate::ibc::applications::transfer::{Memo, PrefixedDenom, TracePath}; -use crate::ibc::core::events::{ +use crate::ibc::apps::transfer::types::{Memo, PrefixedDenom, TracePath}; +use crate::ibc::core::handler::types::events::{ Error as IbcEventError, IbcEvent as RawIbcEvent, }; use crate::tendermint::abci::Event as AbciEvent; diff --git a/core/src/types/storage.rs b/core/src/types/storage.rs index f5f3ceea55..e16318568e 100644 --- a/core/src/types/storage.rs +++ b/core/src/types/storage.rs @@ -162,9 +162,9 @@ impl BlockResults { } } -/// Height of a block, i.e. the level. +/// Height of a block, i.e. the level. The `default` is the +/// [`BlockHeight::sentinel`] value, which doesn't correspond to any block. #[derive( - Default, Clone, Copy, BorshSerialize, @@ -181,6 +181,12 @@ impl BlockResults { )] pub struct BlockHeight(pub u64); +impl Default for BlockHeight { + fn default() -> Self { + Self::sentinel() + } +} + impl Display for BlockHeight { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) @@ -288,6 +294,17 @@ impl TryFrom for BlockHeight { } } impl BlockHeight { + /// The first block height 1. + pub const fn first() -> Self { + Self(1) + } + + /// A sentinel value block height 0 may be used before any block is + /// committed or in queries to read from the latest committed block. + pub const fn sentinel() -> Self { + Self(0) + } + /// Get the height of the next block pub fn next_height(&self) -> BlockHeight { BlockHeight(self.0 + 1) @@ -1175,6 +1192,7 @@ impl Mul for Epoch { #[derive( Clone, Debug, + Default, PartialEq, Eq, PartialOrd, @@ -1189,16 +1207,6 @@ pub struct Epochs { pub first_block_heights: Vec, } -impl Default for Epochs { - /// Initialize predecessor epochs, assuming starting on the epoch 0 and - /// block height 0. - fn default() -> Self { - Self { - first_block_heights: vec![BlockHeight::default()], - } - } -} - impl Epochs { /// Record start of a new epoch at the given block height pub fn new_epoch(&mut self, block_height: BlockHeight) { @@ -1641,11 +1649,13 @@ mod tests { #[test] fn test_predecessor_epochs_and_heights() { - let mut epochs = Epochs::default(); + let mut epochs = Epochs { + first_block_heights: vec![BlockHeight::first()], + }; println!("epochs {:#?}", epochs); assert_eq!( epochs.get_start_height_of_epoch(Epoch(0)), - Some(BlockHeight(0)) + Some(BlockHeight(1)) ); assert_eq!(epochs.get_epoch(BlockHeight(0)), Some(Epoch(0))); @@ -1657,14 +1667,15 @@ mod tests { Some(BlockHeight(10)) ); assert_eq!(epochs.get_epoch(BlockHeight(0)), Some(Epoch(0))); + assert_eq!(epochs.get_epoch_start_height(BlockHeight(0)), None); assert_eq!( - epochs.get_epoch_start_height(BlockHeight(0)), - Some(BlockHeight(0)) + epochs.get_epoch_start_height(BlockHeight(1)), + Some(BlockHeight(1)) ); assert_eq!(epochs.get_epoch(BlockHeight(9)), Some(Epoch(0))); assert_eq!( epochs.get_epoch_start_height(BlockHeight(9)), - Some(BlockHeight(0)) + Some(BlockHeight(1)) ); assert_eq!(epochs.get_epoch(BlockHeight(10)), Some(Epoch(1))); assert_eq!( diff --git a/core/src/types/token.rs b/core/src/types/token.rs index 5c319b7da6..2becc07151 100644 --- a/core/src/types/token.rs +++ b/core/src/types/token.rs @@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; use super::dec::POS_DECIMAL_PRECISION; -use crate::ibc::applications::transfer::Amount as IbcAmount; +use crate::ibc::apps::transfer::types::Amount as IbcAmount; use crate::ledger::storage as ledger_storage; use crate::ledger::storage_api::token::read_denom; use crate::ledger::storage_api::{self, StorageRead, StorageWrite}; diff --git a/core/src/types/transaction/pos.rs b/core/src/types/transaction/pos.rs index bec1a066e8..f44be68d85 100644 --- a/core/src/types/transaction/pos.rs +++ b/core/src/types/transaction/pos.rs @@ -5,11 +5,10 @@ use serde::{Deserialize, Serialize}; use crate::types::address::Address; use crate::types::dec::Dec; -use crate::types::hash::Hash; use crate::types::key::{common, secp256k1}; use crate::types::token; -/// A tx data type to initialize a new validator account. +/// A tx data type to become a validator account. #[derive( Debug, Clone, @@ -20,13 +19,9 @@ use crate::types::token; Serialize, Deserialize, )] -pub struct InitValidator { - /// Public key to be written into the account's storage. This can be used - /// for signature verification of transactions for the newly created - /// account. - pub account_keys: Vec, - /// The minimum number of signatures needed - pub threshold: u8, +pub struct BecomeValidator { + /// Address of an account that will become a validator. + pub address: Address, /// A key to be used for signing blocks and votes on blocks. pub consensus_key: common::PublicKey, /// An Eth bridge governance public key @@ -49,8 +44,6 @@ pub struct InitValidator { pub website: Option, /// The validator's discord handle pub discord_handle: Option, - /// The VP code for validator account - pub validator_vp_code_hash: Hash, } /// A bond is a validator's self-bond or a delegation from non-validator to a diff --git a/encoding_spec/src/main.rs b/encoding_spec/src/main.rs index 4365fd4a01..be9efdc113 100644 --- a/encoding_spec/src/main.rs +++ b/encoding_spec/src/main.rs @@ -82,7 +82,7 @@ fn main() -> Result<(), Box> { let init_account_schema = schema_container_of::(); let init_validator_schema = - schema_container_of::(); + schema_container_of::(); let token_transfer_schema = schema_container_of::(); let update_account = schema_container_of::(); diff --git a/ethereum_bridge/src/oracle/config.rs b/ethereum_bridge/src/oracle/config.rs index b0718e81d9..33b66a34d7 100644 --- a/ethereum_bridge/src/oracle/config.rs +++ b/ethereum_bridge/src/oracle/config.rs @@ -14,6 +14,8 @@ pub struct Config { pub bridge_contract: EthAddress, /// The earliest Ethereum block from which events may be processed. pub start_block: ethereum_structs::BlockHeight, + /// The status of the Ethereum bridge (active / inactive) + pub active: bool, } // TODO: this production Default implementation is temporary, there should be no @@ -26,6 +28,7 @@ impl std::default::Default for Config { min_confirmations: unsafe { NonZeroU64::new_unchecked(100) }, bridge_contract: EthAddress([0; 20]), start_block: 0.into(), + active: true, } } } diff --git a/ethereum_bridge/src/protocol/transactions/ethereum_events/mod.rs b/ethereum_bridge/src/protocol/transactions/ethereum_events/mod.rs index 8b71bb26c4..e9ff768fa0 100644 --- a/ethereum_bridge/src/protocol/transactions/ethereum_events/mod.rs +++ b/ethereum_bridge/src/protocol/transactions/ethereum_events/mod.rs @@ -23,6 +23,7 @@ use super::ChangedKeys; use crate::protocol::transactions::utils; use crate::protocol::transactions::votes::update::NewVotes; use crate::protocol::transactions::votes::{self, calculate_new}; +use crate::storage::eth_bridge_queries::EthBridgeQueries; use crate::storage::vote_tallies::{self, Keys}; impl utils::GetVoters for &HashSet { @@ -63,7 +64,16 @@ where protocol transaction" ); - let updates = events.into_iter().map(Into::::into).collect(); + let updates = events + .into_iter() + .filter_map(|multisigned| { + // NB: discard events with outdated nonces + wl_storage + .ethbridge_queries() + .validate_eth_event_nonce(&multisigned.event) + .then(|| EthMsgUpdate::from(multisigned)) + }) + .collect(); let voting_powers = utils::get_voting_powers(wl_storage, &updates)?; @@ -862,4 +872,89 @@ mod tests { (_, Some(_)) => {} }); } + + /// Test that [`MultiSignedEthEvent`]s with outdated nonces do + /// not result in votes in storage. + #[test] + fn test_apply_derived_tx_outdated_nonce() -> Result<()> { + let (mut wl_storage, _) = test_utils::setup_default_storage(); + + let new_multisigned = |nonce: u64| { + let (validator, _) = test_utils::default_validator(); + let event = EthereumEvent::TransfersToNamada { + nonce: nonce.into(), + transfers: vec![TransferToNamada { + amount: Amount::from(100), + asset: DAI_ERC20_ETH_ADDRESS, + receiver: validator.clone(), + }], + }; + let signers = BTreeSet::from([(validator, BlockHeight(100))]); + ( + MultiSignedEthEvent { + event: event.clone(), + signers, + }, + event, + ) + }; + macro_rules! nonce_ok { + ($nonce:expr) => { + let (multisigned, event) = new_multisigned($nonce); + let tx_result = + apply_derived_tx(&mut wl_storage, vec![multisigned])?; + + let eth_msg_keys = vote_tallies::Keys::from(&event); + assert!( + tx_result.changed_keys.contains(ð_msg_keys.seen()), + "The Ethereum event should have been seen", + ); + assert_eq!( + wl_storage + .ethbridge_queries() + .get_next_nam_transfers_nonce(), + ($nonce + 1).into(), + "The transfers to Namada nonce should have been \ + incremented", + ); + }; + } + macro_rules! nonce_err { + ($nonce:expr) => { + let (multisigned, event) = new_multisigned($nonce); + let tx_result = + apply_derived_tx(&mut wl_storage, vec![multisigned])?; + + let eth_msg_keys = vote_tallies::Keys::from(&event); + assert!( + !tx_result.changed_keys.contains(ð_msg_keys.seen()), + "The Ethereum event should have been ignored", + ); + assert_eq!( + wl_storage + .ethbridge_queries() + .get_next_nam_transfers_nonce(), + NEXT_NONCE_TO_PROCESS.into(), + "The transfers to Namada nonce should not have changed", + ); + }; + } + + // update storage with valid events + const NEXT_NONCE_TO_PROCESS: u64 = 3; + for nonce in 0..NEXT_NONCE_TO_PROCESS { + nonce_ok!(nonce); + } + + // attempts to replay events with older nonces should + // result in the events getting ignored + for nonce in 0..NEXT_NONCE_TO_PROCESS { + nonce_err!(nonce); + } + + // process new valid event + nonce_ok!(NEXT_NONCE_TO_PROCESS); + + Ok(()) + } } diff --git a/ethereum_bridge/src/storage/eth_bridge_queries.rs b/ethereum_bridge/src/storage/eth_bridge_queries.rs index 62a326bf74..06cb1ed024 100644 --- a/ethereum_bridge/src/storage/eth_bridge_queries.rs +++ b/ethereum_bridge/src/storage/eth_bridge_queries.rs @@ -10,7 +10,7 @@ use namada_core::types::address::Address; use namada_core::types::eth_abi::Encode; use namada_core::types::eth_bridge_pool::PendingTransfer; use namada_core::types::ethereum_events::{ - EthAddress, GetEventNonce, TransferToEthereum, Uint, + EthAddress, EthereumEvent, GetEventNonce, TransferToEthereum, Uint, }; use namada_core::types::keccak::KeccakHash; use namada_core::types::storage::{BlockHeight, Epoch, Key as StorageKey}; @@ -40,14 +40,34 @@ pub enum SendValsetUpd { AtPrevHeight, } -#[derive(Debug, Clone, BorshDeserialize, BorshSerialize)] +#[derive( + Debug, + Clone, + BorshDeserialize, + BorshSerialize, + PartialEq, + Eq, + Hash, + Ord, + PartialOrd, +)] /// An enum indicating if the Ethereum bridge is enabled. pub enum EthBridgeStatus { Disabled, Enabled(EthBridgeEnabled), } -#[derive(Debug, Clone, BorshDeserialize, BorshSerialize)] +#[derive( + Debug, + Clone, + BorshDeserialize, + BorshSerialize, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, +)] /// Enum indicating if the bridge was initialized at genesis /// or a later epoch. pub enum EthBridgeEnabled { @@ -520,6 +540,53 @@ where .expect("Reading from storage should not fail") .zip(Some(pending_key)) } + + /// Valdidate an [`EthereumEvent`]'s nonce against the current + /// state of the ledger. + /// + /// # Event kinds + /// + /// In this section, we shall describe the checks perform for + /// each kind of relevant Ethereum event. + /// + /// ## Transfers to Ethereum + /// + /// We need to check if the nonce in the event corresponds to + /// the most recent bridge pool nonce. Unless the nonces match, + /// no state updates derived from the event should be applied. + /// In case the nonces are different, we reject the event, and + /// thus the inclusion of its container Ethereum events vote + /// extension. + /// + /// ## Transfers to Namada + /// + /// For a transfers to Namada event to be considered valid, + /// the nonce of this kind of event must not be lower than + /// the one stored in Namada. + pub fn validate_eth_event_nonce(&self, event: &EthereumEvent) -> bool { + match event { + EthereumEvent::TransfersToEthereum { + nonce: ext_nonce, .. + } => { + let current_bp_nonce = self.get_bridge_pool_nonce(); + if ¤t_bp_nonce != ext_nonce { + return false; + } + } + EthereumEvent::TransfersToNamada { + nonce: ext_nonce, .. + } => { + let next_nam_transfers_nonce = + self.get_next_nam_transfers_nonce(); + if &next_nam_transfers_nonce > ext_nonce { + return false; + } + } + // consider other ethereum event kinds valid + _ => {} + } + true + } } /// Number of tokens to mint after receiving a "transfer diff --git a/ethereum_bridge/src/test_utils.rs b/ethereum_bridge/src/test_utils.rs index 3552b27bf9..cdc33398ac 100644 --- a/ethereum_bridge/src/test_utils.rs +++ b/ethereum_bridge/src/test_utils.rs @@ -228,6 +228,12 @@ pub fn init_storage_with_validators( .write(&protocol_pk_key(validator), protocol_key) .expect("Test failed"); } + // Initialize pred_epochs to the current height + wl_storage + .storage + .block + .pred_epochs + .new_epoch(wl_storage.storage.block.height); wl_storage.commit_block().expect("Test failed"); wl_storage.storage.block.height += 1; @@ -270,20 +276,22 @@ pub fn append_validators_to_storage( let eth_cold_key = &keys.eth_gov.ref_to(); let eth_hot_key = &keys.eth_bridge.ref_to(); - become_validator(BecomeValidator { - storage: wl_storage, - params: ¶ms, - address: &validator, - consensus_key, - protocol_key, - eth_cold_key, - eth_hot_key, - current_epoch, - commission_rate: Dec::new(5, 2).unwrap(), - max_commission_rate_change: Dec::new(1, 2).unwrap(), - metadata: Default::default(), - offset_opt: Some(1), - }) + become_validator( + wl_storage, + BecomeValidator { + params: ¶ms, + address: &validator, + consensus_key, + protocol_key, + eth_cold_key, + eth_hot_key, + current_epoch, + commission_rate: Dec::new(5, 2).unwrap(), + max_commission_rate_change: Dec::new(1, 2).unwrap(), + metadata: Default::default(), + offset_opt: Some(1), + }, + ) .expect("Test failed"); credit_tokens(wl_storage, &staking_token, &validator, stake) .expect("Test failed"); diff --git a/genesis/README.md b/genesis/README.md index 894e3d602c..1aec869104 100644 --- a/genesis/README.md +++ b/genesis/README.md @@ -56,7 +56,7 @@ An unsigned `validator_account` tx example: ```toml [[validator_account]] alias = "validator-0" -vp = "vp_validator" +vp = "vp_user" commission_rate = "0.05" max_commission_rate_change = "0.01" net_address = "127.0.0.1:27656" diff --git a/genesis/localnet/README.md b/genesis/localnet/README.md index e14cfdfb61..f8c874956c 100644 --- a/genesis/localnet/README.md +++ b/genesis/localnet/README.md @@ -1,6 +1,6 @@ # Localnet genesis templates -This directory contains genesis templates for a local network with a single validator. The `src` directory contains generated pre-genesis wallet pre-loaded with unencrypted keys and a single validator `"validator-0" wallet that are being used in the templates. +This directory contains genesis templates for a local network with a single validator. The `src` directory contains generated pre-genesis wallet pre-loaded with unencrypted keys and a single validator `validator-0` wallet that are being used in the templates. If you're modifying any of the files here, you can run this to ensure that the changes are valid: @@ -10,7 +10,7 @@ cargo watch -x "test test_validate_localnet_genesis_templates" ## balances.toml -The pre-genesis balances wallet is located at [pre-genesis/wallet.toml](pre-genesis/wallet.toml) was used to setup the [balances.toml](balances.toml) and can be re-generated from the repo's root dir with: +The pre-genesis balances wallet is located at [pre-genesis/wallet.toml](pre-genesis/wallet.toml) and is used to setup the [balances.toml](balances.toml) and can be re-generated from the repo's root dir with: ```shell cargo run --bin namadaw -- --base-dir "genesis/localnet/src" key gen \ diff --git a/genesis/localnet/src/pre-genesis/validator-0/transactions.toml b/genesis/localnet/src/pre-genesis/validator-0/transactions.toml index bd03907dae..85c174edc2 100644 --- a/genesis/localnet/src/pre-genesis/validator-0/transactions.toml +++ b/genesis/localnet/src/pre-genesis/validator-0/transactions.toml @@ -1,34 +1,34 @@ [[validator_account]] alias = "validator-0" -vp = "vp_validator" +vp = "vp_user" commission_rate = "0.05" max_commission_rate_change = "0.01" email = "null@null.net" net_address = "127.0.0.1:27656" [validator_account.account_key] -pk = "tpknam1qzuaykg8nrmzuaefut39aaxl0gl66y62285cnwe37gq0a96qaf4qgp5yqtw" -authorization = "signam1qpcvzjdqkvhud9lez3exq3vy7dnp4kyjgsk92yx5cslwzjs0q9czx8ajxztx5pftx9hsf9w2shh6rt0uv6xeyu30ljqkrqj6hnrwn5gqfd9pwf" +pk = "tpknam1qpg2tsrplvhu3fd7z7tq5ztc2ne3s7e2ahjl2a2cddufrzdyr752g666ytj" +authorization = "signam1qzyc89wynvm4n7eq7jglv4d8upaxu38mkkktykjjtgqygmk4sq97ffxermz5wpur4rqr8gk6fze5uvc4u7q4qzqsr285gungdyhv2acgna2ltq" [validator_account.consensus_key] -pk = "tpknam1qpudpptwfh9u5mhvksrguyqk6wvyhus0kf2cs9qr0xuq9k4fepldgqv3ztq" -authorization = "signam1qpuhmvgl330cr3acugaddhn6q9xdw3577h3mv9yszau2smxmn7yvmn2yplfym4sk30r2hz943989sd68umu70e4wsk5q6j2gzzjfg4q0qjvz6f" +pk = "tpknam1qr9u5py97pdmcvnrxhzuuv79ydv5rw7r9z402sucwt6h0lvmmmwqy2wrweg" +authorization = "signam1qzt7ww0q00punp93jrvtkq62n4rk8y5d90tllmlkzr0z7urwfdkn7z8ttne92utwskl6ves4qp66r60tg2xqr568ranwfhcm0665wncqq4t5gx" [validator_account.protocol_key] -pk = "tpknam1qzxs6kchkustgjxld3xz0u3c8gfnkvda042vp06auk6zfrru5hhxqqvyxq6" -authorization = "signam1qztaxmfgncmv5jn9tak0au2ryzxwxrlhn2qyfx4fgewuv5p7jelpfpqe9mlp7y73vsw7r8hu509swj8mumgryswu38m7mvxn9asqn0cq7aqvjp" +pk = "tpknam1qrenhfdphzpszlr7fzand6qgmppge430g3a2lquqzhz64fkve5mq2hdfjaa" +authorization = "signam1qqeaqzj9fu0xsu7pvrkwla5asxde2wak7fslst0p79vxxydt40tzdj54js7dmjvqs2quygqqwup8z2cfffvm86ff8cud6gzel9g40ycw25wp5d" [validator_account.tendermint_node_key] -pk = "tpknam1qzckzn2rc4pr26e0clxajgcllasr6tke4yqrsu7wskw89uka29zykram505" -authorization = "signam1qrgvyj39ljlequl20hx2mz9wpuyjl8lj826c0upy9agt4txuyyusuqkhdmm2aajglupssqcsx8nv62etua6vn0duzrucut4m74nmhscwy3knc3" +pk = "tpknam1qpgcgptcjl22hl2te2uqnp33aqjmvfaud3a3f3sgtxezg7uu5rsv6d2flr3" +authorization = "signam1qrq7x5e7svuddy8dyr3xpcdt6a07u6sky0n5qnv5z757g33t5zm3jnnh9uhh073g05n8jx8rmdu5r2djhwh6few6u329u9cld4c7ynsw2592h8" [validator_account.eth_hot_key] -pk = "tpknam1qyp8znkp023autwqh2cy6c6vhnz8vsm4p6w9ngpnnamqk6dj5w6ktxqjnd0qj" -authorization = "signam1q9fd4nkz8df5ajh6jrsn6mrt0apvn4266walr8pnczl0xtn847u6usdemslvusseerhrd6hftse8zfch5tlpmqp4y9xz3563mu0d26hnqq942mt2" +pk = "tpknam1qypnh98mexms8edj8rcwu0cayx0459p39dwzsffxrr394mf4cse707qcctyrx" +authorization = "signam1qyrvwveg76nrz2ppnsl0em82gcl4p90cqw8eadyzcvk59e2dx0jqja8ln9l9j79sxzhhh5gdggduz78vtthzj5nzs0xvpwhjuh3hymapqq07qxzm" [validator_account.eth_cold_key] -pk = "tpknam1qyp4aw7a07f4ltuq3f0c4sgyq3kzgh6z40w8jt40wl7uhfj7e3m3u9qr792xg" -authorization = "signam1qyqcc7wstsnuadu75jnwg8hxz34nglxj9h9yqyx2c4qqdpxw50ff60hu0swfj7xdkz34tgl9e50jlmzphkgtpw3gg0hsgp35lhsl6rmeqqq28kph" +pk = "tpknam1qypz8zr0w8lsz3s98vh4p974xuxeedpecj9s2l3326r3kdz4tc0snrcpnc8yv" +authorization = "signam1q992kq4ymfl6v8arc2s2tn0w7c4f48wx6fxry9qxv2qk8zvjan8q7j9rxg73cx0f5l56fy53x2jgwv7vy8jtxzucckdzgnxc5tpzajs4qq8r02r2" [[transfer]] token = "nam" @@ -41,4 +41,4 @@ signature = "signam1qz8ch7n6jp7g7hvnzkhmprhqc5umd0gatarlttm7gpcdx6g8hmgqffdq67fn source = "validator-0" validator = "validator-0" amount = "100000" -signature = "signam1qrd7wg2sdla73z7626r2ep8895d9ed4ljq37nz6kmy2rcm36yqjugw6vle7kl70l0d585t382s9vd28k2duwz0lu7ux0vua6aaarjssgdf46n2" +signature = "signam1qqukrz3js2pgzrne90u5f7y4mstrzvmzcq7eelml9m3lzrh9zwpf0vhgjq0rsw4ufj4ffdx8ew74uxkk4df649pg6qq5fgwyqa9mpfcyvskk67" diff --git a/genesis/localnet/src/pre-genesis/validator-0/validator-wallet.toml b/genesis/localnet/src/pre-genesis/validator-0/validator-wallet.toml index 4f3db8b8b0..2e0107b173 100644 --- a/genesis/localnet/src/pre-genesis/validator-0/validator-wallet.toml +++ b/genesis/localnet/src/pre-genesis/validator-0/validator-wallet.toml @@ -1,8 +1,8 @@ -account_key = "unencrypted:00eaa8829ff8932ffad86c4b0ad1ed2f2870c12ca49f03b50e4b34d360daa24268" -consensus_key = "unencrypted:00aabd79879fce99cb528f92d8ea4593241dd49507ff456be52ca2aee98c728338" -eth_cold_key = "unencrypted:0181901af21f92e997c78c61337475d1975c8d29591601e36ace3952d7094d9447" -tendermint_node_key = "unencrypted:00afc7747d1e6d76293553864bbf482d061f1932f83b978b24ba4957dcfcda987c" +account_key = "unencrypted:0024204e13c51b26ed9b42c05647bc46b3821bb453e53d194962ede57ce5ec66ac" +consensus_key = "unencrypted:0037a44681b64d42497e2229516479f83e5344a7a30e8316bde45881a1ec745359" +eth_cold_key = "unencrypted:010d34fcb42383f0babe7c86203f07bf4134f0756a630eb07923f21c90cc068602" +tendermint_node_key = "unencrypted:002f2e94bb5834e18433343345baf47b2b5d4e1ef4d46ba0f876d3d2c89d831419" [validator_keys] -protocol_keypair = "ED25519_SK_PREFIX00b0da066a528a0e1221e6453f9d10143b07a675a250c66603e8a7e98bdbb8cf19" -eth_bridge_keypair = "SECP256K1_SK_PREFIX0133deb418af6af5c62aecbde3dc3a0ff62ea20c0c8e33cf703d0f5e35248e5ab1" +protocol_keypair = "ED25519_SK_PREFIX00610677d4c52ab8ca5e8abe7dfb40246a271a03069fded6099763cbc41e04df02" +eth_bridge_keypair = "SECP256K1_SK_PREFIX01a81af251a711382d6b649a44b36ac5d4f41106f356e1f2fb33c001e91ffaa169" diff --git a/genesis/localnet/transactions.toml b/genesis/localnet/transactions.toml index cafe123854..0662c5147b 100644 --- a/genesis/localnet/transactions.toml +++ b/genesis/localnet/transactions.toml @@ -7,35 +7,35 @@ [[validator_account]] alias = "validator-0" -vp = "vp_validator" +vp = "vp_user" commission_rate = "0.05" max_commission_rate_change = "0.01" email = "null@null.net" net_address = "127.0.0.1:27656" [validator_account.account_key] -pk = "tpknam1qzuaykg8nrmzuaefut39aaxl0gl66y62285cnwe37gq0a96qaf4qgp5yqtw" -authorization = "signam1qpcvzjdqkvhud9lez3exq3vy7dnp4kyjgsk92yx5cslwzjs0q9czx8ajxztx5pftx9hsf9w2shh6rt0uv6xeyu30ljqkrqj6hnrwn5gqfd9pwf" +pk = "tpknam1qpg2tsrplvhu3fd7z7tq5ztc2ne3s7e2ahjl2a2cddufrzdyr752g666ytj" +authorization = "signam1qzyc89wynvm4n7eq7jglv4d8upaxu38mkkktykjjtgqygmk4sq97ffxermz5wpur4rqr8gk6fze5uvc4u7q4qzqsr285gungdyhv2acgna2ltq" [validator_account.consensus_key] -pk = "tpknam1qpudpptwfh9u5mhvksrguyqk6wvyhus0kf2cs9qr0xuq9k4fepldgqv3ztq" -authorization = "signam1qpuhmvgl330cr3acugaddhn6q9xdw3577h3mv9yszau2smxmn7yvmn2yplfym4sk30r2hz943989sd68umu70e4wsk5q6j2gzzjfg4q0qjvz6f" +pk = "tpknam1qr9u5py97pdmcvnrxhzuuv79ydv5rw7r9z402sucwt6h0lvmmmwqy2wrweg" +authorization = "signam1qzt7ww0q00punp93jrvtkq62n4rk8y5d90tllmlkzr0z7urwfdkn7z8ttne92utwskl6ves4qp66r60tg2xqr568ranwfhcm0665wncqq4t5gx" [validator_account.protocol_key] -pk = "tpknam1qzxs6kchkustgjxld3xz0u3c8gfnkvda042vp06auk6zfrru5hhxqqvyxq6" -authorization = "signam1qztaxmfgncmv5jn9tak0au2ryzxwxrlhn2qyfx4fgewuv5p7jelpfpqe9mlp7y73vsw7r8hu509swj8mumgryswu38m7mvxn9asqn0cq7aqvjp" +pk = "tpknam1qrenhfdphzpszlr7fzand6qgmppge430g3a2lquqzhz64fkve5mq2hdfjaa" +authorization = "signam1qqeaqzj9fu0xsu7pvrkwla5asxde2wak7fslst0p79vxxydt40tzdj54js7dmjvqs2quygqqwup8z2cfffvm86ff8cud6gzel9g40ycw25wp5d" [validator_account.tendermint_node_key] -pk = "tpknam1qzckzn2rc4pr26e0clxajgcllasr6tke4yqrsu7wskw89uka29zykram505" -authorization = "signam1qrgvyj39ljlequl20hx2mz9wpuyjl8lj826c0upy9agt4txuyyusuqkhdmm2aajglupssqcsx8nv62etua6vn0duzrucut4m74nmhscwy3knc3" +pk = "tpknam1qpgcgptcjl22hl2te2uqnp33aqjmvfaud3a3f3sgtxezg7uu5rsv6d2flr3" +authorization = "signam1qrq7x5e7svuddy8dyr3xpcdt6a07u6sky0n5qnv5z757g33t5zm3jnnh9uhh073g05n8jx8rmdu5r2djhwh6few6u329u9cld4c7ynsw2592h8" [validator_account.eth_hot_key] -pk = "tpknam1qyp8znkp023autwqh2cy6c6vhnz8vsm4p6w9ngpnnamqk6dj5w6ktxqjnd0qj" -authorization = "signam1q9fd4nkz8df5ajh6jrsn6mrt0apvn4266walr8pnczl0xtn847u6usdemslvusseerhrd6hftse8zfch5tlpmqp4y9xz3563mu0d26hnqq942mt2" +pk = "tpknam1qypnh98mexms8edj8rcwu0cayx0459p39dwzsffxrr394mf4cse707qcctyrx" +authorization = "signam1qyrvwveg76nrz2ppnsl0em82gcl4p90cqw8eadyzcvk59e2dx0jqja8ln9l9j79sxzhhh5gdggduz78vtthzj5nzs0xvpwhjuh3hymapqq07qxzm" [validator_account.eth_cold_key] -pk = "tpknam1qyp4aw7a07f4ltuq3f0c4sgyq3kzgh6z40w8jt40wl7uhfj7e3m3u9qr792xg" -authorization = "signam1qyqcc7wstsnuadu75jnwg8hxz34nglxj9h9yqyx2c4qqdpxw50ff60hu0swfj7xdkz34tgl9e50jlmzphkgtpw3gg0hsgp35lhsl6rmeqqq28kph" +pk = "tpknam1qypz8zr0w8lsz3s98vh4p974xuxeedpecj9s2l3326r3kdz4tc0snrcpnc8yv" +authorization = "signam1q992kq4ymfl6v8arc2s2tn0w7c4f48wx6fxry9qxv2qk8zvjan8q7j9rxg73cx0f5l56fy53x2jgwv7vy8jtxzucckdzgnxc5tpzajs4qq8r02r2" [[transfer]] token = "nam" @@ -48,7 +48,8 @@ signature = "signam1qz8ch7n6jp7g7hvnzkhmprhqc5umd0gatarlttm7gpcdx6g8hmgqffdq67fn source = "validator-0" validator = "validator-0" amount = "100000" -signature = "signam1qrd7wg2sdla73z7626r2ep8895d9ed4ljq37nz6kmy2rcm36yqjugw6vle7kl70l0d585t382s9vd28k2duwz0lu7ux0vua6aaarjssgdf46n2" +signature = "signam1qqukrz3js2pgzrne90u5f7y4mstrzvmzcq7eelml9m3lzrh9zwpf0vhgjq0rsw4ufj4ffdx8ew74uxkk4df649pg6qq5fgwyqa9mpfcyvskk67" + # 2. diff --git a/genesis/localnet/validity-predicates.toml b/genesis/localnet/validity-predicates.toml index 907e7c522b..0216abe982 100644 --- a/genesis/localnet/validity-predicates.toml +++ b/genesis/localnet/validity-predicates.toml @@ -8,7 +8,3 @@ filename = "vp_implicit.wasm" [wasm.vp_user] filename = "vp_user.wasm" -# Default validator VP -[wasm.vp_validator] -filename = "vp_validator.wasm" - diff --git a/genesis/starter/validity-predicates.toml b/genesis/starter/validity-predicates.toml index 9c9e76fc83..242cc1c5c5 100644 --- a/genesis/starter/validity-predicates.toml +++ b/genesis/starter/validity-predicates.toml @@ -8,10 +8,6 @@ filename = "vp_implicit.wasm" [wasm.vp_user] filename = "vp_user.wasm" -# Default validator VP -[wasm.vp_validator] -filename = "vp_validator.wasm" - # Token VP [wasm.vp_token] filename = "vp_token.wasm" diff --git a/proof_of_stake/src/lib.rs b/proof_of_stake/src/lib.rs index 5aa6fb6f07..9b902e2ba0 100644 --- a/proof_of_stake/src/lib.rs +++ b/proof_of_stake/src/lib.rs @@ -316,7 +316,7 @@ where } /// Copies the validator sets into all epochs up through the pipeline epoch at -/// genesis. Also computes the total +/// genesis. pub fn copy_genesis_validator_sets( storage: &mut S, params: &OwnedPosParams, @@ -335,7 +335,6 @@ where current_epoch, epoch, )?; - // compute_and_store_total_consensus_stake(storage, epoch)?; } Ok(()) } @@ -1019,8 +1018,6 @@ where let tokens_pre = read_validator_stake(storage, params, validator, epoch)?; - // tracing::debug!("VALIDATOR STAKE BEFORE UPDATE: {}", tokens_pre); - let tokens_post = tokens_pre .change() .checked_add(&token_change) @@ -1548,7 +1545,6 @@ where S: StorageRead, { let handle = validator_set_positions_handle(); - // handle.get_position(storage, &epoch, validator, params) handle.get_data_handler().at(&epoch).get(storage, validator) } @@ -2714,9 +2710,7 @@ where } /// Arguments to [`become_validator`]. -pub struct BecomeValidator<'a, S> { - /// Storage implementation. - pub storage: &'a mut S, +pub struct BecomeValidator<'a> { /// Proof-of-stake parameters. pub params: &'a PosParams, /// The validator's address. @@ -2743,13 +2737,13 @@ pub struct BecomeValidator<'a, S> { /// Initialize data for a new validator. pub fn become_validator( - args: BecomeValidator<'_, S>, + storage: &mut S, + args: BecomeValidator<'_>, ) -> storage_api::Result<()> where S: StorageRead + StorageWrite, { let BecomeValidator { - storage, params, address, consensus_key, @@ -2764,6 +2758,28 @@ where } = args; let offset = offset_opt.unwrap_or(params.pipeline_len); + if !address.is_established() { + return Err(storage_api::Error::new_const( + "The given address {address} is not established. Only an \ + established address can become a validator.", + )); + } + + if is_validator(storage, address)? { + return Err(storage_api::Error::new_const( + "The given address is already a validator", + )); + } + + // If the address is not yet a validator, it cannot have self-bonds, but it + // may have delegations. + if has_bonds(storage, address)? { + return Err(storage_api::Error::new_const( + "The given address has delegations and therefore cannot become a \ + validator. Unbond first.", + )); + } + // This will fail if the key is already being used try_insert_consensus_key(storage, consensus_key)?; @@ -3301,6 +3317,9 @@ where if !amounts.is_empty() { let slashes = find_validator_slashes(storage, &bond_id.validator)?; + let redelegated_bonded = + delegator_redelegated_bonds_handle(&bond_id.source) + .at(&bond_id.validator); // Apply slashes for (&ep, amounts) in amounts.iter_mut() { @@ -3318,7 +3337,32 @@ where .cloned() .collect::>(); - *amount = apply_list_slashes(¶ms, &list_slashes, *amount); + let slash_epoch_filter = + |e: Epoch| e + params.slash_processing_epoch_offset() <= ep; + + let redelegated_bonds = + redelegated_bonded.at(&start).collect_map(storage)?; + + let result_fold = fold_and_slash_redelegated_bonds( + storage, + ¶ms, + &redelegated_bonds, + start, + &list_slashes, + slash_epoch_filter, + ); + + let total_not_redelegated = + *amount - result_fold.total_redelegated; + + let after_not_redelegated = apply_list_slashes( + ¶ms, + &list_slashes, + total_not_redelegated, + ); + + *amount = + after_not_redelegated + result_fold.total_after_slashing; } } } @@ -3623,6 +3667,20 @@ where Ok(delegations) } +/// Find if the given source address has any bonds. +pub fn has_bonds(storage: &S, source: &Address) -> storage_api::Result +where + S: StorageRead, +{ + let max_epoch = Epoch(u64::MAX); + let delegations = find_delegations(storage, source, &max_epoch)?; + Ok(!delegations + .values() + .cloned() + .sum::() + .is_zero()) +} + /// Find PoS slashes applied to a validator, if any pub fn find_validator_slashes( storage: &S, @@ -4438,7 +4496,11 @@ where Ok(()) } -/// Process slashes NEW +/// Process enqueued slashes that were discovered earlier. This function is +/// called upon a new epoch. The final slash rate considering according to the +/// cubic slashing rate is computed. Then, each slash is recorded in storage +/// along with its computed rate, and stake is deducted from the affected +/// validators. pub fn process_slashes( storage: &mut S, current_epoch: Epoch, @@ -5825,20 +5887,22 @@ pub mod test_utils { metadata, } in validators { - become_validator(BecomeValidator { + become_validator( storage, - params, - address: &address, - consensus_key: &consensus_key, - protocol_key: &protocol_key, - eth_cold_key: ð_cold_key, - eth_hot_key: ð_hot_key, - current_epoch, - commission_rate, - max_commission_rate_change, - metadata, - offset_opt: Some(0), - })?; + BecomeValidator { + params, + address: &address, + consensus_key: &consensus_key, + protocol_key: &protocol_key, + eth_cold_key: ð_cold_key, + eth_hot_key: ð_hot_key, + current_epoch, + commission_rate, + max_commission_rate_change, + metadata, + offset_opt: Some(0), + }, + )?; // Credit token amount to be bonded to the validator address so it // can be bonded let staking_token = staking_token_address(storage); @@ -6061,29 +6125,25 @@ where Ok(()) } -/// Claim rewards -pub fn claim_reward_tokens( - storage: &mut S, - source: Option<&Address>, +/// Compute the current available rewards amount due only to existing bonds. +/// This does not include pending rewards held in the rewards counter due to +/// unbonds and redelegations. +pub fn compute_current_rewards_from_bonds( + storage: &S, + source: &Address, validator: &Address, current_epoch: Epoch, ) -> storage_api::Result where - S: StorageRead + StorageWrite, + S: StorageRead, { - tracing::debug!("Claiming rewards in epoch {current_epoch}"); - - let rewards_products = validator_rewards_products_handle(validator); - let source = source.cloned().unwrap_or_else(|| validator.clone()); - tracing::debug!("Source {} --> Validator {}", source, validator); - if current_epoch == Epoch::default() { // Nothing to claim in the first epoch return Ok(token::Amount::zero()); } let last_claim_epoch = - get_last_reward_claim_epoch(storage, &source, validator)?; + get_last_reward_claim_epoch(storage, source, validator)?; if let Some(last_epoch) = last_claim_epoch { if last_epoch == current_epoch { // Already claimed in this epoch @@ -6109,6 +6169,8 @@ where claim_start, claim_end, )?; + + let rewards_products = validator_rewards_products_handle(validator); for (ep, bond_amount) in bond_amounts { debug_assert!(ep >= claim_start); debug_assert!(ep <= claim_end); @@ -6117,6 +6179,32 @@ where reward_tokens += reward; } + Ok(reward_tokens) +} + +/// Claim available rewards, triggering an immediate transfer of tokens from the +/// PoS account to the source address. +pub fn claim_reward_tokens( + storage: &mut S, + source: Option<&Address>, + validator: &Address, + current_epoch: Epoch, +) -> storage_api::Result +where + S: StorageRead + StorageWrite, +{ + tracing::debug!("Claiming rewards in epoch {current_epoch}"); + + let source = source.cloned().unwrap_or_else(|| validator.clone()); + tracing::debug!("Source {} --> Validator {}", source, validator); + + let mut reward_tokens = compute_current_rewards_from_bonds( + storage, + &source, + validator, + current_epoch, + )?; + // Add reward tokens tallied during previous withdrawals reward_tokens += take_rewards_from_counter(storage, &source, validator)?; @@ -6130,6 +6218,30 @@ where Ok(reward_tokens) } +/// Query the amount of available reward tokens for a given bond. +pub fn query_reward_tokens( + storage: &S, + source: Option<&Address>, + validator: &Address, + current_epoch: Epoch, +) -> storage_api::Result +where + S: StorageRead, +{ + let source = source.cloned().unwrap_or_else(|| validator.clone()); + let rewards_from_bonds = compute_current_rewards_from_bonds( + storage, + &source, + validator, + current_epoch, + )?; + + let rewards_from_counter = + read_rewards_counter(storage, &source, validator)?; + + Ok(rewards_from_bonds + rewards_from_counter) +} + /// Get the last epoch in which rewards were claimed from storage, if any pub fn get_last_reward_claim_epoch( storage: &S, @@ -6156,6 +6268,19 @@ where storage.write(&key, epoch) } +/// Read the current token value in the rewards counter. +fn read_rewards_counter( + storage: &S, + source: &Address, + validator: &Address, +) -> storage_api::Result +where + S: StorageRead, +{ + let key = rewards_counter_key(source, validator); + Ok(storage.read::(&key)?.unwrap_or_default()) +} + /// Add tokens to a rewards counter. fn add_rewards_to_counter( storage: &mut S, diff --git a/proof_of_stake/src/rewards.rs b/proof_of_stake/src/rewards.rs index a42d40b67c..449c8a9867 100644 --- a/proof_of_stake/src/rewards.rs +++ b/proof_of_stake/src/rewards.rs @@ -94,7 +94,8 @@ impl PosRewardsCalculator { .total_stake .checked_mul(2.into()) .expect("Amount overflow while computing minimum required votes") - + (3u64 - 1u64)) + .checked_add((3u64 - 1u64).into()) + .expect("Amount overflow while computing minimum required votes")) / 3u64 } } diff --git a/proof_of_stake/src/tests.rs b/proof_of_stake/src/tests.rs index 6beedb955d..0398a7b3d7 100644 --- a/proof_of_stake/src/tests.rs +++ b/proof_of_stake/src/tests.rs @@ -1027,7 +1027,25 @@ fn test_become_validator_aux( ); assert!(!is_validator(&s, &new_validator).unwrap()); - // Initialize the validator account + // Credit the `new_validator` account + let staking_token = staking_token_address(&s); + let amount = token::Amount::from_uint(100_500_000, 0).unwrap(); + // Credit twice the amount as we're gonna bond it in delegation first, then + // self-bond + credit_tokens(&mut s, &staking_token, &new_validator, amount * 2).unwrap(); + + // Add a delegation from `new_validator` to `genesis_validator` + let genesis_validator = &validators.first().unwrap().address; + bond_tokens( + &mut s, + Some(&new_validator), + genesis_validator, + amount, + current_epoch, + None, + ) + .unwrap(); + let consensus_key = new_validator_consensus_key.to_public(); let protocol_sk = common_sk_from_simple_seed(0); let protocol_key = protocol_sk.to_public(); @@ -1037,21 +1055,57 @@ fn test_become_validator_aux( let eth_cold_key = key::common::PublicKey::Secp256k1( key::testing::gen_keypair::().ref_to(), ); - become_validator(BecomeValidator { - storage: &mut s, - params: ¶ms, - address: &new_validator, - consensus_key: &consensus_key, - protocol_key: &protocol_key, - eth_cold_key: ð_cold_key, - eth_hot_key: ð_hot_key, + + // Try to become a validator - it should fail as there is a delegation + let result = become_validator( + &mut s, + BecomeValidator { + params: ¶ms, + address: &new_validator, + consensus_key: &consensus_key, + protocol_key: &protocol_key, + eth_cold_key: ð_cold_key, + eth_hot_key: ð_hot_key, + current_epoch, + commission_rate: Dec::new(5, 2).expect("Dec creation failed"), + max_commission_rate_change: Dec::new(5, 2) + .expect("Dec creation failed"), + metadata: Default::default(), + offset_opt: None, + }, + ); + assert!(result.is_err()); + assert!(!is_validator(&s, &new_validator).unwrap()); + + // Unbond the delegation + unbond_tokens( + &mut s, + Some(&new_validator), + genesis_validator, + amount, current_epoch, - commission_rate: Dec::new(5, 2).expect("Dec creation failed"), - max_commission_rate_change: Dec::new(5, 2) - .expect("Dec creation failed"), - metadata: Default::default(), - offset_opt: None, - }) + false, + ) + .unwrap(); + + // Try to become a validator account again - it should pass now + become_validator( + &mut s, + BecomeValidator { + params: ¶ms, + address: &new_validator, + consensus_key: &consensus_key, + protocol_key: &protocol_key, + eth_cold_key: ð_cold_key, + eth_hot_key: ð_hot_key, + current_epoch, + commission_rate: Dec::new(5, 2).expect("Dec creation failed"), + max_commission_rate_change: Dec::new(5, 2) + .expect("Dec creation failed"), + metadata: Default::default(), + offset_opt: None, + }, + ) .unwrap(); assert!(is_validator(&s, &new_validator).unwrap()); @@ -1066,9 +1120,6 @@ fn test_become_validator_aux( current_epoch = advance_epoch(&mut s, ¶ms); // Self-bond to the new validator - let staking_token = staking_token_address(&s); - let amount = token::Amount::from_uint(100_500_000, 0).unwrap(); - credit_tokens(&mut s, &staking_token, &new_validator, amount).unwrap(); bond_tokens(&mut s, None, &new_validator, amount, current_epoch, None) .unwrap(); diff --git a/proof_of_stake/src/tests/state_machine.rs b/proof_of_stake/src/tests/state_machine.rs index 9681c6f409..781d276105 100644 --- a/proof_of_stake/src/tests/state_machine.rs +++ b/proof_of_stake/src/tests/state_machine.rs @@ -264,20 +264,22 @@ impl StateMachineTest for ConcretePosState { tracing::debug!("\nCONCRETE Init validator"); let current_epoch = state.current_epoch(); - super::become_validator(super::BecomeValidator { - storage: &mut state.s, - params: ¶ms, - address: &address, - consensus_key: &consensus_key, - protocol_key: &protocol_key, - eth_cold_key: ð_cold_key, - eth_hot_key: ð_hot_key, - current_epoch, - commission_rate, - max_commission_rate_change, - metadata: Default::default(), - offset_opt: None, - }) + super::become_validator( + &mut state.s, + super::BecomeValidator { + params: ¶ms, + address: &address, + consensus_key: &consensus_key, + protocol_key: &protocol_key, + eth_cold_key: ð_cold_key, + eth_hot_key: ð_hot_key, + current_epoch, + commission_rate, + max_commission_rate_change, + metadata: Default::default(), + offset_opt: None, + }, + ) .unwrap(); let params = read_pos_params(&state.s).unwrap(); diff --git a/proof_of_stake/src/tests/state_machine_v2.rs b/proof_of_stake/src/tests/state_machine_v2.rs index 70b0216d0b..cf59a59238 100644 --- a/proof_of_stake/src/tests/state_machine_v2.rs +++ b/proof_of_stake/src/tests/state_machine_v2.rs @@ -1992,20 +1992,22 @@ impl StateMachineTest for ConcretePosState { tracing::debug!("\nCONCRETE Init validator"); let current_epoch = state.current_epoch(); - super::become_validator(super::BecomeValidator { - storage: &mut state.s, - params: ¶ms, - address: &address, - consensus_key: &consensus_key, - protocol_key: &protocol_key, - eth_cold_key: ð_cold_key, - eth_hot_key: ð_hot_key, - current_epoch, - commission_rate, - max_commission_rate_change, - metadata: Default::default(), - offset_opt: None, - }) + super::become_validator( + &mut state.s, + super::BecomeValidator { + params: ¶ms, + address: &address, + consensus_key: &consensus_key, + protocol_key: &protocol_key, + eth_cold_key: ð_cold_key, + eth_hot_key: ð_hot_key, + current_epoch, + commission_rate, + max_commission_rate_change, + metadata: Default::default(), + offset_opt: None, + }, + ) .unwrap(); let params = read_pos_params(&state.s).unwrap(); diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 713f99e035..fbb6dda412 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -41,9 +41,7 @@ async-client = [ "async-trait", ] -ibc-mocks = [ - "namada_core/ibc-mocks", -] +async-send = [] # for integration tests and test utilies testing = [ diff --git a/sdk/src/args.rs b/sdk/src/args.rs index 3359c08ec4..395c789f81 100644 --- a/sdk/src/args.rs +++ b/sdk/src/args.rs @@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize}; use zeroize::Zeroizing; use crate::eth_bridge::bridge_pool; -use crate::ibc::core::ics24_host::identifier::{ChannelId, PortId}; +use crate::ibc::core::host::types::identifiers::{ChannelId, PortId}; use crate::signing::SigningTxData; use crate::{rpc, tx, Namada}; @@ -175,9 +175,9 @@ impl TxCustom { impl TxCustom { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { tx::build_custom(context, self).await @@ -281,9 +281,9 @@ impl TxTransfer { impl TxTransfer { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &mut self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { tx::build_transfer(context, self).await @@ -395,9 +395,9 @@ impl TxIbcTransfer { impl TxIbcTransfer { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { tx::build_ibc_transfer(context, self).await @@ -484,9 +484,9 @@ impl InitProposal { impl InitProposal { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { let current_epoch = rpc::query_epoch(context.client()).await?; @@ -641,9 +641,9 @@ impl VoteProposal { impl VoteProposal { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { let current_epoch = rpc::query_epoch(context.client()).await?; @@ -714,15 +714,50 @@ impl TxInitAccount { impl TxInitAccount { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { tx::build_init_account(context, self).await } } +/// Transaction to initialize a new account +#[derive(Clone, Debug)] +pub struct TxBecomeValidator { + /// Common tx arguments + pub tx: Tx, + /// Address of an account that will become a validator. + pub address: C::Address, + /// Signature scheme + pub scheme: SchemeType, + /// Consensus key + pub consensus_key: Option, + /// Ethereum cold key + pub eth_cold_key: Option, + /// Ethereum hot key + pub eth_hot_key: Option, + /// Protocol key + pub protocol_key: Option, + /// Commission rate + pub commission_rate: Dec, + /// Maximum commission rate change + pub max_commission_rate_change: Dec, + /// The validator email + pub email: String, + /// The validator description + pub description: Option, + /// The validator website + pub website: Option, + /// The validator's discord handle + pub discord_handle: Option, + /// Path to the TX WASM code file + pub tx_code_path: PathBuf, + /// Don't encrypt the keypair + pub unsafe_dont_encrypt: bool, +} + /// Transaction to initialize a new account #[derive(Clone, Debug)] pub struct TxInitValidator { @@ -735,11 +770,11 @@ pub struct TxInitValidator { /// The account multisignature threshold pub threshold: Option, /// Consensus key - pub consensus_key: Option, + pub consensus_key: Option, /// Ethereum cold key - pub eth_cold_key: Option, + pub eth_cold_key: Option, /// Ethereum hot key - pub eth_hot_key: Option, + pub eth_hot_key: Option, /// Protocol key pub protocol_key: Option, /// Commission rate @@ -757,7 +792,9 @@ pub struct TxInitValidator { /// Path to the VP WASM code file pub validator_vp_code_path: PathBuf, /// Path to the TX WASM code file - pub tx_code_path: PathBuf, + pub tx_init_account_code_path: PathBuf, + /// Path to the TX WASM code file + pub tx_become_validator_code_path: PathBuf, /// Don't encrypt the keypair pub unsafe_dont_encrypt: bool, } @@ -832,9 +869,9 @@ impl TxUpdateAccount { impl TxUpdateAccount { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { tx::build_update_account(context, self).await @@ -910,9 +947,9 @@ impl Bond { impl Bond { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { tx::build_bond(context, self).await @@ -937,9 +974,9 @@ pub struct Unbond { impl Unbond { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<( crate::proto::Tx, SigningTxData, @@ -1010,9 +1047,9 @@ pub struct Redelegate { impl Redelegate { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData)> { tx::build_redelegation(context, self).await } @@ -1091,9 +1128,9 @@ impl RevealPk { impl RevealPk { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { tx::build_reveal_pk(context, &self.tx, &self.public_key).await @@ -1175,9 +1212,9 @@ impl Withdraw { impl Withdraw { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { tx::build_withdraw(context, self).await @@ -1212,9 +1249,9 @@ impl TxBuilder for ClaimRewards { impl ClaimRewards { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { tx::build_claim_rewards(context, self).await @@ -1345,9 +1382,9 @@ impl CommissionRateChange { impl CommissionRateChange { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { tx::build_validator_commission_change(context, self).await @@ -1362,7 +1399,7 @@ pub struct ConsensusKeyChange { /// Validator address (should be self) pub validator: C::Address, /// New consensus key - pub consensus_key: Option, + pub consensus_key: Option, /// Path to the TX WASM code file pub tx_code_path: PathBuf, } @@ -1404,9 +1441,9 @@ pub struct ConsensusKeyChange { // impl ConsensusKeyChange { // /// Build a transaction from this builder -// pub async fn build<'a>( +// pub async fn build( // &self, -// context: &impl Namada<'a>, +// context: &impl Namada, // ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, // Option)> { // tx::build_change_consensus_key(context, self).await @@ -1463,9 +1500,9 @@ impl MetaDataChange { impl MetaDataChange { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { tx::build_validator_metadata_change(context, self).await @@ -1519,9 +1556,9 @@ impl UpdateStewardCommission { impl UpdateStewardCommission { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { tx::build_update_steward_commission(context, self).await @@ -1568,9 +1605,9 @@ impl ResignSteward { impl ResignSteward { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { tx::build_resign_steward(context, self).await @@ -1617,9 +1654,9 @@ impl TxUnjailValidator { impl TxUnjailValidator { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { tx::build_unjail_validator(context, self).await @@ -1666,9 +1703,9 @@ impl TxDeactivateValidator { impl TxDeactivateValidator { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { tx::build_deactivate_validator(context, self).await @@ -1715,9 +1752,9 @@ impl TxReactivateValidator { impl TxReactivateValidator { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( &self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { tx::build_reactivate_validator(context, self).await @@ -1764,6 +1801,17 @@ pub struct QuerySlashes { pub validator: Option, } +/// Query PoS rewards +#[derive(Clone, Debug)] +pub struct QueryRewards { + /// Common query args + pub query: Query, + /// Address of the source + pub source: Option, + /// Address of the validator + pub validator: C::Address, +} + /// Query PoS delegations #[derive(Clone, Debug)] pub struct QueryDelegations { @@ -1817,7 +1865,7 @@ pub struct Tx { /// The amount being payed (for gas unit) to include the transaction pub fee_amount: Option, /// The fee payer signing key - pub wrapper_fee_payer: Option, + pub wrapper_fee_payer: Option, /// The token in which the fee is being paid pub fee_token: C::Address, /// The optional spending key for fee unshielding @@ -1832,13 +1880,11 @@ pub struct Tx { /// The chain id for which the transaction is intended pub chain_id: Option, /// Sign the tx with the key for the given alias from your wallet - pub signing_keys: Vec, + pub signing_keys: Vec, /// List of signatures to attach to the transaction pub signatures: Vec, /// Path to the TX WASM code file to reveal PK pub tx_reveal_code_path: PathBuf, - /// Sign the tx with the public key for the given alias from your wallet - pub verification_key: Option, /// Password to decrypt key pub password: Option>, /// Use device to sign the transaction @@ -1918,7 +1964,7 @@ pub trait TxBuilder: Sized { }) } /// The fee payer signing key - fn wrapper_fee_payer(self, wrapper_fee_payer: C::Keypair) -> Self { + fn wrapper_fee_payer(self, wrapper_fee_payer: C::PublicKey) -> Self { self.tx(|x| Tx { wrapper_fee_payer: Some(wrapper_fee_payer), ..x @@ -1962,7 +2008,7 @@ pub trait TxBuilder: Sized { }) } /// Sign the tx with the key for the given alias from your wallet - fn signing_keys(self, signing_keys: Vec) -> Self { + fn signing_keys(self, signing_keys: Vec) -> Self { self.tx(|x| Tx { signing_keys, ..x }) } /// List of signatures to attach to the transaction @@ -1976,13 +2022,6 @@ pub trait TxBuilder: Sized { ..x }) } - /// Sign the tx with the public key for the given alias from your wallet - fn verification_key(self, verification_key: C::PublicKey) -> Self { - self.tx(|x| Tx { - verification_key: Some(verification_key), - ..x - }) - } /// Password to decrypt key fn password(self, password: Zeroizing) -> Self { self.tx(|x| Tx { @@ -2288,9 +2327,9 @@ impl EthereumBridgePool { impl EthereumBridgePool { /// Build a transaction from this builder - pub async fn build<'a>( + pub async fn build( self, - context: &impl Namada<'a>, + context: &impl Namada, ) -> crate::error::Result<(crate::proto::Tx, SigningTxData, Option)> { bridge_pool::build_bridge_pool_tx(context, self).await diff --git a/sdk/src/eth_bridge/bridge_pool.rs b/sdk/src/eth_bridge/bridge_pool.rs index e682521987..639257fc70 100644 --- a/sdk/src/eth_bridge/bridge_pool.rs +++ b/sdk/src/eth_bridge/bridge_pool.rs @@ -42,12 +42,13 @@ use crate::rpc::{query_storage_value, query_wasm_code_hash, validate_amount}; use crate::signing::aux_signing_data; use crate::tx::prepare_tx; use crate::{ - args, display, display_line, edisplay_line, Namada, SigningTxData, + args, display, display_line, edisplay_line, MaybeSync, Namada, + SigningTxData, }; /// Craft a transaction that adds a transfer to the Ethereum bridge pool. pub async fn build_bridge_pool_tx( - context: &impl Namada<'_>, + context: &impl Namada, args::EthereumBridgePool { tx: tx_args, nut, @@ -113,7 +114,7 @@ pub async fn build_bridge_pool_tx( /// Perform client validation checks on a Bridge pool transfer. #[allow(clippy::too_many_arguments)] async fn validate_bridge_pool_tx( - context: &impl Namada<'_>, + context: &impl Namada, force: bool, nut: bool, asset: EthAddress, @@ -316,7 +317,7 @@ struct BridgePoolResponse<'pool> { /// Query the contents of the Ethereum bridge pool. /// Prints out a json payload. -pub async fn query_bridge_pool<'a>( +pub async fn query_bridge_pool( client: &(impl Client + Sync), io: &impl Io, ) -> Result, Error> { @@ -353,7 +354,7 @@ pub async fn query_bridge_pool<'a>( /// Query the contents of the Ethereum bridge pool that /// is covered by the latest signed root. /// Prints out a json payload. -pub async fn query_signed_bridge_pool<'a>( +pub async fn query_signed_bridge_pool( client: &(impl Client + Sync), io: &impl Io, ) -> Result, Error> { @@ -392,7 +393,7 @@ pub async fn query_signed_bridge_pool<'a>( /// backing each `TransferToEthereum` event. /// /// Prints a json payload. -pub async fn query_relay_progress<'a>( +pub async fn query_relay_progress( client: &(impl Client + Sync), io: &impl Io, ) -> Result<(), Error> { @@ -417,9 +418,9 @@ pub async fn query_relay_progress<'a>( /// Internal methdod to construct a proof that a set of transfers are in the /// bridge pool. -async fn construct_bridge_pool_proof<'a>( +async fn construct_bridge_pool_proof( client: &(impl Client + Sync), - io: &impl Io, + io: &(impl Io + MaybeSync), args: GenBridgePoolProofReq<'_, '_>, ) -> Result { let in_progress = RPC @@ -513,9 +514,9 @@ struct BridgePoolProofResponse { /// Construct a merkle proof of a batch of transfers in /// the bridge pool and return it to the user (as opposed /// to relaying it to ethereum). -pub async fn construct_proof<'a>( +pub async fn construct_proof( client: &(impl Client + Sync), - io: &impl Io, + io: &(impl Io + MaybeSync), args: args::BridgePoolProof, ) -> Result<(), Error> { let GenBridgePoolProofRsp { @@ -562,10 +563,10 @@ pub async fn construct_proof<'a>( } /// Relay a validator set update, signed off for a given epoch. -pub async fn relay_bridge_pool_proof<'a, E>( +pub async fn relay_bridge_pool_proof( eth_client: Arc, client: &(impl Client + Sync), - io: &impl Io, + io: &(impl Io + MaybeSync), args: args::RelayBridgePoolProof, ) -> Result<(), Error> where @@ -794,8 +795,8 @@ mod recommendations { /// Recommend the most economical batch of transfers to relay based /// on a conversion rate estimates from NAM to ETH and gas usage /// heuristics. - pub async fn recommend_batch<'a>( - context: &impl Namada<'a>, + pub async fn recommend_batch( + context: &impl Namada, args: args::RecommendBatch, ) -> Result<(), Error> { // get transfers that can already been relayed but are awaiting a quorum diff --git a/sdk/src/eth_bridge/validator_set.rs b/sdk/src/eth_bridge/validator_set.rs index 1b7a77466d..e92e5c545e 100644 --- a/sdk/src/eth_bridge/validator_set.rs +++ b/sdk/src/eth_bridge/validator_set.rs @@ -270,7 +270,7 @@ impl From> for RelayResult { /// Query an ABI encoding of the validator set to be installed /// at the given epoch, and its associated proof. -pub async fn query_validator_set_update_proof<'a>( +pub async fn query_validator_set_update_proof( client: &(impl Client + Sync), io: &impl Io, args: args::ValidatorSetProof, @@ -298,7 +298,7 @@ pub async fn query_validator_set_update_proof<'a>( } /// Query an ABI encoding of the Bridge validator set at a given epoch. -pub async fn query_bridge_validator_set<'a>( +pub async fn query_bridge_validator_set( client: &(impl Client + Sync), io: &impl Io, args: args::BridgeValidatorSet, @@ -326,7 +326,7 @@ pub async fn query_bridge_validator_set<'a>( } /// Query an ABI encoding of the Governance validator set at a given epoch. -pub async fn query_governnace_validator_set<'a>( +pub async fn query_governnace_validator_set( client: &(impl Client + Sync), io: &impl Io, args: args::GovernanceValidatorSet, diff --git a/sdk/src/events/log/dumb_queries.rs b/sdk/src/events/log/dumb_queries.rs index 44988fb0dc..8a639b5a1b 100644 --- a/sdk/src/events/log/dumb_queries.rs +++ b/sdk/src/events/log/dumb_queries.rs @@ -12,9 +12,10 @@ use namada_core::types::hash::Hash; use namada_core::types::storage::BlockHeight; use crate::events::{Event, EventType}; -use crate::ibc::core::ics04_channel::packet::Sequence; -use crate::ibc::core::ics24_host::identifier::{ChannelId, ClientId, PortId}; -use crate::ibc::Height as IbcHeight; +use crate::ibc::core::client::types::Height as IbcHeight; +use crate::ibc::core::host::types::identifiers::{ + ChannelId, ClientId, PortId, Sequence, +}; /// A [`QueryMatcher`] verifies if a Namada event matches a /// given Tendermint query. @@ -65,8 +66,9 @@ impl QueryMatcher { client_id: ClientId, consensus_height: BlockHeight, ) -> Self { - use crate::ibc::core::ics02_client::events::{ + use crate::ibc::core::client::types::events::{ CLIENT_ID_ATTRIBUTE_KEY, CONSENSUS_HEIGHTS_ATTRIBUTE_KEY, + UPDATE_CLIENT_EVENT, }; let mut attributes = HashMap::new(); @@ -79,7 +81,7 @@ impl QueryMatcher { .to_string(), ); Self { - event_type: EventType::Ibc("update_client".to_string()), + event_type: EventType::Ibc(UPDATE_CLIENT_EVENT.to_string()), attributes, } } diff --git a/sdk/src/io.rs b/sdk/src/io.rs index 248f6f91d9..7dae730b29 100644 --- a/sdk/src/io.rs +++ b/sdk/src/io.rs @@ -1,9 +1,11 @@ //! Traits for implementing IO handlers. This is to enable //! generic IO. The defaults are the obvious Rust native //! functions. +use crate::{MaybeSend, MaybeSync}; /// A trait that abstracts out I/O operations -#[async_trait::async_trait(?Send)] +#[cfg_attr(feature = "async-send", async_trait::async_trait)] +#[cfg_attr(not(feature = "async-send"), async_trait::async_trait(?Send))] pub trait Io { /// Print the given string fn print(&self, output: impl AsRef) { @@ -57,7 +59,10 @@ pub trait Io { } /// Display the given prompt and return the string input - async fn prompt(&self, question: impl AsRef) -> String { + async fn prompt( + &self, + question: impl AsRef + MaybeSync + MaybeSend, + ) -> String { #[cfg(not(target_family = "wasm"))] { prompt_aux( @@ -81,13 +86,15 @@ pub trait Io { /// Rust native I/O handling. pub struct StdIo; -#[async_trait::async_trait(?Send)] +#[cfg_attr(feature = "async-send", async_trait::async_trait)] +#[cfg_attr(not(feature = "async-send"), async_trait::async_trait(?Send))] impl Io for StdIo {} /// Ignores all I/O operations. pub struct NullIo; -#[async_trait::async_trait(?Send)] +#[cfg_attr(feature = "async-send", async_trait::async_trait)] +#[cfg_attr(not(feature = "async-send"), async_trait::async_trait(?Send))] impl Io for NullIo { fn print(&self, _output: impl AsRef) {} @@ -117,7 +124,10 @@ impl Io for NullIo { panic!("Unsupported operation") } - async fn prompt(&self, _question: impl AsRef) -> String { + async fn prompt( + &self, + _question: impl AsRef + MaybeSend + MaybeSync, + ) -> String { panic!("Unsupported operation") } } diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index f5c0ae37fa..8d667b7b31 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -1,9 +1,8 @@ extern crate alloc; -pub use namada_core::{ibc, ibc_proto, proto, tendermint, tendermint_proto}; +pub use namada_core::{ibc, proto, tendermint, tendermint_proto}; #[cfg(feature = "tendermint-rpc")] pub use tendermint_rpc; -use tx::{TX_INIT_ACCOUNT_WASM, VP_VALIDATOR_WASM}; pub use { bip39, borsh, masp_primitives, masp_proofs, namada_core as core, namada_proof_of_stake as proof_of_stake, zeroize, @@ -28,10 +27,15 @@ pub mod queries; pub mod wallet; use std::collections::HashSet; +#[cfg(feature = "async-send")] +pub use std::marker::Send as MaybeSend; +#[cfg(feature = "async-send")] +pub use std::marker::Sync as MaybeSync; use std::path::PathBuf; use std::str::FromStr; use args::{InputAmount, SdkTypes}; +use namada_core::ibc::core::host::types::identifiers::{ChannelId, PortId}; use namada_core::types::address::Address; use namada_core::types::dec::Dec; use namada_core::types::ethereum_events::EthAddress; @@ -42,7 +46,6 @@ use namada_core::types::token::NATIVE_MAX_DECIMAL_PLACES; use namada_core::types::transaction::GasLimit; use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; -use crate::ibc::core::ics24_host::identifier::{ChannelId, PortId}; use crate::io::Io; use crate::masp::{ShieldedContext, ShieldedUtils}; use crate::proto::Tx; @@ -52,56 +55,62 @@ use crate::rpc::{ use crate::signing::SigningTxData; use crate::token::DenominatedAmount; use crate::tx::{ - ProcessTxResponse, 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_PROPOSAL, - TX_INIT_VALIDATOR_WASM, 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, + 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_UPDATE_STEWARD_COMMISSION, TX_VOTE_PROPOSAL, TX_WITHDRAW_WASM, VP_USER_WASM, }; use crate::wallet::{Wallet, WalletIo, WalletStorage}; -#[async_trait::async_trait(?Send)] +#[cfg(not(feature = "async-send"))] +pub trait MaybeSync {} +#[cfg(not(feature = "async-send"))] +impl MaybeSync for T where T: ?Sized {} +#[cfg(not(feature = "async-send"))] +pub trait MaybeSend {} +#[cfg(not(feature = "async-send"))] +impl MaybeSend for T where T: ?Sized {} + +#[cfg_attr(feature = "async-send", async_trait::async_trait)] +#[cfg_attr(not(feature = "async-send"), async_trait::async_trait(?Send))] /// An interface for high-level interaction with the Namada SDK -pub trait Namada<'a>: Sized { +pub trait Namada: Sized + MaybeSync + MaybeSend { /// A client with async request dispatcher method - type Client: 'a + queries::Client + Sync; + type Client: queries::Client + MaybeSend + Sync; /// Captures the interactive parts of the wallet's functioning - type WalletUtils: 'a + WalletIo + WalletStorage; + type WalletUtils: WalletIo + WalletStorage + MaybeSend + MaybeSync; /// Abstracts platform specific details away from the logic of shielded pool /// operations. - type ShieldedUtils: 'a + ShieldedUtils; + type ShieldedUtils: ShieldedUtils + MaybeSend + MaybeSync; /// Captures the input/output streams used by this object - type Io: 'a + Io; + type Io: Io + MaybeSend + MaybeSync; /// Obtain the client for communicating with the ledger - fn client(&self) -> &'a Self::Client; + fn client(&self) -> &Self::Client; /// Obtain the input/output handle for this context - fn io(&self) -> &'a Self::Io; + fn io(&self) -> &Self::Io; /// Obtain read guard on the wallet - async fn wallet( - &self, - ) -> RwLockReadGuard<&'a mut Wallet>; + async fn wallet(&self) -> RwLockReadGuard>; /// Obtain write guard on the wallet - async fn wallet_mut( - &self, - ) -> RwLockWriteGuard<&'a mut Wallet>; + async fn wallet_mut(&self) -> RwLockWriteGuard>; /// Obtain read guard on the shielded context async fn shielded( &self, - ) -> RwLockReadGuard<&'a mut ShieldedContext>; + ) -> RwLockReadGuard>; /// Obtain write guard on the shielded context async fn shielded_mut( &self, - ) -> RwLockWriteGuard<&'a mut ShieldedContext>; + ) -> RwLockWriteGuard>; /// Return the native token fn native_token(&self) -> Address; @@ -129,7 +138,6 @@ pub trait Namada<'a>: Sized { signing_keys: vec![], signatures: vec![], tx_reveal_code_path: PathBuf::from(TX_REVEAL_PK), - verification_key: None, password: None, use_device: false, } @@ -349,6 +357,33 @@ pub trait Namada<'a>: Sized { } } + /// Make a TxBecomeValidator builder from the given minimum set of arguments + fn new_become_validator( + &self, + address: Address, + commission_rate: Dec, + max_commission_rate_change: Dec, + email: String, + ) -> args::TxBecomeValidator { + args::TxBecomeValidator { + address, + commission_rate, + max_commission_rate_change, + scheme: SchemeType::Ed25519, + consensus_key: None, + eth_cold_key: None, + eth_hot_key: None, + protocol_key: None, + unsafe_dont_encrypt: false, + tx_code_path: PathBuf::from(TX_BECOME_VALIDATOR_WASM), + tx: self.tx_builder(), + email, + description: None, + website: None, + discord_handle: None, + } + } + /// Make a TxInitValidator builder from the given minimum set of arguments fn new_init_validator( &self, @@ -366,9 +401,12 @@ pub trait Namada<'a>: Sized { eth_cold_key: None, eth_hot_key: None, protocol_key: None, - validator_vp_code_path: PathBuf::from(VP_VALIDATOR_WASM), + validator_vp_code_path: PathBuf::from(VP_USER_WASM), unsafe_dont_encrypt: false, - tx_code_path: PathBuf::from(TX_INIT_VALIDATOR_WASM), + tx_init_account_code_path: PathBuf::from(TX_INIT_ACCOUNT_WASM), + tx_become_validator_code_path: PathBuf::from( + TX_BECOME_VALIDATOR_WASM, + ), tx: self.tx_builder(), email, description: None, @@ -496,12 +534,18 @@ pub trait Namada<'a>: Sized { } /// Sign the given transaction using the given signing data - async fn sign>>( + async fn sign< + F: MaybeSend + + MaybeSync + + std::future::Future>, + >( &self, tx: &mut Tx, args: &args::Tx, signing_data: SigningTxData, - with: impl Fn(Tx, common::PublicKey, HashSet) -> F, + with: impl MaybeSend + + MaybeSync + + Fn(Tx, common::PublicKey, HashSet) -> F, ) -> crate::error::Result<()> { signing::sign_tx(self, args, tx, signing_data, with).await } @@ -537,28 +581,28 @@ pub trait Namada<'a>: Sized { } /// Provides convenience methods for common Namada interactions -pub struct NamadaImpl<'a, C, U, V, I> +pub struct NamadaImpl where - C: queries::Client + Sync, + C: queries::Client, U: WalletIo, V: ShieldedUtils, I: Io, { /// Used to send and receive messages from the ledger - pub client: &'a C, + pub client: C, /// Stores the addresses and keys required for ledger interactions - pub wallet: RwLock<&'a mut Wallet>, + pub wallet: RwLock>, /// Stores the current state of the shielded pool - pub shielded: RwLock<&'a mut ShieldedContext>, + pub shielded: RwLock>, /// Captures the input/output streams used by this object - pub io: &'a I, + pub io: I, /// The address of the native token native_token: Address, /// The default builder for a Tx prototype: args::Tx, } -impl<'a, C, U, V, I> NamadaImpl<'a, C, U, V, I> +impl NamadaImpl where C: queries::Client + Sync, U: WalletIo, @@ -567,10 +611,10 @@ where { /// Construct a new Namada context with the given native token address pub fn native_new( - client: &'a C, - wallet: &'a mut Wallet, - shielded: &'a mut ShieldedContext, - io: &'a I, + client: C, + wallet: Wallet, + shielded: ShieldedContext, + io: I, native_token: Address, ) -> Self { NamadaImpl { @@ -600,7 +644,6 @@ where signing_keys: vec![], signatures: vec![], tx_reveal_code_path: PathBuf::from(TX_REVEAL_PK), - verification_key: None, password: None, use_device: false, }, @@ -609,12 +652,12 @@ where /// Construct a new Namada context looking up the native token address pub async fn new( - client: &'a C, - wallet: &'a mut Wallet, - shielded: &'a mut ShieldedContext, - io: &'a I, - ) -> crate::error::Result> { - let native_token = query_native_token(client).await?; + client: C, + wallet: Wallet, + shielded: ShieldedContext, + io: I, + ) -> crate::error::Result> { + let native_token = query_native_token(&client).await?; Ok(NamadaImpl::native_new( client, wallet, @@ -625,13 +668,14 @@ where } } -#[async_trait::async_trait(?Send)] -impl<'a, C, U, V, I> Namada<'a> for NamadaImpl<'a, C, U, V, I> +#[cfg_attr(feature = "async-send", async_trait::async_trait)] +#[cfg_attr(not(feature = "async-send"), async_trait::async_trait(?Send))] +impl Namada for NamadaImpl where - C: queries::Client + Sync, - U: WalletIo + WalletStorage, - V: ShieldedUtils, - I: Io, + C: queries::Client + MaybeSend + Sync, + U: WalletIo + WalletStorage + MaybeSync + MaybeSend, + V: ShieldedUtils + MaybeSend + MaybeSync, + I: Io + MaybeSend + MaybeSync, { type Client = C; type Io = I; @@ -647,41 +691,37 @@ where self.native_token.clone() } - fn io(&self) -> &'a Self::Io { - self.io + fn io(&self) -> &Self::Io { + &self.io } - fn client(&self) -> &'a Self::Client { - self.client + fn client(&self) -> &Self::Client { + &self.client } - async fn wallet( - &self, - ) -> RwLockReadGuard<&'a mut Wallet> { + async fn wallet(&self) -> RwLockReadGuard> { self.wallet.read().await } - async fn wallet_mut( - &self, - ) -> RwLockWriteGuard<&'a mut Wallet> { + async fn wallet_mut(&self) -> RwLockWriteGuard> { self.wallet.write().await } async fn shielded( &self, - ) -> RwLockReadGuard<&'a mut ShieldedContext> { + ) -> RwLockReadGuard> { self.shielded.read().await } async fn shielded_mut( &self, - ) -> RwLockWriteGuard<&'a mut ShieldedContext> { + ) -> RwLockWriteGuard> { self.shielded.write().await } } /// Allow the prototypical Tx builder to be modified -impl<'a, C, U, V, I> args::TxBuilder for NamadaImpl<'a, C, U, V, I> +impl args::TxBuilder for NamadaImpl where C: queries::Client + Sync, U: WalletIo, diff --git a/sdk/src/masp.rs b/sdk/src/masp.rs index 68459688e0..8337d40a38 100644 --- a/sdk/src/masp.rs +++ b/sdk/src/masp.rs @@ -74,7 +74,7 @@ use crate::rpc::{query_conversion, query_storage_value}; use crate::tendermint_rpc::query::Query; use crate::tendermint_rpc::Order; use crate::tx::decode_component; -use crate::{display_line, edisplay_line, rpc, Namada}; +use crate::{display_line, edisplay_line, rpc, MaybeSend, MaybeSync, Namada}; /// Env var to point to a dir with MASP parameters. When not specified, /// the default OS specific path is used. @@ -394,13 +394,13 @@ pub trait ShieldedUtils: fn local_tx_prover(&self) -> LocalTxProver; /// Load up the currently saved ShieldedContext - async fn load( + async fn load( &self, ctx: &mut ShieldedContext, ) -> std::io::Result<()>; /// Save the given ShieldedContext for future loads - async fn save( + async fn save( &self, ctx: &ShieldedContext, ) -> std::io::Result<()>; @@ -619,7 +619,7 @@ impl Default for ShieldedContext { } } -impl ShieldedContext { +impl ShieldedContext { /// Try to load the last saved shielded context from the given context /// directory. If this fails, then leave the current context unchanged. pub async fn load(&mut self) -> std::io::Result<()> { @@ -1220,9 +1220,9 @@ impl ShieldedContext { /// of the specified asset type. Return the total value accumulated plus /// notes and the corresponding diversifiers/merkle paths that were used to /// achieve the total value. - pub async fn collect_unspent_notes<'a>( + pub async fn collect_unspent_notes( &mut self, - context: &impl Namada<'a>, + context: &impl Namada, vk: &ViewingKey, target: I128Sum, target_epoch: Epoch, @@ -1407,9 +1407,9 @@ impl ShieldedContext { /// the epoch of the transaction or even before, so exchange all these /// amounts to the epoch of the transaction in order to get the value that /// would have been displayed in the epoch of the transaction. - pub async fn compute_exchanged_pinned_balance<'a>( + pub async fn compute_exchanged_pinned_balance( &mut self, - context: &impl Namada<'a>, + context: &impl Namada, owner: PaymentAddress, viewing_key: &ViewingKey, ) -> Result<(MaspAmount, Epoch), Error> { @@ -1497,8 +1497,8 @@ impl ShieldedContext { /// UTXOs are sometimes used to make transactions balanced, but it is /// understood that transparent account changes are effected only by the /// amounts and signatures specified by the containing Transfer object. - pub async fn gen_shielded_transfer<'a>( - context: &impl Namada<'a>, + pub async fn gen_shielded_transfer( + context: &impl Namada, source: &TransferSource, target: &TransferTarget, token: &Address, @@ -2115,8 +2115,6 @@ pub mod fs { use std::fs::{File, OpenOptions}; use std::io::{Read, Write}; - use async_trait::async_trait; - use super::*; /// Shielded context file name @@ -2168,7 +2166,8 @@ pub mod fs { } } - #[async_trait(?Send)] + #[cfg_attr(feature = "async-send", async_trait::async_trait)] + #[cfg_attr(not(feature = "async-send"), async_trait::async_trait(?Send))] impl ShieldedUtils for FsShieldedUtils { fn local_tx_prover(&self) -> LocalTxProver { if let Ok(params_dir) = env::var(ENV_VAR_MASP_PARAMS_DIR) { @@ -2185,7 +2184,7 @@ pub mod fs { /// Try to load the last saved shielded context from the given context /// directory. If this fails, then leave the current context unchanged. - async fn load( + async fn load( &self, ctx: &mut ShieldedContext, ) -> std::io::Result<()> { @@ -2202,7 +2201,7 @@ pub mod fs { } /// Save this shielded context into its associated context directory - async fn save( + async fn save( &self, ctx: &ShieldedContext, ) -> std::io::Result<()> { diff --git a/sdk/src/queries/mod.rs b/sdk/src/queries/mod.rs index eaf6bc2dbf..354cd5b6d0 100644 --- a/sdk/src/queries/mod.rs +++ b/sdk/src/queries/mod.rs @@ -18,6 +18,7 @@ pub use self::shell::eth_bridge::{ Erc20FlowControl, GenBridgePoolProofReq, GenBridgePoolProofRsp, TransferToErcArgs, }; +use crate::{MaybeSend, MaybeSync}; #[macro_use] mod router; @@ -157,7 +158,7 @@ mod testing { #[cfg_attr(not(feature = "async-send"), async_trait::async_trait(?Send))] impl Client for TestClient where - RPC: Router + Sync, + RPC: Router + MaybeSync, { type Error = std::io::Error; @@ -257,7 +258,7 @@ pub trait Client { /// from `CheckTx`. async fn broadcast_tx_sync( &self, - tx: impl Into>, + tx: impl Into> + MaybeSend, ) -> Result { self.perform( diff --git a/sdk/src/queries/router.rs b/sdk/src/queries/router.rs index b632097738..c78c0a6fcd 100644 --- a/sdk/src/queries/router.rs +++ b/sdk/src/queries/router.rs @@ -830,7 +830,7 @@ macro_rules! router { /// You can expand the `handlers!` macro invocation with e.g.: /// ```shell -/// cargo expand ledger::queries::router::test_rpc_handlers --features "ibc-mocks, testing, wasm-runtime, tendermint-rpc" --tests --lib +/// cargo expand ledger::queries::router::test_rpc_handlers --features "testing, wasm-runtime, tendermint-rpc" --tests --lib /// ``` #[cfg(test)] mod test_rpc_handlers { @@ -959,7 +959,7 @@ mod test_rpc_handlers { /// You can expand the `router!` macro invocation with e.g.: /// ```shell -/// cargo expand ledger::queries::router::test_rpc --features "ibc-mocks, testing, wasm-runtime, tendermint-rpc" --tests --lib +/// cargo expand ledger::queries::router::test_rpc --features "testing, wasm-runtime, tendermint-rpc" --tests --lib /// ``` #[cfg(test)] mod test_rpc { diff --git a/sdk/src/queries/shell.rs b/sdk/src/queries/shell.rs index c8e907671f..23f7441cae 100644 --- a/sdk/src/queries/shell.rs +++ b/sdk/src/queries/shell.rs @@ -24,8 +24,9 @@ use namada_core::types::transaction::TxResult; use self::eth_bridge::{EthBridge, ETH_BRIDGE}; use crate::events::log::dumb_queries; use crate::events::{Event, EventType}; -use crate::ibc::core::ics04_channel::packet::Sequence; -use crate::ibc::core::ics24_host::identifier::{ChannelId, ClientId, PortId}; +use crate::ibc::core::host::types::identifiers::{ + ChannelId, ClientId, PortId, Sequence, +}; use crate::queries::types::{RequestCtx, RequestQuery}; use crate::queries::{require_latest_height, EncodedResponseQuery}; use crate::tendermint::merkle::proof::ProofOps; diff --git a/sdk/src/queries/vp/pos.rs b/sdk/src/queries/vp/pos.rs index 8a464179f1..9414379b9a 100644 --- a/sdk/src/queries/vp/pos.rs +++ b/sdk/src/queries/vp/pos.rs @@ -19,7 +19,7 @@ use namada_proof_of_stake::types::{ use namada_proof_of_stake::{ self, bond_amount, bond_handle, find_all_enqueued_slashes, find_all_slashes, find_delegation_validators, find_delegations, - read_all_validator_addresses, + query_reward_tokens, read_all_validator_addresses, read_below_capacity_validator_set_addresses_with_stake, read_consensus_validator_set_addresses_with_stake, read_pos_params, read_total_stake, read_validator_description, @@ -86,6 +86,9 @@ router! {POS, ( "bond" / [source: Address] / [validator: Address] / [epoch: opt Epoch] ) -> token::Amount = bond, + ( "rewards" / [validator: Address] / [source: opt Address] ) + -> token::Amount = rewards, + ( "bond_with_slashing" / [source: Address] / [validator: Address] / [epoch: opt Epoch] ) -> token::Amount = bond_with_slashing, @@ -113,6 +116,9 @@ router! {POS, ( "consensus_keys" ) -> BTreeSet = consensus_key_set, + ( "has_bonds" / [source: Address] ) + -> bool = has_bonds, + } /// Enriched bonds data with extra information calculated from the data queried @@ -498,6 +504,24 @@ where Ok(total) } +fn rewards( + ctx: RequestCtx<'_, D, H, V, T>, + validator: Address, + source: Option
, +) -> storage_api::Result +where + D: 'static + DB + for<'iter> DBIter<'iter> + Sync, + H: 'static + StorageHasher + Sync, +{ + let current_epoch = ctx.wl_storage.storage.last_epoch; + query_reward_tokens( + ctx.wl_storage, + source.as_ref(), + &validator, + current_epoch, + ) +} + fn bonds_and_unbonds( ctx: RequestCtx<'_, D, H, V, T>, source: Option
, @@ -597,6 +621,18 @@ where namada_proof_of_stake::get_consensus_key_set(ctx.wl_storage) } +/// Find if the given source address has any bonds. +fn has_bonds( + ctx: RequestCtx<'_, D, H, V, T>, + source: Address, +) -> storage_api::Result +where + D: 'static + DB + for<'iter> DBIter<'iter> + Sync, + H: 'static + StorageHasher + Sync, +{ + namada_proof_of_stake::has_bonds(ctx.wl_storage, &source) +} + /// Client-only methods for the router type are composed from router functions. #[cfg(any(test, feature = "async-client"))] pub mod client_only_methods { diff --git a/sdk/src/rpc.rs b/sdk/src/rpc.rs index 0d0d69a79b..19adb4d365 100644 --- a/sdk/src/rpc.rs +++ b/sdk/src/rpc.rs @@ -52,8 +52,8 @@ use crate::{display_line, edisplay_line, error, Namada}; /// /// If a response is not delivered until `deadline`, we exit the cli with an /// error. -pub async fn query_tx_status<'a>( - context: &impl Namada<'a>, +pub async fn query_tx_status( + context: &impl Namada, status: TxEventQuery<'_>, deadline: time::Instant, ) -> Result { @@ -213,6 +213,14 @@ pub async fn is_delegator_at( ) } +/// Find if the given source address has any bonds. +pub async fn has_bonds( + client: &C, + source: &Address, +) -> Result { + convert_response::(RPC.vp().pos().has_bonds(client, source).await) +} + /// Get the set of consensus keys registered in the network pub async fn get_consensus_keys( client: &C, @@ -276,8 +284,8 @@ pub async fn query_conversions( } /// Query a wasm code hash -pub async fn query_wasm_code_hash<'a>( - context: &impl Namada<'a>, +pub async fn query_wasm_code_hash( + context: &impl Namada, code_path: impl AsRef, ) -> Result { let hash_key = Key::wasm_hash(code_path.as_ref()); @@ -360,7 +368,7 @@ pub async fn query_storage_value_bytes( /// Query a range of storage values with a matching prefix and decode them with /// [`BorshDeserialize`]. Returns an iterator of the storage keys paired with /// their associated values. -pub async fn query_storage_prefix<'a, 'b, N: Namada<'a>, T>( +pub async fn query_storage_prefix<'a, 'b, N: Namada, T>( context: &'b N, key: &storage::Key, ) -> Result>, error::Error> @@ -464,7 +472,7 @@ pub async fn query_tx_events( } /// Dry run a transaction -pub async fn dry_run_tx<'a, N: Namada<'a>>( +pub async fn dry_run_tx( context: &N, tx_bytes: Vec, ) -> Result { @@ -842,8 +850,8 @@ pub async fn get_public_key_at( } /// Query a validator's unbonds for a given epoch -pub async fn query_and_print_unbonds<'a>( - context: &impl Namada<'a>, +pub async fn query_and_print_unbonds( + context: &impl Namada, source: &Address, validator: &Address, ) -> Result<(), error::Error> { @@ -982,7 +990,7 @@ pub async fn enriched_bonds_and_unbonds( } /// Get the correct representation of the amount given the token type. -pub async fn validate_amount<'a, N: Namada<'a>>( +pub async fn validate_amount( context: &N, amount: InputAmount, token: &Address, @@ -1043,7 +1051,7 @@ pub async fn validate_amount<'a, N: Namada<'a>>( } /// Wait for a first block and node to be synced. -pub async fn wait_until_node_is_synched<'a>( +pub async fn wait_until_node_is_synched( client: &(impl Client + Sync), io: &impl Io, ) -> Result<(), Error> { @@ -1140,7 +1148,7 @@ pub async fn format_denominated_amount( } /// Look up the IBC denomination from a IbcToken. -pub async fn query_ibc_denom<'a, N: Namada<'a>>( +pub async fn query_ibc_denom( context: &N, token: &Address, owner: Option<&Address>, diff --git a/sdk/src/signing.rs b/sdk/src/signing.rs index 6784be92ba..16bab7e02f 100644 --- a/sdk/src/signing.rs +++ b/sdk/src/signing.rs @@ -27,7 +27,7 @@ use namada_core::types::transaction::account::{InitAccount, UpdateAccount}; use namada_core::types::transaction::governance::{ InitProposalData, VoteProposalData, }; -use namada_core::types::transaction::pos::InitValidator; +use namada_core::types::transaction::pos::BecomeValidator; use namada_core::types::transaction::{pos, Fee}; use prost::Message; use rand::rngs::OsRng; @@ -41,20 +41,19 @@ use crate::core::ledger::governance::storage::vote::{ StorageProposalVote, VoteType, }; use crate::error::{EncodingError, Error, TxError}; -use crate::ibc::applications::transfer::msgs::transfer::MsgTransfer; -use crate::ibc_proto::google::protobuf::Any; +use crate::ibc::apps::transfer::types::msgs::transfer::MsgTransfer; +use crate::ibc::primitives::proto::Any; use crate::io::*; use crate::masp::make_asset_type; use crate::proto::{MaspBuilder, Section, Tx}; use crate::rpc::validate_amount; use crate::tx::{ - TX_BOND_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_INIT_VALIDATOR_WASM, TX_REACTIVATE_VALIDATOR_WASM, + TX_BECOME_VALIDATOR_WASM, TX_BOND_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_REVEAL_PK, TX_TRANSFER_WASM, TX_UNBOND_WASM, TX_UNJAIL_VALIDATOR_WASM, TX_UPDATE_ACCOUNT_WASM, TX_VOTE_PROPOSAL, TX_WITHDRAW_WASM, VP_USER_WASM, - VP_VALIDATOR_WASM, }; pub use crate::wallet::store::AddressVpType; use crate::wallet::{Wallet, WalletIo}; @@ -86,8 +85,8 @@ pub struct SigningTxData { /// for it from the wallet. If the keypair is encrypted but a password is not /// supplied, then it is interactively prompted. Errors if the key cannot be /// found or loaded. -pub async fn find_pk<'a>( - context: &impl Namada<'a>, +pub async fn find_pk( + context: &impl Namada, addr: &Address, ) -> Result { match addr { @@ -135,21 +134,6 @@ pub fn find_key_by_pk( // We already know the secret key corresponding to the MASP sentinal key Ok(masp_tx_key()) } else { - // Try to get the signer from the signing-keys argument - for signing_key in &args.signing_keys { - if signing_key.ref_to() == *public_key { - return Ok(signing_key.clone()); - } - } - // Try to get the signer from the wrapper-fee-payer argument - match &args.wrapper_fee_payer { - Some(wrapper_fee_payer) - if &wrapper_fee_payer.ref_to() == public_key => - { - return Ok(wrapper_fee_payer.clone()); - } - _ => {} - } // Otherwise we need to search the wallet for the secret key wallet .find_key_by_pk(public_key, args.password.clone()) @@ -167,17 +151,13 @@ pub fn find_key_by_pk( /// signer. Return the given signing key or public key of the given signer if /// possible. If no explicit signer given, use the `default`. If no `default` /// is given, an `Error` is returned. -pub async fn tx_signers<'a>( - context: &impl Namada<'a>, +pub async fn tx_signers( + context: &impl Namada, args: &args::Tx, default: Option
, ) -> Result, Error> { let signer = if !&args.signing_keys.is_empty() { - let public_keys = - args.signing_keys.iter().map(|key| key.ref_to()).collect(); - return Ok(public_keys); - } else if let Some(verification_key) = &args.verification_key { - return Ok(vec![verification_key.clone()]); + return Ok(args.signing_keys.clone()); } else { // Otherwise use the signer determined by the caller default @@ -226,8 +206,8 @@ pub async fn default_sign( /// hashes needed for monitoring the tx on chain. /// /// If it is a dry run, it is not put in a wrapper, but returned as is. -pub async fn sign_tx<'a, F: std::future::Future>>( - context: &impl Namada<'a>, +pub async fn sign_tx>>( + context: &impl Namada, args: &args::Tx, tx: &mut Tx, signing_data: SigningTxData, @@ -260,7 +240,7 @@ pub async fn sign_tx<'a, F: std::future::Future>>( if used_pubkeys.contains(public_key) { None } else { - match find_key_by_pk(*wallet, args, public_key) { + match find_key_by_pk(&mut wallet, args, public_key) { Ok(secret_key) => { used_pubkeys.insert(public_key.clone()); Some(secret_key) @@ -301,7 +281,7 @@ pub async fn sign_tx<'a, F: std::future::Future>>( // Lock the wallet just long enough to extract a key from it without // interfering with the sign closure call let mut wallet = context.wallet_mut().await; - find_key_by_pk(*wallet, args, &signing_data.fee_payer) + find_key_by_pk(&mut wallet, args, &signing_data.fee_payer) }; match key { Ok(fee_payer_keypair) => { @@ -321,8 +301,8 @@ pub async fn sign_tx<'a, F: std::future::Future>>( /// Return the necessary data regarding an account to be able to generate a /// multisignature section -pub async fn aux_signing_data<'a>( - context: &impl Namada<'a>, +pub async fn aux_signing_data( + context: &impl Namada, args: &args::Tx, owner: Option
, default_signer: Option
, @@ -368,7 +348,7 @@ pub async fn aux_signing_data<'a>( .to_public() } else { match &args.wrapper_fee_payer { - Some(keypair) => keypair.to_public(), + Some(keypair) => keypair.clone(), None => public_keys.get(0).ok_or(TxError::InvalidFeePayer)?.clone(), } }; @@ -390,8 +370,8 @@ pub async fn aux_signing_data<'a>( }) } -pub async fn init_validator_signing_data<'a>( - context: &impl Namada<'a>, +pub async fn init_validator_signing_data( + context: &impl Namada, args: &args::Tx, validator_keys: Vec, ) -> Result { @@ -413,7 +393,7 @@ pub async fn init_validator_signing_data<'a>( .to_public() } else { match &args.wrapper_fee_payer { - Some(keypair) => keypair.to_public(), + Some(keypair) => keypair.clone(), None => public_keys.get(0).ok_or(TxError::InvalidFeePayer)?.clone(), } }; @@ -450,7 +430,7 @@ pub struct TxSourcePostBalance { /// wrapper and its payload which is needed for monitoring its /// progress on chain. #[allow(clippy::too_many_arguments)] -pub async fn wrap_tx<'a, N: Namada<'a>>( +pub async fn wrap_tx( context: &N, tx: &mut Tx, args: &args::Tx, @@ -734,8 +714,8 @@ fn make_ledger_amount_addr( /// Adds a Ledger output line describing a given transaction amount and asset /// type -async fn make_ledger_amount_asset<'a>( - context: &impl Namada<'a>, +async fn make_ledger_amount_asset( + context: &impl Namada, tokens: &HashMap, output: &mut Vec, amount: u64, @@ -829,8 +809,8 @@ fn format_outputs(output: &mut Vec) { /// Adds a Ledger output for the sender and destination for transparent and MASP /// transactions -pub async fn make_ledger_masp_endpoints<'a>( - context: &impl Namada<'a>, +pub async fn make_ledger_masp_endpoints( + context: &impl Namada, tokens: &HashMap, output: &mut Vec, transfer: &Transfer, @@ -904,8 +884,8 @@ pub async fn make_ledger_masp_endpoints<'a>( /// Internal method used to generate transaction test vectors #[cfg(feature = "std")] -pub async fn generate_test_vector<'a>( - context: &impl Namada<'a>, +pub async fn generate_test_vector( + context: &impl Namada, tx: &Tx, ) -> Result<(), Error> { use std::env; @@ -1014,8 +994,8 @@ impl<'a> Display for LedgerProposalType<'a> { /// Converts the given transaction to the form that is displayed on the Ledger /// device -pub async fn to_ledger_vector<'a>( - context: &impl Namada<'a>, +pub async fn to_ledger_vector( + context: &impl Namada, tx: &Tx, ) -> Result { // To facilitate lookups of human-readable token names @@ -1067,8 +1047,6 @@ pub async fn to_ledger_vector<'a>( })?; let vp_code = if extra.tag == Some(VP_USER_WASM.to_string()) { "User".to_string() - } else if extra.tag == Some(VP_VALIDATOR_WASM.to_string()) { - "Validator".to_string() } else { HEXLOWER.encode(&extra.code.hash().0) }; @@ -1094,8 +1072,8 @@ pub async fn to_ledger_vector<'a>( format!("Threshold : {}", init_account.threshold), format!("VP type : {}", HEXLOWER.encode(&extra.code.hash().0)), ]); - } else if code_sec.tag == Some(TX_INIT_VALIDATOR_WASM.to_string()) { - let init_validator = InitValidator::try_from_slice( + } else if code_sec.tag == Some(TX_BECOME_VALIDATOR_WASM.to_string()) { + let init_validator = BecomeValidator::try_from_slice( &tx.data() .ok_or_else(|| Error::Other("Invalid Data".to_string()))?, ) @@ -1105,29 +1083,9 @@ pub async fn to_ledger_vector<'a>( tv.name = "Init_Validator_0".to_string(); - let extra = tx - .get_section(&init_validator.validator_vp_code_hash) - .and_then(|x| Section::extra_data_sec(x.as_ref())) - .ok_or_else(|| { - Error::Other("unable to load vp code".to_string()) - })?; - let vp_code = if extra.tag == Some(VP_USER_WASM.to_string()) { - "User".to_string() - } else if extra.tag == Some(VP_VALIDATOR_WASM.to_string()) { - "Validator".to_string() - } else { - HEXLOWER.encode(&extra.code.hash().0) - }; - tv.output.extend(vec!["Type : Init Validator".to_string()]); - tv.output.extend( - init_validator - .account_keys - .iter() - .map(|k| format!("Account key : {}", k)), - ); tv.output.extend(vec![ - format!("Threshold : {}", init_validator.threshold), + format!("Address : {}", init_validator.address), format!("Consensus key : {}", init_validator.consensus_key), format!("Ethereum cold key : {}", init_validator.eth_cold_key), format!("Ethereum hot key : {}", init_validator.eth_hot_key), @@ -1149,16 +1107,9 @@ pub async fn to_ledger_vector<'a>( tv.output .push(format!("Discord handle : {}", discord_handle)); } - tv.output.push(format!("Validator VP type : {}", vp_code)); - tv.output_expert.extend( - init_validator - .account_keys - .iter() - .map(|k| format!("Account key : {}", k)), - ); tv.output_expert.extend(vec![ - format!("Threshold : {}", init_validator.threshold), + format!("Address : {}", init_validator.address), format!("Consensus key : {}", init_validator.consensus_key), format!("Ethereum cold key : {}", init_validator.eth_cold_key), format!("Ethereum hot key : {}", init_validator.eth_hot_key), @@ -1181,10 +1132,6 @@ pub async fn to_ledger_vector<'a>( tv.output_expert .push(format!("Discord handle : {}", discord_handle)); } - tv.output_expert.push(format!( - "Validator VP type : {}", - HEXLOWER.encode(&extra.code.hash().0) - )); } else if code_sec.tag == Some(TX_INIT_PROPOSAL.to_string()) { let init_proposal_data = InitProposalData::try_from_slice( &tx.data() @@ -1314,8 +1261,6 @@ pub async fn to_ledger_vector<'a>( })?; let vp_code = if extra.tag == Some(VP_USER_WASM.to_string()) { "User".to_string() - } else if extra.tag == Some(VP_VALIDATOR_WASM.to_string()) { - "Validator".to_string() } else { HEXLOWER.encode(&extra.code.hash().0) }; diff --git a/sdk/src/tx.rs b/sdk/src/tx.rs index 9378615890..d9c2e2b31d 100644 --- a/sdk/src/tx.rs +++ b/sdk/src/tx.rs @@ -16,13 +16,13 @@ use masp_primitives::transaction::components::transparent::fees::{ InputView as TransparentInputView, OutputView as TransparentOutputView, }; use masp_primitives::transaction::components::I128Sum; -use namada_core::ibc::applications::transfer::msgs::transfer::MsgTransfer; -use namada_core::ibc::applications::transfer::packet::PacketData; -use namada_core::ibc::applications::transfer::PrefixedCoin; -use namada_core::ibc::core::ics04_channel::timeout::TimeoutHeight; -use namada_core::ibc::core::timestamp::Timestamp as IbcTimestamp; -use namada_core::ibc::core::Msg; -use namada_core::ibc::Height as IbcHeight; +use namada_core::ibc::apps::transfer::types::msgs::transfer::MsgTransfer; +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::core::client::types::Height as IbcHeight; +use namada_core::ibc::core::host::types::identifiers::{ChannelId, PortId}; +use namada_core::ibc::primitives::{Msg, Timestamp as IbcTimestamp}; use namada_core::ledger::governance::cli::onchain::{ DefaultProposal, OnChainProposal, PgfFundingProposal, PgfStewardProposal, ProposalVote, @@ -53,7 +53,6 @@ use namada_proof_of_stake::types::{CommissionPair, ValidatorState}; use crate::args::{self, InputAmount}; use crate::control_flow::time; use crate::error::{EncodingError, Error, QueryError, Result, TxError}; -use crate::ibc::core::ics24_host::identifier::{ChannelId, PortId}; use crate::io::Io; use crate::masp::TransferErr::Build; use crate::masp::{make_asset_type, ShieldedContext, ShieldedTransfer}; @@ -70,8 +69,8 @@ use crate::{display_line, edisplay_line, Namada}; /// Initialize account transaction WASM pub const TX_INIT_ACCOUNT_WASM: &str = "tx_init_account.wasm"; -/// Initialize validator transaction WASM path -pub const TX_INIT_VALIDATOR_WASM: &str = "tx_init_validator.wasm"; +/// Become validator transaction WASM path +pub const TX_BECOME_VALIDATOR_WASM: &str = "tx_become_validator.wasm"; /// Unjail validator transaction WASM path pub const TX_UNJAIL_VALIDATOR_WASM: &str = "tx_unjail_validator.wasm"; /// Deactivate validator transaction WASM path @@ -92,8 +91,6 @@ pub const TX_TRANSFER_WASM: &str = "tx_transfer.wasm"; pub const TX_IBC_WASM: &str = "tx_ibc.wasm"; /// User validity predicate WASM path pub const VP_USER_WASM: &str = "vp_user.wasm"; -/// Validator validity predicate WASM path -pub const VP_VALIDATOR_WASM: &str = "vp_validator.wasm"; /// Bond WASM path pub const TX_BOND_WASM: &str = "tx_bond.wasm"; /// Unbond WASM path @@ -173,8 +170,8 @@ pub fn dump_tx(io: &IO, args: &args::Tx, tx: Tx) { /// Prepare a transaction for signing and submission by adding a wrapper header /// to it. #[allow(clippy::too_many_arguments)] -pub async fn prepare_tx<'a>( - context: &impl Namada<'a>, +pub async fn prepare_tx( + context: &impl Namada, args: &args::Tx, tx: &mut Tx, fee_payer: common::PublicKey, @@ -192,8 +189,8 @@ pub async fn prepare_tx<'a>( /// Submit transaction and wait for result. Returns a list of addresses /// initialized in the transaction if any. In dry run, this is always empty. -pub async fn process_tx<'a>( - context: &impl Namada<'a>, +pub async fn process_tx( + context: &impl Namada, args: &args::Tx, tx: Tx, ) -> Result { @@ -266,8 +263,8 @@ pub async fn has_revealed_pk( } /// Submit transaction to reveal the given public key -pub async fn build_reveal_pk<'a>( - context: &impl Namada<'a>, +pub async fn build_reveal_pk( + context: &impl Namada, args: &args::Tx, public_key: &common::PublicKey, ) -> Result<(Tx, SigningTxData, Option)> { @@ -292,8 +289,8 @@ pub async fn build_reveal_pk<'a>( /// the tx has been successfully included into the mempool of a node /// /// In the case of errors in any of those stages, an error message is returned -pub async fn broadcast_tx<'a>( - context: &impl Namada<'a>, +pub async fn broadcast_tx( + context: &impl Namada, to_broadcast: &TxBroadcastData, ) -> Result { let (tx, wrapper_tx_hash, decrypted_tx_hash) = match to_broadcast { @@ -355,8 +352,8 @@ pub async fn broadcast_tx<'a>( /// 3. The decrypted payload of the tx has been included on the blockchain. /// /// In the case of errors in any of those stages, an error message is returned -pub async fn submit_tx<'a>( - context: &impl Namada<'a>, +pub async fn submit_tx( + context: &impl Namada, to_broadcast: TxBroadcastData, ) -> Result { let (_, wrapper_hash, decrypted_hash) = match &to_broadcast { @@ -446,7 +443,7 @@ pub fn decode_component( } /// Save accounts initialized from a tx into the wallet, if any. -pub async fn save_initialized_accounts<'a, N: Namada<'a>>( +pub async fn save_initialized_accounts( context: &N, args: &args::Tx, initialized_accounts: Vec
, @@ -506,8 +503,8 @@ pub async fn save_initialized_accounts<'a, N: Namada<'a>>( } /// Submit validator comission rate change -pub async fn build_validator_commission_change<'a>( - context: &impl Namada<'a>, +pub async fn build_validator_commission_change( + context: &impl Namada, args::CommissionRateChange { tx: tx_args, validator, @@ -618,8 +615,8 @@ pub async fn build_validator_commission_change<'a>( } /// Submit validator metadata change -pub async fn build_validator_metadata_change<'a>( - context: &impl Namada<'a>, +pub async fn build_validator_metadata_change( + context: &impl Namada, args::MetaDataChange { tx: tx_args, validator, @@ -747,8 +744,8 @@ pub async fn build_validator_metadata_change<'a>( } /// Craft transaction to update a steward commission -pub async fn build_update_steward_commission<'a>( - context: &impl Namada<'a>, +pub async fn build_update_steward_commission( + context: &impl Namada, args::UpdateStewardCommission { tx: tx_args, steward, @@ -806,8 +803,8 @@ pub async fn build_update_steward_commission<'a>( } /// Craft transaction to resign as a steward -pub async fn build_resign_steward<'a>( - context: &impl Namada<'a>, +pub async fn build_resign_steward( + context: &impl Namada, args::ResignSteward { tx: tx_args, steward, @@ -846,8 +843,8 @@ pub async fn build_resign_steward<'a>( } /// Submit transaction to unjail a jailed validator -pub async fn build_unjail_validator<'a>( - context: &impl Namada<'a>, +pub async fn build_unjail_validator( + context: &impl Namada, args::TxUnjailValidator { tx: tx_args, validator, @@ -930,11 +927,17 @@ pub async fn build_unjail_validator<'a>( Err(Error::Query( QueryError::NoSuchKey(_) | QueryError::General(_), )) => { - return Err(Error::from(TxError::Other(format!( + edisplay_line!( + context.io(), "The given validator address {} is currently frozen and not \ yet eligible to be unjailed.", &validator - )))); + ); + if !tx_args.force { + return Err(Error::from( + TxError::ValidatorFrozenFromUnjailing(validator.clone()), + )); + } } Err(err) => return Err(err), } @@ -953,8 +956,8 @@ pub async fn build_unjail_validator<'a>( } /// Submit transaction to deactivate a validator -pub async fn build_deactivate_validator<'a>( - context: &impl Namada<'a>, +pub async fn build_deactivate_validator( + context: &impl Namada, args::TxDeactivateValidator { tx: tx_args, validator, @@ -1024,8 +1027,8 @@ pub async fn build_deactivate_validator<'a>( } /// Submit transaction to deactivate a validator -pub async fn build_reactivate_validator<'a>( - context: &impl Namada<'a>, +pub async fn build_reactivate_validator( + context: &impl Namada, args::TxReactivateValidator { tx: tx_args, validator, @@ -1094,8 +1097,8 @@ pub async fn build_reactivate_validator<'a>( } /// Redelegate bonded tokens from one validator to another -pub async fn build_redelegation<'a>( - context: &impl Namada<'a>, +pub async fn build_redelegation( + context: &impl Namada, args::Redelegate { tx: tx_args, src_validator, @@ -1274,8 +1277,8 @@ pub async fn build_redelegation<'a>( } /// Submit transaction to withdraw an unbond -pub async fn build_withdraw<'a>( - context: &impl Namada<'a>, +pub async fn build_withdraw( + context: &impl Namada, args::Withdraw { tx: tx_args, validator, @@ -1357,8 +1360,8 @@ pub async fn build_withdraw<'a>( } /// Submit transaction to withdraw an unbond -pub async fn build_claim_rewards<'a>( - context: &impl Namada<'a>, +pub async fn build_claim_rewards( + context: &impl Namada, args::ClaimRewards { tx: tx_args, validator, @@ -1405,8 +1408,8 @@ pub async fn build_claim_rewards<'a>( } /// Submit a transaction to unbond -pub async fn build_unbond<'a>( - context: &impl Namada<'a>, +pub async fn build_unbond( + context: &impl Namada, args::Unbond { tx: tx_args, validator, @@ -1512,8 +1515,8 @@ pub async fn build_unbond<'a>( } /// Query the unbonds post-tx -pub async fn query_unbonds<'a>( - context: &impl Namada<'a>, +pub async fn query_unbonds( + context: &impl Namada, args: args::Unbond, latest_withdrawal_pre: Option<(Epoch, token::Amount)>, ) -> Result<()> { @@ -1583,8 +1586,8 @@ pub async fn query_unbonds<'a>( } /// Submit a transaction to bond -pub async fn build_bond<'a>( - context: &impl Namada<'a>, +pub async fn build_bond( + context: &impl Namada, args::Bond { tx: tx_args, validator, @@ -1697,8 +1700,8 @@ pub async fn build_bond<'a>( } /// Build a default proposal governance -pub async fn build_default_proposal<'a>( - context: &impl Namada<'a>, +pub async fn build_default_proposal( + context: &impl Namada, args::InitProposal { tx, proposal_data: _, @@ -1750,8 +1753,8 @@ pub async fn build_default_proposal<'a>( } /// Build a proposal vote -pub async fn build_vote_proposal<'a>( - context: &impl Namada<'a>, +pub async fn build_vote_proposal( + context: &impl Namada, args::VoteProposal { tx, proposal_id, @@ -1837,8 +1840,8 @@ pub async fn build_vote_proposal<'a>( } /// Build a pgf funding proposal governance -pub async fn build_pgf_funding_proposal<'a>( - context: &impl Namada<'a>, +pub async fn build_pgf_funding_proposal( + context: &impl Namada, args::InitProposal { tx, proposal_data: _, @@ -1882,8 +1885,8 @@ pub async fn build_pgf_funding_proposal<'a>( } /// Build a pgf funding proposal governance -pub async fn build_pgf_stewards_proposal<'a>( - context: &impl Namada<'a>, +pub async fn build_pgf_stewards_proposal( + context: &impl Namada, args::InitProposal { tx, proposal_data: _, @@ -1928,8 +1931,8 @@ pub async fn build_pgf_stewards_proposal<'a>( } /// Submit an IBC transfer -pub async fn build_ibc_transfer<'a>( - context: &impl Namada<'a>, +pub async fn build_ibc_transfer( + context: &impl Namada, args: &args::TxIbcTransfer, ) -> Result<(Tx, SigningTxData, Option)> { let default_signer = Some(args.source.clone()); @@ -2057,8 +2060,8 @@ pub async fn build_ibc_transfer<'a>( /// Abstraction for helping build transactions #[allow(clippy::too_many_arguments)] -pub async fn build<'a, F, D>( - context: &impl Namada<'a>, +pub async fn build( + context: &impl Namada, tx_args: &crate::args::Tx, path: PathBuf, data: D, @@ -2083,8 +2086,8 @@ where } #[allow(clippy::too_many_arguments)] -async fn build_pow_flag<'a, F, D>( - context: &impl Namada<'a>, +async fn build_pow_flag( + context: &impl Namada, tx_args: &crate::args::Tx, path: PathBuf, mut data: D, @@ -2126,9 +2129,9 @@ where /// Try to decode the given asset type and add its decoding to the supplied set. /// Returns true only if a new decoding has been added to the given set. -async fn add_asset_type<'a>( +async fn add_asset_type( asset_types: &mut HashSet<(Address, MaspDenom, Epoch)>, - context: &impl Namada<'a>, + context: &impl Namada, asset_type: AssetType, ) -> bool { if let Some(asset_type) = context @@ -2146,8 +2149,8 @@ async fn add_asset_type<'a>( /// Collect the asset types used in the given Builder and decode them. This /// function provides the data necessary for offline wallets to present asset /// type information. -async fn used_asset_types<'a, P, R, K, N>( - context: &impl Namada<'a>, +async fn used_asset_types( + context: &impl Namada, builder: &Builder, ) -> std::result::Result, RpcError> { let mut asset_types = HashSet::new(); @@ -2180,7 +2183,7 @@ async fn used_asset_types<'a, P, R, K, N>( } /// Submit an ordinary transfer -pub async fn build_transfer<'a, N: Namada<'a>>( +pub async fn build_transfer( context: &N, args: &mut args::TxTransfer, ) -> Result<(Tx, SigningTxData, Option)> { @@ -2351,8 +2354,8 @@ pub async fn build_transfer<'a, N: Namada<'a>>( } /// Submit a transaction to initialize an account -pub async fn build_init_account<'a>( - context: &impl Namada<'a>, +pub async fn build_init_account( + context: &impl Namada, args::TxInitAccount { tx: tx_args, vp_code_path, @@ -2406,8 +2409,8 @@ pub async fn build_init_account<'a>( } /// Submit a transaction to update a VP -pub async fn build_update_account<'a>( - context: &impl Namada<'a>, +pub async fn build_update_account( + context: &impl Namada, args::TxUpdateAccount { tx: tx_args, vp_code_path, @@ -2488,8 +2491,8 @@ pub async fn build_update_account<'a>( } /// Submit a custom transaction -pub async fn build_custom<'a>( - context: &impl Namada<'a>, +pub async fn build_custom( + context: &impl Namada, args::TxCustom { tx: tx_args, code_path, @@ -2539,7 +2542,7 @@ pub async fn build_custom<'a>( } /// Generate IBC shielded transfer -pub async fn gen_ibc_shielded_transfer<'a, N: Namada<'a>>( +pub async fn gen_ibc_shielded_transfer( context: &N, args: args::GenIbcShieldedTransafer, ) -> Result> { @@ -2612,13 +2615,13 @@ pub async fn gen_ibc_shielded_transfer<'a, N: Namada<'a>>( } } -async fn get_ibc_src_port_channel<'a>( - context: &impl Namada<'a>, +async fn get_ibc_src_port_channel( + context: &impl Namada, dest_port_id: &PortId, dest_channel_id: &ChannelId, ) -> Result<(PortId, ChannelId)> { - use crate::ibc::core::ics04_channel::channel::ChannelEnd; - use crate::ibc_proto::protobuf::Protobuf; + use crate::ibc::core::channel::types::channel::ChannelEnd; + use crate::ibc::primitives::proto::Protobuf; let channel_key = channel_key(dest_port_id, dest_channel_id); let bytes = rpc::query_storage_value_bytes( @@ -2654,9 +2657,9 @@ async fn get_ibc_src_port_channel<'a>( }) } -async fn expect_dry_broadcast<'a>( +async fn expect_dry_broadcast( to_broadcast: TxBroadcastData, - context: &impl Namada<'a>, + context: &impl Namada, ) -> Result { match to_broadcast { TxBroadcastData::DryRun(tx) => { @@ -2678,10 +2681,10 @@ fn lift_rpc_error(res: std::result::Result) -> Result { /// Returns the given validator if the given address is a validator, /// otherwise returns an error, force forces the address through even /// if it isn't a validator -async fn known_validator_or_err<'a>( +async fn known_validator_or_err( validator: Address, force: bool, - context: &impl Namada<'a>, + context: &impl Namada, ) -> Result
{ // Check that the validator address exists on chain let is_validator = rpc::is_validator(context.client(), &validator).await?; @@ -2704,10 +2707,10 @@ async fn known_validator_or_err<'a>( /// general pattern for checking if an address exists on the chain, or /// throwing an error if it's not forced. Takes a generic error /// message and the error type. -async fn address_exists_or_err<'a, F>( +async fn address_exists_or_err( addr: Address, force: bool, - context: &impl Namada<'a>, + context: &impl Namada, message: String, err: F, ) -> Result
@@ -2730,10 +2733,10 @@ where /// Returns the given source address if the given address exists on chain /// otherwise returns an error, force forces the address through even /// if it isn't on chain -async fn source_exists_or_err<'a>( +async fn source_exists_or_err( token: Address, force: bool, - context: &impl Namada<'a>, + context: &impl Namada, ) -> Result
{ let message = format!("The source address {} doesn't exist on chain.", token); @@ -2746,10 +2749,10 @@ async fn source_exists_or_err<'a>( /// Returns the given target address if the given address exists on chain /// otherwise returns an error, force forces the address through even /// if it isn't on chain -async fn target_exists_or_err<'a>( +async fn target_exists_or_err( token: Address, force: bool, - context: &impl Namada<'a>, + context: &impl Namada, ) -> Result
{ let message = format!("The target address {} doesn't exist on chain.", token); @@ -2762,7 +2765,7 @@ async fn target_exists_or_err<'a>( /// Checks the balance at the given address is enough to transfer the /// given amount, along with the balance even existing. Force /// overrides this. Returns the updated balance for fee check if necessary -async fn check_balance_too_low_err<'a, N: Namada<'a>>( +async fn check_balance_too_low_err( token: &Address, source: &Address, amount: token::Amount, @@ -2825,8 +2828,8 @@ async fn check_balance_too_low_err<'a, N: Namada<'a>>( } } -async fn query_wasm_code_hash_buf<'a>( - context: &impl Namada<'a>, +async fn query_wasm_code_hash_buf( + context: &impl Namada, path: &Path, ) -> Result { query_wasm_code_hash(context, path.to_string_lossy()).await diff --git a/sdk/src/wallet/mod.rs b/sdk/src/wallet/mod.rs index 28b25c1076..3fd5579a35 100644 --- a/sdk/src/wallet/mod.rs +++ b/sdk/src/wallet/mod.rs @@ -254,8 +254,8 @@ fn gen_spending_key( #[derive(Error, Debug)] pub enum FindKeyError { /// Could not find a given key in the wallet - #[error("No matching key found")] - KeyNotFound, + #[error("No key matching {0} found")] + KeyNotFound(String), /// Could not decrypt a given key in the wallet #[error("{0}")] KeyDecryptionError(keys::DecryptionError), @@ -403,9 +403,9 @@ impl Wallet { &mut self, alias: impl AsRef, ) -> Result<&ExtendedViewingKey, FindKeyError> { - self.store - .find_viewing_key(alias.as_ref()) - .ok_or(FindKeyError::KeyNotFound) + self.store.find_viewing_key(alias.as_ref()).ok_or_else(|| { + FindKeyError::KeyNotFound(alias.as_ref().to_string()) + }) } /// Find the payment address with the given alias in the wallet and return @@ -688,7 +688,9 @@ impl Wallet { let stored_key = self .store .find_secret_key(alias_pkh_or_pk.as_ref()) - .ok_or(FindKeyError::KeyNotFound)?; + .ok_or_else(|| { + FindKeyError::KeyNotFound(alias_pkh_or_pk.as_ref().to_string()) + })?; Self::decrypt_stored_key::<_>( &mut self.decrypted_key_cache, stored_key, @@ -705,7 +707,9 @@ impl Wallet { self.store .find_public_key(alias_or_pkh.as_ref()) .cloned() - .ok_or(FindKeyError::KeyNotFound) + .ok_or_else(|| { + FindKeyError::KeyNotFound(alias_or_pkh.as_ref().to_string()) + }) } /// Find the spending key with the given alias in the wallet and return it. @@ -726,7 +730,9 @@ impl Wallet { let stored_spendkey = self .store .find_spending_key(alias.as_ref()) - .ok_or(FindKeyError::KeyNotFound)?; + .ok_or_else(|| { + FindKeyError::KeyNotFound(alias.as_ref().to_string()) + })?; Self::decrypt_stored_key::<_>( &mut self.decrypted_spendkey_cache, stored_spendkey, @@ -756,7 +762,7 @@ impl Wallet { ) -> Result { self.store .find_path_by_pkh(pkh) - .ok_or(FindKeyError::KeyNotFound) + .ok_or_else(|| FindKeyError::KeyNotFound(pkh.to_string())) } /// Find the public key by a public key hash. @@ -770,7 +776,7 @@ impl Wallet { self.store .find_public_key_by_pkh(pkh) .cloned() - .ok_or(FindKeyError::KeyNotFound) + .ok_or_else(|| FindKeyError::KeyNotFound(pkh.to_string())) } /// Find the stored key by a public key hash. @@ -795,7 +801,7 @@ impl Wallet { let stored_key = self .store .find_key_by_pkh(pkh) - .ok_or(FindKeyError::KeyNotFound)?; + .ok_or_else(|| FindKeyError::KeyNotFound(pkh.to_string()))?; Self::decrypt_stored_key( &mut self.decrypted_key_cache, stored_key, @@ -830,7 +836,7 @@ impl Wallet { decrypted_key_cache .get(&alias) .cloned() - .ok_or(FindKeyError::KeyNotFound) + .ok_or_else(|| FindKeyError::KeyNotFound(alias.to_string())) } StoredKeypair::Raw(raw) => Ok(raw.clone()), } diff --git a/sdk/src/wallet/store.rs b/sdk/src/wallet/store.rs index 980aa6ae70..4211af3ccc 100644 --- a/sdk/src/wallet/store.rs +++ b/sdk/src/wallet/store.rs @@ -631,15 +631,17 @@ impl Store { let account_pk = other.account_key.ref_to(); let consensus_pk = other.consensus_key.ref_to(); let tendermint_node_pk = other.tendermint_node_key.ref_to(); - let addresses = [ - (account_key_alias.clone(), (&account_pk).into()), - (consensus_key_alias.clone(), (&consensus_pk).into()), + let public_keys = [ + (account_key_alias.clone(), account_pk.clone()), + (consensus_key_alias.clone(), consensus_pk.clone()), ( tendermint_node_key_alias.clone(), - (&tendermint_node_pk).into(), + tendermint_node_pk.clone(), ), ]; - self.addresses.extend(addresses.into_iter()); + self.public_keys.extend(public_keys.clone().into_iter()); + self.addresses + .extend(public_keys.into_iter().map(|(k, v)| (k, (&v).into()))); let pkhs = [ ((&account_pk).into(), account_key_alias), diff --git a/shared/Cargo.toml b/shared/Cargo.toml index 2d83a73498..87ae575175 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -53,11 +53,6 @@ http-client = [ "tendermint-rpc/http-client" ] -ibc-mocks = [ - "namada_core/ibc-mocks", - "namada_sdk/ibc-mocks", -] - # for integration tests and test utilies testing = [ "namada_core/testing", @@ -144,7 +139,7 @@ tokio = {workspace = true, default-features = false, features = ["sync"]} wasmtimer = "0.2.0" [dev-dependencies] -namada_core = {path = "../core", default-features = false, features = ["testing", "ibc-mocks"]} +namada_core = {path = "../core", default-features = false, features = ["testing"]} namada_ethereum_bridge = {path = "../ethereum_bridge", default-features = false, features = ["testing"]} namada_proof_of_stake = {path = "../proof_of_stake", default-features = false, features = ["testing"]} namada_test_utils = {path = "../test_utils"} @@ -152,6 +147,7 @@ assert_matches.workspace = true async-trait.workspace = true base58.workspace = true byte-unit.workspace = true +ibc-testkit.workspace = true k256.workspace = true pretty_assertions.workspace = true proptest.workspace = true diff --git a/shared/src/ledger/native_vp/ibc/mod.rs b/shared/src/ledger/native_vp/ibc/mod.rs index 78e1378baa..a4ca254537 100644 --- a/shared/src/ledger/native_vp/ibc/mod.rs +++ b/shared/src/ledger/native_vp/ibc/mod.rs @@ -22,7 +22,7 @@ use namada_core::types::storage::Key; use namada_proof_of_stake::read_pos_params; use thiserror::Error; -use crate::ibc::core::ics24_host::identifier::ChainId as IbcChainId; +use crate::ibc::core::host::types::identifiers::ChainId as IbcChainId; use crate::ledger::ibc::storage::{calc_hash, is_ibc_denom_key, is_ibc_key}; use crate::ledger::native_vp::{self, Ctx, NativeVp, VpEnv}; use crate::ledger::parameters::read_epoch_duration_parameter; @@ -41,8 +41,6 @@ pub enum Error { IbcAction(ActionError), #[error("State change error: {0}")] StateChange(String), - #[error("Denom error: {0}")] - Denom(String), #[error("IBC event error: {0}")] IbcEvent(String), } @@ -175,7 +173,7 @@ where pipeline_len * epoch_duration.min_duration.0; Ok(ValidationParams { chain_id: IbcChainId::from_str(&chain_id) - .map_err(|e| Error::IbcAction(ActionError::ChainId(e)))?, + .map_err(ActionError::ChainId)?, proof_specs: proof_specs.into(), unbonding_period: Duration::from_secs(unbonding_period_secs), upgrade_path: Vec::new(), @@ -186,24 +184,26 @@ where for key in keys_changed { if let Some((_, hash)) = is_ibc_denom_key(key) { match self.ctx.read_post::(key).map_err(|e| { - Error::Denom(format!( + ActionError::Denom(format!( "Getting the denom failed: Key {}, Error {}", key, e )) })? { Some(denom) => { if calc_hash(&denom) != hash { - return Err(Error::Denom(format!( + return Err(ActionError::Denom(format!( "The denom is invalid: Key {}, Denom {}", key, denom - ))); + )) + .into()); } } None => { - return Err(Error::Denom(format!( + return Err(ActionError::Denom(format!( "The corresponding denom wasn't stored: Key {}", key - ))); + )) + .into()); } } } @@ -313,6 +313,11 @@ mod tests { use borsh::BorshDeserialize; use borsh_ext::BorshSerializeExt; + use ibc_testkit::testapp::ibc::clients::mock::client_state::{ + client_type, MockClientState, MOCK_CLIENT_TYPE, + }; + use ibc_testkit::testapp::ibc::clients::mock::consensus_state::MockConsensusState; + use ibc_testkit::testapp::ibc::clients::mock::header::MockHeader; use namada_core::ledger::gas::TxGasMeter; use namada_core::ledger::governance::parameters::GovernanceParameters; use prost::Message; @@ -333,72 +338,64 @@ mod tests { }; use crate::core::types::address::{nam, InternalAddress}; use crate::core::types::storage::Epoch; - use crate::ibc::applications::transfer::coin::PrefixedCoin; - use crate::ibc::applications::transfer::denom::TracePrefix; - use crate::ibc::applications::transfer::events::{ + use crate::ibc::apps::transfer::types::events::{ AckEvent, DenomTraceEvent, RecvEvent, TimeoutEvent, TransferEvent, }; - use crate::ibc::applications::transfer::msgs::transfer::MsgTransfer; - use crate::ibc::applications::transfer::packet::PacketData; - use crate::ibc::applications::transfer::{ack_success_b64, VERSION}; - use crate::ibc::core::events::{ - IbcEvent as RawIbcEvent, MessageEvent, ModuleEvent, - }; - use crate::ibc::core::ics02_client::events::{CreateClient, UpdateClient}; - use crate::ibc::core::ics02_client::msgs::create_client::MsgCreateClient; - use crate::ibc::core::ics02_client::msgs::update_client::MsgUpdateClient; - use crate::ibc::core::ics03_connection::connection::{ - ConnectionEnd, Counterparty as ConnCounterparty, State as ConnState, - }; - use crate::ibc::core::ics03_connection::events::{ - OpenAck as ConnOpenAck, OpenConfirm as ConnOpenConfirm, - OpenInit as ConnOpenInit, OpenTry as ConnOpenTry, - }; - use crate::ibc::core::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; - use crate::ibc::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; - use crate::ibc::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; - use crate::ibc::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; - use crate::ibc::core::ics03_connection::version::{ - get_compatible_versions, Version as ConnVersion, + use crate::ibc::apps::transfer::types::msgs::transfer::MsgTransfer; + use crate::ibc::apps::transfer::types::packet::PacketData; + use crate::ibc::apps::transfer::types::{ + ack_success_b64, PrefixedCoin, TracePrefix, VERSION, }; - use crate::ibc::core::ics04_channel::acknowledgement::{ + use crate::ibc::core::channel::types::acknowledgement::{ Acknowledgement, AcknowledgementStatus, }; - use crate::ibc::core::ics04_channel::channel::{ + use crate::ibc::core::channel::types::channel::{ ChannelEnd, Counterparty as ChanCounterparty, Order, State as ChanState, }; - use crate::ibc::core::ics04_channel::commitment::PacketCommitment; - use crate::ibc::core::ics04_channel::events::{ + use crate::ibc::core::channel::types::commitment::PacketCommitment; + use crate::ibc::core::channel::types::events::{ AcknowledgePacket, OpenAck as ChanOpenAck, OpenConfirm as ChanOpenConfirm, OpenInit as ChanOpenInit, OpenTry as ChanOpenTry, ReceivePacket, SendPacket, TimeoutPacket, WriteAcknowledgement, }; - use crate::ibc::core::ics04_channel::msgs::{ + use crate::ibc::core::channel::types::msgs::{ MsgAcknowledgement, MsgChannelOpenAck, MsgChannelOpenConfirm, MsgChannelOpenInit, MsgChannelOpenTry, MsgRecvPacket, MsgTimeout, MsgTimeoutOnClose, }; - use crate::ibc::core::ics04_channel::packet::{Packet, Sequence}; - use crate::ibc::core::ics04_channel::timeout::TimeoutHeight; - use crate::ibc::core::ics04_channel::Version as ChanVersion; - use crate::ibc::core::ics23_commitment::commitment::{ + use crate::ibc::core::channel::types::packet::Packet; + use crate::ibc::core::channel::types::timeout::TimeoutHeight; + use crate::ibc::core::channel::types::Version as ChanVersion; + use crate::ibc::core::client::types::events::{CreateClient, UpdateClient}; + use crate::ibc::core::client::types::msgs::{ + MsgCreateClient, MsgUpdateClient, + }; + use crate::ibc::core::client::types::Height; + use crate::ibc::core::commitment_types::commitment::{ CommitmentPrefix, CommitmentProofBytes, }; - use crate::ibc::core::ics24_host::identifier::{ - ChannelId, ClientId, ConnectionId, PortId, + use crate::ibc::core::connection::types::events::{ + OpenAck as ConnOpenAck, OpenConfirm as ConnOpenConfirm, + OpenInit as ConnOpenInit, OpenTry as ConnOpenTry, + }; + use crate::ibc::core::connection::types::msgs::{ + MsgConnectionOpenAck, MsgConnectionOpenConfirm, MsgConnectionOpenInit, + MsgConnectionOpenTry, }; - use crate::ibc::core::timestamp::Timestamp; - use crate::ibc::core::Msg; - use crate::ibc::mock::client_state::{ - client_type, MockClientState, MOCK_CLIENT_TYPE, + use crate::ibc::core::connection::types::version::Version as ConnVersion; + use crate::ibc::core::connection::types::{ + ConnectionEnd, Counterparty as ConnCounterparty, State as ConnState, + }; + use crate::ibc::core::handler::types::events::{ + IbcEvent as RawIbcEvent, MessageEvent, }; - use crate::ibc::mock::consensus_state::MockConsensusState; - use crate::ibc::mock::header::MockHeader; - use crate::ibc::Height; - use crate::ibc_proto::google::protobuf::Any; - use crate::ibc_proto::ibc::core::connection::v1::MsgConnectionOpenTry as RawMsgConnectionOpenTry; - use crate::ibc_proto::protobuf::Protobuf; + use crate::ibc::core::host::types::identifiers::{ + ChannelId, ClientId, ConnectionId, PortId, Sequence, + }; + use crate::ibc::core::router::types::event::ModuleEvent; + use crate::ibc::primitives::proto::{Any, Protobuf}; + use crate::ibc::primitives::{Msg, Timestamp}; use crate::ledger::gas::VpGasMeter; use crate::ledger::parameters::storage::{ get_epoch_duration_storage_key, get_max_expected_time_per_block_key, @@ -408,7 +405,6 @@ mod tests { use crate::ledger::{ibc, pos}; use crate::proto::{Code, Data, Section, Signature, Tx}; use crate::tendermint::time::Time as TmTime; - use crate::tendermint_proto::Protobuf as TmProtobuf; use crate::types::key::testing::keypair_1; use crate::types::storage::{BlockHash, BlockHeight, TxIndex}; use crate::types::time::DurationSecs; @@ -480,7 +476,7 @@ mod tests { timestamp: Timestamp::now(), }; let client_state = MockClientState::new(header); - let bytes = Protobuf::::encode_vec(&client_state); + let bytes = Protobuf::::encode_vec(client_state); wl_storage .write_log .write(&client_state_key, bytes) @@ -488,7 +484,7 @@ mod tests { // insert a mock consensus state let consensus_key = consensus_state_key(&client_id, height); let consensus_state = MockConsensusState::new(header); - let bytes = Protobuf::::encode_vec(&consensus_state); + let bytes = Protobuf::::encode_vec(consensus_state); wl_storage .write_log .write(&consensus_key, bytes) @@ -682,7 +678,7 @@ mod tests { }; // client state let client_state_key = client_state_key(&get_client_id()); - let bytes = Protobuf::::encode_vec(&client_state); + let bytes = Protobuf::::encode_vec(client_state); wl_storage .write_log .write(&client_state_key, bytes) @@ -690,7 +686,7 @@ mod tests { keys_changed.insert(client_state_key); // client consensus let consensus_key = consensus_state_key(&client_id, height); - let bytes = Protobuf::::encode_vec(&consensus_state); + let bytes = Protobuf::::encode_vec(consensus_state); wl_storage .write_log .write(&consensus_key, bytes) @@ -780,7 +776,7 @@ mod tests { // insert only client state let client_state = MockClientState::new(header); let client_state_key = client_state_key(&get_client_id()); - let bytes = Protobuf::::encode_vec(&client_state); + let bytes = Protobuf::::encode_vec(client_state); wl_storage .write_log .write(&client_state_key, bytes) @@ -866,7 +862,7 @@ mod tests { }; // client state let client_state = MockClientState::new(header); - let bytes = Protobuf::::encode_vec(&client_state); + let bytes = Protobuf::::encode_vec(client_state); wl_storage .write_log .write(&client_state_key, bytes) @@ -875,7 +871,7 @@ mod tests { // consensus state let consensus_key = consensus_state_key(&client_id, height); let consensus_state = MockConsensusState::new(header); - let bytes = Protobuf::::encode_vec(&consensus_state); + let bytes = Protobuf::::encode_vec(consensus_state); wl_storage .write_log .write(&consensus_key, bytes) @@ -913,7 +909,7 @@ mod tests { client_type(), consensus_height, vec![consensus_height], - Protobuf::::encode_vec(&header), + Protobuf::::encode_vec(header), )); let message_event = RawIbcEvent::Message(MessageEvent::Client); wl_storage @@ -1190,29 +1186,22 @@ mod tests { }; let client_state = MockClientState::new(header); let proof_height = Height::new(0, 1).unwrap(); - // Convert a message from RawMsgConnectionOpenTry - // because MsgConnectionOpenTry cannot be created directly #[allow(deprecated)] - let msg: MsgConnectionOpenTry = RawMsgConnectionOpenTry { - client_id: get_client_id().as_str().to_string(), - client_state: Some(client_state.into()), - counterparty: Some(get_conn_counterparty().into()), - delay_period: 0, - counterparty_versions: get_compatible_versions() - .iter() - .map(|v| v.clone().into()) - .collect(), - proof_init: dummy_proof().into(), - proof_height: Some(proof_height.into()), - proof_consensus: dummy_proof().into(), - consensus_height: Some(client_state.latest_height().into()), - proof_client: dummy_proof().into(), - signer: "account0".to_string(), + let msg = MsgConnectionOpenTry { + client_id_on_b: get_client_id(), + client_state_of_b_on_a: client_state.into(), + counterparty: get_conn_counterparty(), + versions_on_a: vec![ConnVersion::default()], + proofs_height_on_a: proof_height, + proof_conn_end_on_a: dummy_proof(), + proof_client_state_of_b_on_a: dummy_proof(), + proof_consensus_state_of_b_on_a: dummy_proof(), + consensus_height_of_b_on_a: client_state.latest_height(), + delay_period: Duration::from_secs(0), + signer: "account0".to_string().into(), + proof_consensus_state_of_b: Some(dummy_proof()), previous_connection_id: ConnectionId::default().to_string(), - host_consensus_state_proof: dummy_proof().into(), - } - .try_into() - .expect("invalid message"); + }; // insert a TryOpen connection let conn_id = get_connection_id(); diff --git a/shared/src/lib.rs b/shared/src/lib.rs index 0b0304ab3d..5937c345c9 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -6,7 +6,7 @@ #![deny(rustdoc::broken_intra_doc_links)] #![deny(rustdoc::private_intra_doc_links)] -pub use namada_core::{ibc, ibc_proto, tendermint, tendermint_proto}; +pub use namada_core::{ibc, tendermint, tendermint_proto}; #[cfg(feature = "tendermint-rpc")] pub use tendermint_rpc; pub use {bip39, namada_core as core, namada_proof_of_stake as proof_of_stake}; diff --git a/shared/src/vm/wasm/compilation_cache/common.rs b/shared/src/vm/wasm/compilation_cache/common.rs index f866188970..cd95100d25 100644 --- a/shared/src/vm/wasm/compilation_cache/common.rs +++ b/shared/src/vm/wasm/compilation_cache/common.rs @@ -156,16 +156,22 @@ impl Cache { return Ok(Some((module.clone(), store()))); } - let (module, store) = file_load_module(&self.dir, hash); - tracing::info!( - "{} found {} in file cache.", - N::name(), - hash.to_string() - ); - // Put into cache, ignore result if it's full - let _ = in_memory.put_with_weight(*hash, module.clone()); + if let Ok((module, store)) = + file_load_module(&self.dir, hash) + { + tracing::info!( + "{} found {} in file cache.", + N::name(), + hash.to_string() + ); + // Put into cache, ignore result if it's full + let _ = + in_memory.put_with_weight(*hash, module.clone()); - return Ok(Some((module, store))); + return Ok(Some((module, store))); + } else { + return Ok(None); + } } Some(Compilation::Compiling) => { drop(progress); @@ -183,11 +189,15 @@ impl Cache { let (module, store) = if module_file_exists(&self.dir, hash) { tracing::info!( - "Loading {} {} from file.", + "Trying to load {} {} from file.", N::name(), hash.to_string() ); - file_load_module(&self.dir, hash) + if let Ok(res) = file_load_module(&self.dir, hash) { + res + } else { + return Ok(None); + } } else { return Ok(None); }; @@ -246,13 +256,18 @@ impl Cache { return Ok(Some((module.clone(), store()))); } - let (module, store) = file_load_module(&self.dir, hash); - tracing::info!( - "{} found {} in file cache.", - N::name(), - hash.to_string() - ); - return Ok(Some((module, store))); + if let Ok((module, store)) = + file_load_module(&self.dir, hash) + { + tracing::info!( + "{} found {} in file cache.", + N::name(), + hash.to_string() + ); + return Ok(Some((module, store))); + } else { + return Ok(None); + } } Some(Compilation::Compiling) => { drop(progress); @@ -270,11 +285,15 @@ impl Cache { return if module_file_exists(&self.dir, hash) { tracing::info!( - "Loading {} {} from file.", + "Trying to load {} {} from file.", N::name(), hash.to_string() ); - Ok(Some(file_load_module(&self.dir, hash))) + if let Ok(res) = file_load_module(&self.dir, hash) { + return Ok(Some(res)); + } else { + return Ok(None); + } } else { Ok(None) }; @@ -478,13 +497,22 @@ fn file_write_module(dir: impl AsRef, module: &Module, hash: &Hash) { fs_cache.store(CacheHash::new(hash.0), module).unwrap(); } -fn file_load_module(dir: impl AsRef, hash: &Hash) -> (Module, Store) { +fn file_load_module( + dir: impl AsRef, + hash: &Hash, +) -> Result<(Module, Store), wasmer::DeserializeError> { use wasmer_cache::Cache; let fs_cache = fs_cache(dir, hash); let store = store(); let hash = CacheHash::new(hash.0); - let module = unsafe { fs_cache.load(&store, hash) }.unwrap(); - (module, store) + let module = unsafe { fs_cache.load(&store, hash) }; + if let Err(err) = module.as_ref() { + tracing::error!( + "Error loading cached wasm {}: {err}.", + hash.to_string() + ); + } + Ok((module?, store)) } fn fs_cache(dir: impl AsRef, hash: &Hash) -> FileSystemCache { diff --git a/test_fixtures/masp_proofs/0075192A544500F2AD0C92E1A2D6D32B22A46CEDD254F52B6C69E813898FE60B.bin b/test_fixtures/masp_proofs/0075192A544500F2AD0C92E1A2D6D32B22A46CEDD254F52B6C69E813898FE60B.bin new file mode 100644 index 0000000000..6e8d6b3ae4 Binary files /dev/null and b/test_fixtures/masp_proofs/0075192A544500F2AD0C92E1A2D6D32B22A46CEDD254F52B6C69E813898FE60B.bin differ diff --git a/test_fixtures/masp_proofs/341E00D564C672701199B58E69A57D1F470F585C2F4633E5103CB67AE2726938.bin b/test_fixtures/masp_proofs/341E00D564C672701199B58E69A57D1F470F585C2F4633E5103CB67AE2726938.bin new file mode 100644 index 0000000000..d757eb2fb9 Binary files /dev/null and b/test_fixtures/masp_proofs/341E00D564C672701199B58E69A57D1F470F585C2F4633E5103CB67AE2726938.bin differ diff --git a/test_fixtures/masp_proofs/4F74C729C8F775EF554F4475BD13CAF693649A17FBEE435298C9C1624C6060F2.bin b/test_fixtures/masp_proofs/4F74C729C8F775EF554F4475BD13CAF693649A17FBEE435298C9C1624C6060F2.bin new file mode 100644 index 0000000000..d235345ec7 Binary files /dev/null and b/test_fixtures/masp_proofs/4F74C729C8F775EF554F4475BD13CAF693649A17FBEE435298C9C1624C6060F2.bin differ diff --git a/test_fixtures/masp_proofs/51034B90AF95B8899A631D37B45DB11F0B17E6564F3AA56244770F24B56FC18B.bin b/test_fixtures/masp_proofs/51034B90AF95B8899A631D37B45DB11F0B17E6564F3AA56244770F24B56FC18B.bin new file mode 100644 index 0000000000..e64778b238 Binary files /dev/null and b/test_fixtures/masp_proofs/51034B90AF95B8899A631D37B45DB11F0B17E6564F3AA56244770F24B56FC18B.bin differ diff --git a/test_fixtures/masp_proofs/51EF94B13138B91DB3081F95193F779253B53A9A0BD62FD3DF8F6FCF4AF1E145.bin b/test_fixtures/masp_proofs/51EF94B13138B91DB3081F95193F779253B53A9A0BD62FD3DF8F6FCF4AF1E145.bin deleted file mode 100644 index 8b21aac70d..0000000000 Binary files a/test_fixtures/masp_proofs/51EF94B13138B91DB3081F95193F779253B53A9A0BD62FD3DF8F6FCF4AF1E145.bin and /dev/null differ diff --git a/test_fixtures/masp_proofs/544F7432B95E26E312105FB804BF9BC175A70082068C8785BDDBF49DCCA4BE66.bin b/test_fixtures/masp_proofs/544F7432B95E26E312105FB804BF9BC175A70082068C8785BDDBF49DCCA4BE66.bin deleted file mode 100644 index 1636c1394f..0000000000 Binary files a/test_fixtures/masp_proofs/544F7432B95E26E312105FB804BF9BC175A70082068C8785BDDBF49DCCA4BE66.bin and /dev/null differ diff --git a/test_fixtures/masp_proofs/5F7D9B39ABA3A1CF6A124CFC26BD9698F791D337CEF8DE82C684C1A1279D772E.bin b/test_fixtures/masp_proofs/5F7D9B39ABA3A1CF6A124CFC26BD9698F791D337CEF8DE82C684C1A1279D772E.bin new file mode 100644 index 0000000000..4ff46ab0b3 Binary files /dev/null and b/test_fixtures/masp_proofs/5F7D9B39ABA3A1CF6A124CFC26BD9698F791D337CEF8DE82C684C1A1279D772E.bin differ diff --git a/test_fixtures/masp_proofs/650AB811C362FB33B9190DDA9D2279865699251D54141F79A4989D5343D72681.bin b/test_fixtures/masp_proofs/650AB811C362FB33B9190DDA9D2279865699251D54141F79A4989D5343D72681.bin new file mode 100644 index 0000000000..1e927354c1 Binary files /dev/null and b/test_fixtures/masp_proofs/650AB811C362FB33B9190DDA9D2279865699251D54141F79A4989D5343D72681.bin differ diff --git a/test_fixtures/masp_proofs/68380B89FFFC47364F7AA8D3F992A006D0519A21D3F1D72D7D930324584CD2DE.bin b/test_fixtures/masp_proofs/68380B89FFFC47364F7AA8D3F992A006D0519A21D3F1D72D7D930324584CD2DE.bin new file mode 100644 index 0000000000..ac3c653d1a Binary files /dev/null and b/test_fixtures/masp_proofs/68380B89FFFC47364F7AA8D3F992A006D0519A21D3F1D72D7D930324584CD2DE.bin differ diff --git a/test_fixtures/masp_proofs/6DD5A788D36258E9D5FEF454DBC89879834677F926130D56EB5E4067728EB5CF.bin b/test_fixtures/masp_proofs/6DD5A788D36258E9D5FEF454DBC89879834677F926130D56EB5E4067728EB5CF.bin deleted file mode 100644 index 94f997688b..0000000000 Binary files a/test_fixtures/masp_proofs/6DD5A788D36258E9D5FEF454DBC89879834677F926130D56EB5E4067728EB5CF.bin and /dev/null differ diff --git a/test_fixtures/masp_proofs/6E92D0B97A65FB5ADFA6371A6CBE50202AF004DFD895A721EDA284D96B253ACC.bin b/test_fixtures/masp_proofs/6E92D0B97A65FB5ADFA6371A6CBE50202AF004DFD895A721EDA284D96B253ACC.bin deleted file mode 100644 index 60b6f86069..0000000000 Binary files a/test_fixtures/masp_proofs/6E92D0B97A65FB5ADFA6371A6CBE50202AF004DFD895A721EDA284D96B253ACC.bin and /dev/null differ diff --git a/test_fixtures/masp_proofs/B947FEFC6EC94A041657FF3A9420D5BB3FDEB1199EF712C059C80C4DBF6F3ED8.bin b/test_fixtures/masp_proofs/75FB5C5ECE98BF9246CED847F2F1508A065BC804ED18DA58F0064137E1251EED.bin similarity index 54% rename from test_fixtures/masp_proofs/B947FEFC6EC94A041657FF3A9420D5BB3FDEB1199EF712C059C80C4DBF6F3ED8.bin rename to test_fixtures/masp_proofs/75FB5C5ECE98BF9246CED847F2F1508A065BC804ED18DA58F0064137E1251EED.bin index 9627a1ce5c..f5cd3fca84 100644 Binary files a/test_fixtures/masp_proofs/B947FEFC6EC94A041657FF3A9420D5BB3FDEB1199EF712C059C80C4DBF6F3ED8.bin and b/test_fixtures/masp_proofs/75FB5C5ECE98BF9246CED847F2F1508A065BC804ED18DA58F0064137E1251EED.bin differ diff --git a/test_fixtures/masp_proofs/8032CA7B951C625E43F48AEBD53CEA99A9BC66B2BAB03D4ABA1AE57B12596061.bin b/test_fixtures/masp_proofs/8032CA7B951C625E43F48AEBD53CEA99A9BC66B2BAB03D4ABA1AE57B12596061.bin deleted file mode 100644 index b983254f6b..0000000000 Binary files a/test_fixtures/masp_proofs/8032CA7B951C625E43F48AEBD53CEA99A9BC66B2BAB03D4ABA1AE57B12596061.bin and /dev/null differ diff --git a/test_fixtures/masp_proofs/8A79BF5E0292339E70287DB626F136D4522BAFC99E0E81FD54A28A38E8419CFC.bin b/test_fixtures/masp_proofs/8A79BF5E0292339E70287DB626F136D4522BAFC99E0E81FD54A28A38E8419CFC.bin deleted file mode 100644 index 5aedea90bf..0000000000 Binary files a/test_fixtures/masp_proofs/8A79BF5E0292339E70287DB626F136D4522BAFC99E0E81FD54A28A38E8419CFC.bin and /dev/null differ diff --git a/test_fixtures/masp_proofs/A14785AC0F54CDB43F6DCE5AFB596406702B1323505211981C8DABB0FDC6B41B.bin b/test_fixtures/masp_proofs/A14785AC0F54CDB43F6DCE5AFB596406702B1323505211981C8DABB0FDC6B41B.bin new file mode 100644 index 0000000000..31ef7d9e76 Binary files /dev/null and b/test_fixtures/masp_proofs/A14785AC0F54CDB43F6DCE5AFB596406702B1323505211981C8DABB0FDC6B41B.bin differ diff --git a/test_fixtures/masp_proofs/A8A9963AC2983B576BAE4DE9BA6D2CF14C7F9E90A8588BA75DA0D2860F36E2CB.bin b/test_fixtures/masp_proofs/A8A9963AC2983B576BAE4DE9BA6D2CF14C7F9E90A8588BA75DA0D2860F36E2CB.bin deleted file mode 100644 index e475b08f8b..0000000000 Binary files a/test_fixtures/masp_proofs/A8A9963AC2983B576BAE4DE9BA6D2CF14C7F9E90A8588BA75DA0D2860F36E2CB.bin and /dev/null differ diff --git a/test_fixtures/masp_proofs/AEA19C9B07742FF5F6D759B171396732D2EBF77728D2772EB251123DF2CEF6A1.bin b/test_fixtures/masp_proofs/AEA19C9B07742FF5F6D759B171396732D2EBF77728D2772EB251123DF2CEF6A1.bin deleted file mode 100644 index 4b7967cf85..0000000000 Binary files a/test_fixtures/masp_proofs/AEA19C9B07742FF5F6D759B171396732D2EBF77728D2772EB251123DF2CEF6A1.bin and /dev/null differ diff --git a/test_fixtures/masp_proofs/C788F9057C615CCE7B260BB8BF5CF776D5DE7C9153D67B7FDF22ED6F35558738.bin b/test_fixtures/masp_proofs/C788F9057C615CCE7B260BB8BF5CF776D5DE7C9153D67B7FDF22ED6F35558738.bin deleted file mode 100644 index d3c3a5c241..0000000000 Binary files a/test_fixtures/masp_proofs/C788F9057C615CCE7B260BB8BF5CF776D5DE7C9153D67B7FDF22ED6F35558738.bin and /dev/null differ diff --git a/test_fixtures/masp_proofs/CBF4087F2AB578C83A736E4598DBA1FDB2515DF33D43611F2860B8D3C178B474.bin b/test_fixtures/masp_proofs/CBF4087F2AB578C83A736E4598DBA1FDB2515DF33D43611F2860B8D3C178B474.bin deleted file mode 100644 index 06393963b3..0000000000 Binary files a/test_fixtures/masp_proofs/CBF4087F2AB578C83A736E4598DBA1FDB2515DF33D43611F2860B8D3C178B474.bin and /dev/null differ diff --git a/test_fixtures/masp_proofs/CD50FD3DE1D59F43FBD6F3ED220F348721EF5366FDD8E62B9062254B2D286E0F.bin b/test_fixtures/masp_proofs/CD50FD3DE1D59F43FBD6F3ED220F348721EF5366FDD8E62B9062254B2D286E0F.bin new file mode 100644 index 0000000000..85cb2f2bf8 Binary files /dev/null and b/test_fixtures/masp_proofs/CD50FD3DE1D59F43FBD6F3ED220F348721EF5366FDD8E62B9062254B2D286E0F.bin differ diff --git a/test_fixtures/masp_proofs/CEC3CA2BCC727589C923B70A3F57D436A33F919BC377C8C6EE7A8DC8D210A6D9.bin b/test_fixtures/masp_proofs/CEC3CA2BCC727589C923B70A3F57D436A33F919BC377C8C6EE7A8DC8D210A6D9.bin new file mode 100644 index 0000000000..3f3374c98b Binary files /dev/null and b/test_fixtures/masp_proofs/CEC3CA2BCC727589C923B70A3F57D436A33F919BC377C8C6EE7A8DC8D210A6D9.bin differ diff --git a/test_fixtures/masp_proofs/EDB31EB869290C1252C3395D7ED2D1A30B9CFAD55AA750B6CC36A4BD55D6BD2B.bin b/test_fixtures/masp_proofs/EDB31EB869290C1252C3395D7ED2D1A30B9CFAD55AA750B6CC36A4BD55D6BD2B.bin new file mode 100644 index 0000000000..b8e866408a Binary files /dev/null and b/test_fixtures/masp_proofs/EDB31EB869290C1252C3395D7ED2D1A30B9CFAD55AA750B6CC36A4BD55D6BD2B.bin differ diff --git a/test_fixtures/masp_proofs/EDE8DC791D02098C5C199CAF2F6C8B75587507CA52981F48FD1FC9C5BE0BEE43.bin b/test_fixtures/masp_proofs/EDE8DC791D02098C5C199CAF2F6C8B75587507CA52981F48FD1FC9C5BE0BEE43.bin deleted file mode 100644 index 90da4e0f00..0000000000 Binary files a/test_fixtures/masp_proofs/EDE8DC791D02098C5C199CAF2F6C8B75587507CA52981F48FD1FC9C5BE0BEE43.bin and /dev/null differ diff --git a/test_fixtures/masp_proofs/90502CEAE917AE038FDA2337AFB0464F2130123149D5691B85C35AABC49FA2BD.bin b/test_fixtures/masp_proofs/F6021F5E0CC7E0346EEF9BDF849AF47822630FC911AF7F91B196C540372EC0E8.bin similarity index 52% rename from test_fixtures/masp_proofs/90502CEAE917AE038FDA2337AFB0464F2130123149D5691B85C35AABC49FA2BD.bin rename to test_fixtures/masp_proofs/F6021F5E0CC7E0346EEF9BDF849AF47822630FC911AF7F91B196C540372EC0E8.bin index 44754a7a46..c04d382648 100644 Binary files a/test_fixtures/masp_proofs/90502CEAE917AE038FDA2337AFB0464F2130123149D5691B85C35AABC49FA2BD.bin and b/test_fixtures/masp_proofs/F6021F5E0CC7E0346EEF9BDF849AF47822630FC911AF7F91B196C540372EC0E8.bin differ diff --git a/tests/Cargo.toml b/tests/Cargo.toml index de9b821ac9..f4ed0fbc34 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -21,7 +21,7 @@ wasm-runtime = ["namada/wasm-runtime"] integration = ["namada_apps/integration"] [dependencies] -namada = {path = "../shared", features = ["testing", "ibc-mocks"]} +namada = {path = "../shared", features = ["testing"]} namada_core = {path = "../core", features = ["testing"]} namada_sdk = {path = "../sdk"} namada_test_utils = {path = "../test_utils"} @@ -34,6 +34,8 @@ concat-idents.workspace = true copy_dir = "0.1.3" derivative.workspace = true hyper = {version = "0.14.20", features = ["full"]} +ibc-testkit.workspace = true +ics23.workspace = true lazy_static.workspace = true num-traits.workspace = true prost.workspace = true diff --git a/tests/src/e2e/ibc_tests.rs b/tests/src/e2e/ibc_tests.rs index e1b3479d6e..9d18bb54e5 100644 --- a/tests/src/e2e/ibc_tests.rs +++ b/tests/src/e2e/ibc_tests.rs @@ -17,39 +17,41 @@ use std::path::PathBuf; use color_eyre::eyre::Result; use eyre::eyre; -use namada::ibc::applications::transfer::VERSION as ICS20_VERSION; -use namada::ibc::clients::ics07_tendermint::client_state::{ - AllowUpdate, ClientState as TmClientState, +use namada::ibc::apps::transfer::types::VERSION as ICS20_VERSION; +use namada::ibc::clients::tendermint::client_state::ClientState as TmClientState; +use namada::ibc::clients::tendermint::consensus_state::ConsensusState as TmConsensusState; +use namada::ibc::clients::tendermint::types::{ + AllowUpdate, ClientState as TmClientStateType, Header as IbcTmHeader, + TrustThreshold, }; -use namada::ibc::clients::ics07_tendermint::consensus_state::ConsensusState as TmConsensusState; -use namada::ibc::clients::ics07_tendermint::header::Header as IbcTmHeader; -use namada::ibc::clients::ics07_tendermint::trust_threshold::TrustThreshold; -use namada::ibc::core::ics02_client::msgs::create_client::MsgCreateClient; -use namada::ibc::core::ics02_client::msgs::update_client::MsgUpdateClient; -use namada::ibc::core::ics03_connection::connection::Counterparty as ConnCounterparty; -use namada::ibc::core::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; -use namada::ibc::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; -use namada::ibc::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; -use namada::ibc::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; -use namada::ibc::core::ics03_connection::version::Version as ConnVersion; -use namada::ibc::core::ics04_channel::channel::Order as ChanOrder; -use namada::ibc::core::ics04_channel::msgs::{ +use namada::ibc::core::channel::types::channel::Order as ChanOrder; +use namada::ibc::core::channel::types::msgs::{ MsgAcknowledgement, MsgChannelOpenAck, MsgChannelOpenConfirm, MsgChannelOpenInit, MsgChannelOpenTry, MsgRecvPacket, MsgTimeout, }; -use namada::ibc::core::ics04_channel::packet::Packet; -use namada::ibc::core::ics04_channel::timeout::TimeoutHeight; -use namada::ibc::core::ics04_channel::Version as ChanVersion; -use namada::ibc::core::ics23_commitment::commitment::{ +use namada::ibc::core::channel::types::packet::Packet; +use namada::ibc::core::channel::types::timeout::TimeoutHeight; +use namada::ibc::core::channel::types::Version as ChanVersion; +use namada::ibc::core::client::context::client_state::ClientStateCommon; +use namada::ibc::core::client::types::msgs::{ + MsgCreateClient, MsgUpdateClient, +}; +use namada::ibc::core::client::types::Height; +use namada::ibc::core::commitment_types::commitment::{ CommitmentPrefix, CommitmentProofBytes, }; -use namada::ibc::core::ics23_commitment::merkle::MerkleProof; -use namada::ibc::core::ics24_host::identifier::{ +use namada::ibc::core::commitment_types::merkle::MerkleProof; +use namada::ibc::core::connection::types::msgs::{ + MsgConnectionOpenAck, MsgConnectionOpenConfirm, MsgConnectionOpenInit, + MsgConnectionOpenTry, +}; +use namada::ibc::core::connection::types::version::Version as ConnVersion; +use namada::ibc::core::connection::types::Counterparty as ConnCounterparty; +use namada::ibc::core::host::types::identifiers::{ ChainId, ChannelId, ClientId, ConnectionId, PortId, }; -use namada::ibc::core::Msg; -use namada::ibc::{Height, Signer}; -use namada::ibc_proto::google::protobuf::Any; +use namada::ibc::primitives::proto::Any; +use namada::ibc::primitives::{Msg, Signer, Timestamp}; use namada::ledger::events::EventType; use namada::ledger::ibc::storage::*; use namada::ledger::parameters::{storage as param_storage, EpochDuration}; @@ -299,7 +301,7 @@ fn setup_two_single_node_nets() -> Result<(Test, Test)> { fn create_client(test_a: &Test, test_b: &Test) -> Result<(ClientId, ClientId)> { let height = query_height(test_b)?; let client_state = make_client_state(test_b, height); - let height = client_state.latest_height; + let height = client_state.latest_height(); let message = MsgCreateClient { client_state: client_state.into(), consensus_state: make_consensus_state(test_b, height)?.into(), @@ -309,7 +311,7 @@ fn create_client(test_a: &Test, test_b: &Test) -> Result<(ClientId, ClientId)> { let height = query_height(test_a)?; let client_state = make_client_state(test_a, height); - let height = client_state.latest_height; + let height = client_state.latest_height(); let message = MsgCreateClient { client_state: client_state.into(), consensus_state: make_consensus_state(test_a, height)?.into(), @@ -350,7 +352,7 @@ fn make_client_state(test: &Test, height: Height) -> TmClientState { let max_clock_drift = Duration::new(60, 0); let chain_id = ChainId::from_str(test.net.chain_id.as_str()).unwrap(); - TmClientState::new( + TmClientStateType::new( chain_id, TrustThreshold::default(), Duration::from_secs(trusting_period), @@ -365,6 +367,7 @@ fn make_client_state(test: &Test, height: Height) -> TmClientState { }, ) .unwrap() + .into() } fn make_consensus_state( @@ -396,7 +399,7 @@ fn update_client_with_height( }; let client_state = TmClientState::try_from(cs) .expect("the state should be a TmClientState"); - let trusted_height = client_state.latest_height; + let trusted_height = client_state.latest_height(); update_client( src_test, @@ -496,15 +499,22 @@ fn connection_handshake( Some(conn_id_a.clone()), commitment_prefix(), ); - let msg = make_msg_conn_open_try( - client_id_b.clone(), - client_state, + #[allow(deprecated)] + let msg = MsgConnectionOpenTry { + client_id_on_b: client_id_b.clone(), + client_state_of_b_on_a: client_state.clone().into(), counterparty, - conn_proof, - client_state_proof, - consensus_proof, - height_a, - ); + versions_on_a: vec![ConnVersion::default()], + proofs_height_on_a: height_a, + proof_conn_end_on_a: conn_proof, + proof_client_state_of_b_on_a: client_state_proof, + proof_consensus_state_of_b_on_a: consensus_proof, + consensus_height_of_b_on_a: client_state.latest_height(), + delay_period: Duration::from_secs(0), + signer: "test".to_string().into(), + proof_consensus_state_of_b: None, + previous_connection_id: ConnectionId::default().to_string(), + }; // Update the client state of Chain A on Chain B update_client_with_height(test_a, test_b, client_id_b, height_a)?; // OpenTryConnection on Chain B @@ -518,7 +528,7 @@ fn connection_handshake( let conn_proof = get_connection_proof(test_b, &conn_id_b, height_b)?; let (client_state, client_state_proof, consensus_proof) = get_client_states(test_b, client_id_b, height_b)?; - let consensus_height_of_a_on_b = client_state.latest_height; + let consensus_height_of_a_on_b = client_state.latest_height(); let msg = MsgConnectionOpenAck { conn_id_on_a: conn_id_a.clone(), conn_id_on_b: conn_id_b.clone(), @@ -695,7 +705,7 @@ fn get_client_states( .expect("the state should be a TmClientState"); let client_state_proof = convert_proof(tm_proof)?; - let height = client_state.latest_height; + let height = client_state.latest_height(); let ibc_height = Height::new(0, height.revision_height()).unwrap(); let key = consensus_state_key(client_id, ibc_height); let (_, tm_proof) = query_value_with_proof(test, &key, Some(query_height))?; @@ -1375,19 +1385,15 @@ fn query_value_with_proof( } fn convert_proof(tm_proof: TmProof) -> Result { - use namada::ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof; - use namada::ibc_proto::ics23::CommitmentProof; - let mut proofs = Vec::new(); - for op in &tm_proof.ops { - let mut parsed = CommitmentProof { proof: None }; + let mut parsed = ics23::CommitmentProof { proof: None }; prost::Message::merge(&mut parsed, op.data.as_slice()) .expect("merging CommitmentProof failed"); proofs.push(parsed); } - let merkle_proof = MerkleProof::from(RawMerkleProof { proofs }); + let merkle_proof = MerkleProof { proofs }; CommitmentProofBytes::try_from(merkle_proof).map_err(|e| { eyre!("Proof conversion to CommitmentProofBytes failed: {}", e) }) @@ -1527,40 +1533,6 @@ fn signer() -> Signer { "signer".to_string().into() } -/// Helper function to make the MsgConnectionOpenTry because it has a private -/// field -fn make_msg_conn_open_try( - client_id: ClientId, - client_state: TmClientState, - counterparty: ConnCounterparty, - conn_proof: CommitmentProofBytes, - client_state_proof: CommitmentProofBytes, - consensus_proof: CommitmentProofBytes, - proofs_height: Height, -) -> MsgConnectionOpenTry { - use namada::ibc_proto::ibc::core::connection::v1::MsgConnectionOpenTry as RawMsgConnectionOpenTry; - - let consensus_height = client_state.latest_height; - #[allow(deprecated)] - RawMsgConnectionOpenTry { - client_id: client_id.as_str().to_string(), - client_state: Some(client_state.into()), - counterparty: Some(counterparty.into()), - delay_period: 0, - counterparty_versions: vec![ConnVersion::default().into()], - proof_init: conn_proof.into(), - proof_height: Some(proofs_height.into()), - proof_client: client_state_proof.into(), - proof_consensus: consensus_proof.into(), - consensus_height: Some(consensus_height.into()), - signer: "signer".to_string(), - previous_connection_id: ConnectionId::default().to_string(), - host_consensus_state_proof: vec![], - } - .try_into() - .expect("invalid message") -} - fn get_client_id_from_events(events: &Vec) -> Option { get_attribute_from_events(events, "client_id").map(|v| v.parse().unwrap()) } @@ -1600,7 +1572,16 @@ fn get_packet_from_events(events: &Vec) -> Option { if !attributes.contains_key("packet_src_port") { continue; } - let mut packet = Packet::default(); + let mut packet = Packet { + seq_on_a: 0.into(), + port_id_on_a: PortId::transfer(), + chan_id_on_a: ChannelId::default(), + port_id_on_b: PortId::transfer(), + chan_id_on_b: ChannelId::default(), + data: vec![], + timeout_height_on_b: TimeoutHeight::default(), + timeout_timestamp_on_b: Timestamp::default(), + }; for (key, val) in attributes { match key.as_str() { "packet_src_port" => packet.port_id_on_a = val.parse().unwrap(), diff --git a/tests/src/e2e/ledger_tests.rs b/tests/src/e2e/ledger_tests.rs index 9f584e2b24..a8ffd1a1a3 100644 --- a/tests/src/e2e/ledger_tests.rs +++ b/tests/src/e2e/ledger_tests.rs @@ -1220,9 +1220,31 @@ fn pos_rewards() -> Result<()> { client.exp_string("Transaction is valid.")?; client.assert_success(); + // Query the current rewards for the validator self-bond + let tx_args = vec![ + "rewards", + "--validator", + "validator-0", + "--node", + &validator_0_rpc, + ]; + let mut client = + run_as!(test, Who::Validator(0), Bin::Client, tx_args, Some(40))?; + let (_, res) = client + .exp_regex(r"Current rewards available for claim: [0-9\.]+ NAM") + .unwrap(); + let words = res.split(' ').collect::>(); + let res = words[words.len() - 2]; + let mut last_amount = token::Amount::from_str( + res.split(' ').last().unwrap(), + NATIVE_MAX_DECIMAL_PLACES, + ) + .unwrap(); + client.assert_success(); + // Wait some epochs - let epoch = get_epoch(&test, &validator_0_rpc)?; - let wait_epoch = epoch + 4_u64; + let mut last_epoch = get_epoch(&test, &validator_0_rpc)?; + let wait_epoch = last_epoch + 4_u64; let start = Instant::now(); let loop_timeout = Duration::new(40, 0); @@ -1230,12 +1252,46 @@ fn pos_rewards() -> Result<()> { if Instant::now().duration_since(start) > loop_timeout { panic!("Timed out waiting for epoch: {}", wait_epoch); } + let epoch = epoch_sleep(&test, &validator_0_rpc, 40)?; if dbg!(epoch) >= wait_epoch { break; } + + // Query the current rewards for the validator self-bond and see that it + // grows + let tx_args = vec![ + "rewards", + "--validator", + "validator-0", + "--node", + &validator_0_rpc, + ]; + let mut client = + run_as!(test, Who::Validator(0), Bin::Client, tx_args, Some(40))?; + let (_, res) = client + .exp_regex(r"Current rewards available for claim: [0-9\.]+ NAM") + .unwrap(); + let words = res.split(' ').collect::>(); + let res = words[words.len() - 2]; + let amount = token::Amount::from_str( + res.split(' ').last().unwrap(), + NATIVE_MAX_DECIMAL_PLACES, + ) + .unwrap(); + client.assert_success(); + + if epoch > last_epoch { + assert!(amount > last_amount); + } else { + assert_eq!(amount, last_amount); + } + + last_amount = amount; + last_epoch = epoch; } + // Query the balance of the validator account let query_balance_args = vec![ "balance", "--owner", @@ -1254,6 +1310,7 @@ fn pos_rewards() -> Result<()> { .unwrap(); client.assert_success(); + // Claim rewards let tx_args = vec![ "claim-rewards", "--validator", @@ -1269,6 +1326,8 @@ fn pos_rewards() -> Result<()> { client.exp_string("Transaction is valid.")?; client.assert_success(); + // Query the validator balance again and check that the balance has grown + // after claiming let query_balance_args = vec![ "balance", "--owner", diff --git a/tests/src/vm_host_env/ibc.rs b/tests/src/vm_host_env/ibc.rs index 3ca3705fa9..fda711ad0d 100644 --- a/tests/src/vm_host_env/ibc.rs +++ b/tests/src/vm_host_env/ibc.rs @@ -1,50 +1,51 @@ use core::time::Duration; use std::collections::HashMap; -use namada::ibc::applications::transfer::coin::PrefixedCoin; -use namada::ibc::applications::transfer::error::TokenTransferError; -use namada::ibc::applications::transfer::msgs::transfer::MsgTransfer; -use namada::ibc::applications::transfer::packet::PacketData; -use namada::ibc::applications::transfer::{ack_success_b64, VERSION}; -use namada::ibc::core::ics02_client::msgs::create_client::MsgCreateClient; -use namada::ibc::core::ics02_client::msgs::update_client::MsgUpdateClient; -use namada::ibc::core::ics02_client::msgs::upgrade_client::MsgUpgradeClient; -use namada::ibc::core::ics03_connection::connection::{ - ConnectionEnd, Counterparty as ConnCounterparty, State as ConnState, +use ibc_testkit::testapp::ibc::clients::mock::client_state::{ + client_type, MockClientState, +}; +use ibc_testkit::testapp::ibc::clients::mock::consensus_state::MockConsensusState; +use ibc_testkit::testapp::ibc::clients::mock::header::MockHeader; +use namada::ibc::apps::transfer::types::error::TokenTransferError; +use namada::ibc::apps::transfer::types::msgs::transfer::MsgTransfer; +use namada::ibc::apps::transfer::types::packet::PacketData; +use namada::ibc::apps::transfer::types::{ + ack_success_b64, PrefixedCoin, VERSION, }; -use namada::ibc::core::ics03_connection::msgs::conn_open_ack::MsgConnectionOpenAck; -use namada::ibc::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOpenConfirm; -use namada::ibc::core::ics03_connection::msgs::conn_open_init::MsgConnectionOpenInit; -use namada::ibc::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; -use namada::ibc::core::ics03_connection::version::Version as ConnVersion; -use namada::ibc::core::ics04_channel::acknowledgement::{ +use namada::ibc::core::channel::types::acknowledgement::{ AcknowledgementStatus, StatusValue, }; -use namada::ibc::core::ics04_channel::channel::{ +use namada::ibc::core::channel::types::channel::{ ChannelEnd, Counterparty as ChanCounterparty, Order, State as ChanState, }; -use namada::ibc::core::ics04_channel::msgs::{ +use namada::ibc::core::channel::types::msgs::{ MsgAcknowledgement, MsgChannelCloseConfirm, MsgChannelCloseInit, MsgChannelOpenAck, MsgChannelOpenConfirm, MsgChannelOpenInit, MsgChannelOpenTry, MsgRecvPacket, MsgTimeout, MsgTimeoutOnClose, }; -pub use namada::ibc::core::ics04_channel::packet::{Packet, Sequence}; -use namada::ibc::core::ics04_channel::timeout::TimeoutHeight; -use namada::ibc::core::ics04_channel::Version as ChanVersion; -use namada::ibc::core::ics23_commitment::commitment::{ +pub use namada::ibc::core::channel::types::packet::Packet; +use namada::ibc::core::channel::types::timeout::TimeoutHeight; +use namada::ibc::core::channel::types::Version as ChanVersion; +use namada::ibc::core::client::types::msgs::{ + MsgCreateClient, MsgUpdateClient, MsgUpgradeClient, +}; +use namada::ibc::core::client::types::Height; +use namada::ibc::core::commitment_types::commitment::{ CommitmentPrefix, CommitmentProofBytes, }; -pub use namada::ibc::core::ics24_host::identifier::{ - ChannelId, ClientId, ConnectionId, PortId, +use namada::ibc::core::connection::types::msgs::{ + MsgConnectionOpenAck, MsgConnectionOpenConfirm, MsgConnectionOpenInit, + MsgConnectionOpenTry, +}; +use namada::ibc::core::connection::types::version::Version as ConnVersion; +use namada::ibc::core::connection::types::{ + ConnectionEnd, Counterparty as ConnCounterparty, State as ConnState, +}; +pub use namada::ibc::core::host::types::identifiers::{ + ChannelId, ClientId, ConnectionId, PortId, Sequence, }; -use namada::ibc::core::timestamp::Timestamp; -use namada::ibc::mock::client_state::{client_type, MockClientState}; -use namada::ibc::mock::consensus_state::MockConsensusState; -use namada::ibc::mock::header::MockHeader; -use namada::ibc::Height; -use namada::ibc_proto::google::protobuf::Any; -use namada::ibc_proto::ibc::core::connection::v1::MsgConnectionOpenTry as RawMsgConnectionOpenTry; -use namada::ibc_proto::protobuf::Protobuf; +use namada::ibc::primitives::proto::{Any, Protobuf}; +use namada::ibc::primitives::Timestamp; use namada::ledger::gas::VpGasMeter; pub use namada::ledger::ibc::storage::{ ack_key, channel_counter_key, channel_key, client_counter_key, @@ -71,7 +72,6 @@ use namada::ledger::{ibc, pos}; use namada::proof_of_stake::OwnedPosParams; use namada::proto::Tx; use namada::tendermint::time::Time as TmTime; -use namada::tendermint_proto::Protobuf as TmProtobuf; use namada::types::address::{self, Address, InternalAddress}; use namada::types::hash::Hash; use namada::types::storage::{ @@ -301,12 +301,12 @@ pub fn prepare_client() -> (ClientId, Any, HashMap>) { // client state let client_id = client_id(); let key = client_state_key(&client_id); - let bytes = Protobuf::::encode_vec(&client_state); + let bytes = Protobuf::::encode_vec(client_state); writes.insert(key, bytes); // consensus state let height = client_state.latest_height(); let key = consensus_state_key(&client_id, height); - let bytes = Protobuf::::encode_vec(&consensus_state); + let bytes = Protobuf::::encode_vec(consensus_state); writes.insert(key, bytes); // client update time let key = client_update_timestamp_key(&client_id); @@ -463,26 +463,22 @@ pub fn msg_connection_open_try( client_state: Any, ) -> MsgConnectionOpenTry { let consensus_height = Height::new(0, 1).expect("invalid height"); - // Convert a message from RawMsgConnectionOpenTry - // because MsgConnectionOpenTry cannot be created directly #[allow(deprecated)] - RawMsgConnectionOpenTry { - client_id: client_id.as_str().to_string(), + MsgConnectionOpenTry { + client_id_on_b: client_id, + client_state_of_b_on_a: client_state, + counterparty: dummy_connection_counterparty(), + versions_on_a: vec![ConnVersion::default()], + proofs_height_on_a: dummy_proof_height(), + proof_conn_end_on_a: dummy_proof(), + proof_client_state_of_b_on_a: dummy_proof(), + proof_consensus_state_of_b_on_a: dummy_proof(), + consensus_height_of_b_on_a: consensus_height, + delay_period: Duration::from_secs(0), + signer: "test".to_string().into(), + proof_consensus_state_of_b: Some(dummy_proof()), previous_connection_id: ConnectionId::default().to_string(), - client_state: Some(client_state), - counterparty: Some(dummy_connection_counterparty().into()), - delay_period: 0, - counterparty_versions: vec![ConnVersion::default().into()], - proof_height: Some(dummy_proof_height().into()), - proof_init: dummy_proof().into(), - proof_client: dummy_proof().into(), - proof_consensus: dummy_proof().into(), - consensus_height: Some(consensus_height.into()), - signer: "test".to_string(), - host_consensus_state_proof: dummy_proof().into(), } - .try_into() - .expect("invalid message") } pub fn msg_connection_open_ack( diff --git a/tests/src/vm_host_env/mod.rs b/tests/src/vm_host_env/mod.rs index 25fe337ce2..eed12a6112 100644 --- a/tests/src/vm_host_env/mod.rs +++ b/tests/src/vm_host_env/mod.rs @@ -23,7 +23,7 @@ mod tests { use borsh_ext::BorshSerializeExt; use itertools::Itertools; - use namada::ibc::core::Msg; + use namada::ibc::primitives::Msg; use namada::ledger::ibc::storage as ibc_storage; use namada::ledger::native_vp::ibc::{ get_dummy_header as tm_dummy_header, Error as IbcError, @@ -1039,7 +1039,7 @@ mod tests { // VP should fail because the transfer channel cannot be closed assert!(matches!( result.expect_err("validation succeeded unexpectedly"), - IbcError::IbcAction(IbcActionError::Execution(_)), + IbcError::IbcAction(IbcActionError::Context(_)), )); } diff --git a/tx_prelude/src/proof_of_stake.rs b/tx_prelude/src/proof_of_stake.rs index ec5f6f0ab8..15250e760a 100644 --- a/tx_prelude/src/proof_of_stake.rs +++ b/tx_prelude/src/proof_of_stake.rs @@ -1,9 +1,8 @@ //! Proof of Stake system integration with functions for transactions use namada_core::types::dec::Dec; -use namada_core::types::hash::Hash; use namada_core::types::key::common; -use namada_core::types::transaction::pos::InitValidator; +use namada_core::types::transaction::pos::BecomeValidator; use namada_core::types::{key, token}; pub use namada_proof_of_stake::parameters::PosParams; use namada_proof_of_stake::types::ValidatorMetaData; @@ -12,7 +11,7 @@ use namada_proof_of_stake::{ change_validator_commission_rate, change_validator_metadata, claim_reward_tokens, deactivate_validator, reactivate_validator, read_pos_params, redelegate_tokens, unbond_tokens, unjail_validator, - withdraw_tokens, BecomeValidator, + withdraw_tokens, }; pub use namada_proof_of_stake::{parameters, types, ResultSlashing}; @@ -114,11 +113,10 @@ impl Ctx { /// Attempt to initialize a validator account. On success, returns the /// initialized validator account's address. - pub fn init_validator( + pub fn become_validator( &mut self, - InitValidator { - account_keys, - threshold, + BecomeValidator { + address, consensus_key, eth_cold_key, eth_hot_key, @@ -129,46 +127,36 @@ impl Ctx { description, website, discord_handle, - validator_vp_code_hash: _, - }: InitValidator, - validator_vp_code_hash: Hash, - validator_vp_code_tag: &Option, + }: BecomeValidator, ) -> EnvResult
{ let current_epoch = self.get_block_epoch()?; - // Init validator account - let validator_address = - self.init_account(validator_vp_code_hash, validator_vp_code_tag)?; - storage_api::account::init_account_storage( - self, - &validator_address, - &account_keys, - threshold, - )?; let eth_cold_key = key::common::PublicKey::Secp256k1(eth_cold_key); let eth_hot_key = key::common::PublicKey::Secp256k1(eth_hot_key); - let params = read_pos_params(self)?; - become_validator(BecomeValidator { - storage: self, - params: ¶ms, - address: &validator_address, - consensus_key: &consensus_key, - protocol_key: &protocol_key, - eth_cold_key: ð_cold_key, - eth_hot_key: ð_hot_key, - current_epoch, - commission_rate, - max_commission_rate_change, - metadata: ValidatorMetaData { - email, - description, - website, - discord_handle, + + become_validator( + self, + namada_proof_of_stake::BecomeValidator { + params: ¶ms, + address: &address, + consensus_key: &consensus_key, + protocol_key: &protocol_key, + eth_cold_key: ð_cold_key, + eth_hot_key: ð_hot_key, + current_epoch, + commission_rate, + max_commission_rate_change, + metadata: ValidatorMetaData { + email, + description, + website, + discord_handle, + }, + offset_opt: None, }, - offset_opt: None, - })?; + )?; - Ok(validator_address) + Ok(address) } /// Deactivate validator diff --git a/wasm/Cargo.lock b/wasm/Cargo.lock index 66a3bb5817..0c6177bd22 100644 --- a/wasm/Cargo.lock +++ b/wasm/Cargo.lock @@ -369,7 +369,7 @@ dependencies = [ "hmac 0.12.1", "pbkdf2 0.10.1", "rand 0.8.5", - "sha2 0.10.6", + "sha2 0.10.8", "unicode-normalization", "zeroize", ] @@ -450,7 +450,7 @@ dependencies = [ "cc", "cfg-if 1.0.0", "constant_time_eq", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -594,9 +594,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" dependencies = [ "serde", ] @@ -766,13 +766,13 @@ dependencies = [ "bincode", "bs58", "coins-core", - "digest 0.10.6", + "digest 0.10.7", "getrandom 0.2.10", "hmac 0.12.1", "k256", "lazy_static", "serde", - "sha2 0.10.6", + "sha2 0.10.8", "thiserror", ] @@ -789,7 +789,7 @@ dependencies = [ "once_cell", "pbkdf2 0.12.1", "rand 0.8.5", - "sha2 0.10.6", + "sha2 0.10.8", "thiserror", ] @@ -802,13 +802,13 @@ dependencies = [ "base64 0.21.0", "bech32 0.7.3", "bs58", - "digest 0.10.6", + "digest 0.10.7", "generic-array 0.14.7", "hex", "ripemd", "serde", "serde_derive", - "sha2 0.10.6", + "sha2 0.10.8", "sha3", "thiserror", ] @@ -1206,9 +1206,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", "const-oid", @@ -1286,7 +1286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" dependencies = [ "der", - "digest 0.10.6", + "digest 0.10.7", "elliptic-curve", "rfc6979", "serdect", @@ -1346,7 +1346,7 @@ checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" dependencies = [ "base16ct", "crypto-bigint", - "digest 0.10.6", + "digest 0.10.7", "ff", "generic-array 0.14.7", "group", @@ -1461,7 +1461,7 @@ checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" dependencies = [ "aes", "ctr", - "digest 0.10.6", + "digest 0.10.7", "hex", "hmac 0.12.1", "pbkdf2 0.11.0", @@ -1469,7 +1469,7 @@ dependencies = [ "scrypt", "serde", "serde_json", - "sha2 0.10.6", + "sha2 0.10.8", "sha3", "thiserror", "uuid", @@ -1765,7 +1765,7 @@ dependencies = [ "ethers-core", "hex", "rand 0.8.5", - "sha2 0.10.6", + "sha2 0.10.8", "thiserror", "tracing", ] @@ -2211,7 +2211,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -2328,40 +2328,389 @@ dependencies = [ [[package]] name = "ibc" -version = "0.47.0" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "429b6aca6624a9364878e28c90311438c2621a8270942d80732b2651ac38ac74" +dependencies = [ + "ibc-apps", + "ibc-clients", + "ibc-core", + "ibc-core-host-cosmos", + "ibc-derive", + "ibc-primitives", +] + +[[package]] +name = "ibc-app-transfer" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b177b343385d9654d99be4709b5ed1574d41f91dfa4044b2d26d688be4179d7c" +dependencies = [ + "ibc-app-transfer-types", + "ibc-core", + "serde-json-wasm", +] + +[[package]] +name = "ibc-app-transfer-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95f92a3eda225e5c86e7bb6501c95986583ac541c4369d3c528349d81390f947" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core", + "ibc-proto", + "primitive-types", + "serde", + "uint", +] + +[[package]] +name = "ibc-apps" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4be40d55ed2dea9f2d05b902a3586f20850c723e4bdbfc4fb0ebe7a66ca5e40" +dependencies = [ + "ibc-app-transfer", +] + +[[package]] +name = "ibc-client-tendermint" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119aa5873214228bf69bded3f20022b9ae1bc35b6841d295afcd73e53db05ccf" +dependencies = [ + "ibc-client-tendermint-types", + "ibc-core-client", + "ibc-core-commitment-types", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-primitives", + "prost 0.12.1", + "serde", + "tendermint", + "tendermint-light-client-verifier", +] + +[[package]] +name = "ibc-client-tendermint-types" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "184eb22140cb4143bbcf7ddc8fdfeb9cc058ef73a6066f8ea78162e69d3565d1" +checksum = "6f21679016931b332b295a761e65cc122dc6fbfb98444148b681ad3aaa474665" dependencies = [ "bytes", + "displaydoc", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde", + "tendermint", + "tendermint-light-client-verifier", + "tendermint-proto", +] + +[[package]] +name = "ibc-clients" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c660323e93107a136aa3dbc412b7fa2eafd315c2fe71184096a43800f8ca5" +dependencies = [ + "ibc-client-tendermint", +] + +[[package]] +name = "ibc-core" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "100d9d0aa67432c5078a8a1c818e3fc990a193be6d35ed0abeda5b340d16c1da" +dependencies = [ + "ibc-core-channel", + "ibc-core-client", + "ibc-core-commitment-types", + "ibc-core-connection", + "ibc-core-handler", + "ibc-core-host", + "ibc-core-router", + "ibc-primitives", +] + +[[package]] +name = "ibc-core-channel" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebaa37629ac029f914dfe552ab5dad01ddb240ec885ed0ae68221cbea4e9bfc" +dependencies = [ + "ibc-core-channel-types", + "ibc-core-client", + "ibc-core-commitment-types", + "ibc-core-connection", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-core-router", + "ibc-primitives", + "prost 0.12.1", +] + +[[package]] +name = "ibc-core-channel-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2ba72c56c411b1e0ce6dc3f5e1fa1de9e6c84891f425b7be8a9e1705964378" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-connection-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde", + "sha2 0.10.8", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-client" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c4fac8e05201795073dee8c93d5afe9dfeac9aec2412b4a2b0c5f0d1e1d725" +dependencies = [ + "ibc-core-client-context", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-primitives", + "prost 0.12.1", +] + +[[package]] +name = "ibc-core-client-context" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b82abd9489021730d59ab2d00e9438d3711e8e78ecba4d083b64f833301682b" +dependencies = [ "derive_more", "displaydoc", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-handler-types", + "ibc-core-host-types", "ibc-derive", + "ibc-primitives", + "prost 0.12.1", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-client-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bafdbf6db5dab4c8ad610b6940e23b4f8abd0a6ac5e8e2801415a95defd4a583" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-commitment-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-commitment-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed4256b0216fc49024bac7e01c61b9bb055e31914ffe9ce6f468d7ce496a9357" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-primitives", + "ibc-proto", + "ics23", + "prost 0.12.1", + "serde", + "subtle-encoding", +] + +[[package]] +name = "ibc-core-connection" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e237b70b9ba0177a4e59ac9048fffac2ac44c334703cc0ae403ad221450850" +dependencies = [ + "ibc-core-client", + "ibc-core-connection-types", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-primitives", + "prost 0.12.1", +] + +[[package]] +name = "ibc-core-connection-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca841416fa29626423917099092f3698ae2735074cb3fe42936ddf6b2ccbf2f7" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-handler" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47e5e5a006aa0fc87ec3f5fb1e0ef6dd5aeea5079fa927d799d526c44329987" +dependencies = [ + "ibc-core-channel", + "ibc-core-client", + "ibc-core-commitment-types", + "ibc-core-connection", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-core-router", + "ibc-primitives", +] + +[[package]] +name = "ibc-core-handler-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3d59a8a5eb2069530c42783b4fef63472a89e0e9242334351df1bb58aaf542" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-channel-types", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-connection-types", + "ibc-core-host-types", + "ibc-core-router-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-host" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aa63c895c0e5a75e42fe859b8fd4250c12bfa8b9c6b114f94c927ecfad38a03" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-channel-types", + "ibc-core-client-context", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-connection-types", + "ibc-core-handler-types", + "ibc-core-host-types", + "ibc-primitives", + "prost 0.12.1", + "subtle-encoding", +] + +[[package]] +name = "ibc-core-host-cosmos" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a325862af6c20b0df3d27c072a2d802a7232dc1666214d738cdfbd9a9c99720" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-app-transfer-types", + "ibc-client-tendermint", + "ibc-core-client-context", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-connection-types", + "ibc-core-handler-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde", + "sha2 0.10.8", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-host-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616955da310febbe93c0569a2feebd9f57cafed3eee5a56b0c3bb953a75f6089" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-primitives", + "serde", +] + +[[package]] +name = "ibc-core-router" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31fe115da73e0616bdb44400fa6b11ca251648d070c4ff419d58e27804d30243" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router-types", + "ibc-primitives", + "prost 0.12.1", + "subtle-encoding", +] + +[[package]] +name = "ibc-core-router-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d1fbb0bbbdeafa7ac989ba1693ed46d22e0e3eb0bdae478544e31157a4fdba6" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-host-types", + "ibc-primitives", "ibc-proto", "ics23", - "num-traits", - "parking_lot", - "primitive-types", "prost 0.12.1", "serde", - "serde-json-wasm", - "serde_derive", - "sha2 0.10.6", "subtle-encoding", "tendermint", - "tendermint-light-client-verifier", - "tendermint-proto", - "tendermint-testgen", - "time", - "tracing", - "typed-builder", - "uint", ] [[package]] name = "ibc-derive" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92f1528535e9ca495badb76c143bdd4763c1c9d987f59d1f8b47963ba0c11674" +checksum = "df07bf5bc1e65e291506b7497633e07967e49b36a8db10cda77a8fd686eb4548" dependencies = [ "darling", "proc-macro2", @@ -2369,11 +2718,26 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "ibc-primitives" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5edea4685267fd68514c87e7aa3a62712340c4cff6903f088a9ab571428a08a" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-proto", + "prost 0.12.1", + "serde", + "tendermint", + "time", +] + [[package]] name = "ibc-proto" -version = "0.37.1" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63042806bb2f662ca1c68026231900cfe13361136ddfd0dd09bcb315056a22b8" +checksum = "93cbf4cbe9e5113cc7c70f3208a7029b2205c629502cbb2ae7ea0a09a97d3005" dependencies = [ "base64 0.21.0", "bytes", @@ -2385,6 +2749,27 @@ dependencies = [ "tendermint-proto", ] +[[package]] +name = "ibc-testkit" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f550c91648f3db6474880e18cd2bd294096a99b30621aa01a9059b71e3612d98" +dependencies = [ + "bytes", + "derive_more", + "displaydoc", + "ibc", + "ibc-proto", + "parking_lot", + "primitive-types", + "prost 0.12.1", + "subtle-encoding", + "tendermint", + "tendermint-testgen", + "tracing", + "typed-builder", +] + [[package]] name = "ics23" version = "0.11.0" @@ -2398,7 +2783,7 @@ dependencies = [ "prost 0.12.1", "ripemd", "serde", - "sha2 0.10.6", + "sha2 0.10.8", "sha3", ] @@ -2636,7 +3021,7 @@ dependencies = [ "elliptic-curve", "once_cell", "serdect", - "sha2 0.10.6", + "sha2 0.10.8", "signature", ] @@ -2790,7 +3175,7 @@ dependencies = [ "num-traits", "rand 0.8.5", "rand_core 0.6.4", - "sha2 0.10.6", + "sha2 0.10.8", "subtle 2.4.1", "zcash_encoding", ] @@ -3013,7 +3398,7 @@ dependencies = [ "eyre", "ibc", "ibc-derive", - "ibc-proto", + "ibc-testkit", "ics23", "impl-num-traits", "index-set", @@ -3155,6 +3540,8 @@ dependencies = [ "copy_dir", "derivative", "hyper", + "ibc-testkit", + "ics23", "lazy_static", "namada", "namada_core", @@ -3649,7 +4036,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "password-hash", ] @@ -3659,7 +4046,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -3668,7 +4055,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0ca0b5a68607598bf3bad68f32227a8164f6254833f84eafaac409cd6746c31" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "hmac 0.12.1", ] @@ -3816,9 +4203,9 @@ dependencies = [ [[package]] name = "primitive-types" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", "impl-codec", @@ -4337,7 +4724,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -4582,7 +4969,7 @@ dependencies = [ "hmac 0.12.1", "pbkdf2 0.11.0", "salsa20", - "sha2 0.10.6", + "sha2 0.10.8", ] [[package]] @@ -4806,13 +5193,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -4821,7 +5208,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "keccak", ] @@ -4849,7 +5236,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "rand_core 0.6.4", ] @@ -5086,7 +5473,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc2294fa667c8b548ee27a9ba59115472d0a09c2ba255771092a7f1dcf03a789" dependencies = [ "bytes", - "digest 0.10.6", + "digest 0.10.7", "ed25519", "ed25519-consensus 2.1.0", "flex-error", @@ -5101,7 +5488,7 @@ dependencies = [ "serde_bytes", "serde_json", "serde_repr", - "sha2 0.10.6", + "sha2 0.10.8", "signature", "subtle 2.4.1", "subtle-encoding", @@ -5468,11 +5855,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if 1.0.0", "log", "pin-project-lite", "tracing-attributes", @@ -5481,9 +5867,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.24" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", @@ -5492,9 +5878,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] @@ -5543,18 +5929,18 @@ dependencies = [ [[package]] name = "typed-builder" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c6a006a6d3d6a6f143fda41cf4d1ad35110080687628c9f2117bd3cc7924f3" +checksum = "e47c0496149861b7c95198088cbf36645016b1a0734cf350c50e2a38e070f38a" dependencies = [ "typed-builder-macro", ] [[package]] name = "typed-builder-macro" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fa054ee5e2346187d631d2f1d1fd3b33676772d6d03a2d84e1c5213b31674ee" +checksum = "982ee4197351b5c9782847ef5ec1fdcaf50503fb19d68f9771adae314e72b492" dependencies = [ "proc-macro2", "quote", diff --git a/wasm/checksums.json b/wasm/checksums.json index 8c94ff7a0d..4496b90b40 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,27 +1,26 @@ { - "tx_bond.wasm": "tx_bond.a660b13a79bd5c50c75a055ab4fed8eddb1cc2ae6d93e5505fbeb876b307fc49.wasm", - "tx_bridge_pool.wasm": "tx_bridge_pool.9564137202b291bd8930410700a5b0e08a1949bb4f79da5ee3e3dc9654266f4d.wasm", - "tx_change_consensus_key.wasm": "tx_change_consensus_key.4d2de1a762b4575925222fdeacadada429896a93fe3586f41657f247480161d9.wasm", - "tx_change_validator_commission.wasm": "tx_change_validator_commission.457abeb00c021822e54674b77ae97535620555707efd2029e52b0d4335a32b55.wasm", - "tx_change_validator_metadata.wasm": "tx_change_validator_metadata.b56e2fbaefe19800d8a6d989883ab0ceac439bdeac96fb1299f6aa2ce424e521.wasm", - "tx_claim_rewards.wasm": "tx_claim_rewards.c4fc5d2ace6b0ee785f12f90a6cc600e3a0a8f19f7237ecf9374a32ba27eb99e.wasm", - "tx_deactivate_validator.wasm": "tx_deactivate_validator.c7cb406926241ffaa5df56e43c8cc43854bdcb0ea565144f63b6a3e2eb697a96.wasm", - "tx_ibc.wasm": "tx_ibc.14568fef2ec08752b87ec97cb2c87b76adec72e6eeea771274948d7c7ddb92a8.wasm", - "tx_init_account.wasm": "tx_init_account.0017279b252083d2d337d943bf84251d3f8223756ecfd9648e7ce66305c45796.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.cb9d7a33dd9a37675dd1d9cb761f3f87a48728eae38f377a623c0b8f9a97b612.wasm", - "tx_init_validator.wasm": "tx_init_validator.53fefa66ce6351d6b3e7de7a2c993bd4435fbd478b66caecf5c588b5efdcf669.wasm", - "tx_reactivate_validator.wasm": "tx_reactivate_validator.6a40f8daebdd6b9f6bcc9ab88686b40bb7a7882443cd07443c0795a3fae27cb5.wasm", - "tx_redelegate.wasm": "tx_redelegate.ded70e2609371fc9d81de875cf44b0ec60757fb46f61f23a26418cfa9f437b0f.wasm", - "tx_resign_steward.wasm": "tx_resign_steward.a881ed70174b53a15402cbbe6e64200f72431ec73604f7b173fd77ea80b5aedb.wasm", - "tx_reveal_pk.wasm": "tx_reveal_pk.fbe760707aa0559c898cee47c91a5c7d0bc4b2f545cb47cc459ddcb8f97c455e.wasm", - "tx_transfer.wasm": "tx_transfer.aef75ec63198e4e6f95307a55e53fd0440448caf46617047f7a7557a7a2f1f4e.wasm", - "tx_unbond.wasm": "tx_unbond.1fd257addac3d91d77e1ae334b9394085335075581a6500ce2364cd403d028e9.wasm", - "tx_unjail_validator.wasm": "tx_unjail_validator.ba0e378bb48d5ba577dd898e618478c917e80ee11e46f79b00bb72fea4f91c28.wasm", - "tx_update_account.wasm": "tx_update_account.aa4ef57619b8b7c7c3849fa71873448808f7342fcc8d612e4b5e688a708a174a.wasm", - "tx_update_steward_commission.wasm": "tx_update_steward_commission.e7bf45b9039a5b4ef399fe926a4b56e035e9a7eedc4fdd59fc89210b4a8bbf74.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.4b39fd9c6ccc8a9537a295d154a8b9e60b8d135fe995276a01d714bc8097be6a.wasm", - "tx_withdraw.wasm": "tx_withdraw.2f6bf8c3cafbd5d987849db1583bd63e10bbe06193f619859caa80ab10f2e2a9.wasm", - "vp_implicit.wasm": "vp_implicit.262b8660014cd140bcbbef2d187863160678cb0034903257815dc08d947b03fa.wasm", - "vp_user.wasm": "vp_user.d66a3a289c9c9e6353a2741335775eab1487e2e7ee4b8baa69d32e73083363d3.wasm", - "vp_validator.wasm": "vp_validator.d89911d9c27b2e0926499623cc88ee35c4396c8ef0563f897386ff431c8148e7.wasm" + "tx_become_validator.wasm": "tx_become_validator.7db9c3a8322d8505cc7a2128cd0a2d1a755a9e2a2eed1057d9578cc4bccee9c9.wasm", + "tx_bond.wasm": "tx_bond.fc80252a205b0623c6d99d11cbfea21e3f3595c52b1ae8dee5367f3743863d4d.wasm", + "tx_bridge_pool.wasm": "tx_bridge_pool.c1523e23fb0c0350976898ab8a2bfa45b58e25b72ea8eeafc094a9cec846169f.wasm", + "tx_change_consensus_key.wasm": "tx_change_consensus_key.e5fc03f47b8ad75f0d3b096312b84f16c93ddf93d8c1ac8b96c085a1052baf33.wasm", + "tx_change_validator_commission.wasm": "tx_change_validator_commission.fbffeea7b9912d3258596497cf3c349ac52cba3608e08a31c076669c574b9c29.wasm", + "tx_change_validator_metadata.wasm": "tx_change_validator_metadata.5750661d1dbf22e794edc0ab83d01871806b35886bfc85ce7ef536e8d110f252.wasm", + "tx_claim_rewards.wasm": "tx_claim_rewards.3398d0d391d19387afdf0e68b4edbe85ba0d05b0e1453b5ec85514dc662b1e30.wasm", + "tx_deactivate_validator.wasm": "tx_deactivate_validator.07abfea65726b644b6fb3cc06a3bbe518ccf713f7f8f1de1200a0e210c237b65.wasm", + "tx_ibc.wasm": "tx_ibc.1106ca7afa4677fe06a8190574246106d53d4c503fa7521609570487d7883263.wasm", + "tx_init_account.wasm": "tx_init_account.e8355a63cd514eff0cb4f8c8fc2606f1e598f3b3bc4404c97f675f0aaa79dd56.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.d04e7a203c681611ac42d37fe5b9d2b2a81fe13b098db436d88105aadb5c885a.wasm", + "tx_reactivate_validator.wasm": "tx_reactivate_validator.4fa7ba04bb7555001d4d950b90caaad1ab8aae8ab41586c29d0dc44ec32c6179.wasm", + "tx_redelegate.wasm": "tx_redelegate.6d4c1315afeba78eb4d719aa2ecbe60941e39b177e355a778aee799f9ec1fcc2.wasm", + "tx_resign_steward.wasm": "tx_resign_steward.bdf010721ef674f14869189084a7d89c58e17c6f4d6429e42b5f4fe4f51c7c19.wasm", + "tx_reveal_pk.wasm": "tx_reveal_pk.8748d3e183a81ca1d7b90945046a24863173e9e5b16f42bd3dacde7a174859c1.wasm", + "tx_transfer.wasm": "tx_transfer.784297d2ddf39c90073fa51e685f07c13bf5027ce4928a823a12d9d3a9712ca0.wasm", + "tx_unbond.wasm": "tx_unbond.4baa376531950368d708b492cff275ff7eb61501add5e542a045a8962ccf1a41.wasm", + "tx_unjail_validator.wasm": "tx_unjail_validator.8c0aaef2b867d00e8b36cedac442b67089d3245faca63cf162f24e2fb2bcdee8.wasm", + "tx_update_account.wasm": "tx_update_account.ca862c016bd905c1b030a328b89f624be6747a1ac2c4cefd1aa2f4007c609606.wasm", + "tx_update_steward_commission.wasm": "tx_update_steward_commission.d34fb64426f18d28b8363d0c1eb71d77b0a6d67a0d91bd0ef513a0db92ae5f14.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.e55ea5b4d250d390e273b10d3952ba066e82ed8e4eba4e1a0196a69027997706.wasm", + "tx_withdraw.wasm": "tx_withdraw.08d5f526c2d33b88bc3554d2b9d65d24544d51e4a34ee584667a70f62c9c2235.wasm", + "vp_implicit.wasm": "vp_implicit.09730504e767a7ad56dfc0150cddcdcc84f8ac8040c4e1ac1bdaaa9cbc9dfed3.wasm", + "vp_user.wasm": "vp_user.bb4eff8a82138ceff5c09576a1b1369f8c943acd1ea1c06317785cc191bb5a9a.wasm" } \ No newline at end of file diff --git a/wasm/wasm_source/Cargo.toml b/wasm/wasm_source/Cargo.toml index 8e8e3efe4e..8e198626c2 100644 --- a/wasm/wasm_source/Cargo.toml +++ b/wasm/wasm_source/Cargo.toml @@ -23,7 +23,7 @@ tx_from_intent = ["namada_tx_prelude"] tx_ibc = ["namada_tx_prelude"] tx_init_account = ["namada_tx_prelude"] tx_init_proposal = ["namada_tx_prelude"] -tx_init_validator = ["namada_tx_prelude"] +tx_become_validator = ["namada_tx_prelude"] tx_reactivate_validator = ["namada_tx_prelude"] tx_redelegate = ["namada_tx_prelude"] tx_reveal_pk = ["namada_tx_prelude"] @@ -38,7 +38,6 @@ tx_resign_steward = ["namada_tx_prelude"] vp_implicit = ["namada_vp_prelude", "once_cell"] vp_token = ["namada_vp_prelude"] vp_user = ["namada_vp_prelude", "once_cell"] -vp_validator = ["namada_vp_prelude", "once_cell"] [dependencies] namada_tx_prelude = {path = "../../tx_prelude", optional = true} diff --git a/wasm/wasm_source/Makefile b/wasm/wasm_source/Makefile index 6772a2e739..f01292af1e 100644 --- a/wasm/wasm_source/Makefile +++ b/wasm/wasm_source/Makefile @@ -15,7 +15,7 @@ wasms += tx_deactivate_validator wasms += tx_ibc wasms += tx_init_account wasms += tx_init_proposal -wasms += tx_init_validator +wasms += tx_become_validator wasms += tx_redelegate wasms += tx_reactivate_validator wasms += tx_reveal_pk @@ -29,7 +29,6 @@ wasms += tx_update_steward_commission wasms += tx_resign_steward wasms += vp_implicit wasms += vp_user -wasms += vp_validator # Build all wasms in release mode all: $(wasms) diff --git a/wasm/wasm_source/src/lib.rs b/wasm/wasm_source/src/lib.rs index ae3d121f2c..4e27cb92ad 100644 --- a/wasm/wasm_source/src/lib.rs +++ b/wasm/wasm_source/src/lib.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "tx_become_validator")] +pub mod tx_become_validator; #[cfg(feature = "tx_bond")] pub mod tx_bond; #[cfg(feature = "tx_bridge_pool")] @@ -18,8 +20,6 @@ pub mod tx_ibc; pub mod tx_init_account; #[cfg(feature = "tx_init_proposal")] pub mod tx_init_proposal; -#[cfg(feature = "tx_init_validator")] -pub mod tx_init_validator; #[cfg(feature = "tx_reactivate_validator")] pub mod tx_reactivate_validator; #[cfg(feature = "tx_redelegate")] @@ -47,5 +47,3 @@ pub mod tx_withdraw; pub mod vp_implicit; #[cfg(feature = "vp_user")] pub mod vp_user; -#[cfg(feature = "vp_validator")] -pub mod vp_validator; diff --git a/wasm/wasm_source/src/tx_become_validator.rs b/wasm/wasm_source/src/tx_become_validator.rs new file mode 100644 index 0000000000..4f959f6921 --- /dev/null +++ b/wasm/wasm_source/src/tx_become_validator.rs @@ -0,0 +1,44 @@ +//! A tx to initialize a new validator account with a given public keys and a +//! validity predicates. + +use namada_tx_prelude::transaction::pos::BecomeValidator; +use namada_tx_prelude::*; + +#[transaction(gas = 4395397)] +fn apply_tx(ctx: &mut Ctx, tx_data: Tx) -> TxResult { + let signed = tx_data; + let data = signed.data().ok_or_err_msg("Missing data").map_err(|err| { + ctx.set_commitment_sentinel(); + err + })?; + let become_validator = BecomeValidator::try_from_slice(&data[..]) + .wrap_err("failed to decode InitValidator")?; + debug_log!("apply_tx called to init a new validator account"); + + // Check that the tx has been signed with all the keys to be used for the + // validator account + let all_pks = vec![ + become_validator.consensus_key.clone(), + key::common::PublicKey::Secp256k1( + become_validator.eth_cold_key.clone(), + ), + key::common::PublicKey::Secp256k1(become_validator.eth_hot_key.clone()), + become_validator.protocol_key.clone(), + ]; + if !matches!(verify_signatures_of_pks(ctx, &signed, all_pks), Ok(true)) { + debug_log!("Keys ownership signature verification failed"); + panic!() + } + + // Register the validator in PoS + match ctx.become_validator(become_validator) { + Ok(validator_address) => { + debug_log!("Created validator {}", validator_address.encode(),) + } + Err(err) => { + debug_log!("Validator creation failed with: {}", err); + panic!() + } + } + Ok(()) +} diff --git a/wasm/wasm_source/src/tx_init_validator.rs b/wasm/wasm_source/src/tx_init_validator.rs deleted file mode 100644 index f7aa70997b..0000000000 --- a/wasm/wasm_source/src/tx_init_validator.rs +++ /dev/null @@ -1,64 +0,0 @@ -//! A tx to initialize a new validator account with a given public keys and a -//! validity predicates. - -use namada_tx_prelude::transaction::pos::InitValidator; -use namada_tx_prelude::*; - -#[transaction(gas = 4395397)] -fn apply_tx(ctx: &mut Ctx, tx_data: Tx) -> TxResult { - let signed = tx_data; - let data = signed.data().ok_or_err_msg("Missing data").map_err(|err| { - ctx.set_commitment_sentinel(); - err - })?; - let init_validator = InitValidator::try_from_slice(&data[..]) - .wrap_err("failed to decode InitValidator")?; - debug_log!("apply_tx called to init a new validator account"); - - // Get the validator vp code from the extra section - let validator_vp_code_sec = signed - .get_section(&init_validator.validator_vp_code_hash) - .ok_or_err_msg("validator vp section not found") - .map_err(|err| { - ctx.set_commitment_sentinel(); - err - })? - .extra_data_sec() - .ok_or_err_msg("validator vp section must be tagged as extra") - .map_err(|err| { - ctx.set_commitment_sentinel(); - err - })?; - - // Check that the tx has been signed with all the keys to be used for the - // validator account - let mut all_pks = init_validator.account_keys.clone(); - all_pks.push(init_validator.consensus_key.clone()); - all_pks.push(key::common::PublicKey::Secp256k1( - init_validator.eth_cold_key.clone(), - )); - all_pks.push(key::common::PublicKey::Secp256k1( - init_validator.eth_hot_key.clone(), - )); - all_pks.push(init_validator.protocol_key.clone()); - if !matches!(verify_signatures_of_pks(ctx, &signed, all_pks), Ok(true)) { - debug_log!("Keys ownership signature verification failed"); - panic!() - } - - // Register the validator in PoS - match ctx.init_validator( - init_validator, - validator_vp_code_sec.code.hash(), - &validator_vp_code_sec.tag, - ) { - Ok(validator_address) => { - debug_log!("Created validator {}", validator_address.encode(),) - } - Err(err) => { - debug_log!("Validator creation failed with: {}", err); - panic!() - } - } - Ok(()) -} diff --git a/wasm/wasm_source/src/vp_user.rs b/wasm/wasm_source/src/vp_user.rs index 28bfcbdc9f..390bc389fb 100644 --- a/wasm/wasm_source/src/vp_user.rs +++ b/wasm/wasm_source/src/vp_user.rs @@ -1,16 +1,20 @@ -//! A basic user VP. +//! A basic user VP supports both non-validator and validator accounts. //! //! This VP currently provides a signature verification against a public key for //! sending tokens (receiving tokens is permissive). //! //! It allows to bond, unbond and withdraw tokens to and from PoS system with a -//! valid signature. +//! valid signature(s). +//! +//! For validator a tx to change a validator's commission rate or metadata +//! requires a valid signature(s) only from the validator. //! //! Any other storage key changes are allowed only with a valid signature. use namada_vp_prelude::storage::KeySeg; use namada_vp_prelude::*; use once_cell::unsync::Lazy; +use proof_of_stake::types::ValidatorState; enum KeyType<'a> { Token { owner: &'a Address }, @@ -104,14 +108,14 @@ fn validate_tx( } } KeyType::PoS => { - // Allow the account to be used in PoS + // Bond or unbond let bond_id = proof_of_stake::storage::is_bond_key(key) .map(|(bond_id, _)| bond_id) .or_else(|| { proof_of_stake::storage::is_unbond_key(key) .map(|(bond_id, _, _)| bond_id) }); - let valid = match bond_id { + let valid_bond_or_unbond_change = match bond_id { Some(bond_id) => { // Bonds and unbonds changes for this address // must be signed @@ -122,12 +126,85 @@ fn validate_tx( true } }; - debug_log!( - "PoS key {} {}", - key, - if valid { "accepted" } else { "rejected" } - ); - valid + // Commission rate changes must be signed by the validator + let comm = + proof_of_stake::storage::is_validator_commission_rate_key( + key, + ); + let valid_commission_rate_change = match comm { + Some((validator, _epoch)) => { + *validator == addr && *valid_sig + } + None => true, + }; + // Metadata changes must be signed by the validator whose + // metadata is manipulated + let metadata = + proof_of_stake::storage::is_validator_metadata_key(key); + let valid_metadata_change = match metadata { + Some(address) => *address == addr && *valid_sig, + None => true, + }; + + // Changes due to unjailing, deactivating, and reactivating are + // marked by changes in validator state + let state_change = + proof_of_stake::storage::is_validator_state_key(key); + let valid_state_change = match state_change { + Some((address, epoch)) => { + let params_pre = + proof_of_stake::read_pos_params(&ctx.pre())?; + let state_pre = + proof_of_stake::validator_state_handle(address) + .get(&ctx.pre(), epoch, ¶ms_pre)?; + + let params_post = + proof_of_stake::read_pos_params(&ctx.post())?; + let state_post = + proof_of_stake::validator_state_handle(address) + .get(&ctx.post(), epoch, ¶ms_post)?; + + match (state_pre, state_post) { + (Some(pre), Some(post)) => { + if + // Deactivation case + (matches!( + pre, + ValidatorState::Consensus + | ValidatorState::BelowCapacity + | ValidatorState::BelowThreshold + ) && post == ValidatorState::Inactive) + // Reactivation case + || pre == ValidatorState::Inactive + && post != ValidatorState::Inactive + // Unjail case + || pre == ValidatorState::Jailed + && matches!( + post, + ValidatorState::Consensus + | ValidatorState::BelowCapacity + | ValidatorState::BelowThreshold + ) + { + *address == addr && *valid_sig + } else { + true + } + } + (None, Some(_post)) => { + // Becoming a validator must be authorized + *valid_sig + } + _ => true, + } + } + None => true, + }; + + valid_bond_or_unbond_change + && valid_commission_rate_change + && valid_state_change + && valid_metadata_change } KeyType::GovernanceVote(voter) => { if voter == &addr { @@ -186,7 +263,7 @@ mod tests { use namada::proto::{Code, Data, Signature}; use namada::types::dec::Dec; use namada::types::storage::Epoch; - use namada::types::transaction::TxType; + use namada::types::transaction::{self, TxType}; use namada_test_utils::TestWasms; // Use this as `#[test]` annotation to enable logging use namada_tests::log::test; @@ -398,10 +475,10 @@ mod tests { ); } - /// Test that a PoS action that must be authorized is rejected without a - /// valid signature. + /// Test that a non-validator PoS action that must be authorized is rejected + /// without a valid signature. #[test] - fn test_unsigned_pos_action_rejected() { + fn test_unsigned_non_validator_pos_action_rejected() { // Init PoS genesis let pos_params = PosParams::default(); let validator = address::testing::established_address_3(); @@ -454,7 +531,7 @@ mod tests { // be able to transfer from it tx_env.credit_tokens(&vp_owner, &token, amount); - // Initialize VP environment from a transaction + // Initialize VP environment from non-validator PoS actions vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |_address| { // Bond the tokens, then unbond some of them tx::ctx() @@ -478,10 +555,184 @@ mod tests { ); } - /// Test that a PoS action that must be authorized is accepted with a valid - /// signature. + /// Test that a PoS action to become validator that must be authorized is + /// rejected without a valid signature. + #[test] + fn test_unsigned_become_validator_pos_action_rejected() { + // Init PoS genesis + let pos_params = PosParams::default(); + let validator = address::testing::established_address_3(); + let initial_stake = token::Amount::from_uint(10_098_123, 0).unwrap(); + let consensus_key = key::testing::keypair_2().ref_to(); + let protocol_key = key::testing::keypair_1().ref_to(); + let eth_cold_key = key::testing::keypair_3().ref_to(); + let eth_hot_key = key::testing::keypair_4().ref_to(); + let commission_rate = Dec::new(5, 2).unwrap(); + let max_commission_rate_change = Dec::new(1, 2).unwrap(); + + let genesis_validators = [GenesisValidator { + address: validator, + tokens: initial_stake, + consensus_key, + protocol_key, + commission_rate, + max_commission_rate_change, + eth_hot_key, + eth_cold_key, + metadata: Default::default(), + }]; + + init_pos(&genesis_validators[..], &pos_params, Epoch(0)); + + // Initialize a tx environment + let mut tx_env = tx_host_env::take(); + + let secret_key = key::testing::keypair_1(); + let public_key = secret_key.ref_to(); + let vp_owner: Address = address::testing::established_address_2(); + + // Spawn the accounts to be able to modify their storage + tx_env.init_account_storage(&vp_owner, vec![public_key], 1); + + // Initialize VP environment from PoS action to become a validator + vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { + let consensus_key = key::common::PublicKey::Ed25519( + key::testing::gen_keypair::().ref_to(), + ); + let protocol_key = key::common::PublicKey::Ed25519( + key::testing::gen_keypair::().ref_to(), + ); + let eth_cold_key = + key::testing::gen_keypair::() + .ref_to(); + let eth_hot_key = + key::testing::gen_keypair::() + .ref_to(); + let commission_rate = Dec::new(5, 2).unwrap(); + let max_commission_rate_change = Dec::new(1, 2).unwrap(); + let args = transaction::pos::BecomeValidator { + address: address.clone(), + consensus_key, + eth_cold_key, + eth_hot_key, + protocol_key, + commission_rate, + max_commission_rate_change, + email: "cucumber@tastes.good".to_string(), + description: None, + website: None, + discord_handle: None, + }; + tx::ctx().become_validator(args).unwrap(); + }); + + let vp_env = vp_host_env::take(); + let mut tx_data = Tx::from_type(TxType::Raw); + tx_data.set_data(Data::new(vec![])); + let keys_changed: BTreeSet = + vp_env.all_touched_storage_keys(); + let verifiers: BTreeSet
= BTreeSet::default(); + vp_host_env::set(vp_env); + assert!( + !validate_tx(&CTX, tx_data, vp_owner, keys_changed, verifiers) + .unwrap() + ); + } + + /// Test that a validator PoS action that must be authorized is rejected + /// without a valid signature. + #[test] + fn test_unsigned_validator_pos_action_rejected() { + // Init PoS genesis + let pos_params = PosParams::default(); + let validator = address::testing::established_address_3(); + let initial_stake = token::Amount::from_uint(10_098_123, 0).unwrap(); + let consensus_key = key::testing::keypair_2().ref_to(); + let protocol_key = key::testing::keypair_1().ref_to(); + let eth_cold_key = key::testing::keypair_3().ref_to(); + let eth_hot_key = key::testing::keypair_4().ref_to(); + let commission_rate = Dec::new(5, 2).unwrap(); + let max_commission_rate_change = Dec::new(1, 2).unwrap(); + + let genesis_validators = [GenesisValidator { + address: validator.clone(), + tokens: initial_stake, + consensus_key, + protocol_key, + commission_rate, + max_commission_rate_change, + eth_hot_key, + eth_cold_key, + metadata: Default::default(), + }]; + + init_pos(&genesis_validators[..], &pos_params, Epoch(0)); + + // Initialize a tx environment + let mut tx_env = tx_host_env::take(); + + let secret_key = key::testing::keypair_1(); + let public_key = secret_key.ref_to(); + let target = address::testing::established_address_3(); + let token = address::nam(); + let amount = token::Amount::from_uint(10_098_123, 0).unwrap(); + let bond_amount = token::Amount::from_uint(5_098_123, 0).unwrap(); + let unbond_amount = token::Amount::from_uint(3_098_123, 0).unwrap(); + + // Spawn the accounts to be able to modify their storage + tx_env.spawn_accounts([&target, &token]); + tx_env.init_account_storage(&validator, vec![public_key], 1); + // write the denomination of NAM into storage + storage_api::token::write_denom( + &mut tx_env.wl_storage, + &token, + token::NATIVE_MAX_DECIMAL_PLACES.into(), + ) + .unwrap(); + + // Credit the tokens to the validator before running the transaction to + // be able to transfer from it + tx_env.credit_tokens(&validator, &token, amount); + + // Validator PoS actions + vp_host_env::init_from_tx(validator.clone(), tx_env, |_address| { + // Bond the tokens, then unbond some of them + tx::ctx() + .bond_tokens(Some(&validator), &validator, bond_amount) + .unwrap(); + tx::ctx() + .unbond_tokens(Some(&validator), &validator, unbond_amount) + .unwrap(); + tx::ctx().deactivate_validator(&validator).unwrap(); + tx::ctx() + .change_validator_metadata( + &validator, + Some("email".to_owned()), + Some("desc".to_owned()), + Some("website".to_owned()), + Some("discord".to_owned()), + Some(Dec::new(6, 2).unwrap()), + ) + .unwrap(); + }); + + let vp_env = vp_host_env::take(); + let mut tx_data = Tx::from_type(TxType::Raw); + tx_data.set_data(Data::new(vec![])); + let keys_changed: BTreeSet = + vp_env.all_touched_storage_keys(); + let verifiers: BTreeSet
= BTreeSet::default(); + vp_host_env::set(vp_env); + assert!( + !validate_tx(&CTX, tx_data, validator, keys_changed, verifiers) + .unwrap() + ); + } + + /// Test that a non-validator PoS action that must be authorized is accepted + /// with a valid signature. #[test] - fn test_signed_pos_action_accepted() { + fn test_signed_non_validator_pos_action_accepted() { // Init PoS genesis let pos_params = PosParams::default(); let validator = address::testing::established_address_3(); @@ -539,7 +790,7 @@ mod tests { // be able to transfer from it tx_env.credit_tokens(&vp_owner, &token, amount); - // Initialize VP environment from a transaction + // Initialize VP environment from non-validator PoS actions vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |_address| { // Bond the tokens, then unbond some of them tx::ctx() @@ -573,6 +824,205 @@ mod tests { ); } + /// Test that a signed PoS action to become validator that must be + /// authorized is accepted with a valid signature. + #[test] + fn test_signed_become_validator_pos_action_accepted() { + // Init PoS genesis + let pos_params = PosParams::default(); + let validator = address::testing::established_address_3(); + let initial_stake = token::Amount::from_uint(10_098_123, 0).unwrap(); + let consensus_key = key::testing::keypair_2().ref_to(); + let protocol_key = key::testing::keypair_1().ref_to(); + let eth_cold_key = key::testing::keypair_3().ref_to(); + let eth_hot_key = key::testing::keypair_4().ref_to(); + let commission_rate = Dec::new(5, 2).unwrap(); + let max_commission_rate_change = Dec::new(1, 2).unwrap(); + + let genesis_validators = [GenesisValidator { + address: validator, + tokens: initial_stake, + consensus_key, + protocol_key, + commission_rate, + max_commission_rate_change, + eth_hot_key, + eth_cold_key, + metadata: Default::default(), + }]; + + init_pos(&genesis_validators[..], &pos_params, Epoch(0)); + + // Initialize a tx environment + let mut tx_env = tx_host_env::take(); + + let secret_key = key::testing::keypair_1(); + let public_key = secret_key.ref_to(); + let vp_owner: Address = address::testing::established_address_2(); + + // Spawn the accounts to be able to modify their storage + tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); + + // Initialize VP environment from PoS action to become a validator + vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { + let consensus_key = key::common::PublicKey::Ed25519( + key::testing::gen_keypair::().ref_to(), + ); + let protocol_key = key::common::PublicKey::Ed25519( + key::testing::gen_keypair::().ref_to(), + ); + let eth_cold_key = + key::testing::gen_keypair::() + .ref_to(); + let eth_hot_key = + key::testing::gen_keypair::() + .ref_to(); + let commission_rate = Dec::new(5, 2).unwrap(); + let max_commission_rate_change = Dec::new(1, 2).unwrap(); + let args = transaction::pos::BecomeValidator { + address: address.clone(), + consensus_key, + eth_cold_key, + eth_hot_key, + protocol_key, + commission_rate, + max_commission_rate_change, + email: "cucumber@tastes.good".to_string(), + description: None, + website: None, + discord_handle: None, + }; + tx::ctx().become_validator(args).unwrap(); + }); + + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + + let mut vp_env = vp_host_env::take(); + let mut tx = vp_env.tx.clone(); + tx.set_data(Data::new(vec![])); + tx.set_code(Code::new(vec![], None)); + tx.add_section(Section::Signature(Signature::new( + vec![tx.raw_header_hash()], + pks_map.index_secret_keys(vec![secret_key]), + None, + ))); + let signed_tx = tx.clone(); + vp_env.tx = signed_tx.clone(); + let keys_changed: BTreeSet = + vp_env.all_touched_storage_keys(); + let verifiers: BTreeSet
= BTreeSet::default(); + vp_host_env::set(vp_env); + assert!( + validate_tx(&CTX, signed_tx, vp_owner, keys_changed, verifiers) + .unwrap() + ); + } + + /// Test that a validator PoS action that must be authorized is accepted + /// with a valid signature. + #[test] + fn test_signed_validator_pos_action_accepted() { + // Init PoS genesis + let pos_params = PosParams::default(); + let validator = address::testing::established_address_3(); + let initial_stake = token::Amount::from_uint(10_098_123, 0).unwrap(); + let consensus_key = key::testing::keypair_2().ref_to(); + let protocol_key = key::testing::keypair_1().ref_to(); + let commission_rate = Dec::new(5, 2).unwrap(); + let max_commission_rate_change = Dec::new(1, 2).unwrap(); + + let genesis_validators = [GenesisValidator { + address: validator.clone(), + tokens: initial_stake, + consensus_key, + protocol_key, + commission_rate, + max_commission_rate_change, + eth_hot_key: key::common::PublicKey::Secp256k1( + key::testing::gen_keypair::() + .ref_to(), + ), + eth_cold_key: key::common::PublicKey::Secp256k1( + key::testing::gen_keypair::() + .ref_to(), + ), + metadata: Default::default(), + }]; + + init_pos(&genesis_validators[..], &pos_params, Epoch(0)); + + // Initialize a tx environment + let mut tx_env = tx_host_env::take(); + + let secret_key = key::testing::keypair_1(); + let public_key = secret_key.ref_to(); + let target = address::testing::established_address_3(); + let token = address::nam(); + let amount = token::Amount::from_uint(10_098_123, 0).unwrap(); + let bond_amount = token::Amount::from_uint(5_098_123, 0).unwrap(); + let unbond_amount = token::Amount::from_uint(3_098_123, 0).unwrap(); + + // Spawn the accounts to be able to modify their storage + tx_env.spawn_accounts([&target, &token]); + tx_env.init_account_storage(&validator, vec![public_key.clone()], 1); + + // write the denomination of NAM into storage + storage_api::token::write_denom( + &mut tx_env.wl_storage, + &token, + token::NATIVE_MAX_DECIMAL_PLACES.into(), + ) + .unwrap(); + + // Credit the tokens to the VP owner before running the transaction to + // be able to transfer from it + tx_env.credit_tokens(&validator, &token, amount); + + // Validator PoS actions + vp_host_env::init_from_tx(validator.clone(), tx_env, |_address| { + // Bond the tokens, then unbond some of them + tx::ctx() + .bond_tokens(Some(&validator), &validator, bond_amount) + .unwrap(); + tx::ctx() + .unbond_tokens(Some(&validator), &validator, unbond_amount) + .unwrap(); + tx::ctx().deactivate_validator(&validator).unwrap(); + tx::ctx() + .change_validator_metadata( + &validator, + Some("email".to_owned()), + Some("desc".to_owned()), + Some("website".to_owned()), + Some("discord".to_owned()), + Some(Dec::new(6, 2).unwrap()), + ) + .unwrap(); + }); + + let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); + + let mut vp_env = vp_host_env::take(); + let mut tx = vp_env.tx.clone(); + tx.set_data(Data::new(vec![])); + tx.set_code(Code::new(vec![], None)); + tx.add_section(Section::Signature(Signature::new( + vec![tx.raw_header_hash()], + pks_map.index_secret_keys(vec![secret_key]), + None, + ))); + let signed_tx = tx.clone(); + vp_env.tx = signed_tx.clone(); + let keys_changed: BTreeSet = + vp_env.all_touched_storage_keys(); + let verifiers: BTreeSet
= BTreeSet::default(); + vp_host_env::set(vp_env); + assert!( + validate_tx(&CTX, signed_tx, validator, keys_changed, verifiers) + .unwrap() + ); + } + /// Test that a transfer on with accounts other than self is accepted. #[test] fn test_transfer_between_other_parties_accepted() { diff --git a/wasm/wasm_source/src/vp_validator.rs b/wasm/wasm_source/src/vp_validator.rs deleted file mode 100644 index 2c104c13d8..0000000000 --- a/wasm/wasm_source/src/vp_validator.rs +++ /dev/null @@ -1,1135 +0,0 @@ -//! A basic validator VP. -//! -//! Like the user VP, this VP currently provides a signature verification -//! against a public key for sending tokens (receiving tokens is permissive). -//! -//! It allows to bond, unbond and withdraw tokens to and from PoS system with a -//! valid signature. -//! -//! Currently, the only difference with respect to the user VP is for a tx to -//! change a validator's commission rate: we require a valid signature only from -//! the validator whose commission rate is being changed. -//! -//! Any other storage key changes are allowed only with a valid signature. - -use namada_vp_prelude::storage::KeySeg; -use namada_vp_prelude::*; -use once_cell::unsync::Lazy; -use proof_of_stake::types::ValidatorState; - -enum KeyType<'a> { - Token { owner: &'a Address }, - PoS, - Vp(&'a Address), - PgfStward(&'a Address), - GovernanceVote(&'a Address), - Unknown, -} - -impl<'a> From<&'a storage::Key> for KeyType<'a> { - fn from(key: &'a storage::Key) -> KeyType<'a> { - if let Some([_, owner]) = token::is_any_token_balance_key(key) { - Self::Token { owner } - } else if proof_of_stake::storage::is_pos_key(key) { - Self::PoS - } else if gov_storage::keys::is_vote_key(key) { - let voter_address = gov_storage::keys::get_voter_address(key); - if let Some(address) = voter_address { - Self::GovernanceVote(address) - } else { - Self::Unknown - } - } else if let Some(address) = pgf_storage::keys::is_stewards_key(key) { - Self::PgfStward(address) - } else if let Some(address) = key.is_validity_predicate() { - Self::Vp(address) - } else { - Self::Unknown - } - } -} - -#[validity_predicate(gas = 134761)] -fn validate_tx( - ctx: &Ctx, - tx_data: Tx, - addr: Address, - keys_changed: BTreeSet, - verifiers: BTreeSet
, -) -> VpResult { - debug_log!( - "vp_validator called with user addr: {}, key_changed: {:?}, \ - verifiers: {:?}", - addr, - keys_changed, - verifiers - ); - - let valid_sig = Lazy::new(|| { - matches!(verify_signatures(ctx, &tx_data, &addr), Ok(true)) - }); - - if !is_valid_tx(ctx, &tx_data)? { - return reject(); - } - - for key in keys_changed.iter() { - let key_type: KeyType = key.into(); - let is_valid = match key_type { - KeyType::Token { owner, .. } => { - if owner == &addr { - let pre: token::Amount = - ctx.read_pre(key)?.unwrap_or_default(); - let post: token::Amount = - ctx.read_post(key)?.unwrap_or_default(); - let change = post.change() - pre.change(); - // debit has to signed, credit doesn't - let valid = change.non_negative() || *valid_sig; - debug_log!( - "token key: {}, change: {:?}, valid_sig: {}, valid \ - modification: {}", - key, - change, - *valid_sig, - valid - ); - valid - } else { - debug_log!( - "This address ({}) is not of owner ({}) of token key: \ - {}", - addr, - owner, - key - ); - // If this is not the owner, allow any change - true - } - } - KeyType::PoS => { - // Bond or unbond - let bond_id = proof_of_stake::storage::is_bond_key(key) - .map(|(bond_id, _)| bond_id) - .or_else(|| { - proof_of_stake::storage::is_unbond_key(key) - .map(|(bond_id, _, _)| bond_id) - }); - let valid_bond_or_unbond_change = match bond_id { - Some(bond_id) => { - // Bonds and unbonds changes for this address - // must be signed - bond_id.source != addr || *valid_sig - } - None => { - // Any other PoS changes are allowed without signature - true - } - }; - // Commission rate changes must be signed by the validator - let comm = - proof_of_stake::storage::is_validator_commission_rate_key( - key, - ); - let valid_commission_rate_change = match comm { - Some((validator, _epoch)) => { - *validator == addr && *valid_sig - } - None => true, - }; - // Metadata changes must be signed by the validator whose - // metadata is manipulated - let metadata = - proof_of_stake::storage::is_validator_metadata_key(key); - let valid_metadata_change = match metadata { - Some(address) => *address == addr && *valid_sig, - None => true, - }; - - // Changes due to unjailing, deactivating, and reactivating are - // marked by changes in validator state - let state_change = - proof_of_stake::storage::is_validator_state_key(key); - let valid_state_change = match state_change { - Some((address, epoch)) => { - let params_pre = - proof_of_stake::read_pos_params(&ctx.pre())?; - let state_pre = - proof_of_stake::validator_state_handle(address) - .get(&ctx.pre(), epoch, ¶ms_pre)?; - - let params_post = - proof_of_stake::read_pos_params(&ctx.post())?; - let state_post = - proof_of_stake::validator_state_handle(address) - .get(&ctx.post(), epoch, ¶ms_post)?; - - match (state_pre, state_post) { - (Some(pre), Some(post)) => { - if - // Deactivation case - (matches!( - pre, - ValidatorState::Consensus - | ValidatorState::BelowCapacity - | ValidatorState::BelowThreshold - ) && post == ValidatorState::Inactive) - // Reactivation case - || pre == ValidatorState::Inactive - && post != ValidatorState::Inactive - // Unjail case - || pre == ValidatorState::Jailed - && matches!( - post, - ValidatorState::Consensus - | ValidatorState::BelowCapacity - | ValidatorState::BelowThreshold - ) - { - *address == addr && *valid_sig - } else { - true - } - } - _ => true, - } - } - None => true, - }; - - let valid = valid_bond_or_unbond_change - && valid_commission_rate_change - && valid_state_change - && valid_metadata_change; - debug_log!( - "PoS key {} {}", - key, - if valid { "accepted" } else { "rejected" } - ); - valid - } - KeyType::GovernanceVote(voter) => { - if voter == &addr { - *valid_sig - } else { - true - } - } - KeyType::PgfStward(address) => { - if address == &addr { - *valid_sig - } else { - true - } - } - KeyType::Vp(owner) => { - let has_post: bool = ctx.has_key_post(key)?; - if owner == &addr { - if has_post { - let vp_hash: Vec = - ctx.read_bytes_post(key)?.unwrap(); - *valid_sig && is_vp_whitelisted(ctx, &vp_hash)? - } else { - false - } - } else { - let vp_hash: Vec = ctx.read_bytes_post(key)?.unwrap(); - is_vp_whitelisted(ctx, &vp_hash)? - } - } - KeyType::Unknown => { - if key.segments.get(0) == Some(&addr.to_db_key()) { - // Unknown changes to this address space require a valid - // signature - *valid_sig - } else { - // Unknown changes anywhere else are permitted - true - } - } - }; - if !is_valid { - debug_log!("key {} modification failed vp", key); - return reject(); - } - } - - accept() -} - -#[cfg(test)] -mod tests { - use address::testing::arb_non_internal_address; - use namada::ledger::pos::{GenesisValidator, OwnedPosParams}; - use namada::proto::{Code, Data, Signature}; - use namada::types::dec::Dec; - use namada::types::storage::Epoch; - use namada::types::transaction::TxType; - use namada_test_utils::TestWasms; - // Use this as `#[test]` annotation to enable logging - use namada_tests::log::test; - use namada_tests::native_vp::pos::init_pos; - use namada_tests::tx::{self, tx_host_env, TestTxEnv}; - use namada_tests::vp::vp_host_env::storage::Key; - use namada_tests::vp::*; - use namada_tx_prelude::{StorageWrite, TxEnv}; - use namada_vp_prelude::account::AccountPublicKeysMap; - use namada_vp_prelude::key::RefTo; - use proptest::prelude::*; - use storage::testing::arb_account_storage_key_no_vp; - - use super::*; - - /// Test that no-op transaction (i.e. no storage modifications) accepted. - #[test] - fn test_no_op_transaction() { - let mut tx_data = Tx::from_type(TxType::Raw); - tx_data.set_data(Data::new(vec![])); - let addr: Address = address::testing::established_address_1(); - let keys_changed: BTreeSet = BTreeSet::default(); - let verifiers: BTreeSet
= BTreeSet::default(); - - // The VP env must be initialized before calling `validate_tx` - vp_host_env::init(); - - assert!( - validate_tx(&CTX, tx_data, addr, keys_changed, verifiers).unwrap() - ); - } - - /// Test that a credit transfer is accepted. - #[test] - fn test_credit_transfer_accepted() { - // Initialize a tx environment - let mut tx_env = TestTxEnv::default(); - - let vp_owner = address::testing::established_address_1(); - let source = address::testing::established_address_2(); - let token = address::nam(); - let amount = token::Amount::from_uint(10_098_123, 0).unwrap(); - - // Spawn the accounts to be able to modify their storage - tx_env.spawn_accounts([&vp_owner, &source, &token]); - - // Credit the tokens to the source before running the transaction to be - // able to transfer from it - tx_env.credit_tokens(&source, &token, amount); - // write the denomination of NAM into storage - storage_api::token::write_denom( - &mut tx_env.wl_storage, - &token, - token::NATIVE_MAX_DECIMAL_PLACES.into(), - ) - .unwrap(); - - let amount = token::DenominatedAmount { - amount, - denom: token::NATIVE_MAX_DECIMAL_PLACES.into(), - }; - // Initialize VP environment from a transaction - vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { - // Apply transfer in a transaction - tx_host_env::token::transfer( - tx::ctx(), - &source, - address, - &token, - amount, - ) - .unwrap(); - }); - - let vp_env = vp_host_env::take(); - let mut tx_data = Tx::from_type(TxType::Raw); - tx_data.set_data(Data::new(vec![])); - let keys_changed: BTreeSet = - vp_env.all_touched_storage_keys(); - let verifiers: BTreeSet
= BTreeSet::default(); - vp_host_env::set(vp_env); - assert!( - validate_tx(&CTX, tx_data, vp_owner, keys_changed, verifiers) - .unwrap() - ); - } - - /// Test that a debit transfer without a valid signature is rejected. - #[test] - fn test_unsigned_debit_transfer_rejected() { - // Initialize a tx environment - let mut tx_env = TestTxEnv::default(); - - let vp_owner = address::testing::established_address_1(); - let target = address::testing::established_address_2(); - let token = address::nam(); - let amount = token::Amount::from_uint(10_098_123, 0).unwrap(); - - // Spawn the accounts to be able to modify their storage - tx_env.spawn_accounts([&vp_owner, &target, &token]); - - // Credit the tokens to the VP owner before running the transaction to - // be able to transfer from it - tx_env.credit_tokens(&vp_owner, &token, amount); - let amount = token::DenominatedAmount { - amount, - denom: token::NATIVE_MAX_DECIMAL_PLACES.into(), - }; - // write the denomination of NAM into storage - storage_api::token::write_denom( - &mut tx_env.wl_storage, - &token, - token::NATIVE_MAX_DECIMAL_PLACES.into(), - ) - .unwrap(); - - // Initialize VP environment from a transaction - vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { - // Apply transfer in a transaction - tx_host_env::token::transfer( - tx::ctx(), - address, - &target, - &token, - amount, - ) - .unwrap(); - }); - - let vp_env = vp_host_env::take(); - let mut tx_data = Tx::from_type(TxType::Raw); - tx_data.set_data(Data::new(vec![])); - let keys_changed: BTreeSet = - vp_env.all_touched_storage_keys(); - let verifiers: BTreeSet
= BTreeSet::default(); - vp_host_env::set(vp_env); - assert!( - !validate_tx(&CTX, tx_data, vp_owner, keys_changed, verifiers) - .unwrap() - ); - } - - /// Test that a debit transfer with a valid signature is accepted. - #[test] - fn test_signed_debit_transfer_accepted() { - // Initialize a tx environment - let mut tx_env = TestTxEnv::default(); - - let vp_owner = address::testing::established_address_1(); - let keypair = key::testing::keypair_1(); - let public_key = keypair.ref_to(); - let target = address::testing::established_address_2(); - let token = address::nam(); - let amount = token::Amount::from_uint(10_098_123, 0).unwrap(); - - // Spawn the accounts to be able to modify their storage - tx_env.spawn_accounts([&vp_owner, &target, &token]); - tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); - - // Credit the tokens to the VP owner before running the transaction to - // be able to transfer from it - tx_env.credit_tokens(&vp_owner, &token, amount); - // write the denomination of NAM into storage - storage_api::token::write_denom( - &mut tx_env.wl_storage, - &token, - token::NATIVE_MAX_DECIMAL_PLACES.into(), - ) - .unwrap(); - - let amount = token::DenominatedAmount { - amount, - denom: token::NATIVE_MAX_DECIMAL_PLACES.into(), - }; - - // Initialize VP environment from a transaction - vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { - // Apply transfer in a transaction - tx_host_env::token::transfer( - tx::ctx(), - address, - &target, - &token, - amount, - ) - .unwrap(); - }); - - let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); - - let mut vp_env = vp_host_env::take(); - let mut tx = vp_env.tx.clone(); - tx.set_data(Data::new(vec![])); - tx.set_code(Code::new(vec![], None)); - tx.add_section(Section::Signature(Signature::new( - vec![tx.raw_header_hash()], - pks_map.index_secret_keys(vec![keypair]), - None, - ))); - let signed_tx = tx.clone(); - vp_env.tx = signed_tx.clone(); - let keys_changed: BTreeSet = - vp_env.all_touched_storage_keys(); - let verifiers: BTreeSet
= BTreeSet::default(); - vp_host_env::set(vp_env); - assert!( - validate_tx(&CTX, signed_tx, vp_owner, keys_changed, verifiers) - .unwrap() - ); - } - - /// Test that a PoS action that must be authorized is rejected without a - /// valid signature. - #[test] - fn test_unsigned_pos_action_rejected() { - // Init PoS genesis - let pos_params = OwnedPosParams::default(); - let validator = address::testing::established_address_3(); - let initial_stake = token::Amount::from_uint(10_098_123, 0).unwrap(); - let consensus_key = key::testing::keypair_2().ref_to(); - let protocol_key = key::testing::keypair_1().ref_to(); - let eth_cold_key = key::testing::keypair_3().ref_to(); - let eth_hot_key = key::testing::keypair_4().ref_to(); - let commission_rate = Dec::new(5, 2).unwrap(); - let max_commission_rate_change = Dec::new(1, 2).unwrap(); - - let genesis_validators = [GenesisValidator { - address: validator.clone(), - tokens: initial_stake, - consensus_key, - protocol_key, - commission_rate, - max_commission_rate_change, - eth_hot_key, - eth_cold_key, - metadata: Default::default(), - }]; - - init_pos(&genesis_validators[..], &pos_params, Epoch(0)); - - // Initialize a tx environment - let mut tx_env = tx_host_env::take(); - - let secret_key = key::testing::keypair_1(); - let public_key = secret_key.ref_to(); - let vp_owner: Address = address::testing::established_address_2(); - let target = address::testing::established_address_3(); - let token = address::nam(); - let amount = token::Amount::from_uint(10_098_123, 0).unwrap(); - let bond_amount = token::Amount::from_uint(5_098_123, 0).unwrap(); - let unbond_amount = token::Amount::from_uint(3_098_123, 0).unwrap(); - - // Spawn the accounts to be able to modify their storage - tx_env.spawn_accounts([&target, &token]); - tx_env.init_account_storage(&vp_owner, vec![public_key], 1); - - // Credit the tokens to the VP owner before running the transaction to - // be able to transfer from it - tx_env.credit_tokens(&vp_owner, &token, amount); - // write the denomination of NAM into storage - storage_api::token::write_denom( - &mut tx_env.wl_storage, - &token, - token::NATIVE_MAX_DECIMAL_PLACES.into(), - ) - .unwrap(); - - // Initialize VP environment from a transaction - vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |_address| { - // Bond the tokens, then unbond some of them - tx::ctx() - .bond_tokens(Some(&vp_owner), &validator, bond_amount) - .unwrap(); - tx::ctx() - .unbond_tokens(Some(&vp_owner), &validator, unbond_amount) - .unwrap(); - tx::ctx() - .change_validator_commission_rate( - &validator, - &Dec::new(6, 2).unwrap(), - ) - .unwrap(); - }); - - let vp_env = vp_host_env::take(); - let mut tx_data = Tx::from_type(TxType::Raw); - tx_data.set_data(Data::new(vec![])); - let keys_changed: BTreeSet = - vp_env.all_touched_storage_keys(); - let verifiers: BTreeSet
= BTreeSet::default(); - vp_host_env::set(vp_env); - assert!( - !validate_tx(&CTX, tx_data, vp_owner, keys_changed, verifiers) - .unwrap() - ); - } - - /// Test that a PoS action that must be authorized is accepted with a valid - /// signature. - #[test] - fn test_signed_pos_action_accepted() { - // Init PoS genesis - let pos_params = OwnedPosParams::default(); - let validator = address::testing::established_address_3(); - let initial_stake = token::Amount::from_uint(10_098_123, 0).unwrap(); - let consensus_key = key::testing::keypair_2().ref_to(); - let protocol_key = key::testing::keypair_1().ref_to(); - let commission_rate = Dec::new(5, 2).unwrap(); - let max_commission_rate_change = Dec::new(1, 2).unwrap(); - - let genesis_validators = [GenesisValidator { - address: validator.clone(), - tokens: initial_stake, - consensus_key, - protocol_key, - commission_rate, - max_commission_rate_change, - eth_hot_key: key::common::PublicKey::Secp256k1( - key::testing::gen_keypair::() - .ref_to(), - ), - eth_cold_key: key::common::PublicKey::Secp256k1( - key::testing::gen_keypair::() - .ref_to(), - ), - metadata: Default::default(), - }]; - - init_pos(&genesis_validators[..], &pos_params, Epoch(0)); - - // Initialize a tx environment - let mut tx_env = tx_host_env::take(); - - let secret_key = key::testing::keypair_1(); - let public_key = secret_key.ref_to(); - let target = address::testing::established_address_3(); - let token = address::nam(); - let amount = token::Amount::from_uint(10_098_123, 0).unwrap(); - let bond_amount = token::Amount::from_uint(5_098_123, 0).unwrap(); - let unbond_amount = token::Amount::from_uint(3_098_123, 0).unwrap(); - - // Spawn the accounts to be able to modify their storage - tx_env.spawn_accounts([&validator, &target, &token]); - tx_env.init_account_storage(&validator, vec![public_key.clone()], 1); - - // Credit the tokens to the VP owner before running the transaction to - // be able to transfer from it - tx_env.credit_tokens(&validator, &token, amount); - // write the denomination of NAM into storage - storage_api::token::write_denom( - &mut tx_env.wl_storage, - &token, - token::NATIVE_MAX_DECIMAL_PLACES.into(), - ) - .unwrap(); - - // Initialize VP environment from a transaction - vp_host_env::init_from_tx(validator.clone(), tx_env, |_address| { - // Bond the tokens, then unbond some of them - tx::ctx() - .bond_tokens(Some(&validator), &validator, bond_amount) - .unwrap(); - tx::ctx() - .unbond_tokens(Some(&validator), &validator, unbond_amount) - .unwrap(); - tx::ctx().deactivate_validator(&validator).unwrap(); - tx::ctx() - .change_validator_metadata( - &validator, - Some("email".to_owned()), - Some("desc".to_owned()), - Some("website".to_owned()), - Some("discord".to_owned()), - Some(Dec::new(6, 2).unwrap()), - ) - .unwrap(); - }); - - let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); - - let mut vp_env = vp_host_env::take(); - let mut tx = vp_env.tx.clone(); - tx.set_data(Data::new(vec![])); - tx.set_code(Code::new(vec![], None)); - tx.add_section(Section::Signature(Signature::new( - vec![tx.raw_header_hash()], - pks_map.index_secret_keys(vec![secret_key]), - None, - ))); - let signed_tx = tx.clone(); - vp_env.tx = signed_tx.clone(); - let keys_changed: BTreeSet = - vp_env.all_touched_storage_keys(); - let verifiers: BTreeSet
= BTreeSet::default(); - vp_host_env::set(vp_env); - assert!( - validate_tx(&CTX, signed_tx, validator, keys_changed, verifiers) - .unwrap() - ); - } - - /// Test that a transfer on with accounts other than self is accepted. - #[test] - fn test_transfer_between_other_parties_accepted() { - // Initialize a tx environment - let mut tx_env = TestTxEnv::default(); - - let vp_owner = address::testing::established_address_1(); - let source = address::testing::established_address_2(); - let target = address::testing::established_address_3(); - let token = address::nam(); - let amount = token::Amount::from_uint(10_098_123, 0).unwrap(); - - // Spawn the accounts to be able to modify their storage - tx_env.spawn_accounts([&vp_owner, &source, &target, &token]); - - // Credit the tokens to the VP owner before running the transaction to - // be able to transfer from it - tx_env.credit_tokens(&source, &token, amount); - let amount = token::DenominatedAmount { - amount, - denom: token::NATIVE_MAX_DECIMAL_PLACES.into(), - }; - - // Initialize VP environment from a transaction - vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { - tx::ctx().insert_verifier(address).unwrap(); - // Apply transfer in a transaction - tx_host_env::token::transfer( - tx::ctx(), - &source, - &target, - &token, - amount, - ) - .unwrap(); - }); - - let vp_env = vp_host_env::take(); - let mut tx_data = Tx::from_type(TxType::Raw); - tx_data.set_data(Data::new(vec![])); - let keys_changed: BTreeSet = - vp_env.all_touched_storage_keys(); - let verifiers: BTreeSet
= BTreeSet::default(); - vp_host_env::set(vp_env); - assert!( - validate_tx(&CTX, tx_data, vp_owner, keys_changed, verifiers) - .unwrap() - ); - } - - prop_compose! { - /// Generates an account address and a storage key inside its storage. - fn arb_account_storage_subspace_key() - // Generate an address - (address in arb_non_internal_address()) - // Generate a storage key other than its VP key (VP cannot be - // modified directly via `write`, it has to be modified via - // `tx::update_validity_predicate`. - (storage_key in arb_account_storage_key_no_vp(address.clone()), - // Use the generated address too - address in Just(address)) - -> (Address, Key) { - (address, storage_key) - } - } - - proptest! { - /// Test that an unsigned tx that performs arbitrary storage writes or - /// deletes to the account is rejected. - #[test] - fn test_unsigned_arb_storage_write_rejected( - (vp_owner, storage_key) in arb_account_storage_subspace_key(), - // Generate bytes to write. If `None`, delete from the key instead - storage_value in any::>>(), - ) { - // Initialize a tx environment - let mut tx_env = TestTxEnv::default(); - - // Spawn all the accounts in the storage key to be able to modify - // their storage - let storage_key_addresses = storage_key.find_addresses(); - tx_env.spawn_accounts(storage_key_addresses); - - // Initialize VP environment from a transaction - vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |_address| { - // Write or delete some data in the transaction - if let Some(value) = &storage_value { - tx::ctx().write(&storage_key, value).unwrap(); - } else { - tx::ctx().delete(&storage_key).unwrap(); - } - }); - - let vp_env = vp_host_env::take(); - let mut tx_data = Tx::from_type(TxType::Raw); - tx_data.set_data(Data::new(vec![])); - let keys_changed: BTreeSet = - vp_env.all_touched_storage_keys(); - let verifiers: BTreeSet
= BTreeSet::default(); - vp_host_env::set(vp_env); - assert!(!validate_tx(&CTX, tx_data, vp_owner, keys_changed, verifiers).unwrap()); - } - } - - proptest! { - /// Test that a signed tx that performs arbitrary storage writes or - /// deletes to the account is accepted. - #[test] - fn test_signed_arb_storage_write( - (vp_owner, storage_key) in arb_account_storage_subspace_key(), - // Generate bytes to write. If `None`, delete from the key instead - storage_value in any::>>(), - ) { - // Initialize a tx environment - let mut tx_env = TestTxEnv::default(); - - let keypair = key::testing::keypair_1(); - let public_key = keypair.ref_to(); - - // Spawn all the accounts in the storage key to be able to modify - // their storage - let storage_key_addresses = storage_key.find_addresses(); - tx_env.spawn_accounts(storage_key_addresses); - - tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); - - // Initialize VP environment from a transaction - vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |_address| { - // Write or delete some data in the transaction - if let Some(value) = &storage_value { - tx::ctx().write(&storage_key, value).unwrap(); - } else { - tx::ctx().delete(&storage_key).unwrap(); - } - }); - - let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); - - let mut vp_env = vp_host_env::take(); - let mut tx = vp_env.tx.clone(); - tx.set_data(Data::new(vec![])); - tx.set_code(Code::new(vec![], None)); - tx.add_section(Section::Signature(Signature::new( - vec![tx.raw_header_hash()], - pks_map.index_secret_keys(vec![keypair]), - None, - ))); - let signed_tx = tx.clone(); - vp_env.tx = signed_tx.clone(); - let keys_changed: BTreeSet = - vp_env.all_touched_storage_keys(); - let verifiers: BTreeSet
= BTreeSet::default(); - vp_host_env::set(vp_env); - assert!(validate_tx(&CTX, signed_tx, vp_owner, keys_changed, verifiers).unwrap()); - } - } - - /// Test that a validity predicate update without a valid signature is - /// rejected. - #[test] - fn test_unsigned_vp_update_rejected() { - // Initialize a tx environment - let mut tx_env = TestTxEnv::default(); - - let vp_owner = address::testing::established_address_1(); - let vp_code = TestWasms::VpAlwaysTrue.read_bytes(); - let vp_hash = sha256(&vp_code); - // for the update - tx_env.store_wasm_code(vp_code); - - // Spawn the accounts to be able to modify their storage - tx_env.spawn_accounts([&vp_owner]); - - // Initialize VP environment from a transaction - vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { - // Update VP in a transaction - tx::ctx() - .update_validity_predicate(address, vp_hash, &None) - .unwrap(); - }); - - let vp_env = vp_host_env::take(); - let mut tx_data = Tx::from_type(TxType::Raw); - tx_data.set_data(Data::new(vec![])); - let keys_changed: BTreeSet = - vp_env.all_touched_storage_keys(); - let verifiers: BTreeSet
= BTreeSet::default(); - vp_host_env::set(vp_env); - assert!( - !validate_tx(&CTX, tx_data, vp_owner, keys_changed, verifiers) - .unwrap() - ); - } - - /// Test that a validity predicate update with a valid signature is - /// accepted. - #[test] - fn test_signed_vp_update_accepted() { - // Initialize a tx environment - let mut tx_env = TestTxEnv::default(); - tx_env.init_parameters(None, None, None, None); - - let vp_owner = address::testing::established_address_1(); - let keypair = key::testing::keypair_1(); - let public_key = keypair.ref_to(); - let vp_code = TestWasms::VpAlwaysTrue.read_bytes(); - let vp_hash = sha256(&vp_code); - // for the update - tx_env.store_wasm_code(vp_code); - - // Spawn the accounts to be able to modify their storage - tx_env.spawn_accounts([&vp_owner]); - tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); - - // Initialize VP environment from a transaction - vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { - // Update VP in a transaction - tx::ctx() - .update_validity_predicate(address, vp_hash, &None) - .unwrap(); - }); - - let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); - - let mut vp_env = vp_host_env::take(); - let mut tx = vp_env.tx.clone(); - tx.set_data(Data::new(vec![])); - tx.set_code(Code::new(vec![], None)); - tx.add_section(Section::Signature(Signature::new( - vec![tx.raw_header_hash()], - pks_map.index_secret_keys(vec![keypair]), - None, - ))); - let signed_tx = tx.clone(); - vp_env.tx = signed_tx.clone(); - let keys_changed: BTreeSet = - vp_env.all_touched_storage_keys(); - let verifiers: BTreeSet
= BTreeSet::default(); - vp_host_env::set(vp_env); - assert!( - validate_tx(&CTX, signed_tx, vp_owner, keys_changed, verifiers) - .unwrap() - ); - } - - /// Test that a validity predicate update is rejected if not whitelisted - #[test] - fn test_signed_vp_update_not_whitelisted_rejected() { - // Initialize a tx environment - let mut tx_env = TestTxEnv::default(); - tx_env.init_parameters( - None, - Some(vec!["some_hash".to_string()]), - None, - None, - ); - - let vp_owner = address::testing::established_address_1(); - let keypair = key::testing::keypair_1(); - let public_key = keypair.ref_to(); - let vp_code = TestWasms::VpAlwaysTrue.read_bytes(); - let vp_hash = sha256(&vp_code); - // for the update - tx_env.store_wasm_code(vp_code); - - // Spawn the accounts to be able to modify their storage - tx_env.spawn_accounts([&vp_owner]); - tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); - - // Initialize VP environment from a transaction - vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { - // Update VP in a transaction - tx::ctx() - .update_validity_predicate(address, vp_hash, &None) - .unwrap(); - }); - - let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); - - let mut vp_env = vp_host_env::take(); - let mut tx = vp_env.tx.clone(); - tx.set_data(Data::new(vec![])); - tx.set_code(Code::new(vec![], None)); - tx.add_section(Section::Signature(Signature::new( - vec![tx.raw_header_hash()], - pks_map.index_secret_keys(vec![keypair]), - None, - ))); - let signed_tx = tx.clone(); - vp_env.tx = signed_tx.clone(); - let keys_changed: BTreeSet = - vp_env.all_touched_storage_keys(); - let verifiers: BTreeSet
= BTreeSet::default(); - vp_host_env::set(vp_env); - assert!( - !validate_tx(&CTX, signed_tx, vp_owner, keys_changed, verifiers) - .unwrap() - ); - } - - /// Test that a validity predicate update is accepted if whitelisted - #[test] - fn test_signed_vp_update_whitelisted_accepted() { - // Initialize a tx environment - let mut tx_env = TestTxEnv::default(); - - let vp_owner = address::testing::established_address_1(); - let keypair = key::testing::keypair_1(); - let public_key = keypair.ref_to(); - let vp_code = TestWasms::VpAlwaysTrue.read_bytes(); - let vp_hash = sha256(&vp_code); - // for the update - tx_env.store_wasm_code(vp_code); - - tx_env.init_parameters( - None, - Some(vec![vp_hash.to_string()]), - None, - None, - ); - - // Spawn the accounts to be able to modify their storage - tx_env.spawn_accounts([&vp_owner]); - tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); - - // Initialize VP environment from a transaction - vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { - // Update VP in a transaction - tx::ctx() - .update_validity_predicate(address, vp_hash, &None) - .unwrap(); - }); - - let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); - - let mut vp_env = vp_host_env::take(); - let mut tx = vp_env.tx.clone(); - tx.set_data(Data::new(vec![])); - tx.set_code(Code::new(vec![], None)); - tx.add_section(Section::Signature(Signature::new( - vec![tx.raw_header_hash()], - pks_map.index_secret_keys(vec![keypair]), - None, - ))); - let signed_tx = tx.clone(); - vp_env.tx = signed_tx.clone(); - let keys_changed: BTreeSet = - vp_env.all_touched_storage_keys(); - let verifiers: BTreeSet
= BTreeSet::default(); - vp_host_env::set(vp_env); - assert!( - validate_tx(&CTX, signed_tx, vp_owner, keys_changed, verifiers) - .unwrap() - ); - } - - /// Test that a tx is rejected if not whitelisted - #[test] - fn test_tx_not_whitelisted_rejected() { - // Initialize a tx environment - let mut tx_env = TestTxEnv::default(); - - let vp_owner = address::testing::established_address_1(); - let keypair = key::testing::keypair_1(); - let public_key = keypair.ref_to(); - let vp_code = TestWasms::VpAlwaysTrue.read_bytes(); - let vp_hash = sha256(&vp_code); - // for the update - tx_env.store_wasm_code(vp_code); - - tx_env.init_parameters( - None, - Some(vec![vp_hash.to_string()]), - Some(vec!["some_hash".to_string()]), - None, - ); - - // Spawn the accounts to be able to modify their storage - tx_env.spawn_accounts([&vp_owner]); - tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); - - // Initialize VP environment from a transaction - vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { - // Update VP in a transaction - tx::ctx() - .update_validity_predicate(address, vp_hash, &None) - .unwrap(); - }); - - let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); - - let mut vp_env = vp_host_env::take(); - let mut tx = vp_env.tx.clone(); - tx.set_data(Data::new(vec![])); - tx.set_code(Code::new(vec![], None)); - tx.add_section(Section::Signature(Signature::new( - vec![tx.raw_header_hash()], - pks_map.index_secret_keys(vec![keypair]), - None, - ))); - let signed_tx = tx.clone(); - vp_env.tx = signed_tx.clone(); - let keys_changed: BTreeSet = - vp_env.all_touched_storage_keys(); - let verifiers: BTreeSet
= BTreeSet::default(); - vp_host_env::set(vp_env); - assert!( - !validate_tx(&CTX, signed_tx, vp_owner, keys_changed, verifiers) - .unwrap() - ); - } - - #[test] - fn test_tx_whitelisted_accepted() { - // Initialize a tx environment - let mut tx_env = TestTxEnv::default(); - - let vp_owner = address::testing::established_address_1(); - let keypair = key::testing::keypair_1(); - let public_key = keypair.ref_to(); - let vp_code = TestWasms::VpAlwaysTrue.read_bytes(); - let vp_hash = sha256(&vp_code); - // for the update - tx_env.store_wasm_code(vp_code); - - // hardcoded hash of VP_ALWAYS_TRUE_WASM - tx_env.init_parameters( - None, - Some(vec![vp_hash.to_string()]), - None, - None, - ); - - // Spawn the accounts to be able to modify their storage - tx_env.spawn_accounts([&vp_owner]); - tx_env.init_account_storage(&vp_owner, vec![public_key.clone()], 1); - - // Initialize VP environment from a transaction - vp_host_env::init_from_tx(vp_owner.clone(), tx_env, |address| { - // Update VP in a transaction - tx::ctx() - .update_validity_predicate(address, vp_hash, &None) - .unwrap(); - }); - - let pks_map = AccountPublicKeysMap::from_iter(vec![public_key]); - - let mut vp_env = vp_host_env::take(); - let mut tx = vp_env.tx.clone(); - tx.set_code(Code::new(vec![], None)); - tx.set_data(Data::new(vec![])); - tx.add_section(Section::Signature(Signature::new( - vec![tx.raw_header_hash()], - pks_map.index_secret_keys(vec![keypair]), - None, - ))); - let signed_tx = tx.clone(); - vp_env.tx = signed_tx.clone(); - let keys_changed: BTreeSet = - vp_env.all_touched_storage_keys(); - let verifiers: BTreeSet
= BTreeSet::default(); - vp_host_env::set(vp_env); - assert!( - validate_tx(&CTX, signed_tx, vp_owner, keys_changed, verifiers) - .unwrap() - ); - } -} diff --git a/wasm_for_tests/tx_fail.wasm b/wasm_for_tests/tx_fail.wasm index f6406827b4..6ca73b5dc5 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_memory_limit.wasm b/wasm_for_tests/tx_memory_limit.wasm index efc2fb7bd7..a971952f3f 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_mint_tokens.wasm b/wasm_for_tests/tx_mint_tokens.wasm index e79d206dfd..761e1a14e9 100755 Binary files a/wasm_for_tests/tx_mint_tokens.wasm and b/wasm_for_tests/tx_mint_tokens.wasm differ diff --git a/wasm_for_tests/tx_no_op.wasm b/wasm_for_tests/tx_no_op.wasm index cf752705ea..ec8236720c 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_proposal_code.wasm b/wasm_for_tests/tx_proposal_code.wasm index 022b5cef96..9c162d2f50 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_read_storage_key.wasm b/wasm_for_tests/tx_read_storage_key.wasm index 1fcb89063d..beb31ae2ed 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_write.wasm b/wasm_for_tests/tx_write.wasm index 40cdb97371..f3f214b3f3 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_storage_key.wasm b/wasm_for_tests/tx_write_storage_key.wasm index 902d297af7..2f6e3946b4 100755 Binary files a/wasm_for_tests/tx_write_storage_key.wasm and b/wasm_for_tests/tx_write_storage_key.wasm differ diff --git a/wasm_for_tests/vp_always_false.wasm b/wasm_for_tests/vp_always_false.wasm index bbeaa24274..78dd6538e5 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_true.wasm b/wasm_for_tests/vp_always_true.wasm index 90ea4c6fc4..e63181e765 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_eval.wasm b/wasm_for_tests/vp_eval.wasm index bed4a45383..68452476a0 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_memory_limit.wasm b/wasm_for_tests/vp_memory_limit.wasm index 5c91e6113c..02e35fefbd 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_read_storage_key.wasm b/wasm_for_tests/vp_read_storage_key.wasm index 7665fa7e39..b9794682df 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/wasm_source/Cargo.lock b/wasm_for_tests/wasm_source/Cargo.lock index 133935e7f0..7fe9190e24 100644 --- a/wasm_for_tests/wasm_source/Cargo.lock +++ b/wasm_for_tests/wasm_source/Cargo.lock @@ -369,7 +369,7 @@ dependencies = [ "hmac 0.12.1", "pbkdf2 0.10.1", "rand 0.8.5", - "sha2 0.10.6", + "sha2 0.10.8", "unicode-normalization", "zeroize", ] @@ -450,7 +450,7 @@ dependencies = [ "cc", "cfg-if 1.0.0", "constant_time_eq", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -594,9 +594,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" dependencies = [ "serde", ] @@ -766,13 +766,13 @@ dependencies = [ "bincode", "bs58", "coins-core", - "digest 0.10.6", + "digest 0.10.7", "getrandom 0.2.10", "hmac 0.12.1", "k256", "lazy_static", "serde", - "sha2 0.10.6", + "sha2 0.10.8", "thiserror", ] @@ -789,7 +789,7 @@ dependencies = [ "once_cell", "pbkdf2 0.12.1", "rand 0.8.5", - "sha2 0.10.6", + "sha2 0.10.8", "thiserror", ] @@ -802,13 +802,13 @@ dependencies = [ "base64 0.21.0", "bech32 0.7.3", "bs58", - "digest 0.10.6", + "digest 0.10.7", "generic-array 0.14.7", "hex", "ripemd", "serde", "serde_derive", - "sha2 0.10.6", + "sha2 0.10.8", "sha3", "thiserror", ] @@ -1206,9 +1206,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", "const-oid", @@ -1286,7 +1286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" dependencies = [ "der", - "digest 0.10.6", + "digest 0.10.7", "elliptic-curve", "rfc6979", "serdect", @@ -1346,7 +1346,7 @@ checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" dependencies = [ "base16ct", "crypto-bigint", - "digest 0.10.6", + "digest 0.10.7", "ff", "generic-array 0.14.7", "group", @@ -1461,7 +1461,7 @@ checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" dependencies = [ "aes", "ctr", - "digest 0.10.6", + "digest 0.10.7", "hex", "hmac 0.12.1", "pbkdf2 0.11.0", @@ -1469,7 +1469,7 @@ dependencies = [ "scrypt", "serde", "serde_json", - "sha2 0.10.6", + "sha2 0.10.8", "sha3", "thiserror", "uuid", @@ -1765,7 +1765,7 @@ dependencies = [ "ethers-core", "hex", "rand 0.8.5", - "sha2 0.10.6", + "sha2 0.10.8", "thiserror", "tracing", ] @@ -2211,7 +2211,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -2328,40 +2328,389 @@ dependencies = [ [[package]] name = "ibc" -version = "0.47.0" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "429b6aca6624a9364878e28c90311438c2621a8270942d80732b2651ac38ac74" +dependencies = [ + "ibc-apps", + "ibc-clients", + "ibc-core", + "ibc-core-host-cosmos", + "ibc-derive", + "ibc-primitives", +] + +[[package]] +name = "ibc-app-transfer" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b177b343385d9654d99be4709b5ed1574d41f91dfa4044b2d26d688be4179d7c" +dependencies = [ + "ibc-app-transfer-types", + "ibc-core", + "serde-json-wasm", +] + +[[package]] +name = "ibc-app-transfer-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95f92a3eda225e5c86e7bb6501c95986583ac541c4369d3c528349d81390f947" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core", + "ibc-proto", + "primitive-types", + "serde", + "uint", +] + +[[package]] +name = "ibc-apps" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4be40d55ed2dea9f2d05b902a3586f20850c723e4bdbfc4fb0ebe7a66ca5e40" +dependencies = [ + "ibc-app-transfer", +] + +[[package]] +name = "ibc-client-tendermint" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119aa5873214228bf69bded3f20022b9ae1bc35b6841d295afcd73e53db05ccf" +dependencies = [ + "ibc-client-tendermint-types", + "ibc-core-client", + "ibc-core-commitment-types", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-primitives", + "prost 0.12.1", + "serde", + "tendermint", + "tendermint-light-client-verifier", +] + +[[package]] +name = "ibc-client-tendermint-types" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "184eb22140cb4143bbcf7ddc8fdfeb9cc058ef73a6066f8ea78162e69d3565d1" +checksum = "6f21679016931b332b295a761e65cc122dc6fbfb98444148b681ad3aaa474665" dependencies = [ "bytes", + "displaydoc", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde", + "tendermint", + "tendermint-light-client-verifier", + "tendermint-proto", +] + +[[package]] +name = "ibc-clients" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c660323e93107a136aa3dbc412b7fa2eafd315c2fe71184096a43800f8ca5" +dependencies = [ + "ibc-client-tendermint", +] + +[[package]] +name = "ibc-core" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "100d9d0aa67432c5078a8a1c818e3fc990a193be6d35ed0abeda5b340d16c1da" +dependencies = [ + "ibc-core-channel", + "ibc-core-client", + "ibc-core-commitment-types", + "ibc-core-connection", + "ibc-core-handler", + "ibc-core-host", + "ibc-core-router", + "ibc-primitives", +] + +[[package]] +name = "ibc-core-channel" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebaa37629ac029f914dfe552ab5dad01ddb240ec885ed0ae68221cbea4e9bfc" +dependencies = [ + "ibc-core-channel-types", + "ibc-core-client", + "ibc-core-commitment-types", + "ibc-core-connection", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-core-router", + "ibc-primitives", + "prost 0.12.1", +] + +[[package]] +name = "ibc-core-channel-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2ba72c56c411b1e0ce6dc3f5e1fa1de9e6c84891f425b7be8a9e1705964378" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-connection-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde", + "sha2 0.10.8", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-client" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c4fac8e05201795073dee8c93d5afe9dfeac9aec2412b4a2b0c5f0d1e1d725" +dependencies = [ + "ibc-core-client-context", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-primitives", + "prost 0.12.1", +] + +[[package]] +name = "ibc-core-client-context" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b82abd9489021730d59ab2d00e9438d3711e8e78ecba4d083b64f833301682b" +dependencies = [ "derive_more", "displaydoc", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-handler-types", + "ibc-core-host-types", "ibc-derive", + "ibc-primitives", + "prost 0.12.1", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-client-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bafdbf6db5dab4c8ad610b6940e23b4f8abd0a6ac5e8e2801415a95defd4a583" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-commitment-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-commitment-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed4256b0216fc49024bac7e01c61b9bb055e31914ffe9ce6f468d7ce496a9357" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-primitives", + "ibc-proto", + "ics23", + "prost 0.12.1", + "serde", + "subtle-encoding", +] + +[[package]] +name = "ibc-core-connection" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e237b70b9ba0177a4e59ac9048fffac2ac44c334703cc0ae403ad221450850" +dependencies = [ + "ibc-core-client", + "ibc-core-connection-types", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-primitives", + "prost 0.12.1", +] + +[[package]] +name = "ibc-core-connection-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca841416fa29626423917099092f3698ae2735074cb3fe42936ddf6b2ccbf2f7" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-handler" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47e5e5a006aa0fc87ec3f5fb1e0ef6dd5aeea5079fa927d799d526c44329987" +dependencies = [ + "ibc-core-channel", + "ibc-core-client", + "ibc-core-commitment-types", + "ibc-core-connection", + "ibc-core-handler-types", + "ibc-core-host", + "ibc-core-router", + "ibc-primitives", +] + +[[package]] +name = "ibc-core-handler-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3d59a8a5eb2069530c42783b4fef63472a89e0e9242334351df1bb58aaf542" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-channel-types", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-connection-types", + "ibc-core-host-types", + "ibc-core-router-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-host" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aa63c895c0e5a75e42fe859b8fd4250c12bfa8b9c6b114f94c927ecfad38a03" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-channel-types", + "ibc-core-client-context", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-connection-types", + "ibc-core-handler-types", + "ibc-core-host-types", + "ibc-primitives", + "prost 0.12.1", + "subtle-encoding", +] + +[[package]] +name = "ibc-core-host-cosmos" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a325862af6c20b0df3d27c072a2d802a7232dc1666214d738cdfbd9a9c99720" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-app-transfer-types", + "ibc-client-tendermint", + "ibc-core-client-context", + "ibc-core-client-types", + "ibc-core-commitment-types", + "ibc-core-connection-types", + "ibc-core-handler-types", + "ibc-core-host-types", + "ibc-primitives", + "ibc-proto", + "prost 0.12.1", + "serde", + "sha2 0.10.8", + "subtle-encoding", + "tendermint", +] + +[[package]] +name = "ibc-core-host-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616955da310febbe93c0569a2feebd9f57cafed3eee5a56b0c3bb953a75f6089" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-primitives", + "serde", +] + +[[package]] +name = "ibc-core-router" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31fe115da73e0616bdb44400fa6b11ca251648d070c4ff419d58e27804d30243" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-channel-types", + "ibc-core-host-types", + "ibc-core-router-types", + "ibc-primitives", + "prost 0.12.1", + "subtle-encoding", +] + +[[package]] +name = "ibc-core-router-types" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d1fbb0bbbdeafa7ac989ba1693ed46d22e0e3eb0bdae478544e31157a4fdba6" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-core-host-types", + "ibc-primitives", "ibc-proto", "ics23", - "num-traits", - "parking_lot", - "primitive-types", "prost 0.12.1", "serde", - "serde-json-wasm", - "serde_derive", - "sha2 0.10.6", "subtle-encoding", "tendermint", - "tendermint-light-client-verifier", - "tendermint-proto", - "tendermint-testgen", - "time", - "tracing", - "typed-builder", - "uint", ] [[package]] name = "ibc-derive" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92f1528535e9ca495badb76c143bdd4763c1c9d987f59d1f8b47963ba0c11674" +checksum = "df07bf5bc1e65e291506b7497633e07967e49b36a8db10cda77a8fd686eb4548" dependencies = [ "darling", "proc-macro2", @@ -2369,11 +2718,26 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "ibc-primitives" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5edea4685267fd68514c87e7aa3a62712340c4cff6903f088a9ab571428a08a" +dependencies = [ + "derive_more", + "displaydoc", + "ibc-proto", + "prost 0.12.1", + "serde", + "tendermint", + "time", +] + [[package]] name = "ibc-proto" -version = "0.37.1" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63042806bb2f662ca1c68026231900cfe13361136ddfd0dd09bcb315056a22b8" +checksum = "93cbf4cbe9e5113cc7c70f3208a7029b2205c629502cbb2ae7ea0a09a97d3005" dependencies = [ "base64 0.21.0", "bytes", @@ -2385,6 +2749,27 @@ dependencies = [ "tendermint-proto", ] +[[package]] +name = "ibc-testkit" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f550c91648f3db6474880e18cd2bd294096a99b30621aa01a9059b71e3612d98" +dependencies = [ + "bytes", + "derive_more", + "displaydoc", + "ibc", + "ibc-proto", + "parking_lot", + "primitive-types", + "prost 0.12.1", + "subtle-encoding", + "tendermint", + "tendermint-testgen", + "tracing", + "typed-builder", +] + [[package]] name = "ics23" version = "0.11.0" @@ -2398,7 +2783,7 @@ dependencies = [ "prost 0.12.1", "ripemd", "serde", - "sha2 0.10.6", + "sha2 0.10.8", "sha3", ] @@ -2636,7 +3021,7 @@ dependencies = [ "elliptic-curve", "once_cell", "serdect", - "sha2 0.10.6", + "sha2 0.10.8", "signature", ] @@ -2790,7 +3175,7 @@ dependencies = [ "num-traits", "rand 0.8.5", "rand_core 0.6.4", - "sha2 0.10.6", + "sha2 0.10.8", "subtle 2.4.1", "zcash_encoding", ] @@ -3013,7 +3398,7 @@ dependencies = [ "eyre", "ibc", "ibc-derive", - "ibc-proto", + "ibc-testkit", "ics23", "impl-num-traits", "index-set", @@ -3155,6 +3540,8 @@ dependencies = [ "copy_dir", "derivative", "hyper", + "ibc-testkit", + "ics23", "lazy_static", "namada", "namada_core", @@ -3642,7 +4029,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "password-hash", ] @@ -3652,7 +4039,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -3661,7 +4048,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0ca0b5a68607598bf3bad68f32227a8164f6254833f84eafaac409cd6746c31" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "hmac 0.12.1", ] @@ -3809,9 +4196,9 @@ dependencies = [ [[package]] name = "primitive-types" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", "impl-codec", @@ -4330,7 +4717,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -4575,7 +4962,7 @@ dependencies = [ "hmac 0.12.1", "pbkdf2 0.11.0", "salsa20", - "sha2 0.10.6", + "sha2 0.10.8", ] [[package]] @@ -4799,13 +5186,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -4814,7 +5201,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "keccak", ] @@ -4842,7 +5229,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "rand_core 0.6.4", ] @@ -5079,7 +5466,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc2294fa667c8b548ee27a9ba59115472d0a09c2ba255771092a7f1dcf03a789" dependencies = [ "bytes", - "digest 0.10.6", + "digest 0.10.7", "ed25519", "ed25519-consensus 2.1.0", "flex-error", @@ -5094,7 +5481,7 @@ dependencies = [ "serde_bytes", "serde_json", "serde_repr", - "sha2 0.10.6", + "sha2 0.10.8", "signature", "subtle 2.4.1", "subtle-encoding", @@ -5461,11 +5848,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if 1.0.0", "log", "pin-project-lite", "tracing-attributes", @@ -5474,9 +5860,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.24" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", @@ -5485,9 +5871,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] @@ -5525,18 +5911,18 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "typed-builder" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c6a006a6d3d6a6f143fda41cf4d1ad35110080687628c9f2117bd3cc7924f3" +checksum = "e47c0496149861b7c95198088cbf36645016b1a0734cf350c50e2a38e070f38a" dependencies = [ "typed-builder-macro", ] [[package]] name = "typed-builder-macro" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fa054ee5e2346187d631d2f1d1fd3b33676772d6d03a2d84e1c5213b31674ee" +checksum = "982ee4197351b5c9782847ef5ec1fdcaf50503fb19d68f9771adae314e72b492" dependencies = [ "proc-macro2", "quote",