diff --git a/.changelog/unreleased/bug-fixes/1455-persist-epoch-update-delay.md b/.changelog/unreleased/bug-fixes/1455-persist-epoch-update-delay.md
new file mode 100644
index 0000000000..7560aa3f4c
--- /dev/null
+++ b/.changelog/unreleased/bug-fixes/1455-persist-epoch-update-delay.md
@@ -0,0 +1,3 @@
+- Persists a newly added storage field for epoch update blocks delay to be
+ available after node restart when not `None` which may break consensus.
+ ([\#1455](https://github.com/anoma/namada/pull/1455))
\ No newline at end of file
diff --git a/.changelog/unreleased/bug-fixes/1456-fix-max-wait-tries.md b/.changelog/unreleased/bug-fixes/1456-fix-max-wait-tries.md
new file mode 100644
index 0000000000..fdf18ff5ec
--- /dev/null
+++ b/.changelog/unreleased/bug-fixes/1456-fix-max-wait-tries.md
@@ -0,0 +1,2 @@
+- Client: Fixed an off-by-one error to stop waiting for start or catch-up when
+ max tries are reached. ([\#1456](https://github.com/anoma/namada/pull/1456))
\ No newline at end of file
diff --git a/.changelog/unreleased/features/1110-wallet-deterministic.md b/.changelog/unreleased/features/1110-wallet-deterministic.md
new file mode 100644
index 0000000000..d9551b5ea6
--- /dev/null
+++ b/.changelog/unreleased/features/1110-wallet-deterministic.md
@@ -0,0 +1,2 @@
+- Implements HD wallet derivation / recovery from a given mnemonic code
+ ([\#1110](https://github.com/anoma/namada/pull/1110))
\ No newline at end of file
diff --git a/.changelog/unreleased/features/1344-find-validator-by-tm.md b/.changelog/unreleased/features/1344-find-validator-by-tm.md
new file mode 100644
index 0000000000..f0e923c31a
--- /dev/null
+++ b/.changelog/unreleased/features/1344-find-validator-by-tm.md
@@ -0,0 +1,3 @@
+- PoS: Added a client command `find-validator --tm-address
`
+ to find validator's Namada address by Tendermint address.
+ ([\#1344](https://github.com/anoma/namada/pull/1344))
\ No newline at end of file
diff --git a/.changelog/unreleased/features/892-cubic-slashing.md b/.changelog/unreleased/features/892-cubic-slashing.md
new file mode 100644
index 0000000000..cdd079bfc3
--- /dev/null
+++ b/.changelog/unreleased/features/892-cubic-slashing.md
@@ -0,0 +1,5 @@
+- The implementation of the cubic slashing system that touches virtually all
+ parts of the proof-of-stake system. Slashes tokens are currently kept in the
+ PoS address rather than being transferred to the Slash Pool address. This PR
+ also includes significant testing infrastructure, highlighted by the PoS state
+ machine test with slashing. ([#892](https://github.com/anoma/namada/pull/892))
\ No newline at end of file
diff --git a/.changelog/unreleased/improvements/1093-signable-txs.md b/.changelog/unreleased/improvements/1093-signable-txs.md
new file mode 100644
index 0000000000..e1e244bd0f
--- /dev/null
+++ b/.changelog/unreleased/improvements/1093-signable-txs.md
@@ -0,0 +1,2 @@
+- Make Namada transactions signable on hardware constrained wallets by making
+ them smaller. ([#1093](https://github.com/anoma/namada/pull/1093))
\ No newline at end of file
diff --git a/.changelog/unreleased/improvements/1238-optinal-multicore-feature.md b/.changelog/unreleased/improvements/1238-optinal-multicore-feature.md
new file mode 100644
index 0000000000..ee1a0c1ba1
--- /dev/null
+++ b/.changelog/unreleased/improvements/1238-optinal-multicore-feature.md
@@ -0,0 +1,4 @@
+- Added `multicore` feature flag to the namada and namada_core
+ crate that can be switched off for JS WASM build.
+ Additionally, changed the `trait ShieldedUtils` to be async.
+ ([\#1238](https://github.com/anoma/namada/pull/1238))
\ No newline at end of file
diff --git a/.changelog/unreleased/improvements/1425-wallet-zeroize.md b/.changelog/unreleased/improvements/1425-wallet-zeroize.md
new file mode 100644
index 0000000000..ab32b10f65
--- /dev/null
+++ b/.changelog/unreleased/improvements/1425-wallet-zeroize.md
@@ -0,0 +1,2 @@
+- Zeroizes memory containing passphrases in wallet.
+ ([\#1425](https://github.com/anoma/namada/issues/1425))
\ No newline at end of file
diff --git a/.changelog/unreleased/miscellaneous/cwgoes-remove-unused-named-address.md b/.changelog/unreleased/miscellaneous/cwgoes-remove-unused-named-address.md
new file mode 100644
index 0000000000..3152915455
--- /dev/null
+++ b/.changelog/unreleased/miscellaneous/cwgoes-remove-unused-named-address.md
@@ -0,0 +1 @@
+Remove unused named address file
diff --git a/.changelog/unreleased/unreleased/1444.md b/.changelog/unreleased/unreleased/1444.md
new file mode 100644
index 0000000000..652f9ad334
--- /dev/null
+++ b/.changelog/unreleased/unreleased/1444.md
@@ -0,0 +1 @@
+Common sub-expression elimination in inflation calculation
diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index eec0bb533f..b07e2212e9 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -4,13 +4,11 @@ on:
push:
branches:
- main
- - maint-*
- "!eth-bridge-integration"
# Run in PRs with conflicts (https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request)
pull_request_target:
branches:
- main
- - maint-*
- "!eth-bridge-integration"
types: [opened, synchronize, reopened]
workflow_dispatch:
diff --git a/Cargo.lock b/Cargo.lock
index 43e8327787..f88a6ad938 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -19,10 +19,11 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aead"
-version = "0.4.3"
+version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877"
+checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
dependencies = [
+ "crypto-common",
"generic-array 0.14.7",
]
@@ -33,7 +34,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
dependencies = [
"cfg-if 1.0.0",
- "cipher",
+ "cipher 0.3.0",
"cpufeatures",
"opaque-debug 0.3.0",
]
@@ -49,17 +50,6 @@ dependencies = [
"version_check 0.9.4",
]
-[[package]]
-name = "ahash"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
-dependencies = [
- "cfg-if 1.0.0",
- "once_cell",
- "version_check 0.9.4",
-]
-
[[package]]
name = "aho-corasick"
version = "1.0.1"
@@ -393,7 +383,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.15",
+ "syn 2.0.16",
]
[[package]]
@@ -410,7 +400,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.15",
+ "syn 2.0.16",
]
[[package]]
@@ -527,6 +517,18 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce"
+[[package]]
+name = "base58"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83"
+
+[[package]]
+name = "base58"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581"
+
[[package]]
name = "base64"
version = "0.9.3"
@@ -586,25 +588,36 @@ dependencies = [
"blake2s_simd 0.5.11",
"byteorder",
"crossbeam-channel 0.5.8",
- "ff",
- "group",
+ "ff 0.11.1",
+ "group 0.11.0",
"lazy_static",
"log 0.4.17",
"num_cpus",
- "pairing",
+ "pairing 0.21.0",
"rand_core 0.6.4",
"rayon",
- "subtle",
+ "subtle 2.4.1",
]
[[package]]
-name = "bigint"
-version = "4.4.3"
+name = "bellman"
+version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0e8c8a600052b52482eff2cf4d810e462fdff1f656ac1ecb6232132a1ed7def"
+checksum = "a4dd656ef4fdf7debb6d87d4dd92642fcbcdb78cbf6600c13e25c87e4d1a3807"
dependencies = [
+ "bitvec 1.0.1",
+ "blake2s_simd 1.0.1",
"byteorder",
- "crunchy 0.1.6",
+ "crossbeam-channel 0.5.8",
+ "ff 0.12.1",
+ "group 0.12.1",
+ "lazy_static",
+ "log 0.4.17",
+ "num_cpus",
+ "pairing 0.22.0",
+ "rand_core 0.6.4",
+ "rayon",
+ "subtle 2.4.1",
]
[[package]]
@@ -637,13 +650,13 @@ dependencies = [
"lazy_static",
"lazycell",
"peeking_take_while",
- "prettyplease 0.2.4",
+ "prettyplease 0.2.5",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
- "syn 2.0.15",
+ "syn 2.0.16",
]
[[package]]
@@ -683,7 +696,7 @@ checksum = "0694ea59225b0c5f3cb405ff3f670e4828358ed26aec49dc352f730f0cb1a8a3"
dependencies = [
"bech32 0.9.1",
"bitcoin_hashes",
- "secp256k1 0.24.3",
+ "secp256k1",
"serde 1.0.163",
]
@@ -745,17 +758,6 @@ dependencies = [
"cty",
]
-[[package]]
-name = "blake2b_simd"
-version = "0.5.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
-dependencies = [
- "arrayref",
- "arrayvec 0.5.2",
- "constant_time_eq 0.1.5",
-]
-
[[package]]
name = "blake2b_simd"
version = "1.0.1"
@@ -840,7 +842,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e"
dependencies = [
"block-padding 0.2.1",
- "cipher",
+ "cipher 0.3.0",
]
[[package]]
@@ -879,52 +881,42 @@ version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a829c821999c06be34de314eaeb7dd1b42be38661178bc26ad47a4eacebdb0f9"
dependencies = [
- "ff",
- "group",
- "pairing",
+ "ff 0.11.1",
+ "group 0.11.0",
+ "pairing 0.21.0",
"rand_core 0.6.4",
- "subtle",
+ "subtle 2.4.1",
]
[[package]]
-name = "borsh"
-version = "0.9.4"
-source = "git+https://github.com/heliaxdev/borsh-rs.git?rev=cd5223e5103c4f139e0c54cf8259b7ec5ec4073a#cd5223e5103c4f139e0c54cf8259b7ec5ec4073a"
-dependencies = [
- "borsh-derive 0.9.4",
- "hashbrown 0.11.2",
-]
-
-[[package]]
-name = "borsh"
-version = "0.10.3"
+name = "bls12_381"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b"
+checksum = "a3c196a77437e7cc2fb515ce413a6401291578b5afc8ecb29a3c7ab957f05941"
dependencies = [
- "borsh-derive 0.10.3",
- "hashbrown 0.13.2",
+ "ff 0.12.1",
+ "group 0.12.1",
+ "pairing 0.22.0",
+ "rand_core 0.6.4",
+ "subtle 2.4.1",
]
[[package]]
-name = "borsh-derive"
+name = "borsh"
version = "0.9.4"
source = "git+https://github.com/heliaxdev/borsh-rs.git?rev=cd5223e5103c4f139e0c54cf8259b7ec5ec4073a#cd5223e5103c4f139e0c54cf8259b7ec5ec4073a"
dependencies = [
- "borsh-derive-internal 0.9.4",
- "borsh-schema-derive-internal 0.9.4",
- "proc-macro-crate 0.1.5",
- "proc-macro2",
- "syn 1.0.109",
+ "borsh-derive",
+ "hashbrown 0.11.2",
]
[[package]]
name = "borsh-derive"
-version = "0.10.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7"
+version = "0.9.4"
+source = "git+https://github.com/heliaxdev/borsh-rs.git?rev=cd5223e5103c4f139e0c54cf8259b7ec5ec4073a#cd5223e5103c4f139e0c54cf8259b7ec5ec4073a"
dependencies = [
- "borsh-derive-internal 0.10.3",
- "borsh-schema-derive-internal 0.10.3",
+ "borsh-derive-internal",
+ "borsh-schema-derive-internal",
"proc-macro-crate 0.1.5",
"proc-macro2",
"syn 1.0.109",
@@ -940,17 +932,6 @@ dependencies = [
"syn 1.0.109",
]
-[[package]]
-name = "borsh-derive-internal"
-version = "0.10.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
[[package]]
name = "borsh-schema-derive-internal"
version = "0.9.4"
@@ -961,17 +942,6 @@ dependencies = [
"syn 1.0.109",
]
-[[package]]
-name = "borsh-schema-derive-internal"
-version = "0.10.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
[[package]]
name = "bs58"
version = "0.4.0"
@@ -1152,20 +1122,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6"
dependencies = [
"cfg-if 1.0.0",
- "cipher",
+ "cipher 0.3.0",
"cpufeatures",
- "zeroize",
]
[[package]]
-name = "chacha20poly1305"
+name = "chacha20"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5"
+checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
+dependencies = [
+ "cfg-if 1.0.0",
+ "cipher 0.4.4",
+ "cpufeatures",
+]
+
+[[package]]
+name = "chacha20poly1305"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
dependencies = [
"aead",
- "chacha20",
- "cipher",
+ "chacha20 0.9.1",
+ "cipher 0.4.4",
"poly1305",
"zeroize",
]
@@ -1197,6 +1177,17 @@ dependencies = [
"generic-array 0.14.7",
]
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
+ "zeroize",
+]
+
[[package]]
name = "circular-queue"
version = "0.2.6"
@@ -1515,12 +1506,6 @@ dependencies = [
"cfg-if 1.0.0",
]
-[[package]]
-name = "crunchy"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda"
-
[[package]]
name = "crunchy"
version = "0.2.2"
@@ -1535,7 +1520,7 @@ checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21"
dependencies = [
"generic-array 0.14.7",
"rand_core 0.6.4",
- "subtle",
+ "subtle 2.4.1",
"zeroize",
]
@@ -1551,37 +1536,32 @@ dependencies = [
[[package]]
name = "crypto-mac"
-version = "0.8.0"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
+checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
dependencies = [
- "generic-array 0.14.7",
- "subtle",
+ "generic-array 0.12.4",
+ "subtle 1.0.0",
]
[[package]]
name = "crypto-mac"
-version = "0.11.1"
+version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
+checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
dependencies = [
"generic-array 0.14.7",
- "subtle",
+ "subtle 2.4.1",
]
[[package]]
-name = "crypto_api"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f855e87e75a4799e18b8529178adcde6fd4f97c1449ff4821e747ff728bb102"
-
-[[package]]
-name = "crypto_api_chachapoly"
-version = "0.4.3"
+name = "crypto-mac"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d930b6a026ce9d358a17f9c9046c55d90b14bb847f36b6ebb6b19365d4feffb8"
+checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
dependencies = [
- "crypto_api",
+ "generic-array 0.14.7",
+ "subtle 2.4.1",
]
[[package]]
@@ -1624,7 +1604,7 @@ dependencies = [
"byteorder",
"digest 0.9.0",
"rand_core 0.5.1",
- "subtle",
+ "subtle 2.4.1",
"zeroize",
]
@@ -1661,7 +1641,7 @@ dependencies = [
"ident_case",
"proc-macro2",
"quote",
- "syn 2.0.15",
+ "syn 2.0.16",
]
[[package]]
@@ -1672,7 +1652,7 @@ checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a"
dependencies = [
"darling_core",
"quote",
- "syn 2.0.15",
+ "syn 2.0.16",
]
[[package]]
@@ -1756,7 +1736,7 @@ checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
dependencies = [
"block-buffer 0.10.4",
"crypto-common",
- "subtle",
+ "subtle 2.4.1",
]
[[package]]
@@ -1808,7 +1788,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.15",
+ "syn 2.0.16",
]
[[package]]
@@ -1935,12 +1915,12 @@ dependencies = [
"base16ct",
"crypto-bigint",
"der",
- "ff",
+ "ff 0.11.1",
"generic-array 0.14.7",
- "group",
+ "group 0.11.0",
"rand_core 0.6.4",
"sec1",
- "subtle",
+ "subtle 2.4.1",
"zeroize",
]
@@ -1991,16 +1971,7 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
- "syn 2.0.15",
-]
-
-[[package]]
-name = "equihash"
-version = "0.1.0"
-source = "git+https://github.com/zcash/librustzcash/?rev=2425a08#2425a0869098e3b0588ccd73c42716bcf418612c"
-dependencies = [
- "blake2b_simd 1.0.1",
- "byteorder",
+ "syn 2.0.16",
]
[[package]]
@@ -2118,8 +2089,8 @@ dependencies = [
"ark-std",
"bincode",
"blake2",
- "blake2b_simd 1.0.1",
- "borsh 0.9.4",
+ "blake2b_simd",
+ "borsh",
"digest 0.10.6",
"ed25519-dalek",
"either",
@@ -2136,7 +2107,7 @@ dependencies = [
"serde_bytes",
"serde_json",
"subproductdomain",
- "subtle",
+ "subtle 2.4.1",
"zeroize",
]
@@ -2161,7 +2132,18 @@ checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924"
dependencies = [
"bitvec 0.22.3",
"rand_core 0.6.4",
- "subtle",
+ "subtle 2.4.1",
+]
+
+[[package]]
+name = "ff"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160"
+dependencies = [
+ "bitvec 1.0.1",
+ "rand_core 0.6.4",
+ "subtle 2.4.1",
]
[[package]]
@@ -2272,7 +2254,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd910db5f9ca4dc3116f8c46367825807aa2b942f72565f16b4be0b208a00a9e"
dependencies = [
"block-modes",
- "cipher",
+ "cipher 0.3.0",
"libm",
"num-bigint",
"num-integer",
@@ -2395,7 +2377,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.15",
+ "syn 2.0.16",
]
[[package]]
@@ -2454,8 +2436,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if 1.0.0",
+ "js-sys",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
]
[[package]]
@@ -2465,8 +2449,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
dependencies = [
"cfg-if 1.0.0",
+ "js-sys",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
]
[[package]]
@@ -2526,9 +2512,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89"
dependencies = [
"byteorder",
- "ff",
+ "ff 0.11.1",
+ "rand_core 0.6.4",
+ "subtle 2.4.1",
+]
+
+[[package]]
+name = "group"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7"
+dependencies = [
+ "ff 0.12.1",
+ "memuse",
"rand_core 0.6.4",
- "subtle",
+ "subtle 2.4.1",
]
[[package]]
@@ -2543,8 +2541,8 @@ dependencies = [
"ark-poly",
"ark-serialize",
"ark-std",
- "blake2b_simd 1.0.1",
- "chacha20",
+ "blake2b_simd",
+ "chacha20 0.8.2",
"hex",
"itertools",
"miracl_core",
@@ -2600,27 +2598,13 @@ version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
-[[package]]
-name = "halo2"
-version = "0.1.0-beta.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f186b85ed81082fb1cf59d52b0111f02915e89a4ac61d292b38d075e570f3a9"
-dependencies = [
- "blake2b_simd 0.5.11",
- "ff",
- "group",
- "pasta_curves",
- "rand 0.8.5",
- "rayon",
-]
-
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
dependencies = [
- "ahash 0.7.6",
+ "ahash",
]
[[package]]
@@ -2629,23 +2613,14 @@ version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
dependencies = [
- "ahash 0.7.6",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.13.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
-dependencies = [
- "ahash 0.8.3",
+ "ahash",
]
[[package]]
name = "hdpath"
-version = "0.6.2"
+version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ae1615f843ce3981b47468f3f7c435ac17deb33c2261e64d7f1e87f5c11acc"
+checksum = "dfa5bc9db2c17d2660f53ce217b778d06d68de13d1cd01c0f4e5de4b7918935f"
dependencies = [
"byteorder",
]
@@ -2721,6 +2696,16 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+[[package]]
+name = "hmac"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695"
+dependencies = [
+ "crypto-mac 0.7.0",
+ "digest 0.8.1",
+]
+
[[package]]
name = "hmac"
version = "0.8.1"
@@ -2750,6 +2735,17 @@ dependencies = [
"digest 0.10.6",
]
+[[package]]
+name = "hmac-drbg"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b"
+dependencies = [
+ "digest 0.8.1",
+ "generic-array 0.12.4",
+ "hmac 0.7.1",
+]
+
[[package]]
name = "hmac-drbg"
version = "0.3.0"
@@ -2761,6 +2757,12 @@ dependencies = [
"hmac 0.8.1",
]
+[[package]]
+name = "hmac-sha512"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77e806677ce663d0a199541030c816847b36e8dc095f70dae4a4f4ad63da5383"
+
[[package]]
name = "http"
version = "0.2.9"
@@ -2939,38 +2941,6 @@ dependencies = [
"cc",
]
-[[package]]
-name = "ibc"
-version = "0.36.0"
-source = "git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=db14744bfba6239cc5f58345ff90f8b7d42637d6#db14744bfba6239cc5f58345ff90f8b7d42637d6"
-dependencies = [
- "bytes 1.4.0",
- "cfg-if 1.0.0",
- "derive_more",
- "displaydoc",
- "dyn-clone",
- "erased-serde",
- "ibc-proto 0.26.0 (git+https://github.com/heliaxdev/ibc-proto-rs?rev=dd8ba23110a144ffe2074a0b889676468266435a)",
- "ics23",
- "num-traits 0.2.15",
- "parking_lot 0.12.1",
- "primitive-types",
- "prost",
- "safe-regex",
- "serde 1.0.163",
- "serde_derive",
- "serde_json",
- "sha2 0.10.6",
- "subtle-encoding",
- "tendermint 0.23.5",
- "tendermint-light-client-verifier 0.23.5",
- "tendermint-proto 0.23.5",
- "tendermint-testgen 0.23.5",
- "time 0.3.17",
- "tracing 0.1.37",
- "uint",
-]
-
[[package]]
name = "ibc"
version = "0.36.0"
@@ -2982,7 +2952,7 @@ dependencies = [
"displaydoc",
"dyn-clone",
"erased-serde",
- "ibc-proto 0.26.0 (git+https://github.com/heliaxdev/ibc-proto-rs.git?rev=6f4038fcf4981f1ed70771d1cd89931267f917af)",
+ "ibc-proto",
"ics23",
"num-traits 0.2.15",
"parking_lot 0.12.1",
@@ -2994,10 +2964,10 @@ dependencies = [
"serde_json",
"sha2 0.10.6",
"subtle-encoding",
- "tendermint 0.23.6",
- "tendermint-light-client-verifier 0.23.6",
- "tendermint-proto 0.23.6",
- "tendermint-testgen 0.23.6",
+ "tendermint",
+ "tendermint-light-client-verifier",
+ "tendermint-proto",
+ "tendermint-testgen",
"time 0.3.17",
"tracing 0.1.37",
"uint",
@@ -3014,27 +2984,10 @@ dependencies = [
"prost",
"serde 1.0.163",
"subtle-encoding",
- "tendermint-proto 0.23.6",
+ "tendermint-proto",
"tonic",
]
-[[package]]
-name = "ibc-proto"
-version = "0.26.0"
-source = "git+https://github.com/heliaxdev/ibc-proto-rs?rev=dd8ba23110a144ffe2074a0b889676468266435a#dd8ba23110a144ffe2074a0b889676468266435a"
-dependencies = [
- "base64 0.13.1",
- "borsh 0.10.3",
- "bytes 1.4.0",
- "flex-error",
- "parity-scale-codec",
- "prost",
- "scale-info",
- "serde 1.0.163",
- "subtle-encoding",
- "tendermint-proto 0.23.5",
-]
-
[[package]]
name = "ibc-relayer"
version = "0.22.0"
@@ -3060,7 +3013,7 @@ dependencies = [
"http",
"humantime",
"humantime-serde",
- "ibc-proto 0.26.0 (git+https://github.com/heliaxdev/ibc-proto-rs.git?rev=6f4038fcf4981f1ed70771d1cd89931267f917af)",
+ "ibc-proto",
"ibc-relayer-types",
"itertools",
"moka",
@@ -3070,7 +3023,7 @@ dependencies = [
"regex",
"retry",
"ripemd",
- "secp256k1 0.24.3",
+ "secp256k1",
"semver 1.0.17",
"serde 1.0.163",
"serde_derive",
@@ -3079,19 +3032,19 @@ dependencies = [
"signature",
"strum",
"subtle-encoding",
- "tendermint 0.23.6",
+ "tendermint",
"tendermint-light-client",
- "tendermint-light-client-verifier 0.23.6",
- "tendermint-proto 0.23.6",
- "tendermint-rpc 0.23.6",
+ "tendermint-light-client-verifier",
+ "tendermint-proto",
+ "tendermint-rpc",
"thiserror",
- "tiny-bip39",
+ "tiny-bip39 1.0.0",
"tiny-keccak",
"tokio",
"toml",
"tonic",
"tracing 0.1.37",
- "uuid 1.3.2",
+ "uuid 1.3.3",
]
[[package]]
@@ -3104,7 +3057,7 @@ dependencies = [
"dyn-clone",
"erased-serde",
"flex-error",
- "ibc-proto 0.26.0 (git+https://github.com/heliaxdev/ibc-proto-rs.git?rev=6f4038fcf4981f1ed70771d1cd89931267f917af)",
+ "ibc-proto",
"ics23",
"itertools",
"num-rational",
@@ -3115,11 +3068,11 @@ dependencies = [
"serde_derive",
"serde_json",
"subtle-encoding",
- "tendermint 0.23.6",
- "tendermint-light-client-verifier 0.23.6",
- "tendermint-proto 0.23.6",
- "tendermint-rpc 0.23.6",
- "tendermint-testgen 0.23.6",
+ "tendermint",
+ "tendermint-light-client-verifier",
+ "tendermint-proto",
+ "tendermint-rpc",
+ "tendermint-testgen",
"time 0.3.17",
"uint",
]
@@ -3197,9 +3150,9 @@ dependencies = [
[[package]]
name = "incrementalmerkletree"
-version = "0.2.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "186fd3ab92aeac865d4b80b410de9a7b341d31ba8281373caed0b6d17b2b5e96"
+checksum = "d5ad43a3f5795945459d577f6589cf62a476e92c79b75e70cd954364e14ce17b"
dependencies = [
"serde 1.0.163",
]
@@ -3215,7 +3168,7 @@ name = "index-set"
version = "0.7.1"
source = "git+https://github.com/heliaxdev/index-set?tag=v0.7.1#dc24cdbbe3664514d59f1a4c4031863fc565f1c2"
dependencies = [
- "borsh 0.9.4",
+ "borsh",
"serde 1.0.163",
]
@@ -3230,6 +3183,15 @@ dependencies = [
"serde 1.0.163",
]
+[[package]]
+name = "inout"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
+dependencies = [
+ "generic-array 0.14.7",
+]
+
[[package]]
name = "input_buffer"
version = "0.4.0"
@@ -3303,25 +3265,25 @@ dependencies = [
[[package]]
name = "js-sys"
-version = "0.3.62"
+version = "0.3.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68c16e1bfd491478ab155fd8b4896b86f9ede344949b641e61501e07c2b8b4d5"
+checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "jubjub"
-version = "0.8.0"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e7baec19d4e83f9145d4891178101a604565edff9645770fc979804138b04c"
+checksum = "a575df5f985fe1cd5b2b05664ff6accfc46559032b954529fd225a2168d27b0f"
dependencies = [
- "bitvec 0.22.3",
- "bls12_381",
- "ff",
- "group",
+ "bitvec 1.0.1",
+ "bls12_381 0.7.1",
+ "ff 0.12.1",
+ "group 0.12.1",
"rand_core 0.6.4",
- "subtle",
+ "subtle 2.4.1",
]
[[package]]
@@ -3434,9 +3396,9 @@ dependencies = [
[[package]]
name = "libm"
-version = "0.2.6"
+version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb"
+checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
[[package]]
name = "librocksdb-sys"
@@ -3454,6 +3416,22 @@ dependencies = [
"zstd-sys",
]
+[[package]]
+name = "libsecp256k1"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fc1e2c808481a63dc6da2074752fdd4336a3c8fcc68b83db6f1fd5224ae7962"
+dependencies = [
+ "arrayref",
+ "crunchy",
+ "digest 0.8.1",
+ "hmac-drbg 0.2.0",
+ "rand 0.7.3",
+ "sha2 0.8.2",
+ "subtle 2.4.1",
+ "typenum",
+]
+
[[package]]
name = "libsecp256k1"
version = "0.7.0"
@@ -3462,7 +3440,7 @@ dependencies = [
"arrayref",
"base64 0.13.1",
"digest 0.9.0",
- "hmac-drbg",
+ "hmac-drbg 0.3.0",
"libsecp256k1-core",
"libsecp256k1-gen-ecmult",
"libsecp256k1-gen-genmult",
@@ -3477,9 +3455,9 @@ name = "libsecp256k1-core"
version = "0.3.0"
source = "git+https://github.com/heliaxdev/libsecp256k1?rev=bbb3bd44a49db361f21d9db80f9a087c194c0ae9#bbb3bd44a49db361f21d9db80f9a087c194c0ae9"
dependencies = [
- "crunchy 0.2.2",
+ "crunchy",
"digest 0.9.0",
- "subtle",
+ "subtle 2.4.1",
]
[[package]]
@@ -3621,60 +3599,69 @@ dependencies = [
"serde_yaml",
]
+[[package]]
+name = "masp_note_encryption"
+version = "0.2.0"
+source = "git+https://github.com/anoma/masp?rev=cfea8c95d3f73077ca3e25380fd27e5b46e828fd#cfea8c95d3f73077ca3e25380fd27e5b46e828fd"
+dependencies = [
+ "borsh",
+ "chacha20 0.9.1",
+ "chacha20poly1305",
+ "cipher 0.4.4",
+ "rand_core 0.6.4",
+ "subtle 2.4.1",
+]
+
[[package]]
name = "masp_primitives"
-version = "0.5.0"
-source = "git+https://github.com/anoma/masp?rev=bee40fc465f6afbd10558d12fe96eb1742eee45c#bee40fc465f6afbd10558d12fe96eb1742eee45c"
+version = "0.9.0"
+source = "git+https://github.com/anoma/masp?rev=cfea8c95d3f73077ca3e25380fd27e5b46e828fd#cfea8c95d3f73077ca3e25380fd27e5b46e828fd"
dependencies = [
"aes",
"bip0039",
- "bitvec 0.22.3",
- "blake2b_simd 1.0.1",
+ "bitvec 1.0.1",
+ "blake2b_simd",
"blake2s_simd 1.0.1",
- "bls12_381",
- "borsh 0.9.4",
+ "bls12_381 0.7.1",
+ "borsh",
"byteorder",
- "chacha20poly1305",
- "crypto_api_chachapoly",
- "ff",
+ "ff 0.12.1",
"fpe",
- "group",
+ "group 0.12.1",
"hex",
"incrementalmerkletree",
"jubjub",
"lazy_static",
+ "masp_note_encryption",
+ "memuse",
+ "nonempty",
"rand 0.8.5",
"rand_core 0.6.4",
- "ripemd160",
- "secp256k1 0.20.3",
- "serde 1.0.163",
"sha2 0.9.9",
- "subtle",
+ "subtle 2.4.1",
"zcash_encoding",
- "zcash_primitives",
]
[[package]]
name = "masp_proofs"
-version = "0.5.0"
-source = "git+https://github.com/anoma/masp?rev=bee40fc465f6afbd10558d12fe96eb1742eee45c#bee40fc465f6afbd10558d12fe96eb1742eee45c"
+version = "0.9.0"
+source = "git+https://github.com/anoma/masp?rev=cfea8c95d3f73077ca3e25380fd27e5b46e828fd#cfea8c95d3f73077ca3e25380fd27e5b46e828fd"
dependencies = [
- "bellman",
- "blake2b_simd 1.0.1",
- "bls12_381",
- "byteorder",
+ "bellman 0.13.1",
+ "blake2b_simd",
+ "bls12_381 0.7.1",
"directories",
- "ff",
- "group",
+ "getrandom 0.2.9",
+ "group 0.12.1",
"itertools",
"jubjub",
"lazy_static",
"masp_primitives",
"minreq",
"rand_core 0.6.4",
+ "redjubjub",
+ "tracing 0.1.37",
"wagyu-zcash-parameters",
- "zcash_primitives",
- "zcash_proofs",
]
[[package]]
@@ -3752,9 +3739,12 @@ name = "memuse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2145869435ace5ea6ea3d35f59be559317ec9a0d04e1812d5f185a87b6d36f1a"
-dependencies = [
- "nonempty",
-]
+
+[[package]]
+name = "memzero"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93c0d11ac30a033511ae414355d80f70d9f29a44a49140face477117a1ee90db"
[[package]]
name = "merlin"
@@ -3899,7 +3889,7 @@ dependencies = [
"tagptr",
"thiserror",
"triomphe",
- "uuid 1.3.2",
+ "uuid 1.3.3",
]
[[package]]
@@ -3921,21 +3911,22 @@ dependencies = [
"assert_matches",
"async-std",
"async-trait",
- "bellman",
+ "base58 0.2.0",
+ "bellman 0.11.2",
"bimap",
- "bls12_381",
- "borsh 0.9.4",
+ "bls12_381 0.6.1",
+ "borsh",
"byte-unit",
"circular-queue",
"clru",
"data-encoding",
+ "derivation-path",
"derivative",
- "ibc 0.36.0 (git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=db14744bfba6239cc5f58345ff90f8b7d42637d6)",
- "ibc 0.36.0 (git+https://github.com/heliaxdev/cosmos-ibc-rs.git?rev=e71bc2cc79f8c2b32e970d95312f251398c93d9e)",
- "ibc-proto 0.26.0 (git+https://github.com/heliaxdev/ibc-proto-rs.git?rev=6f4038fcf4981f1ed70771d1cd89931267f917af)",
- "ibc-proto 0.26.0 (git+https://github.com/heliaxdev/ibc-proto-rs?rev=dd8ba23110a144ffe2074a0b889676468266435a)",
+ "hex",
+ "ibc",
+ "ibc-proto",
"itertools",
- "libsecp256k1",
+ "libsecp256k1 0.7.0",
"loupe",
"masp_primitives",
"masp_proofs",
@@ -3952,17 +3943,21 @@ dependencies = [
"rand 0.8.5",
"rand_core 0.6.4",
"rayon",
+ "ripemd",
"rust_decimal",
"rust_decimal_macros",
"serde 1.0.163",
"serde_json",
"sha2 0.9.9",
+ "slip10_ed25519",
"tempfile",
- "tendermint 0.23.6",
- "tendermint-proto 0.23.6",
- "tendermint-rpc 0.23.6",
+ "tendermint",
+ "tendermint-proto",
+ "tendermint-rpc",
"test-log",
"thiserror",
+ "tiny-bip39 0.8.2",
+ "tiny-hderive",
"tokio",
"toml",
"tracing 0.1.37",
@@ -3991,7 +3986,7 @@ dependencies = [
"bimap",
"bit-set",
"blake2b-rs",
- "borsh 0.9.4",
+ "borsh",
"byte-unit",
"byteorder",
"clap",
@@ -4029,6 +4024,7 @@ dependencies = [
"rayon",
"regex",
"reqwest",
+ "ripemd",
"rlimit",
"rocksdb",
"rpassword",
@@ -4043,10 +4039,10 @@ dependencies = [
"sysinfo",
"tar",
"tempfile",
- "tendermint 0.23.6",
- "tendermint-config 0.23.6",
- "tendermint-proto 0.23.6",
- "tendermint-rpc 0.23.6",
+ "tendermint",
+ "tendermint-config",
+ "tendermint-proto",
+ "tendermint-rpc",
"test-log",
"thiserror",
"tokio",
@@ -4054,13 +4050,13 @@ dependencies = [
"toml",
"tonic",
"tower",
- "tower-abci 0.1.0 (git+https://github.com/heliaxdev/tower-abci.git?rev=367d8d958b83c501ed2c09e9c4595f8bf75a0b01)",
- "tower-abci 0.1.0 (git+https://github.com/heliaxdev/tower-abci?rev=a31ce06533f5fbd943508676059d44de27395792)",
+ "tower-abci",
"tracing 0.1.37",
"tracing-log",
"tracing-subscriber 0.3.17",
"websocket",
"winapi 0.3.9",
+ "zeroize",
]
[[package]]
@@ -4072,8 +4068,8 @@ dependencies = [
"ark-serialize",
"assert_matches",
"bech32 0.8.1",
- "bellman",
- "borsh 0.9.4",
+ "bellman 0.11.2",
+ "borsh",
"chrono",
"data-encoding",
"derivative",
@@ -4081,14 +4077,12 @@ dependencies = [
"ferveo",
"ferveo-common",
"group-threshold-cryptography",
- "ibc 0.36.0 (git+https://github.com/heliaxdev/cosmos-ibc-rs?rev=db14744bfba6239cc5f58345ff90f8b7d42637d6)",
- "ibc 0.36.0 (git+https://github.com/heliaxdev/cosmos-ibc-rs.git?rev=e71bc2cc79f8c2b32e970d95312f251398c93d9e)",
- "ibc-proto 0.26.0 (git+https://github.com/heliaxdev/ibc-proto-rs.git?rev=6f4038fcf4981f1ed70771d1cd89931267f917af)",
- "ibc-proto 0.26.0 (git+https://github.com/heliaxdev/ibc-proto-rs?rev=dd8ba23110a144ffe2074a0b889676468266435a)",
+ "ibc",
+ "ibc-proto",
"ics23",
"index-set",
"itertools",
- "libsecp256k1",
+ "libsecp256k1 0.7.0",
"masp_primitives",
"namada_macros",
"pretty_assertions",
@@ -4104,8 +4098,8 @@ dependencies = [
"serde_json",
"sha2 0.9.9",
"sparse-merkle-tree",
- "tendermint 0.23.6",
- "tendermint-proto 0.23.6",
+ "tendermint",
+ "tendermint-proto",
"test-log",
"thiserror",
"tonic-build",
@@ -4118,7 +4112,7 @@ dependencies = [
name = "namada_encoding_spec"
version = "0.16.0"
dependencies = [
- "borsh 0.9.4",
+ "borsh",
"itertools",
"lazy_static",
"madato",
@@ -4138,7 +4132,7 @@ dependencies = [
name = "namada_proof_of_stake"
version = "0.16.0"
dependencies = [
- "borsh 0.9.4",
+ "borsh",
"data-encoding",
"derivative",
"hex",
@@ -4158,7 +4152,7 @@ dependencies = [
name = "namada_test_utils"
version = "0.16.0"
dependencies = [
- "borsh 0.9.4",
+ "borsh",
"namada_core",
"strum",
]
@@ -4168,7 +4162,7 @@ name = "namada_tests"
version = "0.16.0"
dependencies = [
"assert_cmd",
- "borsh 0.9.4",
+ "borsh",
"chrono",
"color-eyre",
"concat-idents",
@@ -4198,10 +4192,10 @@ dependencies = [
"serde_json",
"sha2 0.9.9",
"tempfile",
- "tendermint 0.23.6",
- "tendermint-config 0.23.6",
- "tendermint-proto 0.23.6",
- "tendermint-rpc 0.23.6",
+ "tendermint",
+ "tendermint-config",
+ "tendermint-proto",
+ "tendermint-rpc",
"test-log",
"tokio",
"toml",
@@ -4213,7 +4207,7 @@ dependencies = [
name = "namada_tx_prelude"
version = "0.16.0"
dependencies = [
- "borsh 0.9.4",
+ "borsh",
"masp_primitives",
"namada_core",
"namada_macros",
@@ -4228,10 +4222,9 @@ dependencies = [
name = "namada_vm_env"
version = "0.16.0"
dependencies = [
- "borsh 0.9.4",
+ "borsh",
"hex",
"masp_primitives",
- "masp_proofs",
"namada_core",
]
@@ -4239,7 +4232,7 @@ dependencies = [
name = "namada_vp_prelude"
version = "0.16.0"
dependencies = [
- "borsh 0.9.4",
+ "borsh",
"namada_core",
"namada_macros",
"namada_proof_of_stake",
@@ -4520,7 +4513,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.15",
+ "syn 2.0.16",
]
[[package]]
@@ -4541,33 +4534,6 @@ dependencies = [
"vcpkg",
]
-[[package]]
-name = "orchard"
-version = "0.1.0-beta.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e31f03b6d0aee6d993cac35388b818e04f076ded0ab284979e4d7cd5a8b3c2be"
-dependencies = [
- "aes",
- "arrayvec 0.7.2",
- "bigint",
- "bitvec 0.22.3",
- "blake2b_simd 1.0.1",
- "ff",
- "fpe",
- "group",
- "halo2",
- "incrementalmerkletree",
- "lazy_static",
- "memuse",
- "nonempty",
- "pasta_curves",
- "rand 0.8.5",
- "reddsa",
- "serde 1.0.163",
- "subtle",
- "zcash_note_encryption 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "orion"
version = "0.16.1"
@@ -4576,7 +4542,7 @@ checksum = "c6624905ddd92e460ff0685567539ed1ac985b2dee4c92c7edcd64fce905b00c"
dependencies = [
"ct-codecs",
"getrandom 0.2.9",
- "subtle",
+ "subtle 2.4.1",
"zeroize",
]
@@ -4613,7 +4579,16 @@ version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2e415e349a3006dd7d9482cdab1c980a845bed1377777d768cb693a44540b42"
dependencies = [
- "group",
+ "group 0.11.0",
+]
+
+[[package]]
+name = "pairing"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "135590d8bdba2b31346f9cd1fb2a912329f5135e832a4f422942eb6ead8b6b3b"
+dependencies = [
+ "group 0.12.1",
]
[[package]]
@@ -4707,26 +4682,11 @@ dependencies = [
name = "password-hash"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8"
-dependencies = [
- "base64ct",
- "rand_core 0.6.4",
- "subtle",
-]
-
-[[package]]
-name = "pasta_curves"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d647d91972bad78120fd61e06b225fcda117805c9bbf17676b51bd03a251278b"
-dependencies = [
- "blake2b_simd 0.5.11",
- "ff",
- "group",
- "lazy_static",
- "rand 0.8.5",
- "static_assertions",
- "subtle",
+checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8"
+dependencies = [
+ "base64ct",
+ "rand_core 0.6.4",
+ "subtle 2.4.1",
]
[[package]]
@@ -4735,6 +4695,15 @@ version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
+[[package]]
+name = "pbkdf2"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd"
+dependencies = [
+ "crypto-mac 0.8.0",
+]
+
[[package]]
name = "pbkdf2"
version = "0.9.0"
@@ -4836,7 +4805,7 @@ checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.15",
+ "syn 2.0.16",
]
[[package]]
@@ -4873,9 +4842,9 @@ dependencies = [
[[package]]
name = "poly1305"
-version = "0.7.2"
+version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede"
+checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
dependencies = [
"cpufeatures",
"opaque-debug 0.3.0",
@@ -4939,12 +4908,12 @@ dependencies = [
[[package]]
name = "prettyplease"
-version = "0.2.4"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ceca8aaf45b5c46ec7ed39fff75f57290368c1846d33d24a122ca81416ab058"
+checksum = "617feabb81566b593beb4886fb8c1f38064169dae4dccad0e3220160c3b37203"
dependencies = [
"proc-macro2",
- "syn 2.0.15",
+ "syn 2.0.16",
]
[[package]]
@@ -5004,9 +4973,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.56"
+version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
+checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8"
dependencies = [
"unicode-ident",
]
@@ -5406,17 +5375,15 @@ dependencies = [
]
[[package]]
-name = "reddsa"
-version = "0.1.0"
+name = "redjubjub"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a90e2c94bca3445cae0d55dff7370e29c24885d2403a1665ce19c106c79455e6"
+checksum = "6039ff156887caf92df308cbaccdc058c9d3155a913da046add6e48c4cdbd91d"
dependencies = [
- "blake2b_simd 0.5.11",
+ "blake2b_simd",
"byteorder",
"digest 0.9.0",
- "group",
"jubjub",
- "pasta_curves",
"rand_core 0.6.4",
"serde 1.0.163",
"thiserror",
@@ -5524,9 +5491,9 @@ dependencies = [
[[package]]
name = "reqwest"
-version = "0.11.17"
+version = "0.11.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13293b639a097af28fc8a90f22add145a9c954e49d77da06263d58cf44d5fb91"
+checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55"
dependencies = [
"base64 0.21.0",
"bytes 1.4.0",
@@ -5625,7 +5592,7 @@ dependencies = [
"rkyv_derive",
"seahash",
"tinyvec",
- "uuid 1.3.2",
+ "uuid 1.3.3",
]
[[package]]
@@ -5681,7 +5648,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee9164faf726e4f3ece4978b25ca877ddc6802fa77f38cdccb32c7f805ecd70c"
dependencies = [
"arrayvec 0.7.2",
- "borsh 0.9.4",
+ "borsh",
"num-traits 0.2.15",
"serde 1.0.163",
]
@@ -5899,30 +5866,6 @@ dependencies = [
"winapi-util",
]
-[[package]]
-name = "scale-info"
-version = "2.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfdef77228a4c05dc94211441595746732131ad7f6530c6c18f045da7b7ab937"
-dependencies = [
- "cfg-if 1.0.0",
- "derive_more",
- "parity-scale-codec",
- "scale-info-derive",
-]
-
-[[package]]
-name = "scale-info-derive"
-version = "2.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53012eae69e5aa5c14671942a5dd47de59d4cdcff8532a6dd0e081faf1119482"
-dependencies = [
- "proc-macro-crate 1.3.1",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
[[package]]
name = "schannel"
version = "0.1.21"
@@ -5981,19 +5924,10 @@ checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1"
dependencies = [
"der",
"generic-array 0.14.7",
- "subtle",
+ "subtle 2.4.1",
"zeroize",
]
-[[package]]
-name = "secp256k1"
-version = "0.20.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97d03ceae636d0fed5bae6a7f4f664354c5f4fcedf6eef053fef17e49f837d0a"
-dependencies = [
- "secp256k1-sys 0.4.2",
-]
-
[[package]]
name = "secp256k1"
version = "0.24.3"
@@ -6002,19 +5936,10 @@ checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62"
dependencies = [
"bitcoin_hashes",
"rand 0.8.5",
- "secp256k1-sys 0.6.1",
+ "secp256k1-sys",
"serde 1.0.163",
]
-[[package]]
-name = "secp256k1-sys"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "957da2573cde917463ece3570eab4a0b3f19de6f1646cde62e6fd3868f566036"
-dependencies = [
- "cc",
-]
-
[[package]]
name = "secp256k1-sys"
version = "0.6.1"
@@ -6143,7 +6068,7 @@ checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.15",
+ "syn 2.0.16",
]
[[package]]
@@ -6165,7 +6090,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.15",
+ "syn 2.0.16",
]
[[package]]
@@ -6228,6 +6153,18 @@ dependencies = [
"digest 0.10.6",
]
+[[package]]
+name = "sha2"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69"
+dependencies = [
+ "block-buffer 0.7.3",
+ "digest 0.8.1",
+ "fake-simd",
+ "opaque-debug 0.2.3",
+]
+
[[package]]
name = "sha2"
version = "0.9.9"
@@ -6342,6 +6279,15 @@ dependencies = [
"autocfg 1.1.0",
]
+[[package]]
+name = "slip10_ed25519"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4be0ff28bf14f9610a342169084e87a4f435ad798ec528dc7579a3678fa9dc9a"
+dependencies = [
+ "hmac-sha512",
+]
+
[[package]]
name = "smallvec"
version = "0.6.14"
@@ -6373,7 +6319,7 @@ version = "0.3.1-pre"
source = "git+https://github.com/heliaxdev/sparse-merkle-tree?rev=e086b235ed6e68929bf73f617dd61cd17b000a56#e086b235ed6e68929bf73f617dd61cd17b000a56"
dependencies = [
"blake2b-rs",
- "borsh 0.9.4",
+ "borsh",
"cfg-if 1.0.0",
"ics23",
"sha2 0.9.9",
@@ -6438,6 +6384,12 @@ dependencies = [
"ark-std",
]
+[[package]]
+name = "subtle"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
+
[[package]]
name = "subtle"
version = "2.4.1"
@@ -6472,9 +6424,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.15"
+version = "2.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
+checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01"
dependencies = [
"proc-macro2",
"quote",
@@ -6543,34 +6495,6 @@ dependencies = [
"windows-sys 0.45.0",
]
-[[package]]
-name = "tendermint"
-version = "0.23.5"
-source = "git+https://github.com/heliaxdev/tendermint-rs?rev=a3a0ad5f07d380976bbd5321239aec9cc3a8f916#a3a0ad5f07d380976bbd5321239aec9cc3a8f916"
-dependencies = [
- "async-trait",
- "bytes 1.4.0",
- "ed25519",
- "ed25519-dalek",
- "flex-error",
- "futures 0.3.28",
- "num-traits 0.2.15",
- "once_cell",
- "prost",
- "prost-types",
- "serde 1.0.163",
- "serde_bytes",
- "serde_json",
- "serde_repr",
- "sha2 0.9.9",
- "signature",
- "subtle",
- "subtle-encoding",
- "tendermint-proto 0.23.5",
- "time 0.3.17",
- "zeroize",
-]
-
[[package]]
name = "tendermint"
version = "0.23.6"
@@ -6594,26 +6518,13 @@ dependencies = [
"serde_repr",
"sha2 0.9.9",
"signature",
- "subtle",
+ "subtle 2.4.1",
"subtle-encoding",
- "tendermint-proto 0.23.6",
+ "tendermint-proto",
"time 0.3.17",
"zeroize",
]
-[[package]]
-name = "tendermint-config"
-version = "0.23.5"
-source = "git+https://github.com/heliaxdev/tendermint-rs?rev=a3a0ad5f07d380976bbd5321239aec9cc3a8f916#a3a0ad5f07d380976bbd5321239aec9cc3a8f916"
-dependencies = [
- "flex-error",
- "serde 1.0.163",
- "serde_json",
- "tendermint 0.23.5",
- "toml",
- "url 2.3.1",
-]
-
[[package]]
name = "tendermint-config"
version = "0.23.6"
@@ -6622,7 +6533,7 @@ dependencies = [
"flex-error",
"serde 1.0.163",
"serde_json",
- "tendermint 0.23.6",
+ "tendermint",
"toml",
"url 2.3.1",
]
@@ -6641,26 +6552,13 @@ dependencies = [
"serde_cbor",
"serde_derive",
"static_assertions",
- "tendermint 0.23.6",
- "tendermint-light-client-verifier 0.23.6",
- "tendermint-rpc 0.23.6",
+ "tendermint",
+ "tendermint-light-client-verifier",
+ "tendermint-rpc",
"time 0.3.17",
"tokio",
]
-[[package]]
-name = "tendermint-light-client-verifier"
-version = "0.23.5"
-source = "git+https://github.com/heliaxdev/tendermint-rs?rev=a3a0ad5f07d380976bbd5321239aec9cc3a8f916#a3a0ad5f07d380976bbd5321239aec9cc3a8f916"
-dependencies = [
- "derive_more",
- "flex-error",
- "serde 1.0.163",
- "tendermint 0.23.5",
- "tendermint-rpc 0.23.5",
- "time 0.3.17",
-]
-
[[package]]
name = "tendermint-light-client-verifier"
version = "0.23.6"
@@ -6669,24 +6567,7 @@ dependencies = [
"derive_more",
"flex-error",
"serde 1.0.163",
- "tendermint 0.23.6",
- "time 0.3.17",
-]
-
-[[package]]
-name = "tendermint-proto"
-version = "0.23.5"
-source = "git+https://github.com/heliaxdev/tendermint-rs?rev=a3a0ad5f07d380976bbd5321239aec9cc3a8f916#a3a0ad5f07d380976bbd5321239aec9cc3a8f916"
-dependencies = [
- "bytes 1.4.0",
- "flex-error",
- "num-derive",
- "num-traits 0.2.15",
- "prost",
- "prost-types",
- "serde 1.0.163",
- "serde_bytes",
- "subtle-encoding",
+ "tendermint",
"time 0.3.17",
]
@@ -6707,30 +6588,6 @@ dependencies = [
"time 0.3.17",
]
-[[package]]
-name = "tendermint-rpc"
-version = "0.23.5"
-source = "git+https://github.com/heliaxdev/tendermint-rs?rev=a3a0ad5f07d380976bbd5321239aec9cc3a8f916#a3a0ad5f07d380976bbd5321239aec9cc3a8f916"
-dependencies = [
- "bytes 1.4.0",
- "flex-error",
- "getrandom 0.2.9",
- "peg",
- "pin-project",
- "serde 1.0.163",
- "serde_bytes",
- "serde_json",
- "subtle-encoding",
- "tendermint 0.23.5",
- "tendermint-config 0.23.5",
- "tendermint-proto 0.23.5",
- "thiserror",
- "time 0.3.17",
- "url 2.3.1",
- "uuid 0.8.2",
- "walkdir",
-]
-
[[package]]
name = "tendermint-rpc"
version = "0.23.6"
@@ -6752,9 +6609,9 @@ dependencies = [
"serde_bytes",
"serde_json",
"subtle-encoding",
- "tendermint 0.23.6",
- "tendermint-config 0.23.6",
- "tendermint-proto 0.23.6",
+ "tendermint",
+ "tendermint-config",
+ "tendermint-proto",
"thiserror",
"time 0.3.17",
"tokio",
@@ -6764,21 +6621,6 @@ dependencies = [
"walkdir",
]
-[[package]]
-name = "tendermint-testgen"
-version = "0.23.5"
-source = "git+https://github.com/heliaxdev/tendermint-rs?rev=a3a0ad5f07d380976bbd5321239aec9cc3a8f916#a3a0ad5f07d380976bbd5321239aec9cc3a8f916"
-dependencies = [
- "ed25519-dalek",
- "gumdrop",
- "serde 1.0.163",
- "serde_json",
- "simple-error",
- "tempfile",
- "tendermint 0.23.5",
- "time 0.3.17",
-]
-
[[package]]
name = "tendermint-testgen"
version = "0.23.6"
@@ -6790,7 +6632,7 @@ dependencies = [
"serde_json",
"simple-error",
"tempfile",
- "tendermint 0.23.6",
+ "tendermint",
"time 0.3.17",
]
@@ -6846,7 +6688,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.15",
+ "syn 2.0.16",
]
[[package]]
@@ -6905,6 +6747,24 @@ dependencies = [
"time-core",
]
+[[package]]
+name = "tiny-bip39"
+version = "0.8.2"
+source = "git+https://github.com/anoma/tiny-bip39.git?rev=bf0f6d8713589b83af7a917366ec31f5275c0e57#bf0f6d8713589b83af7a917366ec31f5275c0e57"
+dependencies = [
+ "anyhow",
+ "hmac 0.8.1",
+ "once_cell",
+ "pbkdf2 0.4.0",
+ "rand 0.7.3",
+ "rustc-hash",
+ "sha2 0.9.9",
+ "thiserror",
+ "unicode-normalization",
+ "wasm-bindgen",
+ "zeroize",
+]
+
[[package]]
name = "tiny-bip39"
version = "1.0.0"
@@ -6924,13 +6784,26 @@ dependencies = [
"zeroize",
]
+[[package]]
+name = "tiny-hderive"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01b874a4992538d4b2f4fbbac11b9419d685f4b39bdc3fed95b04e07bfd76040"
+dependencies = [
+ "base58 0.1.0",
+ "hmac 0.7.1",
+ "libsecp256k1 0.3.5",
+ "memzero",
+ "sha2 0.8.2",
+]
+
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
- "crunchy 0.2.2",
+ "crunchy",
]
[[package]]
@@ -7029,7 +6902,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.15",
+ "syn 2.0.16",
]
[[package]]
@@ -7181,15 +7054,15 @@ dependencies = [
[[package]]
name = "toml_datetime"
-version = "0.6.1"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
+checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f"
[[package]]
name = "toml_edit"
-version = "0.19.8"
+version = "0.19.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13"
+checksum = "92d964908cec0d030b812013af25a0e57fddfadb1e066ecc6681d86253129d4f"
dependencies = [
"indexmap",
"toml_datetime",
@@ -7274,25 +7147,7 @@ dependencies = [
"futures 0.3.28",
"pin-project",
"prost",
- "tendermint-proto 0.23.6",
- "tokio",
- "tokio-stream",
- "tokio-util 0.6.10",
- "tower",
- "tracing 0.1.30",
- "tracing-tower",
-]
-
-[[package]]
-name = "tower-abci"
-version = "0.1.0"
-source = "git+https://github.com/heliaxdev/tower-abci?rev=a31ce06533f5fbd943508676059d44de27395792#a31ce06533f5fbd943508676059d44de27395792"
-dependencies = [
- "bytes 1.4.0",
- "futures 0.3.28",
- "pin-project",
- "prost",
- "tendermint-proto 0.23.5",
+ "tendermint-proto",
"tokio",
"tokio-stream",
"tokio-util 0.6.10",
@@ -7364,7 +7219,7 @@ checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.15",
+ "syn 2.0.16",
]
[[package]]
@@ -7543,7 +7398,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52"
dependencies = [
"byteorder",
- "crunchy 0.2.2",
+ "crunchy",
"hex",
"static_assertions",
]
@@ -7607,12 +7462,12 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "universal-hash"
-version = "0.4.1"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05"
+checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5"
dependencies = [
- "generic-array 0.14.7",
- "subtle",
+ "crypto-common",
+ "subtle 2.4.1",
]
[[package]]
@@ -7663,9 +7518,9 @@ checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
[[package]]
name = "uuid"
-version = "1.3.2"
+version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dad5567ad0cf5b760e5665964bec1b47dfd077ba8a2544b513f3556d3d239a2"
+checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2"
dependencies = [
"getrandom 0.2.9",
]
@@ -7815,9 +7670,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
-version = "0.2.85"
+version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b6cb788c4e39112fbe1822277ef6fb3c55cd86b95cb3d3c4c1c9597e4ac74b4"
+checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73"
dependencies = [
"cfg-if 1.0.0",
"wasm-bindgen-macro",
@@ -7825,24 +7680,24 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.85"
+version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35e522ed4105a9d626d885b35d62501b30d9666283a5c8be12c14a8bdafe7822"
+checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb"
dependencies = [
"bumpalo",
"log 0.4.17",
"once_cell",
"proc-macro2",
"quote",
- "syn 2.0.15",
+ "syn 2.0.16",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.35"
+version = "0.4.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "083abe15c5d88556b77bdf7aef403625be9e327ad37c62c4e4129af740168163"
+checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
@@ -7852,9 +7707,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.85"
+version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "358a79a0cb89d21db8120cbfb91392335913e4890665b1a7981d9e956903b434"
+checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -7862,28 +7717,28 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.85"
+version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869"
+checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.15",
+ "syn 2.0.16",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.85"
+version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a901d592cafaa4d711bc324edfaff879ac700b19c3dfd60058d2b445be2691eb"
+checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93"
[[package]]
name = "wasm-encoder"
-version = "0.26.0"
+version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d05d0b6fcd0aeb98adf16e7975331b3c17222aa815148f5b976370ce589d80ef"
+checksum = "e77053dc709db790691d3732cfc458adc5acc881dec524965c608effdcd9c581"
dependencies = [
"leb128",
]
@@ -8126,9 +7981,9 @@ checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a"
[[package]]
name = "wast"
-version = "57.0.0"
+version = "58.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6eb0f5ed17ac4421193c7477da05892c2edafd67f9639e3c11a82086416662dc"
+checksum = "372eecae2d10a5091c2005b32377d7ecd6feecdf2c05838056d02d8b4f07c429"
dependencies = [
"leb128",
"memchr",
@@ -8138,18 +7993,18 @@ dependencies = [
[[package]]
name = "wat"
-version = "1.0.63"
+version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab9ab0d87337c3be2bb6fc5cd331c4ba9fd6bcb4ee85048a0dd59ed9ecf92e53"
+checksum = "6d47446190e112ab1579ab40b3ad7e319d859d74e5134683f04e9f0747bf4173"
dependencies = [
"wast",
]
[[package]]
name = "web-sys"
-version = "0.3.62"
+version = "0.3.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16b5f940c7edfdc6d12126d98c9ef4d1b3d470011c47c76a6581df47ad9ba721"
+checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -8563,83 +8418,10 @@ dependencies = [
[[package]]
name = "zcash_encoding"
version = "0.0.0"
-source = "git+https://github.com/zcash/librustzcash/?rev=2425a08#2425a0869098e3b0588ccd73c42716bcf418612c"
-dependencies = [
- "byteorder",
- "nonempty",
-]
-
-[[package]]
-name = "zcash_note_encryption"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33f84ae538f05a8ac74c82527f06b77045ed9553a0871d9db036166a4c344e3a"
-dependencies = [
- "chacha20",
- "chacha20poly1305",
- "rand_core 0.6.4",
- "subtle",
-]
-
-[[package]]
-name = "zcash_note_encryption"
-version = "0.1.0"
-source = "git+https://github.com/zcash/librustzcash/?rev=2425a08#2425a0869098e3b0588ccd73c42716bcf418612c"
+source = "git+https://github.com/zcash/librustzcash?rev=43c18d0#43c18d000fcbe45363b2d53585d5102841eff99e"
dependencies = [
- "chacha20",
- "chacha20poly1305",
- "rand_core 0.6.4",
- "subtle",
-]
-
-[[package]]
-name = "zcash_primitives"
-version = "0.5.0"
-source = "git+https://github.com/zcash/librustzcash/?rev=2425a08#2425a0869098e3b0588ccd73c42716bcf418612c"
-dependencies = [
- "aes",
- "bip0039",
- "bitvec 0.22.3",
- "blake2b_simd 1.0.1",
- "blake2s_simd 1.0.1",
- "bls12_381",
"byteorder",
- "chacha20poly1305",
- "equihash",
- "ff",
- "fpe",
- "group",
- "hex",
- "incrementalmerkletree",
- "jubjub",
- "lazy_static",
- "memuse",
"nonempty",
- "orchard",
- "rand 0.8.5",
- "rand_core 0.6.4",
- "sha2 0.9.9",
- "subtle",
- "zcash_encoding",
- "zcash_note_encryption 0.1.0 (git+https://github.com/zcash/librustzcash/?rev=2425a08)",
-]
-
-[[package]]
-name = "zcash_proofs"
-version = "0.5.0"
-source = "git+https://github.com/zcash/librustzcash/?rev=2425a08#2425a0869098e3b0588ccd73c42716bcf418612c"
-dependencies = [
- "bellman",
- "blake2b_simd 1.0.1",
- "bls12_381",
- "byteorder",
- "directories",
- "ff",
- "group",
- "jubjub",
- "lazy_static",
- "rand_core 0.6.4",
- "zcash_primitives",
]
[[package]]
@@ -8659,7 +8441,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.15",
+ "syn 2.0.16",
]
[[package]]
diff --git a/Makefile b/Makefile
index a05dffd398..2f8b1b7465 100644
--- a/Makefile
+++ b/Makefile
@@ -41,15 +41,6 @@ check:
make -C $(wasms_for_tests) check && \
$(foreach wasm,$(wasm_templates),$(check-wasm) && ) true
-check-abcipp:
- $(cargo) +$(nightly) check \
- --workspace \
- --exclude namada_tests \
- --all-targets \
- --no-default-features \
- --features "abcipp ibc-mocks-abcipp testing" \
- -Z unstable-options
-
check-mainnet:
$(cargo) check --workspace --features "mainnet"
@@ -61,25 +52,6 @@ clippy:
make -C $(wasms_for_tests) clippy && \
$(foreach wasm,$(wasm_templates),$(clippy-wasm) && ) true
-clippy-abcipp:
- NAMADA_DEV=false $(cargo) +$(nightly) clippy --all-targets \
- --manifest-path ./apps/Cargo.toml \
- --no-default-features \
- --features "std testing abcipp" && \
- $(cargo) +$(nightly) clippy --all-targets \
- --manifest-path ./proof_of_stake/Cargo.toml \
- --features "testing" && \
- $(cargo) +$(nightly) clippy --all-targets \
- --manifest-path ./shared/Cargo.toml \
- --no-default-features \
- --features "testing wasm-runtime abcipp ibc-mocks-abcipp ferveo-tpke" && \
- $(cargo) +$(nightly) clippy \
- --all-targets \
- --manifest-path ./vm_env/Cargo.toml \
- --no-default-features && \
- make -C $(wasms) clippy && \
- $(foreach wasm,$(wasm_templates),$(clippy-wasm) && ) true
-
clippy-mainnet:
$(cargo) +$(nightly) clippy --all-targets --features "mainnet" -- -D warnings
@@ -137,36 +109,6 @@ else
-Z unstable-options --report-time
endif
-test-unit-abcipp:
- $(cargo) test \
- --manifest-path ./apps/Cargo.toml \
- --no-default-features \
- --features "testing std abcipp" \
- -Z unstable-options \
- $(TEST_FILTER) -- \
- -Z unstable-options --report-time && \
- $(cargo) test \
- --manifest-path \
- ./proof_of_stake/Cargo.toml \
- --features "testing" \
- -Z unstable-options \
- $(TEST_FILTER) -- \
- -Z unstable-options --report-time && \
- $(cargo) test \
- --manifest-path ./shared/Cargo.toml \
- --no-default-features \
- --features "testing wasm-runtime abcipp ibc-mocks-abcipp" \
- -Z unstable-options \
- $(TEST_FILTER) -- \
- -Z unstable-options --report-time && \
- $(cargo) test \
- --manifest-path ./vm_env/Cargo.toml \
- --no-default-features \
- --features "abcipp" \
- -Z unstable-options \
- $(TEST_FILTER) -- \
- -Z unstable-options --report-time
-
test-unit:
$(cargo) +$(nightly) test \
$(TEST_FILTER) \
@@ -278,4 +220,4 @@ test-miri:
MIRIFLAGS="-Zmiri-disable-isolation" $(cargo) +$(nightly) miri test
-.PHONY : build check build-release clippy install run-ledger run-gossip reset-ledger test test-debug fmt watch clean build-doc doc build-wasm-scripts-docker debug-wasm-scripts-docker build-wasm-scripts debug-wasm-scripts clean-wasm-scripts dev-deps test-miri test-unit test-unit-abcipp clippy-abcipp
+.PHONY : build check build-release clippy install run-ledger run-gossip reset-ledger test test-debug fmt watch clean build-doc doc build-wasm-scripts-docker debug-wasm-scripts-docker build-wasm-scripts debug-wasm-scripts clean-wasm-scripts dev-deps test-miri test-unit
diff --git a/apps/Cargo.toml b/apps/Cargo.toml
index d79451a358..710d02daf3 100644
--- a/apps/Cargo.toml
+++ b/apps/Cargo.toml
@@ -45,20 +45,10 @@ mainnet = [
"namada/mainnet",
]
dev = ["namada/dev"]
-std = ["ed25519-consensus/std", "rand/std", "rand_core/std"]
+std = ["ed25519-consensus/std", "rand/std", "rand_core/std", "namada/std"]
# for integration tests and test utilies
testing = ["dev"]
-abcipp = [
- "namada/abcipp",
- "namada/tendermint-rpc-abcipp",
- "tendermint-abcipp",
- "tendermint-config-abcipp",
- "tendermint-proto-abcipp",
- "tendermint-rpc-abcipp",
- "tower-abci-abcipp",
-]
-
abciplus = [
"namada/abciplus",
"namada/tendermint-rpc",
@@ -70,7 +60,7 @@ abciplus = [
]
[dependencies]
-namada = {path = "../shared", default-features = false, features = ["wasm-runtime", "ferveo-tpke", "masp-tx-gen"]}
+namada = {path = "../shared", default-features = false, features = ["wasm-runtime", "ferveo-tpke", "masp-tx-gen", "multicore"]}
ark-serialize = "0.3.0"
ark-std = "0.3.0"
# branch = "bat/arse-merkle-tree"
@@ -90,6 +80,7 @@ color-eyre = "0.5.10"
config = "0.11.0"
data-encoding = "2.3.2"
derivative = "2.2.0"
+directories = "4.0.1"
ed25519-consensus = "1.2.0"
ferveo = {git = "https://github.com/anoma/ferveo", rev = "e5abd0acc938da90140351a65a26472eb495ce4d"}
ferveo-common = {git = "https://github.com/anoma/ferveo", rev = "e5abd0acc938da90140351a65a26472eb495ce4d"}
@@ -113,6 +104,7 @@ rand_core = {version = "0.6", default-features = false}
rayon = "=1.5.3"
regex = "1.4.5"
reqwest = "0.11.4"
+ripemd = "0.1"
rlimit = "0.5.4"
rocksdb = {version = "0.21.0", features = ['zstd', 'jemalloc'], default-features = false}
rpassword = "5.0.1"
@@ -125,10 +117,6 @@ signal-hook = "0.3.9"
sysinfo = {version = "=0.21.1", default-features = false}
tar = "0.4.37"
# temporarily using fork work-around
-tendermint-abcipp = {package = "tendermint", git = "https://github.com/heliaxdev/tendermint-rs", rev = "02b256829e80f8cfecf3fa0d625c2a76c79cd043", optional = true}
-tendermint-config-abcipp = {package = "tendermint-config", git = "https://github.com/heliaxdev/tendermint-rs", rev = "02b256829e80f8cfecf3fa0d625c2a76c79cd043", optional = true}
-tendermint-proto-abcipp = {package = "tendermint-proto", git = "https://github.com/heliaxdev/tendermint-rs", rev = "02b256829e80f8cfecf3fa0d625c2a76c79cd043", optional = true}
-tendermint-rpc-abcipp = {package = "tendermint-rpc", git = "https://github.com/heliaxdev/tendermint-rs", rev = "02b256829e80f8cfecf3fa0d625c2a76c79cd043", features = ["http-client", "websocket-client"], optional = true}
tendermint = {version = "0.23.6", optional = true}
tendermint-config = {version = "0.23.6", optional = true}
tendermint-proto = {version = "0.23.6", optional = true}
@@ -140,20 +128,19 @@ tonic = "0.8.3"
tower = "0.4"
# Also, using the same version of tendermint-rs as we do here.
# with a patch for https://github.com/penumbra-zone/tower-abci/issues/7.
-tower-abci-abcipp = {package = "tower-abci", git = "https://github.com/heliaxdev/tower-abci", rev = "a31ce06533f5fbd943508676059d44de27395792", optional = true}
tower-abci = {version = "0.1.0", optional = true}
tracing = "0.1.30"
tracing-log = "0.1.2"
tracing-subscriber = {version = "0.3.7", features = ["env-filter", "json"]}
websocket = "0.26.2"
winapi = "0.3.9"
-#libmasp = { git = "https://github.com/anoma/masp", branch = "murisi/masp-incentive" }
-masp_primitives = { git = "https://github.com/anoma/masp", rev = "bee40fc465f6afbd10558d12fe96eb1742eee45c", features = ["transparent-inputs"] }
-masp_proofs = { git = "https://github.com/anoma/masp", rev = "bee40fc465f6afbd10558d12fe96eb1742eee45c", features = ["bundled-prover", "download-params"] }
+# branch = "murisi/namada-integration"
+masp_primitives = { git = "https://github.com/anoma/masp", rev = "cfea8c95d3f73077ca3e25380fd27e5b46e828fd", features = ["transparent-inputs"] }
+masp_proofs = { git = "https://github.com/anoma/masp", rev = "cfea8c95d3f73077ca3e25380fd27e5b46e828fd", features = ["bundled-prover", "download-params"] }
bimap = {version = "0.6.2", features = ["serde"]}
rust_decimal = "=1.26.1"
rust_decimal_macros = "=1.26.1"
-directories = "4.0.1"
+zeroize = "1.5.5"
[dev-dependencies]
namada = {path = "../shared", default-features = false, features = ["testing", "wasm-runtime"]}
diff --git a/apps/src/bin/namada-client/cli.rs b/apps/src/bin/namada-client/cli.rs
index 10316cb6bf..25d61de3ad 100644
--- a/apps/src/bin/namada-client/cli.rs
+++ b/apps/src/bin/namada-client/cli.rs
@@ -253,6 +253,13 @@ pub async fn main() -> Result<()> {
rpc::query_delegations(&client, &mut ctx.wallet, args)
.await;
}
+ Sub::QueryFindValidator(QueryFindValidator(args)) => {
+ let client =
+ HttpClient::new(args.query.ledger_address.clone())
+ .unwrap();
+ let args = args.to_sdk(&mut ctx);
+ rpc::query_find_validator(&client, args).await;
+ }
Sub::QueryResult(QueryResult(args)) => {
wait_until_node_is_synched(&args.query.ledger_address)
.await;
@@ -341,7 +348,7 @@ async fn wait_until_node_is_synched(ledger_address: &TendermintAddress) {
if is_at_least_height_one && !is_catching_up {
return;
} else {
- if try_count > MAX_TRIES {
+ if try_count == MAX_TRIES {
println!(
"Node is still catching up, wait for it to finish \
synching."
diff --git a/apps/src/bin/namada-wallet/cli.rs b/apps/src/bin/namada-wallet/cli.rs
index 2ec7a3a31c..fb7599ace3 100644
--- a/apps/src/bin/namada-wallet/cli.rs
+++ b/apps/src/bin/namada-wallet/cli.rs
@@ -8,14 +8,14 @@ use color_eyre::eyre::Result;
use itertools::sorted;
use masp_primitives::zip32::ExtendedFullViewingKey;
use namada::ledger::masp::find_valid_diversifier;
-use namada::ledger::wallet::FindKeyError;
+use namada::ledger::wallet::{DecryptionError, FindKeyError};
use namada::types::key::*;
use namada::types::masp::{MaspValue, PaymentAddress};
use namada_apps::cli;
use namada_apps::cli::args::CliToSdk;
use namada_apps::cli::{args, cmds, Context};
use namada_apps::wallet::{
- read_and_confirm_pwd, CliWalletUtils, DecryptionError,
+ read_and_confirm_encryption_password, CliWalletUtils,
};
use rand_core::OsRng;
@@ -23,6 +23,9 @@ pub fn main() -> Result<()> {
let (cmd, mut ctx) = cli::namada_wallet_cli()?;
match cmd {
cmds::NamadaWallet::Key(sub) => match sub {
+ cmds::WalletKey::Restore(cmds::KeyRestore(args)) => {
+ key_and_address_restore(ctx, args)
+ }
cmds::WalletKey::Gen(cmds::KeyGen(args)) => {
key_and_address_gen(ctx, args)
}
@@ -36,6 +39,9 @@ pub fn main() -> Result<()> {
cmds::WalletAddress::Gen(cmds::AddressGen(args)) => {
key_and_address_gen(ctx, args)
}
+ cmds::WalletAddress::Restore(cmds::AddressRestore(args)) => {
+ key_and_address_restore(ctx, args)
+ }
cmds::WalletAddress::Find(cmds::AddressOrAliasFind(args)) => {
address_or_alias_find(ctx, args)
}
@@ -205,7 +211,7 @@ fn spending_key_gen(
) {
let mut wallet = ctx.wallet;
let alias = alias.to_lowercase();
- let password = read_and_confirm_pwd(unsafe_dont_encrypt);
+ let password = read_and_confirm_encryption_password(unsafe_dont_encrypt);
let (alias, _key) = wallet.gen_spending_key(alias, password, alias_force);
namada_apps::wallet::save(&wallet)
.unwrap_or_else(|err| eprintln!("{}", err));
@@ -273,7 +279,8 @@ fn address_key_add(
(alias, "viewing key")
}
MaspValue::ExtendedSpendingKey(spending_key) => {
- let password = read_and_confirm_pwd(unsafe_dont_encrypt);
+ let password =
+ read_and_confirm_encryption_password(unsafe_dont_encrypt);
let alias = ctx
.wallet
.encrypt_insert_spending_key(
@@ -307,6 +314,41 @@ fn address_key_add(
);
}
+/// Restore a keypair and an implicit address from the mnemonic code in the
+/// wallet.
+fn key_and_address_restore(
+ ctx: Context,
+ args::KeyAndAddressRestore {
+ scheme,
+ alias,
+ alias_force,
+ unsafe_dont_encrypt,
+ derivation_path,
+ }: args::KeyAndAddressRestore,
+) {
+ let mut wallet = ctx.wallet;
+ let encryption_password =
+ read_and_confirm_encryption_password(unsafe_dont_encrypt);
+ let (alias, _key) = wallet
+ .derive_key_from_user_mnemonic_code(
+ scheme,
+ alias,
+ alias_force,
+ derivation_path,
+ encryption_password,
+ )
+ .unwrap_or_else(|err| {
+ eprintln!("{}", err);
+ cli::safe_exit(1)
+ });
+ namada_apps::wallet::save(&wallet)
+ .unwrap_or_else(|err| eprintln!("{}", err));
+ println!(
+ "Successfully added a key and an address with alias: \"{}\"",
+ alias
+ );
+}
+
/// Generate a new keypair and derive implicit address from it and store them in
/// the wallet.
fn key_and_address_gen(
@@ -316,11 +358,27 @@ fn key_and_address_gen(
alias,
alias_force,
unsafe_dont_encrypt,
+ derivation_path,
}: args::KeyAndAddressGen,
) {
let mut wallet = ctx.wallet;
- let password = read_and_confirm_pwd(unsafe_dont_encrypt);
- let (alias, _key) = wallet.gen_key(scheme, alias, password, alias_force);
+ let encryption_password =
+ read_and_confirm_encryption_password(unsafe_dont_encrypt);
+ let mut rng = OsRng;
+ let derivation_path_and_mnemonic_rng =
+ derivation_path.map(|p| (p, &mut rng));
+ let (alias, _key) = wallet
+ .gen_key(
+ scheme,
+ alias,
+ alias_force,
+ encryption_password,
+ derivation_path_and_mnemonic_rng,
+ )
+ .unwrap_or_else(|err| {
+ eprintln!("{}", err);
+ cli::safe_exit(1);
+ });
namada_apps::wallet::save(&wallet)
.unwrap_or_else(|err| eprintln!("{}", err));
println!(
diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs
index daecbf5eee..5e7c464b0f 100644
--- a/apps/src/lib/cli.rs
+++ b/apps/src/lib/cli.rs
@@ -175,6 +175,7 @@ pub mod cmds {
.subcommand(QueryBondedStake::def().display_order(3))
.subcommand(QuerySlashes::def().display_order(3))
.subcommand(QueryDelegations::def().display_order(3))
+ .subcommand(QueryFindValidator::def().display_order(3))
.subcommand(QueryResult::def().display_order(3))
.subcommand(QueryRawBytes::def().display_order(3))
.subcommand(QueryProposal::def().display_order(3))
@@ -213,6 +214,8 @@ pub mod cmds {
let query_slashes = Self::parse_with_ctx(matches, QuerySlashes);
let query_delegations =
Self::parse_with_ctx(matches, QueryDelegations);
+ let query_find_validator =
+ Self::parse_with_ctx(matches, QueryFindValidator);
let query_result = Self::parse_with_ctx(matches, QueryResult);
let query_raw_bytes = Self::parse_with_ctx(matches, QueryRawBytes);
let query_proposal = Self::parse_with_ctx(matches, QueryProposal);
@@ -242,6 +245,7 @@ pub mod cmds {
.or(query_bonded_stake)
.or(query_slashes)
.or(query_delegations)
+ .or(query_find_validator)
.or(query_result)
.or(query_raw_bytes)
.or(query_proposal)
@@ -306,6 +310,7 @@ pub mod cmds {
QueryCommissionRate(QueryCommissionRate),
QuerySlashes(QuerySlashes),
QueryDelegations(QueryDelegations),
+ QueryFindValidator(QueryFindValidator),
QueryRawBytes(QueryRawBytes),
QueryProposal(QueryProposal),
QueryProposalResult(QueryProposalResult),
@@ -359,6 +364,7 @@ pub mod cmds {
#[derive(Clone, Debug)]
#[allow(clippy::large_enum_variant)]
pub enum WalletKey {
+ Restore(KeyRestore),
Gen(KeyGen),
Find(KeyFind),
List(KeyList),
@@ -371,10 +377,11 @@ pub mod cmds {
fn parse(matches: &ArgMatches) -> Option {
matches.subcommand_matches(Self::CMD).and_then(|matches| {
let generate = SubCmd::parse(matches).map(Self::Gen);
+ let restore = SubCmd::parse(matches).map(Self::Restore);
let lookup = SubCmd::parse(matches).map(Self::Find);
let list = SubCmd::parse(matches).map(Self::List);
let export = SubCmd::parse(matches).map(Self::Export);
- generate.or(lookup).or(list).or(export)
+ generate.or(restore).or(lookup).or(list).or(export)
})
}
@@ -385,6 +392,7 @@ pub mod cmds {
look-up keys.",
)
.setting(AppSettings::SubcommandRequiredElseHelp)
+ .subcommand(KeyRestore::def())
.subcommand(KeyGen::def())
.subcommand(KeyFind::def())
.subcommand(KeyList::def())
@@ -392,6 +400,31 @@ pub mod cmds {
}
}
+ /// Restore a keypair and implicit address from the mnemonic code
+ #[derive(Clone, Debug)]
+ pub struct KeyRestore(pub args::KeyAndAddressRestore);
+
+ impl SubCmd for KeyRestore {
+ const CMD: &'static str = "restore";
+
+ fn parse(matches: &ArgMatches) -> Option {
+ matches
+ .subcommand_matches(Self::CMD)
+ .map(|matches| Self(args::KeyAndAddressRestore::parse(matches)))
+ }
+
+ fn def() -> App {
+ App::new(Self::CMD)
+ .about(
+ "Restores a keypair from the given mnemonic code and HD \
+ derivation path and derives the implicit address from \
+ its public key. Stores the keypair and the address with \
+ the given alias.",
+ )
+ .add_args::()
+ }
+ }
+
/// Generate a new keypair and an implicit address derived from it
#[derive(Clone, Debug)]
pub struct KeyGen(pub args::KeyAndAddressGen);
@@ -408,7 +441,7 @@ pub mod cmds {
fn def() -> App {
App::new(Self::CMD)
.about(
- "Generates a keypair with a given alias and derive the \
+ "Generates a keypair with a given alias and derives the \
implicit address from its public key. The address will \
be stored with the same alias.",
)
@@ -640,6 +673,7 @@ pub mod cmds {
#[derive(Clone, Debug)]
pub enum WalletAddress {
Gen(AddressGen),
+ Restore(AddressRestore),
Find(AddressOrAliasFind),
List(AddressList),
Add(AddressAdd),
@@ -651,10 +685,11 @@ pub mod cmds {
fn parse(matches: &ArgMatches) -> Option {
matches.subcommand_matches(Self::CMD).and_then(|matches| {
let gen = SubCmd::parse(matches).map(Self::Gen);
+ let restore = SubCmd::parse(matches).map(Self::Restore);
let find = SubCmd::parse(matches).map(Self::Find);
let list = SubCmd::parse(matches).map(Self::List);
let add = SubCmd::parse(matches).map(Self::Add);
- gen.or(find).or(list).or(add)
+ gen.or(restore).or(find).or(list).or(add)
})
}
@@ -666,6 +701,7 @@ pub mod cmds {
)
.setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(AddressGen::def())
+ .subcommand(AddressRestore::def())
.subcommand(AddressOrAliasFind::def())
.subcommand(AddressList::def())
.subcommand(AddressAdd::def())
@@ -688,7 +724,7 @@ pub mod cmds {
fn def() -> App {
App::new(Self::CMD)
.about(
- "Generates a keypair with a given alias and derive the \
+ "Generates a keypair with a given alias and derives the \
implicit address from its public key. The address will \
be stored with the same alias.",
)
@@ -696,6 +732,30 @@ pub mod cmds {
}
}
+ /// Restore a keypair and an implicit address from the mnemonic code
+ #[derive(Clone, Debug)]
+ pub struct AddressRestore(pub args::KeyAndAddressRestore);
+
+ impl SubCmd for AddressRestore {
+ const CMD: &'static str = "restore";
+
+ fn parse(matches: &ArgMatches) -> Option {
+ matches.subcommand_matches(Self::CMD).map(|matches| {
+ AddressRestore(args::KeyAndAddressRestore::parse(matches))
+ })
+ }
+
+ fn def() -> App {
+ App::new(Self::CMD)
+ .about(
+ "Restores a keypair from the given mnemonic code and \
+ derives the implicit address from its public key. Stores \
+ the keypair and the address with the given alias.",
+ )
+ .add_args::()
+ }
+ }
+
/// Find an address by its alias
#[derive(Clone, Debug)]
pub struct AddressOrAliasFind(pub args::AddressOrAliasFind);
@@ -1406,6 +1466,28 @@ pub mod cmds {
}
}
+ #[derive(Clone, Debug)]
+ pub struct QueryFindValidator(pub args::QueryFindValidator);
+
+ impl SubCmd for QueryFindValidator {
+ const CMD: &'static str = "find-validator";
+
+ fn parse(matches: &ArgMatches) -> Option
+ where
+ Self: Sized,
+ {
+ matches.subcommand_matches(Self::CMD).map(|matches| {
+ QueryFindValidator(args::QueryFindValidator::parse(matches))
+ })
+ }
+
+ fn def() -> App {
+ App::new(Self::CMD)
+ .about("Find a PoS validator by its Tendermint address.")
+ .add_args::>()
+ }
+ }
+
#[derive(Clone, Debug)]
pub struct QueryRawBytes(pub args::QueryRawBytes);
@@ -1684,6 +1766,7 @@ pub mod args {
pub const TX_WITHDRAW_WASM: &str = "tx_withdraw.wasm";
pub const TX_CHANGE_COMMISSION_WASM: &str =
"tx_change_validator_commission.wasm";
+ pub const TX_UNJAIL_VALIDATOR_WASM: &str = "tx_unjail_validator.wasm";
pub const ADDRESS: Arg = arg("address");
pub const ALIAS_OPT: ArgOpt = ALIAS.opt();
@@ -1734,6 +1817,9 @@ pub mod args {
pub const GENESIS_VALIDATOR: ArgOpt =
arg("genesis-validator").opt();
pub const HALT_ACTION: ArgFlag = flag("halt");
+ pub const HD_WALLET_DERIVATION_PATH: Arg = arg("hd-path");
+ pub const HD_WALLET_DERIVATION_PATH_OPT: ArgOpt =
+ HD_WALLET_DERIVATION_PATH.opt();
pub const HISTORIC: ArgFlag = flag("historic");
pub const LEDGER_ADDRESS_ABOUT: &str =
"Address of a ledger node as \"{scheme}://{host}:{port}\". If the \
@@ -1789,6 +1875,7 @@ pub mod args {
pub const TENDERMINT_TX_INDEX: ArgFlag = flag("tx-index");
pub const TIMEOUT_HEIGHT: ArgOpt = arg_opt("timeout-height");
pub const TIMEOUT_SEC_OFFSET: ArgOpt = arg_opt("timeout-sec-offset");
+ pub const TM_ADDRESS: Arg = arg("tm-address");
pub const TOKEN_OPT: ArgOpt = TOKEN.opt();
pub const TOKEN: Arg = arg("token");
pub const TRANSFER_SOURCE: Arg = arg("source");
@@ -2054,7 +2141,7 @@ pub mod args {
sub_prefix: self.sub_prefix,
amount: self.amount,
native_token: ctx.native_token.clone(),
- tx_code_path: ctx.read_wasm(self.tx_code_path),
+ tx_code_path: self.tx_code_path.to_path_buf(),
}
}
}
@@ -2109,7 +2196,7 @@ pub mod args {
channel_id: self.channel_id,
timeout_height: self.timeout_height,
timeout_sec_offset: self.timeout_sec_offset,
- tx_code_path: ctx.read_wasm(self.tx_code_path),
+ tx_code_path: self.tx_code_path.to_path_buf(),
}
}
}
@@ -2170,15 +2257,8 @@ pub mod args {
TxInitAccount:: {
tx: self.tx.to_sdk(ctx),
source: ctx.get(&self.source),
- vp_code: ctx.read_wasm(self.vp_code),
- vp_code_path: self
- .vp_code_path
- .as_path()
- .to_str()
- .unwrap()
- .to_string()
- .into_bytes(),
- tx_code_path: ctx.read_wasm(self.tx_code_path),
+ vp_code_path: self.vp_code_path.to_path_buf(),
+ tx_code_path: self.tx_code_path.to_path_buf(),
public_key: ctx.get_cached(&self.public_key),
}
}
@@ -2191,13 +2271,11 @@ pub mod args {
let vp_code_path = CODE_PATH_OPT
.parse(matches)
.unwrap_or_else(|| PathBuf::from(VP_USER_WASM));
- let vp_code = vp_code_path.clone();
let tx_code_path = PathBuf::from(TX_INIT_ACCOUNT_WASM);
let public_key = PUBLIC_KEY.parse(matches);
Self {
tx,
source,
- vp_code,
vp_code_path,
public_key,
tx_code_path,
@@ -2234,13 +2312,9 @@ pub mod args {
max_commission_rate_change: self.max_commission_rate_change,
validator_vp_code_path: self
.validator_vp_code_path
- .as_path()
- .to_str()
- .unwrap()
- .to_string()
- .into_bytes(),
+ .to_path_buf(),
unsafe_dont_encrypt: self.unsafe_dont_encrypt,
- tx_code_path: ctx.read_wasm(self.tx_code_path),
+ tx_code_path: self.tx_code_path.to_path_buf(),
}
}
}
@@ -2324,20 +2398,8 @@ pub mod args {
fn to_sdk(self, ctx: &mut Context) -> TxUpdateVp {
TxUpdateVp:: {
tx: self.tx.to_sdk(ctx),
- vp_code_path: self
- .vp_code_path
- .as_path()
- .to_str()
- .unwrap()
- .to_string()
- .into_bytes(),
- tx_code_path: self
- .tx_code_path
- .as_path()
- .to_str()
- .unwrap()
- .to_string()
- .into_bytes(),
+ vp_code_path: self.vp_code_path,
+ tx_code_path: self.tx_code_path,
addr: ctx.get(&self.addr),
}
}
@@ -2379,7 +2441,7 @@ pub mod args {
amount: self.amount,
source: self.source.map(|x| ctx.get(&x)),
native_token: ctx.native_token.clone(),
- tx_code_path: ctx.read_wasm(self.tx_code_path),
+ tx_code_path: self.tx_code_path.to_path_buf(),
}
}
}
@@ -2419,7 +2481,7 @@ pub mod args {
validator: ctx.get(&self.validator),
amount: self.amount,
source: self.source.map(|x| ctx.get(&x)),
- tx_code_path: ctx.read_wasm(self.tx_code_path),
+ tx_code_path: self.tx_code_path.to_path_buf(),
}
}
}
@@ -2466,7 +2528,7 @@ pub mod args {
/// Native token address
pub native_token: C::NativeAddress,
/// Path to the TX WASM code file
- pub tx_code_path: C::Data,
+ pub tx_code_path: PathBuf,
}
impl CliToSdk> for InitProposal {
@@ -2476,7 +2538,7 @@ pub mod args {
proposal_data: self.proposal_data,
offline: self.offline,
native_token: ctx.native_token.clone(),
- tx_code_path: ctx.read_wasm(self.tx_code_path),
+ tx_code_path: self.tx_code_path,
}
}
}
@@ -2527,7 +2589,7 @@ pub mod args {
/// The proposal file path
pub proposal_data: Option,
/// Path to the TX WASM code file
- pub tx_code_path: C::Data,
+ pub tx_code_path: PathBuf,
}
impl CliToSdk> for VoteProposal {
@@ -2538,7 +2600,7 @@ pub mod args {
vote: self.vote,
offline: self.offline,
proposal_data: self.proposal_data,
- tx_code_path: ctx.read_wasm(self.tx_code_path),
+ tx_code_path: self.tx_code_path.to_path_buf(),
proposal_pgf: self.proposal_pgf,
proposal_eth: self.proposal_eth,
}
@@ -2763,7 +2825,7 @@ pub mod args {
tx: self.tx.to_sdk(ctx),
validator: ctx.get(&self.validator),
source: self.source.map(|x| ctx.get(&x)),
- tx_code_path: ctx.read_wasm(self.tx_code_path),
+ tx_code_path: self.tx_code_path.to_path_buf(),
}
}
}
@@ -2995,7 +3057,7 @@ pub mod args {
tx: self.tx.to_sdk(ctx),
validator: ctx.get(&self.validator),
rate: self.rate,
- tx_code_path: ctx.read_wasm(self.tx_code_path),
+ tx_code_path: self.tx_code_path.to_path_buf(),
}
}
}
@@ -3015,7 +3077,7 @@ pub mod args {
}
fn def(app: App) -> App {
- app.add_args::>()
+ app.add_args::>()
.arg(VALIDATOR.def().about(
"The validator's address whose commission rate to change.",
))
@@ -3027,6 +3089,43 @@ pub mod args {
}
}
+ impl CliToSdk> for TxUnjailValidator {
+ fn to_sdk(self, ctx: &mut Context) -> TxUnjailValidator {
+ TxUnjailValidator {
+ tx: self.tx.to_sdk(ctx),
+ validator: ctx.get(&self.validator),
+ tx_code_path: self
+ .tx_code_path
+ .as_path()
+ .to_str()
+ .unwrap()
+ .to_string()
+ .into_bytes(),
+ }
+ }
+ }
+
+ impl Args for TxUnjailValidator {
+ fn parse(matches: &ArgMatches) -> Self {
+ let tx = Tx::parse(matches);
+ let validator = VALIDATOR.parse(matches);
+ let tx_code_path = PathBuf::from(TX_UNJAIL_VALIDATOR_WASM);
+ Self {
+ tx,
+ validator,
+ tx_code_path,
+ }
+ }
+
+ fn def(app: App) -> App {
+ app.add_args::>().arg(
+ VALIDATOR.def().about(
+ "The address of the jailed validator to re-activate.",
+ ),
+ )
+ }
+ }
+
impl CliToSdk> for QueryCommissionRate {
fn to_sdk(self, ctx: &mut Context) -> QueryCommissionRate {
QueryCommissionRate:: {
@@ -3111,6 +3210,31 @@ pub mod args {
}
}
+ impl Args for QueryFindValidator {
+ fn parse(matches: &ArgMatches) -> Self {
+ let query = Query::parse(matches);
+ let tm_addr = TM_ADDRESS.parse(matches);
+ Self { query, tm_addr }
+ }
+
+ fn def(app: App) -> App {
+ app.add_args::>().arg(
+ TM_ADDRESS
+ .def()
+ .about("The address of the validator in Tendermint."),
+ )
+ }
+ }
+
+ impl CliToSdk> for QueryFindValidator {
+ fn to_sdk(self, ctx: &mut Context) -> QueryFindValidator {
+ QueryFindValidator:: {
+ query: self.query.to_sdk(ctx),
+ tm_addr: self.tm_addr,
+ }
+ }
+ }
+
impl CliToSdk> for QueryRawBytes {
fn to_sdk(self, ctx: &mut Context) -> QueryRawBytes {
QueryRawBytes:: {
@@ -3165,7 +3289,7 @@ pub mod args {
gas_limit: self.gas_limit,
signing_key: self.signing_key.map(|x| ctx.get_cached(&x)),
signer: self.signer.map(|x| ctx.get(&x)),
- tx_code_path: ctx.read_wasm(self.tx_code_path),
+ tx_reveal_code_path: self.tx_reveal_code_path,
password: self.password,
expiration: self.expiration,
chain_id: self.chain_id,
@@ -3201,6 +3325,9 @@ pub mod args {
initialized, the alias will be the prefix of each new \
address joined with a number.",
))
+ .arg(WALLET_ALIAS_FORCE.def().about(
+ "Override the alias without confirmation if it already exists.",
+ ))
.arg(GAS_AMOUNT.def().about(
"The amount being paid for the inclusion of this transaction",
))
@@ -3251,7 +3378,7 @@ pub mod args {
let expiration = EXPIRATION_OPT.parse(matches);
let signing_key = SIGNING_KEY_OPT.parse(matches);
let signer = SIGNER.parse(matches);
- let tx_code_path = PathBuf::from(TX_REVEAL_PK);
+ let tx_reveal_code_path = PathBuf::from(TX_REVEAL_PK);
let chain_id = CHAIN_ID_OPT.parse(matches);
let password = None;
Self {
@@ -3268,7 +3395,7 @@ pub mod args {
expiration,
signing_key,
signer,
- tx_code_path,
+ tx_reveal_code_path,
password,
chain_id,
}
@@ -3318,6 +3445,9 @@ pub mod args {
.def()
.about("An alias to be associated with the new entry."),
)
+ .arg(ALIAS_FORCE.def().about(
+ "Override the alias without confirmation if it already exists.",
+ ))
.arg(
MASP_VALUE
.def()
@@ -3386,6 +3516,9 @@ pub mod args {
"An alias to be associated with the payment address.",
),
)
+ .arg(ALIAS_FORCE.def().about(
+ "Override the alias without confirmation if it already exists.",
+ ))
.arg(VIEWING_KEY.def().about("The viewing key."))
.arg(PIN.def().about(
"Require that the single transaction to this address be \
@@ -3394,17 +3527,65 @@ pub mod args {
}
}
+ impl Args for KeyAndAddressRestore {
+ fn parse(matches: &ArgMatches) -> Self {
+ let scheme = SCHEME.parse(matches);
+ let alias = ALIAS_OPT.parse(matches);
+ let alias_force = ALIAS_FORCE.parse(matches);
+ let unsafe_dont_encrypt = UNSAFE_DONT_ENCRYPT.parse(matches);
+ let derivation_path = HD_WALLET_DERIVATION_PATH_OPT.parse(matches);
+ Self {
+ scheme,
+ alias,
+ alias_force,
+ unsafe_dont_encrypt,
+ derivation_path,
+ }
+ }
+
+ fn def(app: App) -> App {
+ app.arg(SCHEME.def().about(
+ "The type of key that should be added. Argument must be \
+ either ed25519 or secp256k1. If none provided, the default \
+ key scheme is ed25519.",
+ ))
+ .arg(ALIAS_OPT.def().about(
+ "The key and address alias. If none provided, the alias will \
+ be the public key hash.",
+ ))
+ .arg(
+ ALIAS_FORCE
+ .def()
+ .about("Force overwrite the alias if it already exists."),
+ )
+ .arg(UNSAFE_DONT_ENCRYPT.def().about(
+ "UNSAFE: Do not encrypt the keypair. Do not use this for keys \
+ used in a live network.",
+ ))
+ .arg(HD_WALLET_DERIVATION_PATH_OPT.def().about(
+ "HD key derivation path. Use keyword `default` to refer to a \
+ scheme default path:\n- m/44'/60'/0'/0/0 for secp256k1 \
+ scheme\n- m/44'/877'/0'/0'/0' for ed25519 scheme.\nFor \
+ ed25519, all path indices will be promoted to hardened \
+ indexes. If none is specified, the scheme default path is \
+ used.",
+ ))
+ }
+ }
+
impl Args for KeyAndAddressGen {
fn parse(matches: &ArgMatches) -> Self {
let scheme = SCHEME.parse(matches);
let alias = ALIAS_OPT.parse(matches);
let alias_force = ALIAS_FORCE.parse(matches);
let unsafe_dont_encrypt = UNSAFE_DONT_ENCRYPT.parse(matches);
+ let derivation_path = HD_WALLET_DERIVATION_PATH_OPT.parse(matches);
Self {
scheme,
alias,
alias_force,
unsafe_dont_encrypt,
+ derivation_path,
}
}
@@ -3418,10 +3599,22 @@ pub mod args {
"The key and address alias. If none provided, the alias will \
be the public key hash.",
))
+ .arg(ALIAS_FORCE.def().about(
+ "Override the alias without confirmation if it already exists.",
+ ))
.arg(UNSAFE_DONT_ENCRYPT.def().about(
"UNSAFE: Do not encrypt the keypair. Do not use this for keys \
used in a live network.",
))
+ .arg(HD_WALLET_DERIVATION_PATH_OPT.def().about(
+ "Generate a new key and wallet using BIP39 mnemonic code and \
+ HD derivation path. Use keyword `default` to refer to a \
+ scheme default path:\n- m/44'/60'/0'/0/0 for secp256k1 \
+ scheme\n- m/44'/877'/0'/0'/0' for ed25519 scheme.\nFor \
+ ed25519, all path indices will be promoted to hardened \
+ indexes. If none specified, mnemonic code and derivation \
+ path are not used.",
+ ))
}
}
@@ -3586,6 +3779,9 @@ pub mod args {
.def()
.about("An alias to be associated with the address."),
)
+ .arg(ALIAS_FORCE.def().about(
+ "Override the alias without confirmation if it already exists.",
+ ))
.arg(
RAW_ADDRESS
.def()
diff --git a/apps/src/lib/cli/context.rs b/apps/src/lib/cli/context.rs
index 42c1bb6c94..630d329515 100644
--- a/apps/src/lib/cli/context.rs
+++ b/apps/src/lib/cli/context.rs
@@ -1,6 +1,6 @@
//! CLI input types can be used for command arguments
-use std::collections::HashSet;
+use std::collections::{HashMap, HashSet};
use std::env;
use std::marker::PhantomData;
use std::path::{Path, PathBuf};
@@ -194,10 +194,31 @@ impl Context {
wasm_loader::read_wasm_or_exit(self.wasm_dir(), file_name)
}
- /// Get address with vp type
+ /// Try to find an alias for a given address from the wallet. If not found,
+ /// formats the address into a string.
+ pub fn lookup_alias(&self, addr: &Address) -> String {
+ match self.wallet.find_alias(addr) {
+ Some(alias) => alias.to_string(),
+ None => addr.to_string(),
+ }
+ }
+
+ /// Get addresses with tokens VP type.
pub fn tokens(&self) -> HashSet {
self.wallet.get_addresses_with_vp_type(AddressVpType::Token)
}
+
+ /// Get addresses with tokens VP type associated with their aliases.
+ pub fn tokens_with_aliases(&self) -> HashMap {
+ self.wallet
+ .get_addresses_with_vp_type(AddressVpType::Token)
+ .into_iter()
+ .map(|addr| {
+ let alias = self.lookup_alias(&addr);
+ (addr, alias)
+ })
+ .collect()
+ }
}
/// Load global config from expected path in the `base_dir` or try to generate a
diff --git a/apps/src/lib/client/rpc.rs b/apps/src/lib/client/rpc.rs
index 109b0ffa2d..70167f59e2 100644
--- a/apps/src/lib/client/rpc.rs
+++ b/apps/src/lib/client/rpc.rs
@@ -16,8 +16,7 @@ use data_encoding::HEXLOWER;
use itertools::Either;
use masp_primitives::asset_type::AssetType;
use masp_primitives::merkle_tree::MerklePath;
-use masp_primitives::primitives::ViewingKey;
-use masp_primitives::sapling::Node;
+use masp_primitives::sapling::{Node, ViewingKey};
use masp_primitives::transaction::components::Amount;
use masp_primitives::zip32::ExtendedFullViewingKey;
use namada::core::types::transaction::governance::ProposalType;
@@ -1562,6 +1561,30 @@ pub async fn query_delegations(
}
}
+pub async fn query_find_validator(
+ client: &C,
+ args: args::QueryFindValidator,
+) {
+ let args::QueryFindValidator { query: _, tm_addr } = args;
+ if tm_addr.len() != 40 {
+ eprintln!(
+ "Expected 40 characters in Tendermint address, got {}",
+ tm_addr.len()
+ );
+ cli::safe_exit(1);
+ }
+ let tm_addr = tm_addr.to_ascii_uppercase();
+ let validator = unwrap_client_response::(
+ RPC.vp().pos().validator_by_tm_addr(client, &tm_addr).await,
+ );
+ match validator {
+ Some(address) => println!("Found validator address \"{address}\"."),
+ None => {
+ println!("No validator with Tendermint address {tm_addr} found.")
+ }
+ }
+}
+
/// Dry run a transaction
pub async fn dry_run_tx(
client: &C,
diff --git a/apps/src/lib/client/signing.rs b/apps/src/lib/client/signing.rs
index eec89b4f80..c44da88f9b 100644
--- a/apps/src/lib/client/signing.rs
+++ b/apps/src/lib/client/signing.rs
@@ -5,10 +5,10 @@ use namada::ledger::rpc::TxBroadcastData;
use namada::ledger::signing::TxSigningKey;
use namada::ledger::tx;
use namada::ledger::wallet::{Wallet, WalletUtils};
+use namada::proof_of_stake::Epoch;
use namada::proto::Tx;
use namada::types::address::Address;
use namada::types::key::*;
-use namada::types::storage::Epoch;
use crate::cli::args;
@@ -77,8 +77,12 @@ pub async fn sign_tx<
/// Create a wrapper tx from a normal tx. Get the hash of the
/// wrapper and its payload which is needed for monitoring its
/// progress on chain.
-pub async fn sign_wrapper(
+pub async fn sign_wrapper<
+ C: namada::ledger::queries::Client + Sync,
+ U: WalletUtils,
+>(
client: &C,
+ wallet: &mut Wallet,
args: &args::Tx,
epoch: Epoch,
tx: Tx,
@@ -87,6 +91,7 @@ pub async fn sign_wrapper(
) -> TxBroadcastData {
namada::ledger::signing::sign_wrapper(
client,
+ wallet,
args,
epoch,
tx,
diff --git a/apps/src/lib/client/tx.rs b/apps/src/lib/client/tx.rs
index ce334adb41..20bcf7f83b 100644
--- a/apps/src/lib/client/tx.rs
+++ b/apps/src/lib/client/tx.rs
@@ -7,6 +7,7 @@ use std::path::PathBuf;
use async_std::io;
use async_std::io::prelude::WriteExt;
+use async_trait::async_trait;
use borsh::{BorshDeserialize, BorshSerialize};
use data_encoding::HEXLOWER_PERMISSIVE;
use masp_proofs::prover::LocalTxProver;
@@ -15,19 +16,21 @@ use namada::ledger::rpc::{TxBroadcastData, TxResponse};
use namada::ledger::signing::TxSigningKey;
use namada::ledger::wallet::{Wallet, WalletUtils};
use namada::ledger::{masp, tx};
-use namada::proto::Tx;
+use namada::proto::{Code, Data, Section, Tx};
use namada::types::address::Address;
use namada::types::governance::{
OfflineProposal, OfflineVote, Proposal, ProposalVote, VoteType,
};
+use namada::types::hash::Hash;
use namada::types::key::*;
use namada::types::storage::{Epoch, Key};
use namada::types::token;
use namada::types::transaction::governance::{
InitProposalData, ProposalType, VoteProposalData,
};
-use namada::types::transaction::InitValidator;
+use namada::types::transaction::{InitValidator, TxType};
use rust_decimal::Decimal;
+use sha2::{Digest as Sha2Digest, Sha256};
use tendermint_rpc::HttpClient;
use super::rpc;
@@ -35,9 +38,12 @@ use crate::cli::context::WalletAddress;
use crate::cli::{args, safe_exit, Context};
use crate::client::rpc::query_wasm_code_hash;
use crate::client::signing::find_keypair;
+use crate::client::tx::tx::ProcessTxResponse;
use crate::facade::tendermint_rpc::endpoint::broadcast::tx_sync::Response;
use crate::node::ledger::tendermint_node;
-use crate::wallet::{gen_validator_keys, read_and_confirm_pwd, CliWalletUtils};
+use crate::wallet::{
+ gen_validator_keys, read_and_confirm_encryption_password, CliWalletUtils,
+};
pub async fn submit_custom(
client: &C,
@@ -111,14 +117,17 @@ pub async fn submit_init_validator<
let consensus_key_alias = format!("{}-consensus-key", alias);
let account_key = account_key.unwrap_or_else(|| {
println!("Generating validator account key...");
- let password = read_and_confirm_pwd(unsafe_dont_encrypt);
+ let password =
+ read_and_confirm_encryption_password(unsafe_dont_encrypt);
ctx.wallet
.gen_key(
scheme,
Some(validator_key_alias.clone()),
- password,
tx_args.wallet_alias_force,
+ password,
+ None,
)
+ .expect("Key generation should not fail.")
.1
.ref_to()
});
@@ -133,15 +142,18 @@ pub async fn submit_init_validator<
})
.unwrap_or_else(|| {
println!("Generating consensus key...");
- let password = read_and_confirm_pwd(unsafe_dont_encrypt);
+ let password =
+ read_and_confirm_encryption_password(unsafe_dont_encrypt);
ctx.wallet
.gen_key(
// Note that TM only allows ed25519 for consensus key
SchemeType::Ed25519,
Some(consensus_key_alias.clone()),
- password,
tx_args.wallet_alias_force,
+ password,
+ None,
)
+ .expect("Key generation should not fail.")
.1
});
@@ -160,11 +172,12 @@ pub async fn submit_init_validator<
.expect("DKG sessions keys should have been created")
.public();
- let vp_code_path = String::from_utf8(validator_vp_code_path).unwrap();
- let validator_vp_code_hash =
- query_wasm_code_hash::(client, vp_code_path)
- .await
- .unwrap();
+ let validator_vp_code_hash = query_wasm_code_hash::(
+ client,
+ validator_vp_code_path.to_str().unwrap(),
+ )
+ .await
+ .unwrap();
// Validate the commission rate data
if commission_rate > Decimal::ONE || commission_rate < Decimal::ZERO {
@@ -192,6 +205,12 @@ pub async fn submit_init_validator<
.await
.unwrap();
+ let mut tx = Tx::new(TxType::Raw);
+ let extra = tx.add_section(Section::ExtraData(Code::from_hash(
+ validator_vp_code_hash,
+ )));
+ let extra_hash =
+ Hash(extra.hash(&mut Sha256::new()).finalize_reset().into());
let data = InitValidator {
account_key,
consensus_key: consensus_key.ref_to(),
@@ -199,15 +218,14 @@ pub async fn submit_init_validator<
dkg_key,
commission_rate,
max_commission_rate_change,
- validator_vp_code_hash,
+ validator_vp_code_hash: extra_hash,
};
let data = data.try_to_vec().expect("Encoding tx data shouldn't fail");
- let tx = Tx::new(
- tx_code_hash.to_vec(),
- Some(data),
- tx_args.chain_id.clone().unwrap(),
- tx_args.expiration,
- );
+ tx.header.chain_id = tx_args.chain_id.clone().unwrap();
+ tx.header.expiration = tx_args.expiration;
+ tx.set_data(Data::new(data));
+ tx.set_code(Code::from_hash(tx_code_hash));
+
let (mut ctx, result) = process_tx(
client,
ctx,
@@ -315,7 +333,7 @@ impl CLIShieldedUtils {
&& output_path.exists())
{
println!("MASP parameters not present, downloading...");
- masp_proofs::download_parameters()
+ masp_proofs::download_masp_parameters(None)
.expect("MASP parameters not present or downloadable");
println!("MASP parameter download complete, resuming execution...");
}
@@ -336,6 +354,7 @@ impl Default for CLIShieldedUtils {
}
}
+#[async_trait(?Send)]
impl masp::ShieldedUtils for CLIShieldedUtils {
type C = tendermint_rpc::HttpClient;
@@ -354,7 +373,7 @@ impl masp::ShieldedUtils for CLIShieldedUtils {
/// Try to load the last saved shielded context from the given context
/// directory. If this fails, then leave the current context unchanged.
- fn load(self) -> std::io::Result> {
+ async fn load(self) -> std::io::Result> {
// Try to load shielded context from file
let mut ctx_file = File::open(self.context_dir.join(FILE_NAME))?;
let mut bytes = Vec::new();
@@ -367,7 +386,10 @@ impl masp::ShieldedUtils for CLIShieldedUtils {
}
/// Save this shielded context into its associated context directory
- fn save(&self, ctx: &masp::ShieldedContext) -> std::io::Result<()> {
+ async fn save(
+ &self,
+ ctx: &masp::ShieldedContext,
+ ) -> std::io::Result<()> {
// TODO: use mktemp crate?
let tmp_path = self.context_dir.join(TMP_FILE_NAME);
{
@@ -434,9 +456,9 @@ pub async fn submit_init_proposal(
serde_json::from_reader(file).expect("JSON was not well-formatted");
let signer = WalletAddress::new(proposal.clone().author.to_string());
- let governance_parameters = rpc::get_governance_parameters(client).await;
let current_epoch = rpc::query_and_print_epoch(client).await;
+ let governance_parameters = rpc::get_governance_parameters(client).await;
if proposal.voting_start_epoch <= current_epoch
|| proposal.voting_start_epoch.0
% governance_parameters.min_proposal_period
@@ -527,13 +549,10 @@ pub async fn submit_init_proposal(
safe_exit(1)
};
- let balance = rpc::get_token_balance(
- client,
- &args.native_token,
- &proposal.author,
- )
- .await
- .unwrap_or_default();
+ let balance =
+ rpc::get_token_balance(client, &ctx.native_token, &proposal.author)
+ .await
+ .unwrap_or_default();
if balance
< token::Amount::from(governance_parameters.min_proposal_fund)
{
@@ -551,18 +570,17 @@ pub async fn submit_init_proposal(
safe_exit(1);
}
+ let mut tx = Tx::new(TxType::Raw);
let data = init_proposal_data
.try_to_vec()
.expect("Encoding proposal data shouldn't fail");
let tx_code_hash = query_wasm_code_hash(client, args::TX_INIT_PROPOSAL)
.await
.unwrap();
- let tx = Tx::new(
- tx_code_hash.to_vec(),
- Some(data),
- ctx.config.ledger.chain_id.clone(),
- args.tx.expiration,
- );
+ tx.header.chain_id = ctx.config.ledger.chain_id.clone();
+ tx.header.expiration = args.tx.expiration;
+ tx.set_data(Data::new(data));
+ tx.set_code(Code::from_hash(tx_code_hash));
process_tx::(
client,
@@ -806,8 +824,18 @@ pub async fn submit_vote_proposal(
let data = tx_data
.try_to_vec()
.expect("Encoding proposal data shouldn't fail");
- let tx_code = args.tx_code_path;
- let tx = Tx::new(tx_code, Some(data), chain_id, expiration);
+
+ let tx_code_hash = query_wasm_code_hash(
+ client,
+ args.tx_code_path.to_str().unwrap(),
+ )
+ .await
+ .unwrap();
+ let mut tx = Tx::new(TxType::Raw);
+ tx.header.chain_id = chain_id;
+ tx.header.expiration = expiration;
+ tx.set_data(Data::new(data));
+ tx.set_code(Code::from_hash(tx_code_hash));
process_tx::(
client,
@@ -873,7 +901,7 @@ pub async fn submit_reveal_pk_aux(
ctx: &mut Context,
public_key: &common::PublicKey,
args: &args::Tx,
-) -> Result<(), tx::Error> {
+) -> Result {
let args = args::Tx {
chain_id: args
.clone()
@@ -990,6 +1018,20 @@ pub async fn submit_validator_commission_change<
.await
}
+pub async fn submit_unjail_validator<
+ C: namada::ledger::queries::Client + Sync,
+>(
+ client: &C,
+ mut ctx: Context,
+ mut args: args::TxUnjailValidator,
+) -> Result<(), tx::Error> {
+ args.tx.chain_id = args
+ .tx
+ .chain_id
+ .or_else(|| Some(ctx.config.ledger.chain_id.clone()));
+ tx::submit_unjail_validator::(client, &mut ctx.wallet, args).await
+}
+
/// Submit transaction and wait for result. Returns a list of addresses
/// initialized in the transaction if any. In dry run, this is always empty.
async fn process_tx(
@@ -1001,7 +1043,10 @@ async fn process_tx(
#[cfg(not(feature = "mainnet"))] requires_pow: bool,
) -> Result<(Context, Vec), tx::Error> {
let args = args::Tx {
- chain_id: args.clone().chain_id.or_else(|| Some(tx.chain_id.clone())),
+ chain_id: args
+ .clone()
+ .chain_id
+ .or_else(|| Some(tx.header.chain_id.clone())),
..args.clone()
};
let res: Vec = tx::process_tx::(
@@ -1013,7 +1058,8 @@ async fn process_tx(
#[cfg(not(feature = "mainnet"))]
requires_pow,
)
- .await?;
+ .await?
+ .initialized_accounts();
Ok((ctx, res))
}
diff --git a/apps/src/lib/client/utils.rs b/apps/src/lib/client/utils.rs
index 107c5465dd..cb3f42b377 100644
--- a/apps/src/lib/client/utils.rs
+++ b/apps/src/lib/client/utils.rs
@@ -31,7 +31,9 @@ use crate::config::{self, Config, TendermintMode};
use crate::facade::tendermint::node::Id as TendermintNodeId;
use crate::facade::tendermint_config::net::Address as TendermintAddress;
use crate::node::ledger::tendermint_node;
-use crate::wallet::{pre_genesis, read_and_confirm_pwd, CliWalletUtils};
+use crate::wallet::{
+ pre_genesis, read_and_confirm_encryption_password, CliWalletUtils,
+};
use crate::wasm_loader;
pub const NET_ACCOUNTS_DIR: &str = "setup";
@@ -491,7 +493,7 @@ pub fn init_network(
config.address = Some(address.to_string());
// Generate the consensus, account and reward keys, unless they're
- // pre-defined.
+ // pre-defined. Do not use mnemonic code / HD derivation path.
let mut wallet = crate::wallet::load_or_new(&chain_dir);
let consensus_pk = try_parse_public_key(
@@ -501,13 +503,11 @@ pub fn init_network(
.unwrap_or_else(|| {
let alias = format!("{}-consensus-key", name);
println!("Generating validator {} consensus key...", name);
- let password = read_and_confirm_pwd(unsafe_dont_encrypt);
- let (_alias, keypair) = wallet.gen_key(
- SchemeType::Ed25519,
- Some(alias),
- password,
- true,
- );
+ let password =
+ read_and_confirm_encryption_password(unsafe_dont_encrypt);
+ let (_alias, keypair) = wallet
+ .gen_key(SchemeType::Ed25519, Some(alias), true, password, None)
+ .expect("Key generation should not fail.");
// Write consensus key for Tendermint
tendermint_node::write_validator_key(&tm_home_dir, &keypair);
@@ -522,13 +522,11 @@ pub fn init_network(
.unwrap_or_else(|| {
let alias = format!("{}-account-key", name);
println!("Generating validator {} account key...", name);
- let password = read_and_confirm_pwd(unsafe_dont_encrypt);
- let (_alias, keypair) = wallet.gen_key(
- SchemeType::Ed25519,
- Some(alias),
- password,
- true,
- );
+ let password =
+ read_and_confirm_encryption_password(unsafe_dont_encrypt);
+ let (_alias, keypair) = wallet
+ .gen_key(SchemeType::Ed25519, Some(alias), true, password, None)
+ .expect("Key generation should not fail.");
keypair.ref_to()
});
@@ -539,13 +537,11 @@ pub fn init_network(
.unwrap_or_else(|| {
let alias = format!("{}-protocol-key", name);
println!("Generating validator {} protocol signing key...", name);
- let password = read_and_confirm_pwd(unsafe_dont_encrypt);
- let (_alias, keypair) = wallet.gen_key(
- SchemeType::Ed25519,
- Some(alias),
- password,
- true,
- );
+ let password =
+ read_and_confirm_encryption_password(unsafe_dont_encrypt);
+ let (_alias, keypair) = wallet
+ .gen_key(SchemeType::Ed25519, Some(alias), true, password, None)
+ .expect("Key generation should not fail.");
keypair.ref_to()
});
@@ -593,7 +589,8 @@ pub fn init_network(
crate::wallet::save(&wallet).unwrap();
});
- // Create a wallet for all accounts other than validators
+ // Create a wallet for all accounts other than validators.
+ // Do not use mnemonic code / HD derivation path.
let mut wallet =
crate::wallet::load_or_new(&accounts_dir.join(NET_OTHER_ACCOUNTS_DIR));
if let Some(established) = &mut config.established {
@@ -625,13 +622,17 @@ pub fn init_network(
"Generating implicit account {} key and address ...",
name
);
- let password = read_and_confirm_pwd(unsafe_dont_encrypt);
- let (_alias, keypair) = wallet.gen_key(
- SchemeType::Ed25519,
- Some(name.clone()),
- password,
- true,
- );
+ let password =
+ read_and_confirm_encryption_password(unsafe_dont_encrypt);
+ let (_alias, keypair) = wallet
+ .gen_key(
+ SchemeType::Ed25519,
+ Some(name.clone()),
+ true,
+ password,
+ None,
+ )
+ .expect("Key generation should not fail.");
let public_key =
genesis_config::HexString(keypair.ref_to().to_string());
config.public_key = Some(public_key);
@@ -877,13 +878,17 @@ fn init_established_account(
}
if config.public_key.is_none() {
println!("Generating established account {} key...", name.as_ref());
- let password = read_and_confirm_pwd(unsafe_dont_encrypt);
- let (_alias, keypair) = wallet.gen_key(
- SchemeType::Ed25519,
- Some(format!("{}-key", name.as_ref())),
- password,
- true,
- );
+ let password =
+ read_and_confirm_encryption_password(unsafe_dont_encrypt);
+ let (_alias, keypair) = wallet
+ .gen_key(
+ SchemeType::Ed25519,
+ Some(format!("{}-key", name.as_ref())),
+ true,
+ password,
+ None, // do not use mnemonic code / HD derivation path
+ )
+ .expect("Key generation should not fail.");
let public_key =
genesis_config::HexString(keypair.ref_to().to_string());
config.public_key = Some(public_key);
diff --git a/apps/src/lib/config/genesis.rs b/apps/src/lib/config/genesis.rs
index 922b0c445f..fb9ae608dc 100644
--- a/apps/src/lib/config/genesis.rs
+++ b/apps/src/lib/config/genesis.rs
@@ -305,6 +305,9 @@ pub mod genesis_config {
// light client attack.
// XXX: u64 doesn't work with toml-rs!
pub light_client_attack_min_slash_rate: Decimal,
+ /// Number of epochs above and below (separately) the current epoch to
+ /// consider when doing cubic slashing
+ pub cubic_slashing_window_length: u64,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
@@ -647,6 +650,7 @@ pub mod genesis_config {
target_staked_ratio,
duplicate_vote_min_slash_rate,
light_client_attack_min_slash_rate,
+ cubic_slashing_window_length,
} = pos_params;
let pos_params = PosParams {
max_validator_slots,
@@ -659,6 +663,7 @@ pub mod genesis_config {
target_staked_ratio,
duplicate_vote_min_slash_rate,
light_client_attack_min_slash_rate,
+ cubic_slashing_window_length,
};
let mut genesis = Genesis {
diff --git a/apps/src/lib/node/ledger/shell/finalize_block.rs b/apps/src/lib/node/ledger/shell/finalize_block.rs
index 84a8bd6efd..f57018a75a 100644
--- a/apps/src/lib/node/ledger/shell/finalize_block.rs
+++ b/apps/src/lib/node/ledger/shell/finalize_block.rs
@@ -103,7 +103,10 @@ where
// Invariant: This has to be applied after
// `copy_validator_sets_and_positions` if we're starting a new epoch
- self.slash();
+ self.record_slashes_from_evidence();
+ if new_epoch {
+ self.process_slashes();
+ }
let wrapper_fees = self.get_wrapper_tx_fees();
let mut stats = InternalStats::default();
@@ -127,26 +130,19 @@ where
if ErrorCodes::from_u32(processed_tx.result.code).unwrap()
== ErrorCodes::InvalidSig
{
- let mut tx_event = match process_tx(tx.clone()) {
- Ok(tx @ TxType::Wrapper(_))
- | Ok(tx @ TxType::Protocol(_)) => {
+ let mut tx_event = match tx.header().tx_type {
+ TxType::Wrapper(_) | TxType::Protocol(_) => {
Event::new_tx_event(&tx, height.0)
}
- _ => match TxType::try_from(tx) {
- Ok(tx @ TxType::Wrapper(_))
- | Ok(tx @ TxType::Protocol(_)) => {
- Event::new_tx_event(&tx, height.0)
- }
- _ => {
- tracing::error!(
- "Internal logic error: FinalizeBlock received \
- a tx with an invalid signature error code \
- that could not be deserialized to a \
- WrapperTx / ProtocolTx type"
- );
- continue;
- }
- },
+ _ => {
+ tracing::error!(
+ "Internal logic error: FinalizeBlock received a \
+ tx with an invalid signature error code that \
+ could not be deserialized to a WrapperTx / \
+ ProtocolTx type"
+ );
+ continue;
+ }
};
tx_event["code"] = processed_tx.result.code.to_string();
tx_event["info"] =
@@ -156,8 +152,8 @@ where
continue;
}
- let tx_type = if let Ok(tx_type) = process_tx(tx) {
- tx_type
+ let tx = if let Ok(()) = tx.validate_header() {
+ tx
} else {
tracing::error!(
"Internal logic error: FinalizeBlock received tx that \
@@ -165,12 +161,13 @@ where
);
continue;
};
+ let tx_type = tx.header();
// If [`process_proposal`] rejected a Tx, emit an event here and
// move on to next tx
if ErrorCodes::from_u32(processed_tx.result.code).unwrap()
!= ErrorCodes::Ok
{
- let mut tx_event = Event::new_tx_event(&tx_type, height.0);
+ let mut tx_event = Event::new_tx_event(&tx, height.0);
tx_event["code"] = processed_tx.result.code.to_string();
tx_event["info"] =
format!("Tx rejected: {}", &processed_tx.result.info);
@@ -179,7 +176,7 @@ where
// if the rejected tx was decrypted, remove it
// from the queue of txs to be processed and remove the hash
// from storage
- if let TxType::Decrypted(_) = &tx_type {
+ if let TxType::Decrypted(_) = &tx_type.tx_type {
let tx_hash = self
.wl_storage
.storage
@@ -187,7 +184,9 @@ where
.pop()
.expect("Missing wrapper tx in queue")
.tx
- .tx_hash;
+ .clone()
+ .update_header(TxType::Raw)
+ .header_hash();
let tx_hash_key =
replay_protection::get_tx_hash_key(&tx_hash);
self.wl_storage
@@ -198,24 +197,26 @@ where
continue;
}
- let (mut tx_event, tx_unsigned_hash) = match &tx_type {
+ let (mut tx_event, tx_unsigned_hash) = match &tx_type.tx_type {
TxType::Wrapper(wrapper) => {
stats.increment_wrapper_txs();
- let mut tx_event = Event::new_tx_event(&tx_type, height.0);
+ let mut tx_event = Event::new_tx_event(&tx, height.0);
// Writes both txs hash to storage
- let tx = Tx::try_from(processed_tx.tx.as_ref()).unwrap();
+ let processed_tx =
+ Tx::try_from(processed_tx.tx.as_ref()).unwrap();
let wrapper_tx_hash_key =
replay_protection::get_tx_hash_key(&hash::Hash(
- tx.unsigned_hash(),
+ processed_tx.header_hash().0,
));
self.wl_storage
.storage
.write(&wrapper_tx_hash_key, vec![])
.expect("Error while writing tx hash to storage");
- let inner_tx_hash_key =
- replay_protection::get_tx_hash_key(&wrapper.tx_hash);
+ let inner_tx_hash_key = replay_protection::get_tx_hash_key(
+ &tx.clone().update_header(TxType::Raw).header_hash(),
+ );
self.wl_storage
.storage
.write(&inner_tx_hash_key, vec![])
@@ -276,8 +277,8 @@ where
}
}
- self.wl_storage.storage.tx_queue.push(WrapperTxInQueue {
- tx: wrapper.clone(),
+ self.wl_storage.storage.tx_queue.push(TxInQueue {
+ tx: processed_tx.clone(),
#[cfg(not(feature = "mainnet"))]
has_valid_pow,
});
@@ -292,20 +293,23 @@ where
.pop()
.expect("Missing wrapper tx in queue")
.tx
- .tx_hash;
- let mut event = Event::new_tx_event(&tx_type, height.0);
+ .clone()
+ .update_header(TxType::Raw)
+ .header_hash();
+ let mut event = Event::new_tx_event(&tx, height.0);
match inner {
- DecryptedTx::Decrypted {
- tx,
- has_valid_pow: _,
- } => {
- stats.increment_tx_type(
- namada::core::types::hash::Hash(tx.code_hash())
- .to_string(),
- );
+ DecryptedTx::Decrypted { has_valid_pow: _ } => {
+ if let Some(code_sec) = tx
+ .get_section(tx.code_sechash())
+ .and_then(Section::code_sec)
+ {
+ stats.increment_tx_type(
+ code_sec.code.hash().to_string(),
+ );
+ }
}
- DecryptedTx::Undecryptable(_) => {
+ DecryptedTx::Undecryptable => {
event["log"] =
"Transaction could not be decrypted.".into();
event["code"] = ErrorCodes::Undecryptable.into();
@@ -313,7 +317,7 @@ where
}
(event, Some(wrapper_hash))
}
- TxType::Raw(_) => {
+ TxType::Raw => {
tracing::error!(
"Internal logic error: FinalizeBlock received a \
TxType::Raw transaction"
@@ -330,7 +334,7 @@ where
};
match protocol::apply_tx(
- tx_type,
+ tx.clone(),
tx_length,
TxIndex(
tx_index
@@ -418,8 +422,8 @@ where
.storage
.delete(&tx_hash_key)
.expect(
- "Error while deleting tx hash key from storage",
- );
+ "Error while deleting tx hash key from storage",
+ );
}
}
@@ -601,7 +605,7 @@ where
/// executed while finalizing the first block of a new epoch and is applied
/// with respect to the previous epoch.
fn apply_inflation(&mut self, current_epoch: Epoch) -> Result<()> {
- let last_epoch = current_epoch - 1;
+ let last_epoch = current_epoch.prev();
// Get input values needed for the PD controller for PoS and MASP.
// Run the PD controllers to calculate new rates.
//
@@ -892,26 +896,39 @@ mod test_finalize_block {
use namada::ledger::parameters::EpochDuration;
use namada::ledger::storage_api;
use namada::proof_of_stake::btree_set::BTreeSetShims;
- use namada::proof_of_stake::types::WeightedValidator;
+ use namada::proof_of_stake::parameters::PosParams;
+ use namada::proof_of_stake::storage::{
+ is_validator_slashes_key, slashes_prefix,
+ };
+ use namada::proof_of_stake::types::{
+ decimal_mult_amount, BondId, SlashType, ValidatorState,
+ WeightedValidator,
+ };
use namada::proof_of_stake::{
+ enqueued_slashes_handle, get_num_consensus_validators,
read_consensus_validator_set_addresses_with_stake,
- rewards_accumulator_handle, validator_consensus_key_handle,
- validator_rewards_products_handle,
+ rewards_accumulator_handle, unjail_validator,
+ validator_consensus_key_handle, validator_rewards_products_handle,
+ validator_slashes_handle, validator_state_handle, write_pos_params,
};
+ use namada::proto::{Code, Data, Section, Signature};
use namada::types::governance::ProposalVote;
use namada::types::key::tm_consensus_key_raw_hash;
use namada::types::storage::Epoch;
use namada::types::time::DurationSecs;
+ use namada::types::token::Amount;
use namada::types::transaction::governance::{
InitProposalData, ProposalType, VoteProposalData,
};
- use namada::types::transaction::{EncryptionKey, Fee, WrapperTx, MIN_FEE};
+ use namada::types::transaction::{Fee, WrapperTx, MIN_FEE};
use namada_test_utils::TestWasms;
use rust_decimal_macros::dec;
use test_log::test;
use super::*;
- use crate::facade::tendermint_proto::abci::{Validator, VoteInfo};
+ use crate::facade::tendermint_proto::abci::{
+ Misbehavior, Validator, VoteInfo,
+ };
use crate::node::ledger::shell::test_utils::*;
use crate::node::ledger::shims::abcipp_shim_types::shim::request::{
FinalizeBlock, ProcessedTx,
@@ -940,31 +957,31 @@ mod test_finalize_block {
// create some wrapper txs
for i in 1u64..5 {
- let raw_tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some(format!("transaction data: {}", i).as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
- Fee {
- amount: MIN_FEE.into(),
- token: shell.wl_storage.storage.native_token.clone(),
- },
+ let mut wrapper =
+ Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
+ Fee {
+ amount: MIN_FEE.into(),
+ token: shell.wl_storage.storage.native_token.clone(),
+ },
+ &keypair,
+ Epoch(0),
+ 0.into(),
+ #[cfg(not(feature = "mainnet"))]
+ None,
+ ))));
+ wrapper.header.chain_id = shell.chain_id.clone();
+ wrapper.set_data(Data::new("wasm_code".as_bytes().to_owned()));
+ wrapper.set_code(Code::new(
+ format!("transaction data: {}", i).as_bytes().to_owned(),
+ ));
+ wrapper.add_section(Section::Signature(Signature::new(
+ &wrapper.header_hash(),
&keypair,
- Epoch(0),
- 0.into(),
- raw_tx.clone(),
- Default::default(),
- #[cfg(not(feature = "mainnet"))]
- None,
- );
- let tx = wrapper
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Test failed");
+ )));
+ wrapper.encrypt(&Default::default());
if i > 1 {
processed_txs.push(ProcessedTx {
- tx: tx.to_bytes(),
+ tx: wrapper.to_bytes(),
result: TxResult {
code: u32::try_from(i.rem_euclid(2))
.expect("Test failed"),
@@ -1000,10 +1017,9 @@ mod test_finalize_block {
for wrapper in shell.iter_tx_queue() {
// we cannot easily implement the PartialEq trait for WrapperTx
// so we check the hashes of the inner txs for equality
- assert_eq!(
- wrapper.tx.tx_hash,
- valid_tx.next().expect("Test failed").tx_hash
- );
+ let valid_tx = valid_tx.next().expect("Test failed");
+ assert_eq!(wrapper.tx.header.code_hash, *valid_tx.code_sechash());
+ assert_eq!(wrapper.tx.header.data_hash, *valid_tx.data_sechash());
counter += 1;
}
assert_eq!(counter, 3);
@@ -1017,13 +1033,7 @@ mod test_finalize_block {
fn test_process_proposal_rejected_decrypted_tx() {
let (mut shell, _) = setup(1);
let keypair = gen_keypair();
- let raw_tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some(String::from("transaction data").as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
+ let mut outer_tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -1031,25 +1041,28 @@ mod test_finalize_block {
&keypair,
Epoch(0),
0.into(),
- raw_tx.clone(),
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
-
+ ))));
+ outer_tx.header.chain_id = shell.chain_id.clone();
+ outer_tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ outer_tx.set_data(Data::new(
+ String::from("transaction data").as_bytes().to_owned(),
+ ));
+ outer_tx.encrypt(&Default::default());
+ shell.enqueue_tx(outer_tx.clone());
+
+ outer_tx.update_header(TxType::Decrypted(DecryptedTx::Decrypted {
+ #[cfg(not(feature = "mainnet"))]
+ has_valid_pow: false,
+ }));
let processed_tx = ProcessedTx {
- tx: Tx::from(TxType::Decrypted(DecryptedTx::Decrypted {
- tx: raw_tx,
- #[cfg(not(feature = "mainnet"))]
- has_valid_pow: false,
- }))
- .to_bytes(),
+ tx: outer_tx.to_bytes(),
result: TxResult {
code: ErrorCodes::InvalidTx.into(),
info: "".into(),
},
};
- shell.enqueue_tx(wrapper);
// check that the decrypted tx was not applied
for event in shell
@@ -1074,13 +1087,7 @@ mod test_finalize_block {
let (mut shell, _) = setup(1);
let keypair = crate::wallet::defaults::daewon_keypair();
- let pubkey = EncryptionKey::default();
// not valid tx bytes
- let tx = "garbage data".as_bytes().to_owned();
- let inner_tx =
- namada::types::transaction::encrypted::EncryptedTx::encrypt(
- &tx, pubkey,
- );
let wrapper = WrapperTx {
fee: Fee {
amount: 0.into(),
@@ -1089,23 +1096,20 @@ mod test_finalize_block {
pk: keypair.ref_to(),
epoch: Epoch(0),
gas_limit: 0.into(),
- inner_tx,
- tx_hash: hash_tx(&tx),
#[cfg(not(feature = "mainnet"))]
pow_solution: None,
};
let processed_tx = ProcessedTx {
- tx: Tx::from(TxType::Decrypted(DecryptedTx::Undecryptable(
- wrapper.clone(),
- )))
- .to_bytes(),
+ tx: Tx::new(TxType::Decrypted(DecryptedTx::Undecryptable))
+ .to_bytes(),
result: TxResult {
code: ErrorCodes::Ok.into(),
info: "".into(),
},
};
- shell.enqueue_tx(wrapper);
+ let tx = Tx::new(TxType::Wrapper(Box::new(wrapper)));
+ shell.enqueue_tx(tx);
// check that correct error message is returned
for event in shell
@@ -1149,37 +1153,35 @@ mod test_finalize_block {
// create two decrypted txs
let tx_code = TestWasms::TxNoOp.read_bytes();
for i in 0..2 {
- let raw_tx = Tx::new(
- tx_code.clone(),
- Some(
- format!("Decrypted transaction data: {}", i)
- .as_bytes()
- .to_owned(),
- ),
- shell.chain_id.clone(),
- None,
- );
- let wrapper_tx = WrapperTx::new(
- Fee {
- amount: MIN_FEE.into(),
- token: shell.wl_storage.storage.native_token.clone(),
- },
- &keypair,
- Epoch(0),
- 0.into(),
- raw_tx.clone(),
- Default::default(),
+ let mut outer_tx =
+ Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
+ Fee {
+ amount: MIN_FEE.into(),
+ token: shell.wl_storage.storage.native_token.clone(),
+ },
+ &keypair,
+ Epoch(0),
+ 0.into(),
+ #[cfg(not(feature = "mainnet"))]
+ None,
+ ))));
+ outer_tx.header.chain_id = shell.chain_id.clone();
+ outer_tx.set_code(Code::new(tx_code.clone()));
+ outer_tx.set_data(Data::new(
+ format!("Decrypted transaction data: {}", i)
+ .as_bytes()
+ .to_owned(),
+ ));
+ outer_tx.encrypt(&Default::default());
+ shell.enqueue_tx(outer_tx.clone());
+ outer_tx.update_header(TxType::Decrypted(DecryptedTx::Decrypted {
#[cfg(not(feature = "mainnet"))]
- None,
- );
- shell.enqueue_tx(wrapper_tx);
+ has_valid_pow: false,
+ }));
+ outer_tx.decrypt(::G2Affine::prime_subgroup_generator())
+ .expect("Test failed");
processed_txs.push(ProcessedTx {
- tx: Tx::from(TxType::Decrypted(DecryptedTx::Decrypted {
- tx: raw_tx,
- #[cfg(not(feature = "mainnet"))]
- has_valid_pow: false,
- }))
- .to_bytes(),
+ tx: outer_tx.to_bytes(),
result: TxResult {
code: ErrorCodes::Ok.into(),
info: "".into(),
@@ -1188,35 +1190,33 @@ mod test_finalize_block {
}
// create two wrapper txs
for i in 0..2 {
- let raw_tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some(
- format!("Encrypted transaction data: {}", i)
- .as_bytes()
- .to_owned(),
- ),
- shell.chain_id.clone(),
- None,
- );
- let wrapper_tx = WrapperTx::new(
- Fee {
- amount: MIN_FEE.into(),
- token: shell.wl_storage.storage.native_token.clone(),
- },
+ let mut wrapper_tx =
+ Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
+ Fee {
+ amount: MIN_FEE.into(),
+ token: shell.wl_storage.storage.native_token.clone(),
+ },
+ &keypair,
+ Epoch(0),
+ 0.into(),
+ #[cfg(not(feature = "mainnet"))]
+ None,
+ ))));
+ wrapper_tx.header.chain_id = shell.chain_id.clone();
+ wrapper_tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ wrapper_tx.set_data(Data::new(
+ format!("Encrypted transaction data: {}", i)
+ .as_bytes()
+ .to_owned(),
+ ));
+ wrapper_tx.add_section(Section::Signature(Signature::new(
+ &wrapper_tx.header_hash(),
&keypair,
- Epoch(0),
- 0.into(),
- raw_tx.clone(),
- Default::default(),
- #[cfg(not(feature = "mainnet"))]
- None,
- );
- let wrapper = wrapper_tx
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Test failed");
- valid_txs.push(wrapper_tx);
+ )));
+ wrapper_tx.encrypt(&Default::default());
+ valid_txs.push(wrapper_tx.clone());
processed_txs.push(ProcessedTx {
- tx: wrapper.to_bytes(),
+ tx: wrapper_tx.to_bytes(),
result: TxResult {
code: ErrorCodes::Ok.into(),
info: "".into(),
@@ -1262,10 +1262,9 @@ mod test_finalize_block {
let mut counter = 0;
for wrapper in shell.iter_tx_queue() {
- assert_eq!(
- wrapper.tx.tx_hash,
- txs.next().expect("Test failed").tx_hash
- );
+ let next = txs.next().expect("Test failed");
+ assert_eq!(wrapper.tx.header.code_hash, *next.code_sechash());
+ assert_eq!(wrapper.tx.header.data_hash, *next.data_sechash());
counter += 1;
}
assert_eq!(counter, 2);
@@ -1507,7 +1506,7 @@ mod test_finalize_block {
// FINALIZE BLOCK 1. Tell Namada that val1 is the block proposer. We
// won't receive votes from TM since we receive votes at a 1-block
// delay, so votes will be empty here
- next_block_for_inflation(&mut shell, pkh1.clone(), vec![]);
+ next_block_for_inflation(&mut shell, pkh1.clone(), vec![], None);
assert!(
rewards_accumulator_handle()
.is_empty(&shell.wl_storage)
@@ -1517,7 +1516,7 @@ mod test_finalize_block {
// FINALIZE BLOCK 2. Tell Namada that val1 is the block proposer.
// Include votes that correspond to block 1. Make val2 the next block's
// proposer.
- next_block_for_inflation(&mut shell, pkh2.clone(), votes.clone());
+ next_block_for_inflation(&mut shell, pkh2.clone(), votes.clone(), None);
assert!(rewards_prod_1.is_empty(&shell.wl_storage).unwrap());
assert!(rewards_prod_2.is_empty(&shell.wl_storage).unwrap());
assert!(rewards_prod_3.is_empty(&shell.wl_storage).unwrap());
@@ -1540,7 +1539,7 @@ mod test_finalize_block {
);
// FINALIZE BLOCK 3, with val1 as proposer for the next block.
- next_block_for_inflation(&mut shell, pkh1.clone(), votes);
+ next_block_for_inflation(&mut shell, pkh1.clone(), votes, None);
assert!(rewards_prod_1.is_empty(&shell.wl_storage).unwrap());
assert!(rewards_prod_2.is_empty(&shell.wl_storage).unwrap());
assert!(rewards_prod_3.is_empty(&shell.wl_storage).unwrap());
@@ -1592,7 +1591,7 @@ mod test_finalize_block {
// FINALIZE BLOCK 4. The next block proposer will be val1. Only val1,
// val2, and val3 vote on this block.
- next_block_for_inflation(&mut shell, pkh1.clone(), votes.clone());
+ next_block_for_inflation(&mut shell, pkh1.clone(), votes.clone(), None);
assert!(rewards_prod_1.is_empty(&shell.wl_storage).unwrap());
assert!(rewards_prod_2.is_empty(&shell.wl_storage).unwrap());
assert!(rewards_prod_3.is_empty(&shell.wl_storage).unwrap());
@@ -1625,7 +1624,12 @@ mod test_finalize_block {
get_rewards_acc(&shell.wl_storage),
get_rewards_sum(&shell.wl_storage),
);
- next_block_for_inflation(&mut shell, pkh1.clone(), votes.clone());
+ next_block_for_inflation(
+ &mut shell,
+ pkh1.clone(),
+ votes.clone(),
+ None,
+ );
}
assert!(
rewards_accumulator_handle()
@@ -1680,12 +1684,26 @@ mod test_finalize_block {
shell: &mut TestShell,
proposer_address: Vec,
votes: Vec,
+ byzantine_validators: Option>,
) {
- let req = FinalizeBlock {
+ // Let the header time be always ahead of the next epoch min start time
+ let header = Header {
+ time: shell
+ .wl_storage
+ .storage
+ .next_epoch_min_start_time
+ .next_second(),
+ ..Default::default()
+ };
+ let mut req = FinalizeBlock {
+ header,
proposer_address,
votes,
..Default::default()
};
+ if let Some(byz_vals) = byzantine_validators {
+ req.byzantine_validators = byz_vals;
+ }
shell.finalize_block(req).unwrap();
shell.commit();
}
@@ -1701,29 +1719,35 @@ mod test_finalize_block {
wasm_path.push("wasm_for_tests/tx_no_op.wasm");
let tx_code = std::fs::read(wasm_path)
.expect("Expected a file at given code path");
- let raw_tx = Tx::new(
- tx_code,
- Some("Encrypted transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper_tx = WrapperTx::new(
- Fee {
- amount: 0.into(),
- token: shell.wl_storage.storage.native_token.clone(),
- },
- &keypair,
- Epoch(0),
- 0.into(),
- raw_tx.clone(),
- Default::default(),
+ let mut wrapper_tx =
+ Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
+ Fee {
+ amount: 0.into(),
+ token: shell.wl_storage.storage.native_token.clone(),
+ },
+ &keypair,
+ Epoch(0),
+ 0.into(),
+ #[cfg(not(feature = "mainnet"))]
+ None,
+ ))));
+ wrapper_tx.header.chain_id = shell.chain_id.clone();
+ wrapper_tx.set_code(Code::new(tx_code));
+ wrapper_tx.set_data(Data::new(
+ "Encrypted transaction data".as_bytes().to_owned(),
+ ));
+ let mut decrypted_tx = wrapper_tx.clone();
+ wrapper_tx.encrypt(&Default::default());
+
+ decrypted_tx.update_header(TxType::Decrypted(DecryptedTx::Decrypted {
#[cfg(not(feature = "mainnet"))]
- None,
- );
+ has_valid_pow: false,
+ }));
// Write inner hash in storage
- let inner_hash_key =
- replay_protection::get_tx_hash_key(&wrapper_tx.tx_hash);
+ let inner_hash_key = replay_protection::get_tx_hash_key(
+ &wrapper_tx.clone().update_header(TxType::Raw).header_hash(),
+ );
shell
.wl_storage
.storage
@@ -1731,12 +1755,7 @@ mod test_finalize_block {
.expect("Test failed");
let processed_tx = ProcessedTx {
- tx: Tx::from(TxType::Decrypted(DecryptedTx::Decrypted {
- tx: raw_tx,
- #[cfg(not(feature = "mainnet"))]
- has_valid_pow: false,
- }))
- .to_bytes(),
+ tx: decrypted_tx.to_bytes(),
result: TxResult {
code: ErrorCodes::Ok.into(),
info: "".into(),
@@ -1766,4 +1785,1226 @@ mod test_finalize_block {
// .0
// )
}
+
+ #[test]
+ fn test_ledger_slashing() -> storage_api::Result<()> {
+ let num_validators = 7_u64;
+ let (mut shell, _) = setup(num_validators);
+ let mut params = read_pos_params(&shell.wl_storage).unwrap();
+ params.unbonding_len = 4;
+ write_pos_params(&mut shell.wl_storage, params.clone())?;
+
+ let validator_set: Vec =
+ read_consensus_validator_set_addresses_with_stake(
+ &shell.wl_storage,
+ Epoch::default(),
+ )
+ .unwrap()
+ .into_iter()
+ .collect();
+
+ let val1 = validator_set[0].clone();
+ let val2 = validator_set[1].clone();
+
+ let initial_stake = val1.bonded_stake;
+ let total_initial_stake = num_validators * initial_stake;
+
+ let get_pkh = |address, epoch| {
+ let ck = validator_consensus_key_handle(&address)
+ .get(&shell.wl_storage, epoch, ¶ms)
+ .unwrap()
+ .unwrap();
+ let hash_string = tm_consensus_key_raw_hash(&ck);
+ HEXUPPER.decode(hash_string.as_bytes()).unwrap()
+ };
+
+ let mut all_pkhs: Vec> = Vec::new();
+ let mut behaving_pkhs: Vec> = Vec::new();
+ for (idx, validator) in validator_set.iter().enumerate() {
+ // Every validator should be in the consensus set
+ assert_eq!(
+ validator_state_handle(&validator.address)
+ .get(&shell.wl_storage, Epoch::default(), ¶ms)
+ .unwrap(),
+ Some(ValidatorState::Consensus)
+ );
+ all_pkhs.push(get_pkh(validator.address.clone(), Epoch::default()));
+ if idx > 1_usize {
+ behaving_pkhs
+ .push(get_pkh(validator.address.clone(), Epoch::default()));
+ }
+ }
+
+ let pkh1 = all_pkhs[0].clone();
+ let pkh2 = all_pkhs[1].clone();
+
+ // Finalize block 1 (no votes since this is the first block)
+ next_block_for_inflation(&mut shell, pkh1.clone(), vec![], None);
+
+ let votes = get_default_true_votes(
+ &shell.wl_storage,
+ shell.wl_storage.storage.block.epoch,
+ );
+ assert!(!votes.is_empty());
+ assert_eq!(votes.len(), 7_usize);
+
+ // For block 2, include the evidences found for block 1.
+ // NOTE: Only the type, height, and validator address fields from the
+ // Misbehavior struct are used in Namada
+ let byzantine_validators = vec![
+ Misbehavior {
+ r#type: 1,
+ validator: Some(Validator {
+ address: pkh1.clone(),
+ power: Default::default(),
+ }),
+ height: 1,
+ time: Default::default(),
+ total_voting_power: Default::default(),
+ },
+ Misbehavior {
+ r#type: 2,
+ validator: Some(Validator {
+ address: pkh2,
+ power: Default::default(),
+ }),
+ height: 1,
+ time: Default::default(),
+ total_voting_power: Default::default(),
+ },
+ ];
+ next_block_for_inflation(
+ &mut shell,
+ pkh1.clone(),
+ votes,
+ Some(byzantine_validators),
+ );
+
+ let processing_epoch = shell.wl_storage.storage.block.epoch
+ + params.unbonding_len
+ + 1_u64
+ + params.cubic_slashing_window_length;
+
+ // Check that the ValidatorState, enqueued slashes, and validator sets
+ // are properly updated
+ assert_eq!(
+ validator_state_handle(&val1.address)
+ .get(&shell.wl_storage, Epoch::default(), ¶ms)
+ .unwrap(),
+ Some(ValidatorState::Consensus)
+ );
+ assert_eq!(
+ validator_state_handle(&val2.address)
+ .get(&shell.wl_storage, Epoch::default(), ¶ms)
+ .unwrap(),
+ Some(ValidatorState::Consensus)
+ );
+ assert!(
+ enqueued_slashes_handle()
+ .at(&Epoch::default())
+ .is_empty(&shell.wl_storage)?
+ );
+ assert_eq!(
+ get_num_consensus_validators(&shell.wl_storage, Epoch::default())
+ .unwrap(),
+ 7_u64
+ );
+ for epoch in Epoch::default().next().iter_range(params.pipeline_len) {
+ assert_eq!(
+ validator_state_handle(&val1.address)
+ .get(&shell.wl_storage, epoch, ¶ms)
+ .unwrap(),
+ Some(ValidatorState::Jailed)
+ );
+ assert_eq!(
+ validator_state_handle(&val2.address)
+ .get(&shell.wl_storage, epoch, ¶ms)
+ .unwrap(),
+ Some(ValidatorState::Jailed)
+ );
+ assert!(
+ enqueued_slashes_handle()
+ .at(&epoch)
+ .is_empty(&shell.wl_storage)?
+ );
+ assert_eq!(
+ get_num_consensus_validators(&shell.wl_storage, epoch).unwrap(),
+ 5_u64
+ );
+ }
+ assert!(
+ !enqueued_slashes_handle()
+ .at(&processing_epoch)
+ .is_empty(&shell.wl_storage)?
+ );
+
+ // Advance to the processing epoch
+ let votes = get_default_true_votes(&shell.wl_storage, Epoch::default());
+ loop {
+ next_block_for_inflation(
+ &mut shell,
+ pkh1.clone(),
+ votes.clone(),
+ None,
+ );
+ // println!(
+ // "Block {} epoch {}",
+ // shell.wl_storage.storage.block.height,
+ // shell.wl_storage.storage.block.epoch
+ // );
+ if shell.wl_storage.storage.block.epoch == processing_epoch {
+ // println!("Reached processing epoch");
+ break;
+ } else {
+ assert!(
+ enqueued_slashes_handle()
+ .at(&shell.wl_storage.storage.block.epoch)
+ .is_empty(&shell.wl_storage)?
+ );
+ let stake1 = read_validator_stake(
+ &shell.wl_storage,
+ ¶ms,
+ &val1.address,
+ shell.wl_storage.storage.block.epoch,
+ )?
+ .unwrap();
+ let stake2 = read_validator_stake(
+ &shell.wl_storage,
+ ¶ms,
+ &val2.address,
+ shell.wl_storage.storage.block.epoch,
+ )?
+ .unwrap();
+ let total_stake = read_total_stake(
+ &shell.wl_storage,
+ ¶ms,
+ shell.wl_storage.storage.block.epoch,
+ )?;
+ assert_eq!(stake1, initial_stake);
+ assert_eq!(stake2, initial_stake);
+ assert_eq!(total_stake, total_initial_stake);
+ }
+ }
+
+ let num_slashes = storage_api::iter_prefix_bytes(
+ &shell.wl_storage,
+ &slashes_prefix(),
+ )?
+ .filter(|kv_res| {
+ let (k, _v) = kv_res.as_ref().unwrap();
+ is_validator_slashes_key(k).is_some()
+ })
+ .count();
+
+ assert_eq!(num_slashes, 2);
+ assert_eq!(
+ validator_slashes_handle(&val1.address)
+ .len(&shell.wl_storage)
+ .unwrap(),
+ 1_u64
+ );
+ assert_eq!(
+ validator_slashes_handle(&val2.address)
+ .len(&shell.wl_storage)
+ .unwrap(),
+ 1_u64
+ );
+
+ let slash1 = validator_slashes_handle(&val1.address)
+ .get(&shell.wl_storage, 0)?
+ .unwrap();
+ let slash2 = validator_slashes_handle(&val2.address)
+ .get(&shell.wl_storage, 0)?
+ .unwrap();
+
+ assert_eq!(slash1.r#type, SlashType::DuplicateVote);
+ assert_eq!(slash2.r#type, SlashType::LightClientAttack);
+ assert_eq!(slash1.epoch, Epoch::default());
+ assert_eq!(slash2.epoch, Epoch::default());
+
+ // Each validator has equal weight in this test, and two have been
+ // slashed
+ let frac = dec!(2) / dec!(7);
+ let cubic_rate = dec!(9) * frac * frac;
+
+ assert_eq!(slash1.rate, cubic_rate);
+ assert_eq!(slash2.rate, cubic_rate);
+
+ // Check that there are still 5 consensus validators and the 2
+ // misbehaving ones are still jailed
+ for epoch in shell
+ .wl_storage
+ .storage
+ .block
+ .epoch
+ .iter_range(params.pipeline_len + 1)
+ {
+ assert_eq!(
+ validator_state_handle(&val1.address)
+ .get(&shell.wl_storage, epoch, ¶ms)
+ .unwrap(),
+ Some(ValidatorState::Jailed)
+ );
+ assert_eq!(
+ validator_state_handle(&val2.address)
+ .get(&shell.wl_storage, epoch, ¶ms)
+ .unwrap(),
+ Some(ValidatorState::Jailed)
+ );
+ assert_eq!(
+ get_num_consensus_validators(&shell.wl_storage, epoch).unwrap(),
+ 5_u64
+ );
+ }
+
+ // Check that the deltas at the pipeline epoch are slashed
+ let pipeline_epoch =
+ shell.wl_storage.storage.block.epoch + params.pipeline_len;
+ let stake1 = read_validator_stake(
+ &shell.wl_storage,
+ ¶ms,
+ &val1.address,
+ pipeline_epoch,
+ )?
+ .unwrap();
+ let stake2 = read_validator_stake(
+ &shell.wl_storage,
+ ¶ms,
+ &val2.address,
+ pipeline_epoch,
+ )?
+ .unwrap();
+ let total_stake =
+ read_total_stake(&shell.wl_storage, ¶ms, pipeline_epoch)?;
+
+ let expected_slashed = decimal_mult_amount(cubic_rate, initial_stake);
+ assert_eq!(stake1, initial_stake - expected_slashed);
+ assert_eq!(stake2, initial_stake - expected_slashed);
+ assert_eq!(total_stake, total_initial_stake - 2 * expected_slashed);
+
+ // Unjail one of the validators
+ let current_epoch = shell.wl_storage.storage.block.epoch;
+ unjail_validator(&mut shell.wl_storage, &val1.address, current_epoch)?;
+ let pipeline_epoch = current_epoch + params.pipeline_len;
+
+ // Check that the state is the same until the pipeline epoch, at which
+ // point one validator is unjailed
+ for epoch in shell
+ .wl_storage
+ .storage
+ .block
+ .epoch
+ .iter_range(params.pipeline_len)
+ {
+ assert_eq!(
+ validator_state_handle(&val1.address)
+ .get(&shell.wl_storage, epoch, ¶ms)
+ .unwrap(),
+ Some(ValidatorState::Jailed)
+ );
+ assert_eq!(
+ validator_state_handle(&val2.address)
+ .get(&shell.wl_storage, epoch, ¶ms)
+ .unwrap(),
+ Some(ValidatorState::Jailed)
+ );
+ assert_eq!(
+ get_num_consensus_validators(&shell.wl_storage, epoch).unwrap(),
+ 5_u64
+ );
+ }
+ assert_eq!(
+ validator_state_handle(&val1.address)
+ .get(&shell.wl_storage, pipeline_epoch, ¶ms)
+ .unwrap(),
+ Some(ValidatorState::Consensus)
+ );
+ assert_eq!(
+ validator_state_handle(&val2.address)
+ .get(&shell.wl_storage, pipeline_epoch, ¶ms)
+ .unwrap(),
+ Some(ValidatorState::Jailed)
+ );
+ assert_eq!(
+ get_num_consensus_validators(&shell.wl_storage, pipeline_epoch)
+ .unwrap(),
+ 6_u64
+ );
+
+ Ok(())
+ }
+
+ /// NOTE: must call `get_default_true_votes` before every call to
+ /// `next_block_for_inflation`
+ #[test]
+ fn test_multiple_misbehaviors() -> storage_api::Result<()> {
+ for num_validators in 4u64..10u64 {
+ println!("NUM VALIDATORS = {}", num_validators);
+ test_multiple_misbehaviors_by_num_vals(num_validators)?;
+ }
+ Ok(())
+ }
+
+ /// Current test procedure (prefixed by epoch in which the event occurs):
+ /// 0) Validator initial stake of 200_000
+ /// 1) Delegate 67_231 to validator
+ /// 1) Self-unbond 154_654
+ /// 2) Unbond delegation of 18_000
+ /// 3) Self-bond 9_123
+ /// 4) Self-unbond 15_000
+ /// 5) Delegate 8_144 to validator
+ /// 6) Discover misbehavior in epoch 3
+ /// 7) Discover misbehavior in epoch 3
+ /// 7) Discover misbehavior in epoch 4
+ fn test_multiple_misbehaviors_by_num_vals(
+ num_validators: u64,
+ ) -> storage_api::Result<()> {
+ // Setup the network with pipeline_len = 2, unbonding_len = 4
+ // let num_validators = 8_u64;
+ let (mut shell, _) = setup(num_validators);
+ let mut params = read_pos_params(&shell.wl_storage).unwrap();
+ params.unbonding_len = 4;
+ params.max_validator_slots = 4;
+ write_pos_params(&mut shell.wl_storage, params.clone())?;
+
+ // Slash pool balance
+ let nam_address = shell.wl_storage.storage.native_token.clone();
+ let slash_balance_key = token::balance_key(
+ &nam_address,
+ &namada_proof_of_stake::SLASH_POOL_ADDRESS,
+ );
+ let slash_pool_balance_init: token::Amount = shell
+ .wl_storage
+ .read(&slash_balance_key)
+ .expect("must be able to read")
+ .unwrap_or_default();
+ debug_assert_eq!(slash_pool_balance_init, token::Amount::default());
+
+ let consensus_set: Vec =
+ read_consensus_validator_set_addresses_with_stake(
+ &shell.wl_storage,
+ Epoch::default(),
+ )
+ .unwrap()
+ .into_iter()
+ .collect();
+
+ let val1 = consensus_set[0].clone();
+ let pkh1 = get_pkh_from_address(
+ &shell.wl_storage,
+ ¶ms,
+ val1.address.clone(),
+ Epoch::default(),
+ );
+
+ let initial_stake = val1.bonded_stake;
+ let total_initial_stake = num_validators * initial_stake;
+
+ // Finalize block 1
+ next_block_for_inflation(&mut shell, pkh1.clone(), vec![], None);
+
+ let votes = get_default_true_votes(&shell.wl_storage, Epoch::default());
+ assert!(!votes.is_empty());
+
+ // Advance to epoch 1 and
+ // 1. Delegate 67231 NAM to validator
+ // 2. Validator self-unbond 154654 NAM
+ let current_epoch = advance_epoch(&mut shell, &pkh1, &votes, None);
+ assert_eq!(shell.wl_storage.storage.block.epoch.0, 1_u64);
+
+ // Make an account with balance and delegate some tokens
+ let delegator = address::testing::gen_implicit_address();
+ let del_1_amount = token::Amount::whole(67_231);
+ let staking_token = shell.wl_storage.storage.native_token.clone();
+ credit_tokens(
+ &mut shell.wl_storage,
+ &staking_token,
+ &delegator,
+ token::Amount::whole(200_000),
+ )
+ .unwrap();
+ namada_proof_of_stake::bond_tokens(
+ &mut shell.wl_storage,
+ Some(&delegator),
+ &val1.address,
+ del_1_amount,
+ current_epoch,
+ )
+ .unwrap();
+
+ // Self-unbond
+ let self_unbond_1_amount = token::Amount::whole(154_654);
+ namada_proof_of_stake::unbond_tokens(
+ &mut shell.wl_storage,
+ None,
+ &val1.address,
+ self_unbond_1_amount,
+ current_epoch,
+ )
+ .unwrap();
+
+ let val_stake = namada_proof_of_stake::read_validator_stake(
+ &shell.wl_storage,
+ ¶ms,
+ &val1.address,
+ current_epoch + params.pipeline_len,
+ )
+ .unwrap()
+ .unwrap_or_default();
+
+ let total_stake = namada_proof_of_stake::read_total_stake(
+ &shell.wl_storage,
+ ¶ms,
+ current_epoch + params.pipeline_len,
+ )
+ .unwrap();
+
+ assert_eq!(
+ val_stake,
+ initial_stake + del_1_amount - self_unbond_1_amount
+ );
+ assert_eq!(
+ total_stake,
+ total_initial_stake + del_1_amount - self_unbond_1_amount
+ );
+
+ // Advance to epoch 2 and
+ // 1. Unbond 18000 NAM from delegation
+ let votes = get_default_true_votes(
+ &shell.wl_storage,
+ shell.wl_storage.storage.block.epoch,
+ );
+ let current_epoch = advance_epoch(&mut shell, &pkh1, &votes, None);
+ println!("\nUnbonding in epoch 2");
+ let del_unbond_1_amount = token::Amount::whole(18_000);
+ namada_proof_of_stake::unbond_tokens(
+ &mut shell.wl_storage,
+ Some(&delegator),
+ &val1.address,
+ del_unbond_1_amount,
+ current_epoch,
+ )
+ .unwrap();
+
+ let val_stake = namada_proof_of_stake::read_validator_stake(
+ &shell.wl_storage,
+ ¶ms,
+ &val1.address,
+ current_epoch + params.pipeline_len,
+ )
+ .unwrap()
+ .unwrap_or_default();
+ let total_stake = namada_proof_of_stake::read_total_stake(
+ &shell.wl_storage,
+ ¶ms,
+ current_epoch + params.pipeline_len,
+ )
+ .unwrap();
+ assert_eq!(
+ val_stake,
+ initial_stake + del_1_amount
+ - self_unbond_1_amount
+ - del_unbond_1_amount
+ );
+ assert_eq!(
+ total_stake,
+ total_initial_stake + del_1_amount
+ - self_unbond_1_amount
+ - del_unbond_1_amount
+ );
+
+ // Advance to epoch 3 and
+ // 1. Validator self-bond 9123 NAM
+ let votes = get_default_true_votes(
+ &shell.wl_storage,
+ shell.wl_storage.storage.block.epoch,
+ );
+ let current_epoch = advance_epoch(&mut shell, &pkh1, &votes, None);
+ println!("\nBonding in epoch 3");
+
+ let self_bond_1_amount = token::Amount::whole(9_123);
+ namada_proof_of_stake::bond_tokens(
+ &mut shell.wl_storage,
+ None,
+ &val1.address,
+ self_bond_1_amount,
+ current_epoch,
+ )
+ .unwrap();
+
+ // Advance to epoch 4
+ // 1. Validator self-unbond 15000 NAM
+ let votes = get_default_true_votes(
+ &shell.wl_storage,
+ shell.wl_storage.storage.block.epoch,
+ );
+ let current_epoch = advance_epoch(&mut shell, &pkh1, &votes, None);
+ assert_eq!(current_epoch.0, 4_u64);
+
+ let self_unbond_2_amount = token::Amount::whole(15_000);
+ namada_proof_of_stake::unbond_tokens(
+ &mut shell.wl_storage,
+ None,
+ &val1.address,
+ self_unbond_2_amount,
+ current_epoch,
+ )
+ .unwrap();
+
+ // Advance to epoch 5 and
+ // Delegate 8144 NAM to validator
+ let votes = get_default_true_votes(
+ &shell.wl_storage,
+ shell.wl_storage.storage.block.epoch,
+ );
+ let current_epoch = advance_epoch(&mut shell, &pkh1, &votes, None);
+ assert_eq!(current_epoch.0, 5_u64);
+ println!("Delegating in epoch 5");
+
+ // Delegate
+ let del_2_amount = token::Amount::whole(8_144);
+ namada_proof_of_stake::bond_tokens(
+ &mut shell.wl_storage,
+ Some(&delegator),
+ &val1.address,
+ del_2_amount,
+ current_epoch,
+ )
+ .unwrap();
+
+ println!("Advancing to epoch 6");
+
+ // Advance to epoch 6
+ let votes = get_default_true_votes(
+ &shell.wl_storage,
+ shell.wl_storage.storage.block.epoch,
+ );
+ let current_epoch = advance_epoch(&mut shell, &pkh1, &votes, None);
+ assert_eq!(current_epoch.0, 6_u64);
+
+ // Discover a misbehavior committed in epoch 3
+ // NOTE: Only the type, height, and validator address fields from the
+ // Misbehavior struct are used in Namada
+ let misbehavior_epoch = Epoch(3_u64);
+ let height = shell
+ .wl_storage
+ .storage
+ .block
+ .pred_epochs
+ .first_block_heights[misbehavior_epoch.0 as usize];
+ let misbehaviors = vec![Misbehavior {
+ r#type: 1,
+ validator: Some(Validator {
+ address: pkh1.clone(),
+ power: Default::default(),
+ }),
+ height: height.0 as i64,
+ time: Default::default(),
+ total_voting_power: Default::default(),
+ }];
+ let votes = get_default_true_votes(
+ &shell.wl_storage,
+ shell.wl_storage.storage.block.epoch,
+ );
+ next_block_for_inflation(
+ &mut shell,
+ pkh1.clone(),
+ votes.clone(),
+ Some(misbehaviors),
+ );
+
+ // Assertions
+ assert_eq!(current_epoch.0, 6_u64);
+ let processing_epoch = misbehavior_epoch
+ + params.unbonding_len
+ + 1_u64
+ + params.cubic_slashing_window_length;
+ let enqueued_slash = enqueued_slashes_handle()
+ .at(&processing_epoch)
+ .at(&val1.address)
+ .front(&shell.wl_storage)
+ .unwrap()
+ .unwrap();
+ assert_eq!(enqueued_slash.epoch, misbehavior_epoch);
+ assert_eq!(enqueued_slash.r#type, SlashType::DuplicateVote);
+ assert_eq!(enqueued_slash.rate, Decimal::ZERO);
+ let last_slash =
+ namada_proof_of_stake::read_validator_last_slash_epoch(
+ &shell.wl_storage,
+ &val1.address,
+ )
+ .unwrap();
+ assert_eq!(last_slash, Some(misbehavior_epoch));
+ assert!(
+ namada_proof_of_stake::validator_slashes_handle(&val1.address)
+ .is_empty(&shell.wl_storage)
+ .unwrap()
+ );
+
+ println!("Advancing to epoch 7");
+
+ // Advance to epoch 7
+ let current_epoch = advance_epoch(&mut shell, &pkh1, &votes, None);
+
+ // Discover two more misbehaviors, one committed in epoch 3, one in
+ // epoch 4
+ let height4 = shell
+ .wl_storage
+ .storage
+ .block
+ .pred_epochs
+ .first_block_heights[4];
+ let misbehaviors = vec![
+ Misbehavior {
+ r#type: 1,
+ validator: Some(Validator {
+ address: pkh1.clone(),
+ power: Default::default(),
+ }),
+ height: height.0 as i64,
+ time: Default::default(),
+ total_voting_power: Default::default(),
+ },
+ Misbehavior {
+ r#type: 2,
+ validator: Some(Validator {
+ address: pkh1.clone(),
+ power: Default::default(),
+ }),
+ height: height4.0 as i64,
+ time: Default::default(),
+ total_voting_power: Default::default(),
+ },
+ ];
+ next_block_for_inflation(
+ &mut shell,
+ pkh1.clone(),
+ votes.clone(),
+ Some(misbehaviors),
+ );
+ assert_eq!(current_epoch.0, 7_u64);
+ let enqueued_slashes_8 = enqueued_slashes_handle()
+ .at(&processing_epoch)
+ .at(&val1.address);
+ let enqueued_slashes_9 = enqueued_slashes_handle()
+ .at(&processing_epoch.next())
+ .at(&val1.address);
+
+ assert_eq!(enqueued_slashes_8.len(&shell.wl_storage).unwrap(), 2_u64);
+ assert_eq!(enqueued_slashes_9.len(&shell.wl_storage).unwrap(), 1_u64);
+ let last_slash =
+ namada_proof_of_stake::read_validator_last_slash_epoch(
+ &shell.wl_storage,
+ &val1.address,
+ )
+ .unwrap();
+ assert_eq!(last_slash, Some(Epoch(4)));
+ assert!(
+ namada_proof_of_stake::is_validator_frozen(
+ &shell.wl_storage,
+ &val1.address,
+ current_epoch,
+ ¶ms
+ )
+ .unwrap()
+ );
+ assert!(
+ namada_proof_of_stake::validator_slashes_handle(&val1.address)
+ .is_empty(&shell.wl_storage)
+ .unwrap()
+ );
+
+ let pre_stake_10 = namada_proof_of_stake::read_validator_stake(
+ &shell.wl_storage,
+ ¶ms,
+ &val1.address,
+ Epoch(10),
+ )
+ .unwrap()
+ .unwrap_or_default();
+ assert_eq!(
+ pre_stake_10,
+ initial_stake + del_1_amount
+ - self_unbond_1_amount
+ - del_unbond_1_amount
+ + self_bond_1_amount
+ - self_unbond_2_amount
+ + del_2_amount
+ );
+
+ println!("\nNow processing the infractions\n");
+
+ // Advance to epoch 9, where the infractions committed in epoch 3 will
+ // be processed
+ let votes = get_default_true_votes(
+ &shell.wl_storage,
+ shell.wl_storage.storage.block.epoch,
+ );
+ let _ = advance_epoch(&mut shell, &pkh1, &votes, None);
+ let votes = get_default_true_votes(
+ &shell.wl_storage,
+ shell.wl_storage.storage.block.epoch,
+ );
+ let current_epoch = advance_epoch(&mut shell, &pkh1, &votes, None);
+ assert_eq!(current_epoch.0, 9_u64);
+
+ let val_stake_3 = namada_proof_of_stake::read_validator_stake(
+ &shell.wl_storage,
+ ¶ms,
+ &val1.address,
+ Epoch(3),
+ )
+ .unwrap()
+ .unwrap_or_default();
+ let val_stake_4 = namada_proof_of_stake::read_validator_stake(
+ &shell.wl_storage,
+ ¶ms,
+ &val1.address,
+ Epoch(4),
+ )
+ .unwrap()
+ .unwrap_or_default();
+
+ let tot_stake_3 = namada_proof_of_stake::read_total_stake(
+ &shell.wl_storage,
+ ¶ms,
+ Epoch(3),
+ )
+ .unwrap();
+ let tot_stake_4 = namada_proof_of_stake::read_total_stake(
+ &shell.wl_storage,
+ ¶ms,
+ Epoch(4),
+ )
+ .unwrap();
+
+ let vp_frac_3 = Decimal::from(val_stake_3) / Decimal::from(tot_stake_3);
+ let vp_frac_4 = Decimal::from(val_stake_4) / Decimal::from(tot_stake_4);
+ let tot_frac = dec!(2) * vp_frac_3 + vp_frac_4;
+ let cubic_rate =
+ std::cmp::min(Decimal::ONE, dec!(9) * tot_frac * tot_frac);
+ dbg!(&cubic_rate);
+
+ let equal_enough = |rate1: Decimal, rate2: Decimal| -> bool {
+ let tolerance = dec!(0.000000001);
+ (rate1 - rate2).abs() < tolerance
+ };
+
+ // There should be 2 slashes processed for the validator, each with rate
+ // equal to the cubic slashing rate
+ let val_slashes =
+ namada_proof_of_stake::validator_slashes_handle(&val1.address);
+ assert_eq!(val_slashes.len(&shell.wl_storage).unwrap(), 2u64);
+ let is_rate_good = val_slashes
+ .iter(&shell.wl_storage)
+ .unwrap()
+ .all(|s| equal_enough(s.unwrap().rate, cubic_rate));
+ assert!(is_rate_good);
+
+ // Check the amount of stake deducted from the futuremost epoch while
+ // processing the slashes
+ let post_stake_10 = namada_proof_of_stake::read_validator_stake(
+ &shell.wl_storage,
+ ¶ms,
+ &val1.address,
+ Epoch(10),
+ )
+ .unwrap()
+ .unwrap_or_default();
+ // The amount unbonded after the infraction that affected the deltas
+ // before processing is `del_unbond_1_amount + self_bond_1_amount -
+ // self_unbond_2_amount` (since this self-bond was enacted then unbonded
+ // all after the infraction). Thus, the additional deltas to be
+ // deducted is the (infraction stake - this) * rate
+ let slash_rate_3 = std::cmp::min(Decimal::ONE, dec!(2) * cubic_rate);
+ let exp_slashed_during_processing_9 = decimal_mult_amount(
+ slash_rate_3,
+ initial_stake + del_1_amount
+ - self_unbond_1_amount
+ - del_unbond_1_amount
+ + self_bond_1_amount
+ - self_unbond_2_amount,
+ );
+ assert_eq!(
+ pre_stake_10 - post_stake_10,
+ exp_slashed_during_processing_9
+ );
+
+ // Check that we can compute the stake at the pipeline epoch
+ // NOTE: may be off. by 1 namnam due to rounding;
+ let exp_pipeline_stake = decimal_mult_amount(
+ Decimal::ONE - slash_rate_3,
+ initial_stake + del_1_amount
+ - self_unbond_1_amount
+ - del_unbond_1_amount
+ + self_bond_1_amount
+ - self_unbond_2_amount,
+ ) + del_2_amount;
+ assert!(
+ (exp_pipeline_stake.change() - post_stake_10.change()).abs() <= 1
+ );
+
+ // Check the balance of the Slash Pool
+ // TODO: finish once implemented
+ // let slash_pool_balance: token::Amount = shell
+ // .wl_storage
+ // .read(&slash_balance_key)
+ // .expect("must be able to read")
+ // .unwrap_or_default();
+ // let exp_slashed_3 = decimal_mult_amount(
+ // std::cmp::min(Decimal::TWO * cubic_rate, Decimal::ONE),
+ // val_stake_3 - del_unbond_1_amount + self_bond_1_amount
+ // - self_unbond_2_amount,
+ // );
+ // assert_eq!(slash_pool_balance, exp_slashed_3);
+
+ let _pre_stake_11 = namada_proof_of_stake::read_validator_stake(
+ &shell.wl_storage,
+ ¶ms,
+ &val1.address,
+ Epoch(10),
+ )
+ .unwrap()
+ .unwrap_or_default();
+
+ // Advance to epoch 10, where the infraction committed in epoch 4 will
+ // be processed
+ let votes = get_default_true_votes(
+ &shell.wl_storage,
+ shell.wl_storage.storage.block.epoch,
+ );
+ let current_epoch = advance_epoch(&mut shell, &pkh1, &votes, None);
+ assert_eq!(current_epoch.0, 10_u64);
+
+ // Check the balance of the Slash Pool
+ // TODO: finish once implemented
+ // let slash_pool_balance: token::Amount = shell
+ // .wl_storage
+ // .read(&slash_balance_key)
+ // .expect("must be able to read")
+ // .unwrap_or_default();
+
+ // let exp_slashed_4 = if dec!(2) * cubic_rate >= Decimal::ONE {
+ // token::Amount::default()
+ // } else if dec!(3) * cubic_rate >= Decimal::ONE {
+ // decimal_mult_amount(
+ // Decimal::ONE - dec!(2) * cubic_rate,
+ // val_stake_4 + self_bond_1_amount - self_unbond_2_amount,
+ // )
+ // } else {
+ // decimal_mult_amount(
+ // std::cmp::min(cubic_rate, Decimal::ONE),
+ // val_stake_4 + self_bond_1_amount - self_unbond_2_amount,
+ // )
+ // };
+ // dbg!(slash_pool_balance, exp_slashed_3 + exp_slashed_4);
+ // assert!(
+ // (slash_pool_balance.change()
+ // - (exp_slashed_3 + exp_slashed_4).change())
+ // .abs()
+ // <= 1
+ // );
+
+ let val_stake = read_validator_stake(
+ &shell.wl_storage,
+ ¶ms,
+ &val1.address,
+ current_epoch + params.pipeline_len,
+ )?
+ .unwrap_or_default();
+
+ let post_stake_11 = namada_proof_of_stake::read_validator_stake(
+ &shell.wl_storage,
+ ¶ms,
+ &val1.address,
+ Epoch(10),
+ )
+ .unwrap()
+ .unwrap_or_default();
+
+ assert_eq!(post_stake_11, val_stake);
+ // dbg!(&val_stake);
+ // dbg!(pre_stake_10 - post_stake_10);
+
+ // dbg!(&exp_slashed_during_processing_9);
+ // TODO: finish once implemented
+ // assert!(
+ // ((pre_stake_11 - post_stake_11).change() -
+ // exp_slashed_4.change()) .abs()
+ // <= 1
+ // );
+
+ // dbg!(&val_stake, &exp_stake);
+ // dbg!(exp_slashed_during_processing_8 +
+ // exp_slashed_during_processing_9); dbg!(
+ // val_stake_3
+ // - (exp_slashed_during_processing_8 +
+ // exp_slashed_during_processing_9)
+ // );
+
+ // let exp_stake = val_stake_3 - del_unbond_1_amount +
+ // self_bond_1_amount
+ // - self_unbond_2_amount
+ // + del_2_amount
+ // - exp_slashed_3
+ // - exp_slashed_4;
+
+ // assert!((exp_stake.change() - post_stake_11.change()).abs() <= 1);
+
+ for _ in 0..2 {
+ let votes = get_default_true_votes(
+ &shell.wl_storage,
+ shell.wl_storage.storage.block.epoch,
+ );
+ let _ = advance_epoch(&mut shell, &pkh1, &votes, None);
+ }
+ let current_epoch = shell.wl_storage.storage.block.epoch;
+ assert_eq!(current_epoch.0, 12_u64);
+
+ println!("\nCHECK BOND AND UNBOND DETAILS");
+ let details = namada_proof_of_stake::bonds_and_unbonds(
+ &shell.wl_storage,
+ None,
+ None,
+ )
+ .unwrap();
+
+ let del_id = BondId {
+ source: delegator.clone(),
+ validator: val1.address.clone(),
+ };
+ let self_id = BondId {
+ source: val1.address.clone(),
+ validator: val1.address.clone(),
+ };
+
+ let del_details = details.get(&del_id).unwrap();
+ let self_details = details.get(&self_id).unwrap();
+ // dbg!(del_details, self_details);
+
+ // Check slashes
+ assert_eq!(del_details.slashes, self_details.slashes);
+ assert_eq!(del_details.slashes.len(), 3);
+ assert_eq!(del_details.slashes[0].epoch, Epoch(3));
+ assert!(equal_enough(del_details.slashes[0].rate, cubic_rate));
+ assert_eq!(del_details.slashes[1].epoch, Epoch(3));
+ assert!(equal_enough(del_details.slashes[1].rate, cubic_rate));
+ assert_eq!(del_details.slashes[2].epoch, Epoch(4));
+ assert!(equal_enough(del_details.slashes[2].rate, cubic_rate));
+
+ // Check delegations
+ assert_eq!(del_details.bonds.len(), 2);
+ assert_eq!(del_details.bonds[0].start, Epoch(3));
+ assert_eq!(
+ del_details.bonds[0].amount,
+ del_1_amount - del_unbond_1_amount
+ );
+ // TODO: decimal mult issues should be resolved with PR 1282
+ assert!(
+ (del_details.bonds[0].slashed_amount.unwrap().change()
+ - decimal_mult_amount(
+ std::cmp::min(Decimal::ONE, dec!(3) * cubic_rate),
+ del_1_amount - del_unbond_1_amount
+ )
+ .change())
+ .abs()
+ <= 2
+ );
+ assert_eq!(del_details.bonds[1].start, Epoch(7));
+ assert_eq!(del_details.bonds[1].amount, del_2_amount);
+ assert_eq!(del_details.bonds[1].slashed_amount, None);
+
+ // Check self-bonds
+ assert_eq!(self_details.bonds.len(), 1);
+ assert_eq!(self_details.bonds[0].start, Epoch(0));
+ assert_eq!(
+ self_details.bonds[0].amount,
+ initial_stake - self_unbond_1_amount + self_bond_1_amount
+ - self_unbond_2_amount
+ );
+ // TODO: not sure why this is correct??? (with + self_bond_1_amount -
+ // self_unbond_2_amount)
+ // TODO: Make sure this is sound and what we expect
+ assert_eq!(
+ self_details.bonds[0].slashed_amount,
+ Some(decimal_mult_amount(
+ std::cmp::min(Decimal::ONE, dec!(3) * cubic_rate),
+ initial_stake - self_unbond_1_amount + self_bond_1_amount
+ - self_unbond_2_amount
+ ))
+ );
+
+ // Check delegation unbonds
+ assert_eq!(del_details.unbonds.len(), 1);
+ assert_eq!(del_details.unbonds[0].start, Epoch(3));
+ assert_eq!(del_details.unbonds[0].withdraw, Epoch(9));
+ assert_eq!(del_details.unbonds[0].amount, del_unbond_1_amount);
+ assert!(
+ (del_details.unbonds[0].slashed_amount.unwrap().change()
+ - decimal_mult_amount(
+ std::cmp::min(Decimal::ONE, dec!(2) * cubic_rate),
+ del_unbond_1_amount
+ )
+ .change())
+ .abs()
+ <= 1
+ );
+
+ // Check self-unbonds
+ assert_eq!(self_details.unbonds.len(), 3);
+ assert_eq!(self_details.unbonds[0].start, Epoch(0));
+ assert_eq!(self_details.unbonds[0].withdraw, Epoch(8));
+ assert_eq!(self_details.unbonds[1].start, Epoch(0));
+ assert_eq!(self_details.unbonds[1].withdraw, Epoch(11));
+ assert_eq!(self_details.unbonds[2].start, Epoch(5));
+ assert_eq!(self_details.unbonds[2].withdraw, Epoch(11));
+ assert_eq!(self_details.unbonds[0].amount, self_unbond_1_amount);
+ assert_eq!(self_details.unbonds[0].slashed_amount, None);
+ assert_eq!(
+ self_details.unbonds[1].amount,
+ self_unbond_2_amount - self_bond_1_amount
+ );
+ assert_eq!(
+ self_details.unbonds[1].slashed_amount,
+ Some(decimal_mult_amount(
+ std::cmp::min(Decimal::ONE, dec!(3) * cubic_rate),
+ self_unbond_2_amount - self_bond_1_amount
+ ))
+ );
+ assert_eq!(self_details.unbonds[2].amount, self_bond_1_amount);
+ assert_eq!(self_details.unbonds[2].slashed_amount, None);
+
+ println!("\nWITHDRAWING DELEGATION UNBOND");
+ // let slash_pool_balance_pre_withdraw = slash_pool_balance;
+ // Withdraw the delegation unbonds, which total to 18_000. This should
+ // only be affected by the slashes in epoch 3
+ let del_withdraw = namada_proof_of_stake::withdraw_tokens(
+ &mut shell.wl_storage,
+ Some(&delegator),
+ &val1.address,
+ current_epoch,
+ )
+ .unwrap();
+
+ let exp_del_withdraw_slashed_amount =
+ decimal_mult_amount(slash_rate_3, del_unbond_1_amount);
+ assert_eq!(
+ del_withdraw,
+ del_unbond_1_amount - exp_del_withdraw_slashed_amount
+ );
+
+ // TODO: finish once implemented
+ // Check the balance of the Slash Pool
+ // let slash_pool_balance: token::Amount = shell
+ // .wl_storage
+ // .read(&slash_balance_key)
+ // .expect("must be able to read")
+ // .unwrap_or_default();
+ // dbg!(del_withdraw, slash_pool_balance);
+ // assert_eq!(
+ // slash_pool_balance - slash_pool_balance_pre_withdraw,
+ // exp_del_withdraw_slashed_amount
+ // );
+
+ // println!("\nWITHDRAWING SELF UNBOND");
+ // Withdraw the self unbonds, which total 154_654 + 15_000 - 9_123. Only
+ // the (15_000 - 9_123) tokens are slashable.
+ // let self_withdraw = namada_proof_of_stake::withdraw_tokens(
+ // &mut shell.wl_storage,
+ // None,
+ // &val1.address,
+ // current_epoch,
+ // )
+ // .unwrap();
+
+ // let exp_self_withdraw_slashed_amount = decimal_mult_amount(
+ // std::cmp::min(dec!(3) * cubic_rate, Decimal::ONE),
+ // self_unbond_2_amount - self_bond_1_amount,
+ // );
+ // Check the balance of the Slash Pool
+ // let slash_pool_balance: token::Amount = shell
+ // .wl_storage
+ // .read(&slash_balance_key)
+ // .expect("must be able to read")
+ // .unwrap_or_default();
+
+ // dbg!(self_withdraw, slash_pool_balance);
+ // dbg!(
+ // decimal_mult_amount(dec!(2) * cubic_rate, val_stake_3)
+ // + decimal_mult_amount(cubic_rate, val_stake_4)
+ // );
+
+ // assert_eq!(
+ // exp_self_withdraw_slashed_amount,
+ // slash_pool_balance
+ // - slash_pool_balance_pre_withdraw
+ // - exp_del_withdraw_slashed_amount
+ // );
+
+ Ok(())
+ }
+
+ fn get_default_true_votes(storage: &S, epoch: Epoch) -> Vec
+ where
+ S: StorageRead,
+ {
+ let params = read_pos_params(storage).unwrap();
+ read_consensus_validator_set_addresses_with_stake(storage, epoch)
+ .unwrap()
+ .into_iter()
+ .map(|val| {
+ let pkh = get_pkh_from_address(
+ storage,
+ ¶ms,
+ val.address.clone(),
+ epoch,
+ );
+ VoteInfo {
+ validator: Some(Validator {
+ address: pkh,
+ power: u64::from(val.bonded_stake) as i64,
+ }),
+ signed_last_block: true,
+ }
+ })
+ .collect::>()
+ }
+
+ fn advance_epoch(
+ shell: &mut TestShell,
+ proposer_address: &[u8],
+ consensus_votes: &[VoteInfo],
+ misbehaviors: Option>,
+ ) -> Epoch {
+ let current_epoch = shell.wl_storage.storage.block.epoch;
+ loop {
+ next_block_for_inflation(
+ shell,
+ proposer_address.to_owned(),
+ consensus_votes.to_owned(),
+ misbehaviors.clone(),
+ );
+ if shell.wl_storage.storage.block.epoch == current_epoch.next() {
+ break;
+ }
+ }
+ shell.wl_storage.storage.block.epoch
+ }
+
+ fn get_pkh_from_address(
+ storage: &S,
+ params: &PosParams,
+ address: Address,
+ epoch: Epoch,
+ ) -> Vec
+ where
+ S: StorageRead,
+ {
+ let ck = validator_consensus_key_handle(&address)
+ .get(storage, epoch, params)
+ .unwrap()
+ .unwrap();
+ let hash_string = tm_consensus_key_raw_hash(&ck);
+ HEXUPPER.decode(hash_string.as_bytes()).unwrap()
+ }
}
diff --git a/apps/src/lib/node/ledger/shell/governance.rs b/apps/src/lib/node/ledger/shell/governance.rs
index dfdae4d04e..9ff5ebc279 100644
--- a/apps/src/lib/node/ledger/shell/governance.rs
+++ b/apps/src/lib/node/ledger/shell/governance.rs
@@ -12,6 +12,7 @@ use namada::ledger::storage::types::encode;
use namada::ledger::storage::{DBIter, StorageHasher, DB};
use namada::ledger::storage_api::{token, StorageWrite};
use namada::proof_of_stake::read_total_stake;
+use namada::proto::{Code, Data};
use namada::types::address::Address;
use namada::types::governance::{Council, Tally, TallyResult, VotePower};
use namada::types::storage::Epoch;
@@ -147,17 +148,13 @@ where
let proposal_code = shell.read_storage_key_bytes(&proposal_code_key);
match proposal_code {
Some(proposal_code) => {
- let tx = Tx::new(
- proposal_code,
- Some(encode(&id)),
- shell.chain_id.clone(),
- None,
- );
- let tx_type = TxType::Decrypted(DecryptedTx::Decrypted {
- tx,
+ let mut tx = Tx::new(TxType::Decrypted(DecryptedTx::Decrypted {
#[cfg(not(feature = "mainnet"))]
has_valid_pow: false,
- });
+ }));
+ tx.header.chain_id = shell.chain_id.clone();
+ tx.set_data(Data::new(encode(&id)));
+ tx.set_code(Code::new(proposal_code));
let pending_execution_key =
gov_storage::get_proposal_execution_key(id);
shell
@@ -165,7 +162,7 @@ where
.write(&pending_execution_key, ())
.expect("Should be able to write to storage.");
let tx_result = protocol::apply_tx(
- tx_type,
+ tx,
0, /* this is used to compute the fee
* based on the code size. We dont
* need it here. */
diff --git a/apps/src/lib/node/ledger/shell/mod.rs b/apps/src/lib/node/ledger/shell/mod.rs
index acf2e103a0..6b9dec5a76 100644
--- a/apps/src/lib/node/ledger/shell/mod.rs
+++ b/apps/src/lib/node/ledger/shell/mod.rs
@@ -22,7 +22,6 @@ use std::path::{Path, PathBuf};
use std::rc::Rc;
use borsh::{BorshDeserialize, BorshSerialize};
-use namada::core::types::hash::Hash;
use namada::ledger::events::log::EventLog;
use namada::ledger::events::Event;
use namada::ledger::gas::BlockGasMeter;
@@ -35,11 +34,11 @@ use namada::ledger::storage::{
};
use namada::ledger::storage_api::{self, StorageRead, StorageWrite};
use namada::ledger::{ibc, pos, protocol, replay_protection};
-use namada::proof_of_stake::{self, read_pos_params, slash};
-use namada::proto::{self, Tx};
+use namada::proof_of_stake::{self, process_slashes, read_pos_params, slash};
+use namada::proto::{self, Section, Tx};
use namada::types::address::{masp, masp_tx_key, Address};
use namada::types::chain::ChainId;
-use namada::types::internal::WrapperTxInQueue;
+use namada::types::internal::TxInQueue;
use namada::types::key::*;
use namada::types::storage::{BlockHeight, Key, TxIndex};
use namada::types::time::{DateTimeUtc, TimeZone, Utc};
@@ -47,8 +46,8 @@ use namada::types::token::{self};
#[cfg(not(feature = "mainnet"))]
use namada::types::transaction::MIN_FEE;
use namada::types::transaction::{
- hash_tx, process_tx, verify_decrypted_correctly, AffineCurve, DecryptedTx,
- EllipticCurve, PairingEngine, TxType, WrapperTx,
+ hash_tx, verify_decrypted_correctly, AffineCurve, DecryptedTx,
+ EllipticCurve, PairingEngine, TxType,
};
use namada::types::{address, hash};
use namada::vm::wasm::{TxCache, VpCache};
@@ -414,7 +413,7 @@ where
/// Iterate over the wrapper txs in order
#[allow(dead_code)]
- fn iter_tx_queue(&mut self) -> impl Iterator {
+ fn iter_tx_queue(&mut self) -> impl Iterator {
self.wl_storage.storage.tx_queue.iter()
}
@@ -494,7 +493,7 @@ where
}
/// Apply PoS slashes from the evidence
- fn slash(&mut self) {
+ fn record_slashes_from_evidence(&mut self) {
if !self.byzantine_validators.is_empty() {
let byzantine_validators =
mem::take(&mut self.byzantine_validators);
@@ -502,6 +501,7 @@ where
let pos_params = read_pos_params(&self.wl_storage).unwrap();
let current_epoch = self.wl_storage.storage.block.epoch;
for evidence in byzantine_validators {
+ // dbg!(&evidence);
tracing::info!("Processing evidence {evidence:?}.");
let evidence_height = match u64::try_from(evidence.height) {
Ok(height) => height,
@@ -529,7 +529,12 @@ where
continue;
}
};
- if evidence_epoch + pos_params.unbonding_len <= current_epoch {
+ // Disregard evidences that should have already been processed
+ // at this time
+ if evidence_epoch + pos_params.slash_processing_epoch_offset()
+ - pos_params.cubic_slashing_window_length
+ <= current_epoch
+ {
tracing::info!(
"Skipping outdated evidence from epoch \
{evidence_epoch}"
@@ -609,6 +614,19 @@ where
}
}
+ /// Process and apply slashes that have already been recorded for the
+ /// current epoch
+ fn process_slashes(&mut self) {
+ let current_epoch = self.wl_storage.storage.block.epoch;
+ if let Err(err) = process_slashes(&mut self.wl_storage, current_epoch) {
+ tracing::error!(
+ "Error while processing slashes queued for epoch {}: {}",
+ current_epoch,
+ err
+ );
+ }
+ }
+
/// INVARIANT: This method must be stateless.
#[cfg(feature = "abcipp")]
pub fn extend_vote(
@@ -656,19 +674,20 @@ where
/// block construction and validation
pub fn replay_protection_checks(
&self,
- wrapper: &WrapperTx,
+ wrapper: &Tx,
tx_bytes: &[u8],
temp_wl_storage: &mut TempWlStorage,
) -> Result<()> {
- let inner_hash_key =
- replay_protection::get_tx_hash_key(&wrapper.tx_hash);
+ let inner_tx_hash =
+ wrapper.clone().update_header(TxType::Raw).header_hash();
+ let inner_hash_key = replay_protection::get_tx_hash_key(&inner_tx_hash);
if temp_wl_storage
.has_key(&inner_hash_key)
.expect("Error while checking inner tx hash key in storage")
{
return Err(Error::ReplayAttempt(format!(
"Inner transaction hash {} already in storage",
- &wrapper.tx_hash
+ &inner_tx_hash,
)));
}
@@ -679,7 +698,7 @@ where
let tx =
Tx::try_from(tx_bytes).expect("Deserialization shouldn't fail");
- let wrapper_hash = Hash(tx.unsigned_hash());
+ let wrapper_hash = tx.header_hash();
let wrapper_hash_key =
replay_protection::get_tx_hash_key(&wrapper_hash);
if temp_wl_storage
@@ -728,17 +747,17 @@ where
};
// Tx chain id
- if tx.chain_id != self.chain_id {
+ if tx.header.chain_id != self.chain_id {
response.code = ErrorCodes::InvalidChainId.into();
response.log = format!(
"Tx carries a wrong chain id: expected {}, found {}",
- self.chain_id, tx.chain_id
+ self.chain_id, tx.header.chain_id
);
return response;
}
// Tx expiration
- if let Some(exp) = tx.expiration {
+ if let Some(exp) = tx.header.expiration {
let last_block_timestamp = self.get_block_timestamp(None);
if last_block_timestamp > exp {
@@ -752,8 +771,8 @@ where
}
// Tx signature check
- let tx_type = match process_tx(tx) {
- Ok(ty) => ty,
+ let tx_type = match tx.validate_header() {
+ Ok(()) => tx.header(),
Err(msg) => {
response.code = ErrorCodes::InvalidSig.into();
response.log = msg.to_string();
@@ -762,10 +781,13 @@ where
};
// Tx type check
- if let TxType::Wrapper(wrapper) = tx_type {
+ if let TxType::Wrapper(wrapper) = tx_type.tx_type {
// Replay protection check
+ let mut inner_tx = tx;
+ inner_tx.update_header(TxType::Raw);
+ let inner_tx_hash = &inner_tx.header_hash();
let inner_hash_key =
- replay_protection::get_tx_hash_key(&wrapper.tx_hash);
+ replay_protection::get_tx_hash_key(inner_tx_hash);
if self
.wl_storage
.storage
@@ -777,14 +799,14 @@ where
response.log = format!(
"Inner transaction hash {} already in storage, replay \
attempt",
- wrapper.tx_hash
+ inner_tx_hash
);
return response;
}
let tx =
Tx::try_from(tx_bytes).expect("Deserialization shouldn't fail");
- let wrapper_hash = hash::Hash(tx.unsigned_hash());
+ let wrapper_hash = hash::Hash(tx.header_hash().0);
let wrapper_hash_key =
replay_protection::get_tx_hash_key(&wrapper_hash);
if self
@@ -848,13 +870,6 @@ where
let mut tx_wasm_cache = self.tx_wasm_cache.read_only();
match Tx::try_from(tx_bytes) {
Ok(tx) => {
- let tx = TxType::Decrypted(DecryptedTx::Decrypted {
- tx,
- #[cfg(not(feature = "mainnet"))]
- // To be able to dry-run testnet faucet withdrawal, pretend
- // that we got a valid PoW
- has_valid_pow: true,
- });
match protocol::apply_tx(
tx,
tx_bytes.len(),
@@ -985,6 +1000,7 @@ mod test_utils {
use namada::ledger::storage::mockdb::MockDB;
use namada::ledger::storage::{update_allowed_conversions, Sha256Hasher};
+ use namada::proto::{Code, Data};
use namada::types::chain::ChainId;
use namada::types::hash::Hash;
use namada::types::key::*;
@@ -1141,16 +1157,12 @@ mod test_utils {
/// Add a wrapper tx to the queue of txs to be decrypted
/// in the current block proposal
#[cfg(test)]
- pub fn enqueue_tx(&mut self, wrapper: WrapperTx) {
- self.shell
- .wl_storage
- .storage
- .tx_queue
- .push(WrapperTxInQueue {
- tx: wrapper,
- #[cfg(not(feature = "mainnet"))]
- has_valid_pow: false,
- });
+ pub fn enqueue_tx(&mut self, tx: Tx) {
+ self.shell.wl_storage.storage.tx_queue.push(TxInQueue {
+ tx,
+ #[cfg(not(feature = "mainnet"))]
+ has_valid_pow: false,
+ });
}
}
@@ -1224,13 +1236,7 @@ mod test_utils {
.expect("begin_block failed");
let keypair = gen_keypair();
// enqueue a wrapper tx
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
+ let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: native_token,
@@ -1238,12 +1244,15 @@ mod test_utils {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
- shell.wl_storage.storage.tx_queue.push(WrapperTxInQueue {
+ ))));
+ wrapper.header.chain_id = shell.chain_id.clone();
+ wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ wrapper.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ wrapper.encrypt(&Default::default());
+
+ shell.wl_storage.storage.tx_queue.push(TxInQueue {
tx: wrapper,
#[cfg(not(feature = "mainnet"))]
has_valid_pow: false,
@@ -1281,7 +1290,7 @@ mod test_utils {
#[cfg(test)]
mod test_mempool_validate {
use namada::proof_of_stake::Epoch;
- use namada::proto::SignedTxData;
+ use namada::proto::{Code, Data, Section, Signature, Tx};
use namada::types::transaction::{Fee, WrapperTx};
use super::test_utils::TestShell;
@@ -1294,41 +1303,23 @@ mod test_mempool_validate {
let keypair = super::test_utils::gen_keypair();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
-
- let mut wrapper = WrapperTx::new(
- Fee {
- amount: 100.into(),
- token: shell.wl_storage.storage.native_token.clone(),
- },
- &keypair,
- Epoch(0),
- 0.into(),
- tx,
- Default::default(),
- #[cfg(not(feature = "mainnet"))]
- None,
- )
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Wrapper signing failed");
-
- let unsigned_wrapper = if let Some(Ok(SignedTxData {
- data: Some(data),
- sig: _,
- })) = wrapper
- .data
- .take()
- .map(|data| SignedTxData::try_from_slice(&data[..]))
- {
- Tx::new(vec![], Some(data), shell.chain_id.clone(), None)
- } else {
- panic!("Test failed")
- };
+ let mut unsigned_wrapper =
+ Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
+ Fee {
+ amount: 100.into(),
+ token: shell.wl_storage.storage.native_token.clone(),
+ },
+ &keypair,
+ Epoch(0),
+ 0.into(),
+ #[cfg(not(feature = "mainnet"))]
+ None,
+ ))));
+ unsigned_wrapper.header.chain_id = shell.chain_id.clone();
+ unsigned_wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ unsigned_wrapper
+ .set_data(Data::new("transaction data".as_bytes().to_owned()));
+ unsigned_wrapper.encrypt(&Default::default());
let mut result = shell.mempool_validate(
unsigned_wrapper.to_bytes().as_ref(),
@@ -1349,67 +1340,33 @@ mod test_mempool_validate {
let keypair = super::test_utils::gen_keypair();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
-
- let mut wrapper = WrapperTx::new(
- Fee {
- amount: 100.into(),
- token: shell.wl_storage.storage.native_token.clone(),
- },
+ let mut invalid_wrapper =
+ Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
+ Fee {
+ amount: 100.into(),
+ token: shell.wl_storage.storage.native_token.clone(),
+ },
+ &keypair,
+ Epoch(0),
+ 0.into(),
+ #[cfg(not(feature = "mainnet"))]
+ None,
+ ))));
+ invalid_wrapper.header.chain_id = shell.chain_id.clone();
+ invalid_wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ invalid_wrapper
+ .set_data(Data::new("transaction data".as_bytes().to_owned()));
+ invalid_wrapper.add_section(Section::Signature(Signature::new(
+ &invalid_wrapper.header_hash(),
&keypair,
- Epoch(0),
- 0.into(),
- tx,
- Default::default(),
- #[cfg(not(feature = "mainnet"))]
- None,
- )
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Wrapper signing failed");
-
- let invalid_wrapper = if let Some(Ok(SignedTxData {
- data: Some(data),
- sig,
- })) = wrapper
- .data
- .take()
- .map(|data| SignedTxData::try_from_slice(&data[..]))
- {
- let mut new_wrapper = if let TxType::Wrapper(wrapper) =
- ::deserialize(&mut data.as_ref())
- .expect("Test failed")
- {
- wrapper
- } else {
- panic!("Test failed")
- };
+ )));
+ invalid_wrapper.encrypt(&Default::default());
- // we mount a malleability attack to try and remove the fee
- new_wrapper.fee.amount = 0.into();
- let new_data = TxType::Wrapper(new_wrapper)
- .try_to_vec()
- .expect("Test failed");
- Tx::new(
- vec![],
- Some(
- SignedTxData {
- sig,
- data: Some(new_data),
- }
- .try_to_vec()
- .expect("Test failed"),
- ),
- shell.chain_id.clone(),
- None,
- )
- } else {
- panic!("Test failed");
- };
+ // we mount a malleability attack to try and remove the fee
+ let mut new_wrapper =
+ invalid_wrapper.header().wrapper().expect("Test failed");
+ new_wrapper.fee.amount = 0.into();
+ invalid_wrapper.update_header(TxType::Wrapper(Box::new(new_wrapper)));
let mut result = shell.mempool_validate(
invalid_wrapper.to_bytes().as_ref(),
@@ -1429,12 +1386,9 @@ mod test_mempool_validate {
let (shell, _) = TestShell::new();
// Test Raw TxType
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- None,
- shell.chain_id.clone(),
- None,
- );
+ let mut tx = Tx::new(TxType::Raw);
+ tx.header.chain_id = shell.chain_id.clone();
+ tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
let result = shell.mempool_validate(
tx.to_bytes().as_ref(),
@@ -1452,14 +1406,7 @@ mod test_mempool_validate {
let keypair = super::test_utils::gen_keypair();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
-
- let wrapper = WrapperTx::new(
+ let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 100.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -1467,27 +1414,26 @@ mod test_mempool_validate {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- )
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Wrapper signing failed");
-
- let tx_type = match process_tx(wrapper.clone()).expect("Test failed") {
- TxType::Wrapper(t) => t,
- _ => panic!("Test failed"),
- };
+ ))));
+ wrapper.header.chain_id = shell.chain_id.clone();
+ wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ wrapper.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ wrapper.add_section(Section::Signature(Signature::new(
+ &wrapper.header_hash(),
+ &keypair,
+ )));
+ wrapper.encrypt(&Default::default());
// Write wrapper hash to storage
- let wrapper_hash = hash::Hash(wrapper.unsigned_hash());
+ let wrapper_hash = wrapper.header_hash();
let wrapper_hash_key =
replay_protection::get_tx_hash_key(&wrapper_hash);
shell
.wl_storage
.storage
- .write(&wrapper_hash_key, &wrapper_hash)
+ .write(&wrapper_hash_key, wrapper_hash)
.expect("Test failed");
// Try wrapper tx replay attack
@@ -1519,13 +1465,14 @@ mod test_mempool_validate {
)
);
+ let inner_tx_hash =
+ wrapper.clone().update_header(TxType::Raw).header_hash();
// Write inner hash in storage
- let inner_hash_key =
- replay_protection::get_tx_hash_key(&tx_type.tx_hash);
+ let inner_hash_key = replay_protection::get_tx_hash_key(&inner_tx_hash);
shell
.wl_storage
.storage
- .write(&inner_hash_key, &tx_type.tx_hash)
+ .write(&inner_hash_key, inner_tx_hash)
.expect("Test failed");
// Try inner tx replay attack
@@ -1538,7 +1485,7 @@ mod test_mempool_validate {
result.log,
format!(
"Inner transaction hash {} already in storage, replay attempt",
- tx_type.tx_hash
+ inner_tx_hash
)
);
@@ -1551,7 +1498,7 @@ mod test_mempool_validate {
result.log,
format!(
"Inner transaction hash {} already in storage, replay attempt",
- tx_type.tx_hash
+ inner_tx_hash
)
)
}
@@ -1564,13 +1511,14 @@ mod test_mempool_validate {
let keypair = super::test_utils::gen_keypair();
let wrong_chain_id = ChainId("Wrong chain id".to_string());
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- wrong_chain_id.clone(),
- None,
- )
- .sign(&keypair);
+ let mut tx = Tx::new(TxType::Raw);
+ tx.header.chain_id = wrong_chain_id.clone();
+ tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ tx.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ tx.add_section(Section::Signature(Signature::new(
+ &tx.header_hash(),
+ &keypair,
+ )));
let result = shell.mempool_validate(
tx.to_bytes().as_ref(),
@@ -1593,13 +1541,15 @@ mod test_mempool_validate {
let keypair = super::test_utils::gen_keypair();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- Some(DateTimeUtc::now()),
- )
- .sign(&keypair);
+ let mut tx = Tx::new(TxType::Raw);
+ tx.header.expiration = Some(DateTimeUtc::now());
+ tx.header.chain_id = shell.chain_id.clone();
+ tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ tx.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ tx.add_section(Section::Signature(Signature::new(
+ &tx.header_hash(),
+ &keypair,
+ )));
let result = shell.mempool_validate(
tx.to_bytes().as_ref(),
diff --git a/apps/src/lib/node/ledger/shell/prepare_proposal.rs b/apps/src/lib/node/ledger/shell/prepare_proposal.rs
index 41d05fea5d..7d126a5218 100644
--- a/apps/src/lib/node/ledger/shell/prepare_proposal.rs
+++ b/apps/src/lib/node/ledger/shell/prepare_proposal.rs
@@ -4,11 +4,12 @@ use namada::core::hints;
use namada::ledger::storage::{DBIter, StorageHasher, TempWlStorage, DB};
use namada::proof_of_stake::pos_queries::PosQueries;
use namada::proto::Tx;
-use namada::types::internal::WrapperTxInQueue;
+use namada::types::internal::TxInQueue;
use namada::types::time::DateTimeUtc;
-use namada::types::transaction::tx_types::TxType;
use namada::types::transaction::wrapper::wrapper_tx::PairingEngine;
-use namada::types::transaction::{AffineCurve, DecryptedTx, EllipticCurve};
+use namada::types::transaction::{
+ AffineCurve, DecryptedTx, EllipticCurve, TxType,
+};
use super::super::*;
#[allow(unused_imports)]
@@ -21,8 +22,10 @@ use super::block_space_alloc::{AllocFailure, BlockSpaceAllocator};
#[cfg(feature = "abcipp")]
use crate::facade::tendermint_proto::abci::ExtendedCommitInfo;
use crate::facade::tendermint_proto::abci::RequestPrepareProposal;
+#[cfg(feature = "abcipp")]
+use crate::facade::tendermint_proto::abci::{tx_record::TxAction, TxRecord};
use crate::facade::tendermint_proto::google::protobuf::Timestamp;
-use crate::node::ledger::shell::{process_tx, ShellMode};
+use crate::node::ledger::shell::ShellMode;
use crate::node::ledger::shims::abcipp_shim_types::shim::{response, TxBytes};
impl Shell
@@ -45,7 +48,6 @@ where
let txs = if let ShellMode::Validator { .. } = self.mode {
// start counting allotted space for txs
let alloc = self.get_encrypted_txs_allocator();
-
// add encrypted txs
let (encrypted_txs, alloc) = self.build_encrypted_txs(
alloc,
@@ -140,13 +142,11 @@ where
// If tx doesn't have an expiration it is valid. If time cannot be
// retrieved from block default to last block datetime which has
// already been checked by mempool_validate, so it's valid
- if let (Some(block_time), Some(exp)) = (block_time.as_ref(), &tx.expiration) {
+ if let (Some(block_time), Some(exp)) = (block_time.as_ref(), &tx.header.expiration) {
if block_time > exp { return None }
}
- if let Ok(TxType::Wrapper(ref wrapper)) = process_tx(tx) {
- if self.replay_protection_checks(wrapper, tx_bytes.as_slice(), &mut temp_wl_storage).is_ok() {
- return Some(tx_bytes.clone())
- }
+ if tx.validate_header().is_ok() && tx.header().wrapper().is_some() && self.replay_protection_checks(&tx, tx_bytes.as_slice(), &mut temp_wl_storage).is_ok() {
+ return Some(tx_bytes.clone());
}
}
None
@@ -202,7 +202,6 @@ where
// TODO: This should not be hardcoded
let privkey =
::G2Affine::prime_subgroup_generator();
-
let pos_queries = self.wl_storage.pos_queries();
let txs = self
.wl_storage
@@ -210,20 +209,30 @@ where
.tx_queue
.iter()
.map(
- |WrapperTxInQueue {
+ |TxInQueue {
tx,
#[cfg(not(feature = "mainnet"))]
has_valid_pow,
- }| {
- Tx::from(match tx.decrypt(privkey) {
- Ok(tx) => DecryptedTx::Decrypted {
- tx,
- #[cfg(not(feature = "mainnet"))]
- has_valid_pow: *has_valid_pow,
+ }| {
+ let mut tx = tx.clone();
+ match tx.decrypt(privkey).ok()
+ {
+ Some(()) => {
+ tx.update_header(TxType::Decrypted(DecryptedTx::Decrypted {
+ #[cfg(not(feature = "mainnet"))]
+ has_valid_pow: *has_valid_pow,
+ }));
+ tx
+ },
+ // An absent or undecryptable inner_tx are both
+ // treated as undecryptable
+ None => {
+ tx.update_header(TxType::Decrypted(
+ DecryptedTx::Undecryptable
+ ));
+ tx
},
- _ => DecryptedTx::Undecryptable(tx.clone()),
- })
- .to_bytes()
+ }.to_bytes()
},
)
// TODO: make sure all decrypted txs are accepted
@@ -280,7 +289,7 @@ mod test_prepare_proposal {
use borsh::BorshSerialize;
use namada::ledger::replay_protection;
use namada::proof_of_stake::Epoch;
- use namada::types::hash::Hash;
+ use namada::proto::{Code, Data, Header, Section, Signature};
use namada::types::transaction::{Fee, WrapperTx};
use super::*;
@@ -292,12 +301,10 @@ mod test_prepare_proposal {
#[test]
fn test_prepare_proposal_rejects_non_wrapper_tx() {
let (shell, _) = test_utils::setup(1);
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction_data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
+ let mut tx = Tx::new(TxType::Decrypted(DecryptedTx::Decrypted {
+ has_valid_pow: true,
+ }));
+ tx.header.chain_id = shell.chain_id.clone();
let req = RequestPrepareProposal {
txs: vec![tx.to_bytes()],
..Default::default()
@@ -312,36 +319,23 @@ mod test_prepare_proposal {
fn test_error_in_processing_tx() {
let (shell, _) = test_utils::setup(1);
let keypair = gen_keypair();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction_data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
// an unsigned wrapper will cause an error in processing
- let wrapper = Tx::new(
- "".as_bytes().to_owned(),
- Some(
- WrapperTx::new(
- Fee {
- amount: 0.into(),
- token: shell.wl_storage.storage.native_token.clone(),
- },
- &keypair,
- Epoch(0),
- 0.into(),
- tx,
- Default::default(),
- #[cfg(not(feature = "mainnet"))]
- None,
- )
- .try_to_vec()
- .expect("Test failed"),
- ),
- shell.chain_id.clone(),
+ let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
+ Fee {
+ amount: 0.into(),
+ token: shell.wl_storage.storage.native_token.clone(),
+ },
+ &keypair,
+ Epoch(0),
+ 0.into(),
+ #[cfg(not(feature = "mainnet"))]
None,
- )
- .to_bytes();
+ ))));
+ wrapper.header.chain_id = shell.chain_id.clone();
+ wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ wrapper.set_data(Data::new("transaction_data".as_bytes().to_owned()));
+ wrapper.encrypt(&Default::default());
+ let wrapper = wrapper.to_bytes();
#[allow(clippy::redundant_clone)]
let req = RequestPrepareProposal {
txs: vec![wrapper.clone()],
@@ -367,18 +361,7 @@ mod test_prepare_proposal {
// create a request with two new wrappers from mempool and
// two wrappers from the previous block to be decrypted
for i in 0..2 {
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some(format!("transaction data: {}", i).as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- expected_decrypted.push(Tx::from(DecryptedTx::Decrypted {
- tx: tx.clone(),
- #[cfg(not(feature = "mainnet"))]
- has_valid_pow: false,
- }));
- let wrapper_tx = WrapperTx::new(
+ let mut tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -386,39 +369,58 @@ mod test_prepare_proposal {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
- let wrapper = wrapper_tx
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Test failed");
- shell.enqueue_tx(wrapper_tx);
- expected_wrapper.push(wrapper.clone());
- req.txs.push(wrapper.to_bytes());
+ ))));
+ tx.header.chain_id = shell.chain_id.clone();
+ tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ tx.set_data(Data::new(
+ format!("transaction data: {}", i).as_bytes().to_owned(),
+ ));
+ tx.add_section(Section::Signature(Signature::new(
+ &tx.header_hash(),
+ &keypair,
+ )));
+ tx.encrypt(&Default::default());
+
+ shell.enqueue_tx(tx.clone());
+ expected_wrapper.push(tx.clone());
+ req.txs.push(tx.to_bytes());
+ tx.update_header(TxType::Decrypted(DecryptedTx::Decrypted {
+ #[cfg(not(feature = "mainnet"))]
+ has_valid_pow: false,
+ }));
+ expected_decrypted.push(tx.clone());
}
- let expected_txs: Vec = expected_wrapper
+ // we extract the inner data from the txs for testing
+ // equality since otherwise changes in timestamps would
+ // fail the test
+ let expected_txs: Vec = expected_wrapper
.into_iter()
.chain(expected_decrypted.into_iter())
- // we extract the inner data from the txs for testing
- // equality since otherwise changes in timestamps would
- // fail the test
- .map(|tx| tx.data.expect("Test failed"))
+ .map(|tx| tx.header)
.collect();
- let received: Vec = shell
+ let received: Vec = shell
.prepare_proposal(req)
.txs
.into_iter()
.map(|tx_bytes| {
Tx::try_from(tx_bytes.as_slice())
.expect("Test failed")
- .data
- .expect("Test failed")
+ .header
})
.collect();
// check that the order of the txs is correct
- assert_eq!(received, expected_txs);
+ assert_eq!(
+ received
+ .iter()
+ .map(|x| x.try_to_vec().unwrap())
+ .collect::>(),
+ expected_txs
+ .iter()
+ .map(|x| x.try_to_vec().unwrap())
+ .collect::>(),
+ );
}
/// Test that if the unsigned wrapper tx hash is known (replay attack), the
@@ -428,14 +430,7 @@ mod test_prepare_proposal {
let (mut shell, _) = test_utils::setup(1);
let keypair = crate::wallet::defaults::daewon_keypair();
-
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
+ let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -443,17 +438,20 @@ mod test_prepare_proposal {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
- let signed = wrapper
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Test failed");
+ ))));
+ wrapper.header.chain_id = shell.chain_id.clone();
+ wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ wrapper.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ wrapper.add_section(Section::Signature(Signature::new(
+ &wrapper.header_hash(),
+ &keypair,
+ )));
+ wrapper.encrypt(&Default::default());
// Write wrapper hash to storage
- let wrapper_unsigned_hash = Hash(signed.unsigned_hash());
+ let wrapper_unsigned_hash = wrapper.header_hash();
let hash_key =
replay_protection::get_tx_hash_key(&wrapper_unsigned_hash);
shell
@@ -463,7 +461,7 @@ mod test_prepare_proposal {
.expect("Test failed");
let req = RequestPrepareProposal {
- txs: vec![signed.to_bytes()],
+ txs: vec![wrapper.to_bytes()],
..Default::default()
};
@@ -471,7 +469,7 @@ mod test_prepare_proposal {
shell.prepare_proposal(req).txs.into_iter().map(|tx_bytes| {
Tx::try_from(tx_bytes.as_slice())
.expect("Test failed")
- .data
+ .data()
.expect("Test failed")
});
assert_eq!(received.len(), 0);
@@ -484,14 +482,7 @@ mod test_prepare_proposal {
let (shell, _) = test_utils::setup(1);
let keypair = crate::wallet::defaults::daewon_keypair();
-
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
+ let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -499,23 +490,27 @@ mod test_prepare_proposal {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
- let signed = wrapper
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Test failed");
+ ))));
+ wrapper.header.chain_id = shell.chain_id.clone();
+ wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ wrapper.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ wrapper.add_section(Section::Signature(Signature::new(
+ &wrapper.header_hash(),
+ &keypair,
+ )));
+ wrapper.encrypt(&Default::default());
+
let req = RequestPrepareProposal {
- txs: vec![signed.to_bytes(); 2],
+ txs: vec![wrapper.to_bytes(); 2],
..Default::default()
};
let received =
shell.prepare_proposal(req).txs.into_iter().map(|tx_bytes| {
Tx::try_from(tx_bytes.as_slice())
.expect("Test failed")
- .data
+ .data()
.expect("Test failed")
});
assert_eq!(received.len(), 1);
@@ -528,14 +523,7 @@ mod test_prepare_proposal {
let (mut shell, _) = test_utils::setup(1);
let keypair = crate::wallet::defaults::daewon_keypair();
-
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
+ let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -543,15 +531,19 @@ mod test_prepare_proposal {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
- let inner_unsigned_hash = wrapper.tx_hash.clone();
- let signed = wrapper
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Test failed");
+ ))));
+ wrapper.header.chain_id = shell.chain_id.clone();
+ wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ wrapper.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ wrapper.add_section(Section::Signature(Signature::new(
+ &wrapper.header_hash(),
+ &keypair,
+ )));
+ wrapper.encrypt(&Default::default());
+ let inner_unsigned_hash =
+ wrapper.clone().update_header(TxType::Raw).header_hash();
// Write inner hash to storage
let hash_key = replay_protection::get_tx_hash_key(&inner_unsigned_hash);
@@ -562,7 +554,7 @@ mod test_prepare_proposal {
.expect("Test failed");
let req = RequestPrepareProposal {
- txs: vec![signed.to_bytes()],
+ txs: vec![wrapper.to_bytes()],
..Default::default()
};
@@ -570,7 +562,7 @@ mod test_prepare_proposal {
shell.prepare_proposal(req).txs.into_iter().map(|tx_bytes| {
Tx::try_from(tx_bytes.as_slice())
.expect("Test failed")
- .data
+ .data()
.expect("Test failed")
});
assert_eq!(received.len(), 0);
@@ -584,14 +576,7 @@ mod test_prepare_proposal {
let keypair = crate::wallet::defaults::daewon_keypair();
let keypair_2 = crate::wallet::defaults::daewon_keypair();
-
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
+ let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -599,41 +584,51 @@ mod test_prepare_proposal {
&keypair,
Epoch(0),
0.into(),
- tx.clone(),
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
- let signed = wrapper
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Test failed");
+ ))));
+ wrapper.header.chain_id = shell.chain_id.clone();
+ let tx_code = Code::new("wasm_code".as_bytes().to_owned());
+ wrapper.set_code(tx_code.clone());
+ let tx_data = Data::new("transaction data".as_bytes().to_owned());
+ wrapper.set_data(tx_data.clone());
+ wrapper.add_section(Section::Signature(Signature::new(
+ &wrapper.header_hash(),
+ &keypair,
+ )));
+ wrapper.encrypt(&Default::default());
- let new_wrapper = WrapperTx::new(
- Fee {
- amount: 0.into(),
- token: shell.wl_storage.storage.native_token.clone(),
- },
- &keypair_2,
- Epoch(0),
- 0.into(),
- tx,
- Default::default(),
- #[cfg(not(feature = "mainnet"))]
- None,
- );
- let new_signed = new_wrapper
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Test failed");
+ let mut new_wrapper =
+ Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
+ Fee {
+ amount: 0.into(),
+ token: shell.wl_storage.storage.native_token.clone(),
+ },
+ &keypair_2,
+ Epoch(0),
+ 0.into(),
+ #[cfg(not(feature = "mainnet"))]
+ None,
+ ))));
+ new_wrapper.header.chain_id = shell.chain_id.clone();
+ new_wrapper.header.timestamp = wrapper.header.timestamp;
+ new_wrapper.set_code(tx_code);
+ new_wrapper.set_data(tx_data);
+ new_wrapper.add_section(Section::Signature(Signature::new(
+ &new_wrapper.header_hash(),
+ &keypair,
+ )));
+ new_wrapper.encrypt(&Default::default());
let req = RequestPrepareProposal {
- txs: vec![signed.to_bytes(), new_signed.to_bytes()],
+ txs: vec![wrapper.to_bytes(), new_wrapper.to_bytes()],
..Default::default()
};
let received =
shell.prepare_proposal(req).txs.into_iter().map(|tx_bytes| {
Tx::try_from(tx_bytes.as_slice())
.expect("Test failed")
- .data
+ .data()
.expect("Test failed")
});
assert_eq!(received.len(), 1);
@@ -645,28 +640,28 @@ mod test_prepare_proposal {
let (shell, _) = test_utils::setup(1);
let keypair = gen_keypair();
let tx_time = DateTimeUtc::now();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper_tx = WrapperTx::new(
- Fee {
- amount: 0.into(),
- token: shell.wl_storage.storage.native_token.clone(),
- },
+ let mut wrapper_tx =
+ Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
+ Fee {
+ amount: 0.into(),
+ token: shell.wl_storage.storage.native_token.clone(),
+ },
+ &keypair,
+ Epoch(0),
+ 0.into(),
+ #[cfg(not(feature = "mainnet"))]
+ None,
+ ))));
+ wrapper_tx.header.chain_id = shell.chain_id.clone();
+ wrapper_tx.header.expiration = Some(tx_time);
+ wrapper_tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ wrapper_tx
+ .set_data(Data::new("transaction data".as_bytes().to_owned()));
+ wrapper_tx.add_section(Section::Signature(Signature::new(
+ &wrapper_tx.header_hash(),
&keypair,
- Epoch(0),
- 0.into(),
- tx,
- Default::default(),
- #[cfg(not(feature = "mainnet"))]
- None,
- );
- let wrapper = wrapper_tx
- .sign(&keypair, shell.chain_id.clone(), Some(tx_time))
- .expect("Test failed");
+ )));
+ wrapper_tx.encrypt(&Default::default());
let time = DateTimeUtc::now();
let block_time =
@@ -675,7 +670,7 @@ mod test_prepare_proposal {
nanos: time.0.timestamp_subsec_nanos() as i32,
};
let req = RequestPrepareProposal {
- txs: vec![wrapper.to_bytes()],
+ txs: vec![wrapper_tx.to_bytes()],
max_tx_bytes: 0,
time: Some(block_time),
..Default::default()
diff --git a/apps/src/lib/node/ledger/shell/process_proposal.rs b/apps/src/lib/node/ledger/shell/process_proposal.rs
index 6ad5a71048..2837ac6600 100644
--- a/apps/src/lib/node/ledger/shell/process_proposal.rs
+++ b/apps/src/lib/node/ledger/shell/process_proposal.rs
@@ -6,7 +6,7 @@ use namada::core::hints;
use namada::core::ledger::storage::WlStorage;
use namada::ledger::storage::TempWlStorage;
use namada::proof_of_stake::pos_queries::PosQueries;
-use namada::types::internal::WrapperTxInQueue;
+use namada::types::internal::TxInQueue;
use super::*;
use crate::facade::tendermint_proto::abci::response_process_proposal::ProposalStatus;
@@ -193,7 +193,7 @@ where
pub(crate) fn process_single_tx<'a>(
&self,
tx_bytes: &[u8],
- tx_queue_iter: &mut impl Iterator,
+ tx_queue_iter: &mut impl Iterator,
metadata: &mut ValidationMeta,
temp_wl_storage: &mut TempWlStorage,
block_time: DateTimeUtc,
@@ -229,17 +229,17 @@ where
})
},
|tx| {
- let tx_chain_id = tx.chain_id.clone();
- let tx_expiration = tx.expiration;
- let tx_type = process_tx(tx).map_err(|err| {
+ let tx_chain_id = tx.header.chain_id.clone();
+ let tx_expiration = tx.header.expiration;
+ if let Err(err) = tx.validate_header() {
// This occurs if the wrapper / protocol tx signature is
// invalid
- TxResult {
+ return Err(TxResult {
code: ErrorCodes::InvalidSig.into(),
info: err.to_string(),
- }
- })?;
- Ok((tx_chain_id, tx_expiration, tx_type))
+ });
+ }
+ Ok((tx_chain_id, tx_expiration, tx))
},
);
let (tx_chain_id, tx_expiration, tx) = match maybe_tx {
@@ -250,9 +250,15 @@ where
// TODO: This should not be hardcoded
let privkey = ::G2Affine::prime_subgroup_generator();
- match tx {
+ if let Err(err) = tx.validate_header() {
+ return TxResult {
+ code: ErrorCodes::InvalidSig.into(),
+ info: err.to_string(),
+ };
+ }
+ match tx.header().tx_type {
// If it is a raw transaction, we do no further validation
- TxType::Raw(_) => TxResult {
+ TxType::Raw => TxResult {
code: ErrorCodes::InvalidTx.into(),
info: "Transaction rejected: Non-encrypted transactions are \
not supported"
@@ -290,11 +296,19 @@ where
.into(),
}
}
- TxType::Decrypted(tx) => {
+ TxType::Decrypted(tx_header) => {
metadata.has_decrypted_txs = true;
match tx_queue_iter.next() {
Some(wrapper) => {
- if wrapper.tx.tx_hash != tx.hash_commitment() {
+ let mut inner_tx = tx;
+ inner_tx.update_header(TxType::Raw);
+ if wrapper
+ .tx
+ .clone()
+ .update_header(TxType::Raw)
+ .header_hash()
+ != inner_tx.header_hash()
+ {
TxResult {
code: ErrorCodes::InvalidOrder.into(),
info: "Process proposal rejected a decrypted \
@@ -302,41 +316,38 @@ where
determined in the previous block"
.into(),
}
- } else if verify_decrypted_correctly(&tx, privkey) {
- if let DecryptedTx::Decrypted {
- tx,
- has_valid_pow: _,
- } = tx
- {
- // Tx chain id
- if tx.chain_id != self.chain_id {
+ } else if verify_decrypted_correctly(
+ &tx_header,
+ wrapper.tx.clone(),
+ privkey,
+ ) {
+ // Tx chain id
+ if wrapper.tx.header.chain_id != self.chain_id {
+ return TxResult {
+ code: ErrorCodes::InvalidDecryptedChainId
+ .into(),
+ info: format!(
+ "Decrypted tx carries a wrong chain \
+ id: expected {}, found {}",
+ self.chain_id,
+ wrapper.tx.header.chain_id
+ ),
+ };
+ }
+
+ // Tx expiration
+ if let Some(exp) = wrapper.tx.header.expiration {
+ if block_time > exp {
return TxResult {
- code:
- ErrorCodes::InvalidDecryptedChainId
- .into(),
+ code: ErrorCodes::ExpiredDecryptedTx
+ .into(),
info: format!(
- "Decrypted tx carries a wrong \
- chain id: expected {}, found {}",
- self.chain_id, tx.chain_id
+ "Decrypted tx expired at {:#?}, \
+ block time: {:#?}",
+ exp, block_time
),
};
}
-
- // Tx expiration
- if let Some(exp) = tx.expiration {
- if block_time > exp {
- return TxResult {
- code:
- ErrorCodes::ExpiredDecryptedTx
- .into(),
- info: format!(
- "Decrypted tx expired at \
- {:#?}, block time: {:#?}",
- exp, block_time
- ),
- };
- }
- }
}
TxResult {
code: ErrorCodes::Ok.into(),
@@ -423,7 +434,7 @@ where
}
// validate the ciphertext via Ferveo
- if !wrapper.validate_ciphertext() {
+ if !tx.validate_ciphertext() {
TxResult {
code: ErrorCodes::InvalidTx.into(),
info: format!(
@@ -434,7 +445,7 @@ where
} else {
// Replay protection checks
if let Err(e) = self.replay_protection_checks(
- &wrapper,
+ &tx,
tx_bytes,
temp_wl_storage,
) {
@@ -504,16 +515,14 @@ where
/// are covered by the e2e tests.
#[cfg(test)]
mod test_process_proposal {
- use borsh::BorshDeserialize;
use namada::ledger::parameters::storage::get_wrapper_tx_fees_key;
- use namada::proto::SignedTxData;
+ use namada::proto::{Code, Data, Section, Signature};
use namada::types::hash::Hash;
use namada::types::key::*;
use namada::types::storage::Epoch;
use namada::types::token::Amount;
- use namada::types::transaction::encrypted::EncryptedTx;
- use namada::types::transaction::protocol::ProtocolTxType;
- use namada::types::transaction::{EncryptionKey, Fee, WrapperTx, MIN_FEE};
+ use namada::types::transaction::protocol::{ProtocolTx, ProtocolTxType};
+ use namada::types::transaction::{Fee, WrapperTx, MIN_FEE};
use super::*;
use crate::node::ledger::shell::test_utils::{
@@ -526,13 +535,7 @@ mod test_process_proposal {
fn test_unsigned_wrapper_rejected() {
let (mut shell, _) = test_utils::setup(1);
let keypair = gen_keypair();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
+ let mut outer_tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -540,18 +543,14 @@ mod test_process_proposal {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
- let tx = Tx::new(
- vec![],
- Some(TxType::Wrapper(wrapper).try_to_vec().expect("Test failed")),
- shell.chain_id.clone(),
- None,
- )
- .to_bytes();
+ ))));
+ outer_tx.header.chain_id = shell.chain_id.clone();
+ outer_tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ outer_tx.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ outer_tx.encrypt(&Default::default());
+ let tx = outer_tx.to_bytes();
#[allow(clippy::redundant_clone)]
let request = ProcessProposal {
txs: vec![tx.clone()],
@@ -566,7 +565,10 @@ mod test_process_proposal {
);
assert_eq!(
response[0].result.info,
- String::from("Wrapper transactions must be signed")
+ String::from(
+ "WrapperTx signature verification failed: Transaction \
+ doesn't have any data with a signature."
+ )
);
}
}
@@ -578,14 +580,7 @@ mod test_process_proposal {
fn test_wrapper_bad_signature_rejected() {
let (mut shell, _) = test_utils::setup(1);
let keypair = gen_keypair();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let timestamp = tx.timestamp;
- let mut wrapper = WrapperTx::new(
+ let mut outer_tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 100.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -593,51 +588,23 @@ mod test_process_proposal {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- )
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Test failed");
- let new_tx = if let Some(Ok(SignedTxData {
- data: Some(data),
- sig,
- })) = wrapper
- .data
- .take()
- .map(|data| SignedTxData::try_from_slice(&data[..]))
- {
- let mut new_wrapper = if let TxType::Wrapper(wrapper) =
- ::deserialize(&mut data.as_ref())
- .expect("Test failed")
- {
- wrapper
- } else {
- panic!("Test failed")
- };
-
+ ))));
+ outer_tx.header.chain_id = shell.chain_id.clone();
+ outer_tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ outer_tx.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ outer_tx.add_section(Section::Signature(Signature::new(
+ &outer_tx.header_hash(),
+ &keypair,
+ )));
+ outer_tx.encrypt(&Default::default());
+ let mut new_tx = outer_tx.clone();
+ if let TxType::Wrapper(wrapper) = &mut new_tx.header.tx_type {
// we mount a malleability attack to try and remove the fee
- new_wrapper.fee.amount = 0.into();
- let new_data = TxType::Wrapper(new_wrapper)
- .try_to_vec()
- .expect("Test failed");
- Tx {
- code_or_hash: vec![],
- data: Some(
- SignedTxData {
- sig,
- data: Some(new_data),
- }
- .try_to_vec()
- .expect("Test failed"),
- ),
- timestamp,
- chain_id: shell.chain_id.clone(),
- expiration: None,
- }
+ wrapper.fee.amount = 0.into();
} else {
- panic!("Test failed");
+ panic!("Test failed")
};
let request = ProcessProposal {
txs: vec![new_tx.to_bytes()],
@@ -646,8 +613,9 @@ mod test_process_proposal {
match shell.process_proposal(request) {
Ok(_) => panic!("Test failed"),
Err(TestError::RejectProposal(response)) => {
- let expected_error =
- "Signature verification failed: Invalid signature";
+ let expected_error = "WrapperTx signature verification \
+ failed: Transaction doesn't have any \
+ data with a signature.";
assert_eq!(
response[0].result.code,
u32::from(ErrorCodes::InvalidSig)
@@ -676,13 +644,7 @@ mod test_process_proposal {
)
.unwrap();
let keypair = gen_keypair();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
+ let mut outer_tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 1.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -690,15 +652,20 @@ mod test_process_proposal {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- )
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Test failed");
+ ))));
+ outer_tx.header.chain_id = shell.chain_id.clone();
+ outer_tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ outer_tx.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ outer_tx.add_section(Section::Signature(Signature::new(
+ &outer_tx.header_hash(),
+ &keypair,
+ )));
+ outer_tx.encrypt(&Default::default());
+
let request = ProcessProposal {
- txs: vec![wrapper.to_bytes()],
+ txs: vec![outer_tx.to_bytes()],
};
match shell.process_proposal(request) {
@@ -744,13 +711,7 @@ mod test_process_proposal {
)
.unwrap();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
+ let mut outer_tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: Amount::whole(1_000_100),
token: shell.wl_storage.storage.native_token.clone(),
@@ -758,16 +719,20 @@ mod test_process_proposal {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- )
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Test failed");
+ ))));
+ outer_tx.header.chain_id = shell.chain_id.clone();
+ outer_tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ outer_tx.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ outer_tx.add_section(Section::Signature(Signature::new(
+ &outer_tx.header_hash(),
+ &keypair,
+ )));
+ outer_tx.encrypt(&Default::default());
let request = ProcessProposal {
- txs: vec![wrapper.to_bytes()],
+ txs: vec![outer_tx.to_bytes()],
};
match shell.process_proposal(request) {
@@ -796,34 +761,31 @@ mod test_process_proposal {
let keypair = gen_keypair();
let mut txs = vec![];
for i in 0..3 {
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some(format!("transaction data: {}", i).as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
- Fee {
- amount: i.into(),
- token: shell.wl_storage.storage.native_token.clone(),
- },
- &keypair,
- Epoch(0),
- 0.into(),
- tx.clone(),
- Default::default(),
- #[cfg(not(feature = "mainnet"))]
- None,
- );
- shell.enqueue_tx(wrapper);
- let mut decrypted_tx =
- Tx::from(TxType::Decrypted(DecryptedTx::Decrypted {
- tx,
+ let mut outer_tx =
+ Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
+ Fee {
+ amount: i.into(),
+ token: shell.wl_storage.storage.native_token.clone(),
+ },
+ &keypair,
+ Epoch(0),
+ 0.into(),
#[cfg(not(feature = "mainnet"))]
- has_valid_pow: false,
- }));
- decrypted_tx.chain_id = shell.chain_id.clone();
- txs.push(decrypted_tx);
+ None,
+ ))));
+ outer_tx.header.chain_id = shell.chain_id.clone();
+ outer_tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ outer_tx.set_data(Data::new(
+ format!("transaction data: {}", i).as_bytes().to_owned(),
+ ));
+ outer_tx.encrypt(&Default::default());
+ shell.enqueue_tx(outer_tx.clone());
+
+ outer_tx.update_header(TxType::Decrypted(DecryptedTx::Decrypted {
+ #[cfg(not(feature = "mainnet"))]
+ has_valid_pow: false,
+ }));
+ txs.push(outer_tx);
}
let response = {
let request = ProcessProposal {
@@ -859,13 +821,7 @@ mod test_process_proposal {
let (mut shell, _) = test_utils::setup(1);
let keypair = gen_keypair();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
+ let mut tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -873,17 +829,16 @@ mod test_process_proposal {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
- shell.enqueue_tx(wrapper.clone());
-
- let mut tx =
- Tx::from(TxType::Decrypted(DecryptedTx::Undecryptable(wrapper)));
- tx.chain_id = shell.chain_id.clone();
-
+ ))));
+ tx.header.chain_id = shell.chain_id.clone();
+ tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ tx.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ tx.encrypt(&Default::default());
+ shell.enqueue_tx(tx.clone());
+
+ tx.header.tx_type = TxType::Decrypted(DecryptedTx::Undecryptable);
let request = ProcessProposal {
txs: vec![tx.to_bytes()],
};
@@ -914,13 +869,7 @@ mod test_process_proposal {
let (mut shell, _) = test_utils::setup(1);
let keypair = crate::wallet::defaults::daewon_keypair();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let mut wrapper = WrapperTx::new(
+ let mut tx = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -928,20 +877,19 @@ mod test_process_proposal {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
- wrapper.tx_hash = Hash([0; 32]);
+ ))));
+ tx.header.chain_id = shell.chain_id.clone();
+ tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ tx.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ tx.set_code_sechash(Hash([0u8; 32]));
+ tx.set_data_sechash(Hash([0u8; 32]));
+ tx.encrypt(&Default::default());
- shell.enqueue_tx(wrapper.clone());
- let mut tx = Tx::from(TxType::Decrypted(DecryptedTx::Undecryptable(
- #[allow(clippy::redundant_clone)]
- wrapper.clone(),
- )));
- tx.chain_id = shell.chain_id.clone();
+ shell.enqueue_tx(tx.clone());
+ tx.header.tx_type = TxType::Decrypted(DecryptedTx::Undecryptable);
let request = ProcessProposal {
txs: vec![tx.to_bytes()],
};
@@ -964,10 +912,7 @@ mod test_process_proposal {
fn test_undecryptable() {
let (mut shell, _) = test_utils::setup(1);
let keypair = crate::wallet::defaults::daewon_keypair();
- let pubkey = EncryptionKey::default();
// not valid tx bytes
- let tx = "garbage data".as_bytes().to_owned();
- let inner_tx = EncryptedTx::encrypt(&tx, pubkey);
let wrapper = WrapperTx {
fee: Fee {
amount: 0.into(),
@@ -976,21 +921,18 @@ mod test_process_proposal {
pk: keypair.ref_to(),
epoch: Epoch(0),
gas_limit: 0.into(),
- inner_tx,
- tx_hash: hash_tx(&tx),
#[cfg(not(feature = "mainnet"))]
pow_solution: None,
};
- shell.enqueue_tx(wrapper.clone());
- let mut signed =
- Tx::from(TxType::Decrypted(DecryptedTx::Undecryptable(
- #[allow(clippy::redundant_clone)]
- wrapper.clone(),
- )));
- signed.chain_id = shell.chain_id.clone();
+ let tx = Tx::new(TxType::Wrapper(Box::new(wrapper)));
+ let mut decrypted = tx.clone();
+ decrypted.update_header(TxType::Decrypted(DecryptedTx::Undecryptable));
+
+ shell.enqueue_tx(tx);
+
let request = ProcessProposal {
- txs: vec![signed.to_bytes()],
+ txs: vec![decrypted.to_bytes()],
};
let response = if let [resp] = shell
.process_proposal(request)
@@ -1009,20 +951,13 @@ mod test_process_proposal {
#[test]
fn test_too_many_decrypted_txs() {
let (mut shell, _) = test_utils::setup(1);
-
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
-
- let mut tx = Tx::from(TxType::Decrypted(DecryptedTx::Decrypted {
- tx,
+ let mut tx = Tx::new(TxType::Decrypted(DecryptedTx::Decrypted {
#[cfg(not(feature = "mainnet"))]
has_valid_pow: false,
}));
- tx.chain_id = shell.chain_id.clone();
+ tx.header.chain_id = shell.chain_id.clone();
+ tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ tx.set_data(Data::new("transaction data".as_bytes().to_owned()));
let request = ProcessProposal {
txs: vec![tx.to_bytes()],
@@ -1050,14 +985,11 @@ mod test_process_proposal {
fn test_raw_tx_rejected() {
let (mut shell, _) = test_utils::setup(1);
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let mut tx = Tx::from(TxType::Raw(tx));
- tx.chain_id = shell.chain_id.clone();
+ let mut tx = Tx::new(TxType::Raw);
+ tx.header.chain_id = shell.chain_id.clone();
+ tx.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ tx.set_data(Data::new("transaction data".as_bytes().to_owned()));
+
let request = ProcessProposal {
txs: vec![tx.to_bytes()],
};
@@ -1088,13 +1020,7 @@ mod test_process_proposal {
let keypair = crate::wallet::defaults::daewon_keypair();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
+ let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -1102,17 +1028,20 @@ mod test_process_proposal {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
- let signed = wrapper
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Test failed");
+ ))));
+ wrapper.header.chain_id = shell.chain_id.clone();
+ wrapper.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ wrapper.add_section(Section::Signature(Signature::new(
+ &wrapper.header_hash(),
+ &keypair,
+ )));
+ wrapper.encrypt(&Default::default());
// Write wrapper hash to storage
- let wrapper_unsigned_hash = Hash(signed.unsigned_hash());
+ let wrapper_unsigned_hash = wrapper.header_hash();
let hash_key =
replay_protection::get_tx_hash_key(&wrapper_unsigned_hash);
shell
@@ -1123,8 +1052,9 @@ mod test_process_proposal {
// Run validation
let request = ProcessProposal {
- txs: vec![signed.to_bytes()],
+ txs: vec![wrapper.to_bytes()],
};
+
match shell.process_proposal(request) {
Ok(_) => panic!("Test failed"),
Err(TestError::RejectProposal(response)) => {
@@ -1162,13 +1092,7 @@ mod test_process_proposal {
.write(&balance_key, Amount::whole(1000).try_to_vec().unwrap())
.unwrap();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
+ let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -1176,18 +1100,21 @@ mod test_process_proposal {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
- let signed = wrapper
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Test failed");
+ ))));
+ wrapper.header.chain_id = shell.chain_id.clone();
+ wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ wrapper.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ wrapper.add_section(Section::Signature(Signature::new(
+ &wrapper.header_hash(),
+ &keypair,
+ )));
+ wrapper.encrypt(&Default::default());
// Run validation
let request = ProcessProposal {
- txs: vec![signed.to_bytes(); 2],
+ txs: vec![wrapper.to_bytes(); 2],
};
match shell.process_proposal(request) {
Ok(_) => panic!("Test failed"),
@@ -1205,7 +1132,10 @@ mod test_process_proposal {
format!(
"Transaction replay attempt: Inner transaction hash \
{} already in storage",
- wrapper.tx_hash
+ wrapper
+ .clone()
+ .update_header(TxType::Raw)
+ .header_hash(),
)
);
}
@@ -1220,13 +1150,7 @@ mod test_process_proposal {
let keypair = crate::wallet::defaults::daewon_keypair();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
+ let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -1234,15 +1158,19 @@ mod test_process_proposal {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
- let inner_unsigned_hash = wrapper.tx_hash.clone();
- let signed = wrapper
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Test failed");
+ ))));
+ wrapper.header.chain_id = shell.chain_id.clone();
+ wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ wrapper.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ wrapper.add_section(Section::Signature(Signature::new(
+ &wrapper.header_hash(),
+ &keypair,
+ )));
+ wrapper.encrypt(&Default::default());
+ let inner_unsigned_hash =
+ wrapper.clone().update_header(TxType::Raw).header_hash();
// Write inner hash to storage
let hash_key = replay_protection::get_tx_hash_key(&inner_unsigned_hash);
@@ -1254,7 +1182,7 @@ mod test_process_proposal {
// Run validation
let request = ProcessProposal {
- txs: vec![signed.to_bytes()],
+ txs: vec![wrapper.to_bytes()],
};
match shell.process_proposal(request) {
Ok(_) => panic!("Test failed"),
@@ -1306,13 +1234,7 @@ mod test_process_proposal {
.write(&balance_key, Amount::whole(1000).try_to_vec().unwrap())
.unwrap();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
+ let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -1320,17 +1242,22 @@ mod test_process_proposal {
&keypair,
Epoch(0),
0.into(),
- tx.clone(),
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
- let inner_unsigned_hash = wrapper.tx_hash.clone();
- let signed = wrapper
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Test failed");
+ ))));
+ wrapper.header.chain_id = shell.chain_id.clone();
+ wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ wrapper.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ let mut new_wrapper = wrapper.clone();
+ wrapper.add_section(Section::Signature(Signature::new(
+ &wrapper.header_hash(),
+ &keypair,
+ )));
+ wrapper.encrypt(&Default::default());
+ let inner_unsigned_hash =
+ wrapper.clone().update_header(TxType::Raw).header_hash();
- let new_wrapper = WrapperTx::new(
+ new_wrapper.update_header(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -1338,18 +1265,18 @@ mod test_process_proposal {
&keypair_2,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
- let new_signed = new_wrapper
- .sign(&keypair, shell.chain_id.clone(), None)
- .expect("Test failed");
+ ))));
+ new_wrapper.add_section(Section::Signature(Signature::new(
+ &new_wrapper.header_hash(),
+ &keypair,
+ )));
+ new_wrapper.encrypt(&Default::default());
// Run validation
let request = ProcessProposal {
- txs: vec![signed.to_bytes(), new_signed.to_bytes()],
+ txs: vec![wrapper.to_bytes(), new_wrapper.to_bytes()],
};
match shell.process_proposal(request) {
Ok(_) => panic!("Test failed"),
@@ -1378,13 +1305,7 @@ mod test_process_proposal {
let (mut shell, _) = test_utils::setup(1);
let keypair = crate::wallet::defaults::daewon_keypair();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
+ let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -1392,25 +1313,32 @@ mod test_process_proposal {
&keypair,
Epoch(0),
0.into(),
- tx.clone(),
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
+ ))));
let wrong_chain_id = ChainId("Wrong chain id".to_string());
- let signed = wrapper
- .sign(&keypair, wrong_chain_id.clone(), None)
- .expect("Test failed");
+ wrapper.header.chain_id = wrong_chain_id.clone();
+ wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ wrapper.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ let mut protocol_tx = wrapper.clone();
+ wrapper.add_section(Section::Signature(Signature::new(
+ &wrapper.header_hash(),
+ &keypair,
+ )));
+ wrapper.encrypt(&Default::default());
- let protocol_tx = ProtocolTxType::EthereumStateUpdate(tx).sign(
- &keypair.ref_to(),
+ protocol_tx.update_header(TxType::Protocol(Box::new(ProtocolTx {
+ pk: keypair.ref_to(),
+ tx: ProtocolTxType::EthereumStateUpdate,
+ })));
+ protocol_tx.add_section(Section::Signature(Signature::new(
+ &protocol_tx.header_hash(),
&keypair,
- wrong_chain_id.clone(),
- );
+ )));
// Run validation
let request = ProcessProposal {
- txs: vec![signed.to_bytes(), protocol_tx.to_bytes()],
+ txs: vec![wrapper.to_bytes(), protocol_tx.to_bytes()],
};
match shell.process_proposal(request) {
Ok(_) => panic!("Test failed"),
@@ -1441,19 +1369,7 @@ mod test_process_proposal {
let keypair = crate::wallet::defaults::daewon_keypair();
let wrong_chain_id = ChainId("Wrong chain id".to_string());
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("new transaction data".as_bytes().to_owned()),
- wrong_chain_id.clone(),
- None,
- );
- let decrypted: Tx = DecryptedTx::Decrypted {
- tx: tx.clone(),
- has_valid_pow: false,
- }
- .into();
- let signed_decrypted = decrypted.sign(&keypair);
- let wrapper = WrapperTx::new(
+ let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -1461,12 +1377,24 @@ mod test_process_proposal {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
- let wrapper_in_queue = WrapperTxInQueue {
+ ))));
+ wrapper.header.chain_id = wrong_chain_id.clone();
+ wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ wrapper
+ .set_data(Data::new("new transaction data".as_bytes().to_owned()));
+ let mut decrypted = wrapper.clone();
+ wrapper.encrypt(&Default::default());
+
+ decrypted.update_header(TxType::Decrypted(DecryptedTx::Decrypted {
+ has_valid_pow: false,
+ }));
+ decrypted.add_section(Section::Signature(Signature::new(
+ &decrypted.header_hash(),
+ &keypair,
+ )));
+ let wrapper_in_queue = TxInQueue {
tx: wrapper,
has_valid_pow: false,
};
@@ -1474,7 +1402,7 @@ mod test_process_proposal {
// Run validation
let request = ProcessProposal {
- txs: vec![signed_decrypted.to_bytes()],
+ txs: vec![decrypted.to_bytes()],
};
match shell.process_proposal(request) {
@@ -1502,13 +1430,7 @@ mod test_process_proposal {
let (mut shell, _) = test_utils::setup(1);
let keypair = crate::wallet::defaults::daewon_keypair();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- None,
- );
- let wrapper = WrapperTx::new(
+ let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -1516,18 +1438,22 @@ mod test_process_proposal {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
- let signed = wrapper
- .sign(&keypair, shell.chain_id.clone(), Some(DateTimeUtc::now()))
- .expect("Test failed");
+ ))));
+ wrapper.header.chain_id = shell.chain_id.clone();
+ wrapper.header.expiration = Some(DateTimeUtc::now());
+ wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ wrapper.set_data(Data::new("transaction data".as_bytes().to_owned()));
+ wrapper.add_section(Section::Signature(Signature::new(
+ &wrapper.header_hash(),
+ &keypair,
+ )));
+ wrapper.encrypt(&Default::default());
// Run validation
let request = ProcessProposal {
- txs: vec![signed.to_bytes()],
+ txs: vec![wrapper.to_bytes()],
};
match shell.process_proposal(request) {
Ok(_) => panic!("Test failed"),
@@ -1547,19 +1473,7 @@ mod test_process_proposal {
let (mut shell, _) = test_utils::setup(1);
let keypair = crate::wallet::defaults::daewon_keypair();
- let tx = Tx::new(
- "wasm_code".as_bytes().to_owned(),
- Some("new transaction data".as_bytes().to_owned()),
- shell.chain_id.clone(),
- Some(DateTimeUtc::now()),
- );
- let decrypted: Tx = DecryptedTx::Decrypted {
- tx: tx.clone(),
- has_valid_pow: false,
- }
- .into();
- let signed_decrypted = decrypted.sign(&keypair);
- let wrapper = WrapperTx::new(
+ let mut wrapper = Tx::new(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount: 0.into(),
token: shell.wl_storage.storage.native_token.clone(),
@@ -1567,12 +1481,25 @@ mod test_process_proposal {
&keypair,
Epoch(0),
0.into(),
- tx,
- Default::default(),
#[cfg(not(feature = "mainnet"))]
None,
- );
- let wrapper_in_queue = WrapperTxInQueue {
+ ))));
+ wrapper.header.chain_id = shell.chain_id.clone();
+ wrapper.header.expiration = Some(DateTimeUtc::now());
+ wrapper.set_code(Code::new("wasm_code".as_bytes().to_owned()));
+ wrapper
+ .set_data(Data::new("new transaction data".as_bytes().to_owned()));
+ let mut decrypted = wrapper.clone();
+ wrapper.encrypt(&Default::default());
+
+ decrypted.update_header(TxType::Decrypted(DecryptedTx::Decrypted {
+ has_valid_pow: false,
+ }));
+ decrypted.add_section(Section::Signature(Signature::new(
+ &decrypted.header_hash(),
+ &keypair,
+ )));
+ let wrapper_in_queue = TxInQueue {
tx: wrapper,
has_valid_pow: false,
};
@@ -1580,7 +1507,7 @@ mod test_process_proposal {
// Run validation
let request = ProcessProposal {
- txs: vec![signed_decrypted.to_bytes()],
+ txs: vec![decrypted.to_bytes()],
};
match shell.process_proposal(request) {
Ok(response) => {
diff --git a/apps/src/lib/node/ledger/shims/abcipp_shim.rs b/apps/src/lib/node/ledger/shims/abcipp_shim.rs
index 05ffbf8de0..7bb02a6aef 100644
--- a/apps/src/lib/node/ledger/shims/abcipp_shim.rs
+++ b/apps/src/lib/node/ledger/shims/abcipp_shim.rs
@@ -186,7 +186,7 @@ impl AbcippShim {
let mut end_block_request: FinalizeBlock =
begin_block_request.into();
let hash = self.get_hash();
- end_block_request.hash = BlockHash::from(hash.clone());
+ end_block_request.hash = BlockHash::from(hash);
end_block_request.txs = txs;
self.service
.call(Request::FinalizeBlock(end_block_request))
diff --git a/apps/src/lib/node/ledger/storage/mod.rs b/apps/src/lib/node/ledger/storage/mod.rs
index 73c21ba6ca..e9222ab213 100644
--- a/apps/src/lib/node/ledger/storage/mod.rs
+++ b/apps/src/lib/node/ledger/storage/mod.rs
@@ -246,7 +246,7 @@ mod tests {
// insert
let vp1 = Hash::sha256("vp1".as_bytes());
- storage.write(&key, vp1.clone()).expect("write failed");
+ storage.write(&key, vp1).expect("write failed");
// check
let (vp_code_hash, gas) =
diff --git a/apps/src/lib/node/ledger/storage/rocksdb.rs b/apps/src/lib/node/ledger/storage/rocksdb.rs
index 9d54bc6de3..695946e651 100644
--- a/apps/src/lib/node/ledger/storage/rocksdb.rs
+++ b/apps/src/lib/node/ledger/storage/rocksdb.rs
@@ -537,6 +537,19 @@ impl DB for RocksDB {
return Ok(None);
}
};
+ let update_epoch_blocks_delay: Option = match self
+ .0
+ .get_cf(state_cf, "update_epoch_blocks_delay")
+ .map_err(|e| Error::DBError(e.into_string()))?
+ {
+ Some(bytes) => types::decode(bytes).map_err(Error::CodingError)?,
+ None => {
+ tracing::error!(
+ "Couldn't load epoch update block delay from the DB"
+ );
+ return Ok(None);
+ }
+ };
let tx_queue: TxQueue = match self
.0
.get_cf(state_cf, "tx_queue")
@@ -636,6 +649,7 @@ impl DB for RocksDB {
results,
next_epoch_min_start_height,
next_epoch_min_start_time,
+ update_epoch_blocks_delay,
address_gen,
tx_queue,
}))
@@ -660,10 +674,11 @@ impl DB for RocksDB {
height,
epoch,
pred_epochs,
- results,
next_epoch_min_start_height,
next_epoch_min_start_time,
+ update_epoch_blocks_delay,
address_gen,
+ results,
tx_queue,
}: BlockStateWrite = state;
@@ -704,6 +719,24 @@ impl DB for RocksDB {
"next_epoch_min_start_time",
types::encode(&next_epoch_min_start_time),
);
+ if let Some(current_value) = self
+ .0
+ .get_cf(state_cf, "update_epoch_blocks_delay")
+ .map_err(|e| Error::DBError(e.into_string()))?
+ {
+ // Write the predecessor value for rollback
+ batch.0.put_cf(
+ state_cf,
+ "pred/update_epoch_blocks_delay",
+ current_value,
+ );
+ }
+ batch.0.put_cf(
+ state_cf,
+ "update_epoch_blocks_delay",
+ types::encode(&update_epoch_blocks_delay),
+ );
+
// Tx queue
if let Some(pred_tx_queue) = self
.0
@@ -1412,6 +1445,7 @@ mod test {
let height = BlockHeight::default();
let next_epoch_min_start_height = BlockHeight::default();
let next_epoch_min_start_time = DateTimeUtc::now();
+ let update_epoch_blocks_delay = None;
let address_gen = EstablishedAddressGen::new("whatever");
let tx_queue = TxQueue::default();
let results = BlockResults::default();
@@ -1425,6 +1459,7 @@ mod test {
pred_epochs: &pred_epochs,
next_epoch_min_start_height,
next_epoch_min_start_time,
+ update_epoch_blocks_delay,
address_gen: &address_gen,
tx_queue: &tx_queue,
};
diff --git a/apps/src/lib/wallet/keys.rs b/apps/src/lib/wallet/keys.rs
deleted file mode 100644
index 8b13789179..0000000000
--- a/apps/src/lib/wallet/keys.rs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/apps/src/lib/wallet/mod.rs b/apps/src/lib/wallet/mod.rs
index 04aae73dc6..5e97d1bd68 100644
--- a/apps/src/lib/wallet/mod.rs
+++ b/apps/src/lib/wallet/mod.rs
@@ -1,5 +1,4 @@
pub mod defaults;
-mod keys;
pub mod pre_genesis;
mod store;
@@ -7,15 +6,16 @@ use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::{env, fs};
+use namada::bip39::{Language, Mnemonic};
pub use namada::ledger::wallet::alias::Alias;
use namada::ledger::wallet::{
- ConfirmationResponse, FindKeyError, Wallet, WalletUtils,
-};
-pub use namada::ledger::wallet::{
- DecryptionError, StoredKeypair, ValidatorData, ValidatorKeys,
+ ConfirmationResponse, FindKeyError, GenRestoreKeyError, Wallet, WalletUtils,
};
+pub use namada::ledger::wallet::{ValidatorData, ValidatorKeys};
use namada::types::key::*;
+use rand_core::OsRng;
pub use store::wallet_file;
+use zeroize::Zeroizing;
use crate::cli;
use crate::config::genesis::genesis_config::GenesisConfig;
@@ -24,28 +24,57 @@ use crate::config::genesis::genesis_config::GenesisConfig;
pub struct CliWalletUtils;
impl WalletUtils for CliWalletUtils {
+ type Rng = OsRng;
type Storage = PathBuf;
- /// Read the password for encryption/decryption from the file/env/stdin.
- /// Panics if all options are empty/invalid.
- fn read_password(prompt_msg: &str) -> String {
+ fn read_decryption_password() -> Zeroizing {
+ match env::var("NAMADA_WALLET_PASSWORD_FILE") {
+ Ok(path) => Zeroizing::new(
+ fs::read_to_string(path)
+ .expect("Something went wrong reading the file"),
+ ),
+ Err(_) => match env::var("NAMADA_WALLET_PASSWORD") {
+ Ok(password) => Zeroizing::new(password),
+ Err(_) => {
+ let prompt = "Enter your decryption password: ";
+ rpassword::read_password_from_tty(Some(prompt))
+ .map(Zeroizing::new)
+ .expect("Failed reading password from tty.")
+ }
+ },
+ }
+ }
+
+ fn read_encryption_password() -> Zeroizing {
let pwd = match env::var("NAMADA_WALLET_PASSWORD_FILE") {
- Ok(path) => fs::read_to_string(path)
- .expect("Something went wrong reading the file"),
+ Ok(path) => Zeroizing::new(
+ fs::read_to_string(path)
+ .expect("Something went wrong reading the file"),
+ ),
Err(_) => match env::var("NAMADA_WALLET_PASSWORD") {
- Ok(password) => password,
- Err(_) => rpassword::read_password_from_tty(Some(prompt_msg))
- .unwrap_or_default(),
+ Ok(password) => Zeroizing::new(password),
+ Err(_) => {
+ let prompt = "Enter your encryption password: ";
+ read_and_confirm_passphrase_tty(prompt).unwrap_or_else(
+ |e| {
+ eprintln!("{e}");
+ eprintln!(
+ "Action cancelled, no changes persisted."
+ );
+ cli::safe_exit(1)
+ },
+ )
+ }
},
};
- if pwd.is_empty() {
+ if pwd.as_str().is_empty() {
eprintln!("Password cannot be empty");
+ eprintln!("Action cancelled, no changes persisted.");
cli::safe_exit(1)
}
pwd
}
- /// Read an alias from the file/env/stdin.
fn read_alias(prompt_msg: &str) -> String {
print!("Choose an alias for {}: ", prompt_msg);
io::stdout().flush().unwrap();
@@ -54,6 +83,26 @@ impl WalletUtils for CliWalletUtils {
alias.trim().to_owned()
}
+ fn read_mnemonic_code() -> Result {
+ let phrase = get_secure_user_input("Input mnemonic code: ")
+ .map_err(|_| GenRestoreKeyError::MnemonicInputError)?;
+ Mnemonic::from_phrase(phrase.as_ref(), Language::English)
+ .map_err(|_| GenRestoreKeyError::MnemonicInputError)
+ }
+
+ fn read_mnemonic_passphrase(confirm: bool) -> Zeroizing {
+ let prompt = "Enter BIP39 passphrase (empty for none): ";
+ let result = if confirm {
+ read_and_confirm_passphrase_tty(prompt)
+ } else {
+ rpassword::read_password_from_tty(Some(prompt)).map(Zeroizing::new)
+ };
+ result.unwrap_or_else(|e| {
+ eprintln!("{}", e);
+ cli::safe_exit(1);
+ })
+ }
+
// The given alias has been selected but conflicts with another alias in
// the store. Offer the user to either replace existing mapping, alter the
// chosen alias to a name of their chosing, or cancel the aliasing.
@@ -101,6 +150,38 @@ impl WalletUtils for CliWalletUtils {
}
}
+fn get_secure_user_input(request: S) -> std::io::Result>
+where
+ S: std::fmt::Display,
+{
+ print!("{} ", request);
+ std::io::stdout().flush()?;
+
+ let mut response = Zeroizing::default();
+ std::io::stdin().read_line(&mut response)?;
+ Ok(response)
+}
+
+pub fn read_and_confirm_passphrase_tty(
+ prompt: &str,
+) -> Result, std::io::Error> {
+ let passphrase =
+ rpassword::read_password_from_tty(Some(prompt)).map(Zeroizing::new)?;
+ if !passphrase.is_empty() {
+ let confirmed = rpassword::read_password_from_tty(Some(
+ "Enter same passphrase again: ",
+ ))
+ .map(Zeroizing::new)?;
+ if confirmed != passphrase {
+ return Err(std::io::Error::new(
+ std::io::ErrorKind::InvalidInput,
+ "Passphrases did not match",
+ ));
+ }
+ }
+ Ok(passphrase)
+}
+
/// Generate keypair
/// for signing protocol txs and for the DKG (which will also be stored)
/// A protocol keypair may be optionally provided, indicating that
@@ -183,28 +264,38 @@ pub fn load_or_new_from_genesis(
Wallet::::new(store_dir.to_path_buf(), store)
}
-/// Read the password for encryption from the file/env/stdin with
-/// confirmation.
-pub fn read_and_confirm_pwd(unsafe_dont_encrypt: bool) -> Option {
- let password = if unsafe_dont_encrypt {
+/// Read the password for encryption from the file/env/stdin, with
+/// confirmation if read from stdin.
+pub fn read_and_confirm_encryption_password(
+ unsafe_dont_encrypt: bool,
+) -> Option> {
+ if unsafe_dont_encrypt {
println!("Warning: The keypair will NOT be encrypted.");
None
} else {
- Some(CliWalletUtils::read_password(
- "Enter your encryption password: ",
- ))
- };
- // Bis repetita for confirmation.
- let to_confirm = if unsafe_dont_encrypt {
- None
- } else {
- Some(CliWalletUtils::read_password(
- "To confirm, please enter the same encryption password once more: ",
- ))
- };
- if to_confirm != password {
- eprintln!("Your two inputs do not match!");
- cli::safe_exit(1)
+ Some(CliWalletUtils::read_encryption_password())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use namada::bip39::MnemonicType;
+ use namada::ledger::wallet::WalletUtils;
+ use rand_core;
+
+ use super::CliWalletUtils;
+
+ #[test]
+ fn test_generate_mnemonic() {
+ const MNEMONIC_TYPE: MnemonicType = MnemonicType::Words12;
+
+ let mut rng = rand_core::OsRng;
+ let mnemonic1 =
+ CliWalletUtils::generate_mnemonic_code(MNEMONIC_TYPE, &mut rng)
+ .unwrap();
+ let mnemonic2 =
+ CliWalletUtils::generate_mnemonic_code(MNEMONIC_TYPE, &mut rng)
+ .unwrap();
+ assert_ne!(mnemonic1.into_phrase(), mnemonic2.into_phrase());
}
- password
}
diff --git a/apps/src/lib/wallet/pre_genesis.rs b/apps/src/lib/wallet/pre_genesis.rs
index 12209d5674..55638ab31e 100644
--- a/apps/src/lib/wallet/pre_genesis.rs
+++ b/apps/src/lib/wallet/pre_genesis.rs
@@ -8,9 +8,10 @@ use namada::ledger::wallet::pre_genesis::{
};
use namada::ledger::wallet::{gen_key_to_store, WalletUtils};
use namada::types::key::SchemeType;
+use zeroize::Zeroizing;
use crate::wallet::store::gen_validator_keys;
-use crate::wallet::{read_and_confirm_pwd, CliWalletUtils};
+use crate::wallet::{read_and_confirm_encryption_password, CliWalletUtils};
/// Validator pre-genesis wallet file name
const VALIDATOR_FILE_NAME: &str = "wallet.toml";
@@ -27,7 +28,7 @@ pub fn gen_and_store(
unsafe_dont_encrypt: bool,
store_dir: &Path,
) -> std::io::Result {
- let password = read_and_confirm_pwd(unsafe_dont_encrypt);
+ let password = read_and_confirm_encryption_password(unsafe_dont_encrypt);
let validator = gen(scheme, password);
let data = validator.store.encode();
let wallet_path = validator_file_name(store_dir);
@@ -66,9 +67,7 @@ pub fn load(store_dir: &Path) -> Result {
|| store.consensus_key.is_encrypted()
|| store.account_key.is_encrypted()
{
- Some(CliWalletUtils::read_password(
- "Enter decryption password: ",
- ))
+ Some(CliWalletUtils::read_decryption_password())
} else {
None
};
@@ -99,17 +98,20 @@ pub fn load(store_dir: &Path) -> Result {
/// Generate a new [`ValidatorWallet`] with required pre-genesis keys. Will
/// prompt for password when `!unsafe_dont_encrypt`.
-fn gen(scheme: SchemeType, password: Option) -> ValidatorWallet {
- let (account_key, account_sk) = gen_key_to_store(scheme, &password);
+fn gen(
+ scheme: SchemeType,
+ password: Option>,
+) -> ValidatorWallet {
+ let (account_key, account_sk) = gen_key_to_store(scheme, password.clone());
let (consensus_key, consensus_sk) = gen_key_to_store(
// Note that TM only allows ed25519 for consensus key
SchemeType::Ed25519,
- &password,
+ password.clone(),
);
let (tendermint_node_key, tendermint_node_sk) = gen_key_to_store(
// Note that TM only allows ed25519 for node IDs
SchemeType::Ed25519,
- &password,
+ password,
);
let validator_keys = gen_validator_keys(None, scheme);
let store = ValidatorStore {
diff --git a/apps/src/lib/wallet/store.rs b/apps/src/lib/wallet/store.rs
index fcdcfb24d9..4b2fcfa9ed 100644
--- a/apps/src/lib/wallet/store.rs
+++ b/apps/src/lib/wallet/store.rs
@@ -12,7 +12,7 @@ use file_lock::{FileLock, FileOptions};
use namada::ledger::wallet::store::AddressVpType;
#[cfg(feature = "dev")]
use namada::ledger::wallet::StoredKeypair;
-use namada::ledger::wallet::{gen_sk, Store, ValidatorKeys};
+use namada::ledger::wallet::{gen_sk_rng, Store, ValidatorKeys};
#[cfg(not(feature = "dev"))]
use namada::types::address::Address;
use namada::types::key::*;
@@ -169,7 +169,8 @@ pub fn gen_validator_keys(
protocol_keypair: Option,
scheme: SchemeType,
) -> ValidatorKeys {
- let protocol_keypair = protocol_keypair.unwrap_or_else(|| gen_sk(scheme));
+ let protocol_keypair =
+ protocol_keypair.unwrap_or_else(|| gen_sk_rng(scheme));
let dkg_keypair = ferveo_common::Keypair::::new(
&mut StdRng::from_entropy(),
);
diff --git a/core/Cargo.toml b/core/Cargo.toml
index a2d8358a23..8f155db2d5 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -7,7 +7,7 @@ resolver = "2"
version = "0.16.0"
[features]
-default = []
+default = ["multicore"]
mainnet = []
ferveo-tpke = [
"ferveo",
@@ -25,12 +25,6 @@ secp256k1-sign-verify = [
"libsecp256k1/hmac",
]
-abcipp = [
- "ibc-proto-abcipp",
- "ibc-abcipp",
- "tendermint-abcipp",
- "tendermint-proto-abcipp",
-]
abciplus = [
"ibc",
"ibc-proto",
@@ -42,9 +36,9 @@ ibc-mocks = [
"ibc/mocks",
"ibc/std",
]
-ibc-mocks-abcipp = [
- "ibc-abcipp/mocks",
- "ibc-abcipp/std",
+
+multicore = [
+ "bellman/multicore"
]
# for integration tests and test utilies
@@ -63,7 +57,7 @@ ark-serialize = {version = "0.3"}
# branch = "bat/arse-merkle-tree"
arse-merkle-tree = {package = "sparse-merkle-tree", git = "https://github.com/heliaxdev/sparse-merkle-tree", rev = "e086b235ed6e68929bf73f617dd61cd17b000a56", default-features = false, features = ["std", "borsh"]}
bech32 = "0.8.0"
-bellman = "0.11.2"
+bellman = { version = "0.11.2", default-features = false, features = ["groth16"] }
borsh = "0.9.0"
chrono = {version = "0.4.22", default-features = false, features = ["clock", "std"]}
data-encoding = "2.3.2"
@@ -75,13 +69,12 @@ tpke = {package = "group-threshold-cryptography", optional = true, git = "https:
# TODO using the same version of tendermint-rs as we do here.
ibc = {version = "0.36.0", default-features = false, features = ["serde"], optional = true}
ibc-proto = {version = "0.26.0", default-features = false, optional = true}
-ibc-abcipp = {package = "ibc", git = "https://github.com/heliaxdev/cosmos-ibc-rs", rev = "db14744bfba6239cc5f58345ff90f8b7d42637d6", default-features = false, features = ["serde"], optional = true}
-ibc-proto-abcipp = {package = "ibc-proto", git = "https://github.com/heliaxdev/ibc-proto-rs", rev = "dd8ba23110a144ffe2074a0b889676468266435a", default-features = false, optional = true}
ics23 = "0.9.0"
index-set = {git = "https://github.com/heliaxdev/index-set", tag = "v0.7.1", features = ["serialize-borsh", "serialize-serde"]}
itertools = "0.10.0"
libsecp256k1 = {git = "https://github.com/heliaxdev/libsecp256k1", rev = "bbb3bd44a49db361f21d9db80f9a087c194c0ae9", default-features = false, features = ["std", "static-context"]}
-masp_primitives = { git = "https://github.com/anoma/masp", rev = "bee40fc465f6afbd10558d12fe96eb1742eee45c" }
+# branch = "murisi/namada-integration"
+masp_primitives = { git = "https://github.com/anoma/masp", rev = "cfea8c95d3f73077ca3e25380fd27e5b46e828fd" }
proptest = {git = "https://github.com/heliaxdev/proptest", rev = "8f1b4abe7ebd35c0781bf9a00a4ee59833ffa2a1", optional = true}
prost = "0.11.6"
prost-types = "0.11.6"
@@ -95,8 +88,6 @@ serde_json = "1.0.62"
sha2 = "0.9.3"
tendermint = {version = "0.23.6", optional = true}
tendermint-proto = {version = "0.23.6", optional = true}
-tendermint-abcipp = {package = "tendermint", git = "https://github.com/heliaxdev/tendermint-rs", rev = "02b256829e80f8cfecf3fa0d625c2a76c79cd043", optional = true}
-tendermint-proto-abcipp = {package = "tendermint-proto", git = "https://github.com/heliaxdev/tendermint-rs", rev = "02b256829e80f8cfecf3fa0d625c2a76c79cd043", optional = true}
thiserror = "1.0.38"
tracing = "0.1.30"
zeroize = {version = "1.5.5", features = ["zeroize_derive"]}
diff --git a/core/src/ledger/storage/merkle_tree.rs b/core/src/ledger/storage/merkle_tree.rs
index 31fb40b1eb..046ebca4e6 100644
--- a/core/src/ledger/storage/merkle_tree.rs
+++ b/core/src/ledger/storage/merkle_tree.rs
@@ -723,7 +723,7 @@ mod test {
let stores_write = tree.stores();
let mut stores_read = MerkleTreeStoresRead::default();
for st in StoreType::iter() {
- stores_read.set_root(st, stores_write.root(st).clone());
+ stores_read.set_root(st, *stores_write.root(st));
stores_read.set_store(stores_write.store(st).to_owned());
}
let restored_tree =
diff --git a/core/src/ledger/storage/mockdb.rs b/core/src/ledger/storage/mockdb.rs
index 16e28d2759..c8cfc3361b 100644
--- a/core/src/ledger/storage/mockdb.rs
+++ b/core/src/ledger/storage/mockdb.rs
@@ -83,6 +83,13 @@ impl DB for MockDB {
}
None => return Ok(None),
};
+ let update_epoch_blocks_delay: Option =
+ match self.0.borrow().get("update_epoch_blocks_delay") {
+ Some(bytes) => {
+ types::decode(bytes).map_err(Error::CodingError)?
+ }
+ None => return Ok(None),
+ };
#[cfg(feature = "ferveo-tpke")]
let tx_queue: TxQueue = match self.0.borrow().get("tx_queue") {
Some(bytes) => types::decode(bytes).map_err(Error::CodingError)?,
@@ -160,6 +167,7 @@ impl DB for MockDB {
pred_epochs,
next_epoch_min_start_height,
next_epoch_min_start_time,
+ update_epoch_blocks_delay,
address_gen,
results,
#[cfg(feature = "ferveo-tpke")]
@@ -188,6 +196,7 @@ impl DB for MockDB {
pred_epochs,
next_epoch_min_start_height,
next_epoch_min_start_time,
+ update_epoch_blocks_delay,
address_gen,
results,
#[cfg(feature = "ferveo-tpke")]
@@ -203,6 +212,10 @@ impl DB for MockDB {
"next_epoch_min_start_time".into(),
types::encode(&next_epoch_min_start_time),
);
+ self.0.borrow_mut().insert(
+ "update_epoch_blocks_delay".into(),
+ types::encode(&update_epoch_blocks_delay),
+ );
#[cfg(feature = "ferveo-tpke")]
{
self.0
diff --git a/core/src/ledger/storage/mod.rs b/core/src/ledger/storage/mod.rs
index cb3f9299df..fac8c9892d 100644
--- a/core/src/ledger/storage/mod.rs
+++ b/core/src/ledger/storage/mod.rs
@@ -168,6 +168,8 @@ pub struct BlockStateRead {
pub next_epoch_min_start_height: BlockHeight,
/// Minimum block time at which the next epoch may start
pub next_epoch_min_start_time: DateTimeUtc,
+ /// Update epoch delay
+ pub update_epoch_blocks_delay: Option,
/// Established address generator
pub address_gen: EstablishedAddressGen,
/// Results of applying transactions
@@ -195,6 +197,8 @@ pub struct BlockStateWrite<'a> {
pub next_epoch_min_start_height: BlockHeight,
/// Minimum block time at which the next epoch may start
pub next_epoch_min_start_time: DateTimeUtc,
+ /// Update epoch delay
+ pub update_epoch_blocks_delay: Option,
/// Established address generator
pub address_gen: &'a EstablishedAddressGen,
/// Results of applying transactions
@@ -390,6 +394,7 @@ where
pred_epochs,
next_epoch_min_start_height,
next_epoch_min_start_time,
+ update_epoch_blocks_delay,
results,
address_gen,
#[cfg(feature = "ferveo-tpke")]
@@ -405,6 +410,7 @@ where
self.last_epoch = epoch;
self.next_epoch_min_start_height = next_epoch_min_start_height;
self.next_epoch_min_start_time = next_epoch_min_start_time;
+ self.update_epoch_blocks_delay = update_epoch_blocks_delay;
self.address_gen = address_gen;
// Rebuild Merkle tree
self.block.tree = MerkleTree::new(merkle_tree_stores)
@@ -462,6 +468,7 @@ where
pred_epochs: &self.block.pred_epochs,
next_epoch_min_start_height: self.next_epoch_min_start_height,
next_epoch_min_start_time: self.next_epoch_min_start_time,
+ update_epoch_blocks_delay: self.update_epoch_blocks_delay,
address_gen: &self.address_gen,
#[cfg(feature = "ferveo-tpke")]
tx_queue: &self.tx_queue,
@@ -919,7 +926,6 @@ where
}
}
}
-
Ok(())
}
}
diff --git a/core/src/ledger/storage/write_log.rs b/core/src/ledger/storage/write_log.rs
index bf4881aab0..938e4e8948 100644
--- a/core/src/ledger/storage/write_log.rs
+++ b/core/src/ledger/storage/write_log.rs
@@ -439,11 +439,7 @@ impl WriteLog {
}
StorageModification::InitAccount { vp_code_hash } => {
storage
- .batch_write_subspace_val(
- batch,
- key,
- vp_code_hash.clone(),
- )
+ .batch_write_subspace_val(batch, key, *vp_code_hash)
.map_err(Error::StorageError)?;
}
// temporary value isn't persisted
@@ -609,7 +605,7 @@ mod tests {
// init
let init_vp = "initialized".as_bytes().to_vec();
let vp_hash = Hash::sha256(init_vp);
- let (addr, gas) = write_log.init_account(&address_gen, vp_hash.clone());
+ let (addr, gas) = write_log.init_account(&address_gen, vp_hash);
let vp_key = storage::Key::validity_predicate(&addr);
assert_eq!(gas, (vp_key.len() + vp_hash.len()) as u64);
@@ -693,7 +689,7 @@ mod tests {
// initialize an account
let vp1 = Hash::sha256("vp1".as_bytes());
- let (addr1, _) = write_log.init_account(&address_gen, vp1.clone());
+ let (addr1, _) = write_log.init_account(&address_gen, vp1);
write_log.commit_tx();
// write values
diff --git a/core/src/ledger/storage_api/collections/lazy_map.rs b/core/src/ledger/storage_api/collections/lazy_map.rs
index c1e8ae6dbf..5870fd7b3f 100644
--- a/core/src/ledger/storage_api/collections/lazy_map.rs
+++ b/core/src/ledger/storage_api/collections/lazy_map.rs
@@ -740,4 +740,119 @@ mod test {
Ok(())
}
+
+ #[test]
+ fn test_nested_map_basics() -> storage_api::Result<()> {
+ let mut storage = TestWlStorage::default();
+ let key = storage::Key::parse("testing").unwrap();
+
+ // A nested map from u32 -> String -> u32
+ let nested_map = NestedMap::>::open(key);
+
+ assert!(nested_map.is_empty(&storage)?);
+ assert!(nested_map.iter(&storage)?.next().is_none());
+
+ // Insert a value
+ nested_map
+ .at(&0)
+ .insert(&mut storage, "string1".to_string(), 100)?;
+
+ assert!(!nested_map.is_empty(&storage)?);
+ assert!(nested_map.iter(&storage)?.next().is_some());
+ assert_eq!(
+ nested_map.at(&0).get(&storage, &"string1".to_string())?,
+ Some(100)
+ );
+ assert_eq!(
+ nested_map.at(&0).get(&storage, &"string2".to_string())?,
+ None
+ );
+
+ // Insert more values
+ nested_map
+ .at(&1)
+ .insert(&mut storage, "string1".to_string(), 200)?;
+ nested_map
+ .at(&0)
+ .insert(&mut storage, "string2".to_string(), 300)?;
+
+ let mut it = nested_map.iter(&storage)?;
+ let (
+ NestedSubKey::Data {
+ key,
+ nested_sub_key: SubKey::Data(inner_key),
+ },
+ inner_val,
+ ) = it.next().unwrap()?;
+ assert_eq!(key, 0);
+ assert_eq!(inner_key, "string1".to_string());
+ assert_eq!(inner_val, 100);
+
+ let (
+ NestedSubKey::Data {
+ key,
+ nested_sub_key: SubKey::Data(inner_key),
+ },
+ inner_val,
+ ) = it.next().unwrap()?;
+ assert_eq!(key, 0);
+ assert_eq!(inner_key, "string2".to_string());
+ assert_eq!(inner_val, 300);
+
+ let (
+ NestedSubKey::Data {
+ key,
+ nested_sub_key: SubKey::Data(inner_key),
+ },
+ inner_val,
+ ) = it.next().unwrap()?;
+ assert_eq!(key, 1);
+ assert_eq!(inner_key, "string1".to_string());
+ assert_eq!(inner_val, 200);
+
+ // Next element should be None
+ assert!(it.next().is_none());
+ drop(it);
+
+ // Start removing elements
+ let rem = nested_map
+ .at(&0)
+ .remove(&mut storage, &"string2".to_string())?;
+ assert_eq!(rem, Some(300));
+ assert_eq!(
+ nested_map.at(&0).get(&storage, &"string2".to_string())?,
+ None
+ );
+ assert_eq!(nested_map.at(&0).len(&storage)?, 1_u64);
+ assert_eq!(nested_map.at(&1).len(&storage)?, 1_u64);
+ assert_eq!(nested_map.iter(&storage)?.count(), 2);
+
+ // Start removing elements
+ let rem = nested_map
+ .at(&0)
+ .remove(&mut storage, &"string1".to_string())?;
+ assert_eq!(rem, Some(100));
+ assert_eq!(
+ nested_map.at(&0).get(&storage, &"string1".to_string())?,
+ None
+ );
+ assert_eq!(nested_map.at(&0).len(&storage)?, 0_u64);
+ assert_eq!(nested_map.at(&1).len(&storage)?, 1_u64);
+ assert_eq!(nested_map.iter(&storage)?.count(), 1);
+
+ // Start removing elements
+ let rem = nested_map
+ .at(&1)
+ .remove(&mut storage, &"string1".to_string())?;
+ assert_eq!(rem, Some(200));
+ assert_eq!(
+ nested_map.at(&1).get(&storage, &"string1".to_string())?,
+ None
+ );
+ assert_eq!(nested_map.at(&0).len(&storage)?, 0_u64);
+ assert_eq!(nested_map.at(&1).len(&storage)?, 0_u64);
+ assert!(nested_map.is_empty(&storage)?);
+
+ Ok(())
+ }
}
diff --git a/core/src/ledger/storage_api/collections/lazy_vec.rs b/core/src/ledger/storage_api/collections/lazy_vec.rs
index 1e83456814..d21ca1c515 100644
--- a/core/src/ledger/storage_api/collections/lazy_vec.rs
+++ b/core/src/ledger/storage_api/collections/lazy_vec.rs
@@ -407,7 +407,7 @@ impl LazyVec {
// `LazyVec` methods with borsh encoded values `T`
impl LazyVec
where
- T: BorshSerialize + BorshDeserialize + 'static,
+ T: BorshSerialize + BorshDeserialize + 'static + Debug,
{
/// Appends an element to the back of a collection.
pub fn push(&self, storage: &mut S, val: T) -> Result<()>
@@ -470,6 +470,23 @@ where
storage.read(&self.get_data_key(index))
}
+ /// Read the first element
+ pub fn front(&self, storage: &S) -> Result