diff --git a/.cargo/config.toml b/.cargo/config.toml index 5355758f7a4fa..66b28b3485d86 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -18,14 +18,15 @@ rustflags = [ "-Aclippy::borrowed-box", # Reasonable to fix this one "-Aclippy::too-many-arguments", # (Turning this on would lead to) "-Aclippy::unnecessary_cast", # Types may change - "-Aclippy::identity-op", # One case where we do 0 + + "-Aclippy::identity-op", # One case where we do 0 + "-Aclippy::useless_conversion", # Types may change "-Aclippy::unit_arg", # styalistic. "-Aclippy::option-map-unit-fn", # styalistic - "-Aclippy::bind_instead_of_map", # styalistic + "-Aclippy::bind_instead_of_map", # styalistic "-Aclippy::erasing_op", # E.g. 0 * DOLLARS "-Aclippy::eq_op", # In tests we test equality. "-Aclippy::while_immutable_condition", # false positives "-Aclippy::needless_option_as_deref", # false positives "-Aclippy::derivable_impls", # false positives + "-Aclippy::stable_sort_primitive", # prefer stable sort ] diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 765112bfa9e62..e6f26cbfd5cf7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -41,7 +41,7 @@ workflow: - if: $CI_COMMIT_TAG - if: $CI_COMMIT_BRANCH -variables: &default-vars +variables: GIT_STRATEGY: fetch GIT_DEPTH: 100 CARGO_INCREMENTAL: 0 @@ -131,6 +131,18 @@ default: - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 +# handle the specific case where benches could store incorrect bench data because of the downstream staging runs +# exclude cargo-check-benches from such runs +.test-refs-check-benches: + rules: + - if: $CI_COMMIT_REF_NAME == "master" && $CI_PIPELINE_SOURCE == "parent_pipeline" && $CI_IMAGE =~ /staging$/ + when: never + - if: $CI_PIPELINE_SOURCE == "web" + - if: $CI_PIPELINE_SOURCE == "schedule" + - if: $CI_COMMIT_REF_NAME == "master" + - if: $CI_COMMIT_REF_NAME =~ /^[0-9]+$/ # PRs + - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 + .test-refs-no-trigger: rules: - if: $CI_PIPELINE_SOURCE == "pipeline" @@ -266,8 +278,6 @@ rusty-cachier-notify: PR_NUM: "${PR_NUM}" trigger: project: "parity/infrastructure/ci_cd/pipeline-stopper" - # remove branch, when pipeline-stopper for polakdot is updated to the same branch - branch: "as-improve" # need to copy jobs this way because otherwise gitlab will wait # for all 3 jobs to finish instead of cancelling if one fails diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs index b0244fbdab85b..96731770ff2ea 100644 --- a/.maintain/frame-weight-template.hbs +++ b/.maintain/frame-weight-template.hbs @@ -64,6 +64,7 @@ impl WeightInfo for SubstrateWeight { {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { + // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. Weight::from_ref_time({{underscore benchmark.base_weight}} as u64) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} @@ -99,6 +100,7 @@ impl WeightInfo for () { {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { + // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. Weight::from_ref_time({{underscore benchmark.base_weight}} as u64) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} diff --git a/Cargo.lock b/Cargo.lock index 9c408b6614e46..8da71741265e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if 1.0.0", - "cipher 0.3.0", + "cipher", "cpufeatures", "opaque-debug 0.3.0", ] @@ -56,7 +56,7 @@ checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" dependencies = [ "aead", "aes", - "cipher 0.3.0", + "cipher", "ctr", "ghash", "subtle", @@ -130,9 +130,15 @@ dependencies = [ [[package]] name = "arbitrary" -version = "1.1.2" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29d47fbf90d5149a107494b15a7dc8d69b351be2db3bb9691740e88ec17fd880" + +[[package]] +name = "array-bytes" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25e0a02cf12f1b1f48b14cb7f8217b876d09992b39c816ffb3b1ba64dd979a87" +checksum = "6a913633b0c922e6b745072795f50d90ebea78ba31a57e2ac8c2fc7b50950949" [[package]] name = "arrayref" @@ -173,36 +179,46 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "async-channel" version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28" dependencies = [ - "concurrent-queue", + "concurrent-queue 1.2.4", "event-listener", "futures-core", ] [[package]] name = "async-executor" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b" dependencies = [ + "async-lock", "async-task", - "concurrent-queue", + "concurrent-queue 2.0.0", "fastrand", "futures-lite", - "once_cell", "slab", ] [[package]] name = "async-global-executor" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da5b41ee986eed3f524c380e6d64965aea573882a8907682ad100f7859305ca" +checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" dependencies = [ "async-channel", "async-executor", @@ -215,16 +231,16 @@ dependencies = [ [[package]] name = "async-io" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e21f3a490c72b3b0cf44962180e60045de2925d8dff97918f7ee43c8f637c7" +checksum = "e8121296a9f05be7f34aa4196b1747243b3b62e048bb7906f644f3fbfc490cf7" dependencies = [ + "async-lock", "autocfg", - "concurrent-queue", + "concurrent-queue 1.2.4", "futures-lite", "libc", "log", - "once_cell", "parking", "polling", "slab", @@ -267,6 +283,7 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" dependencies = [ + "async-attributes", "async-channel", "async-global-executor", "async-io", @@ -290,9 +307,9 @@ dependencies = [ [[package]] name = "async-std-resolver" -version = "0.21.2" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2f8a4a203be3325981310ab243a28e6e4ea55b6519bffce05d41ab60e09ad8" +checksum = "6ba50e24d9ee0a8950d3d03fc6d0dd10aa14b5de3b101949b4e160f7fee7c723" dependencies = [ "async-std", "async-trait", @@ -343,9 +360,9 @@ dependencies = [ [[package]] name = "asynchronous-codec" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0de5164e5edbf51c45fb8c2d9664ae1c095cce1b265ecf7569093c0d66ef690" +checksum = "06a0daa378f5fd10634e44b0a29b2a87b890657658e072a30d6f26e57ddee182" dependencies = [ "bytes", "futures-sink", @@ -416,6 +433,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64ct" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" + [[package]] name = "beef" version = "0.5.2" @@ -429,12 +452,12 @@ dependencies = [ name = "beefy-gadget" version = "4.0.0-dev" dependencies = [ + "array-bytes", "async-trait", "beefy-primitives", "fnv", "futures", "futures-timer", - "hex", "log", "parity-scale-codec", "parking_lot 0.12.1", @@ -445,6 +468,7 @@ dependencies = [ "sc-finality-grandpa", "sc-keystore", "sc-network", + "sc-network-common", "sc-network-gossip", "sc-network-test", "sc-utils", @@ -496,37 +520,32 @@ dependencies = [ name = "beefy-merkle-tree" version = "4.0.0-dev" dependencies = [ + "array-bytes", "beefy-primitives", "env_logger", - "hex", - "hex-literal", "log", "sp-api", - "tiny-keccak", + "sp-runtime", ] [[package]] name = "beefy-primitives" version = "4.0.0-dev" dependencies = [ - "hex", - "hex-literal", + "array-bytes", "parity-scale-codec", "scale-info", + "serde", "sp-api", "sp-application-crypto", "sp-core", + "sp-io", "sp-keystore", + "sp-mmr-primitives", "sp-runtime", "sp-std", ] -[[package]] -name = "bimap" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0455254eb5c6964c4545d8bac815e1a1be4f3afe0ae695ea539c12d728d44b" - [[package]] name = "bincode" version = "1.3.3" @@ -538,9 +557,9 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.59.2" +version = "0.60.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" +checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" dependencies = [ "bitflags", "cexpr", @@ -575,9 +594,9 @@ dependencies = [ [[package]] name = "blake2" -version = "0.10.4" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9cf849ee05b2ee5fba5e36f97ff8ec2533916700fc0758d40d92136a42f3388" +checksum = "b12e5fd123190ce1c2e559308a94c9bacad77907d4c6005d9e58fe1a0689e55e" dependencies = [ "digest 0.10.5", ] @@ -814,9 +833,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.73" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" dependencies = [ "jobserver", ] @@ -851,6 +870,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "chacha20" version = "0.8.2" @@ -858,7 +883,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" dependencies = [ "cfg-if 1.0.0", - "cipher 0.3.0", + "cipher", "cpufeatures", "zeroize", ] @@ -871,16 +896,16 @@ checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" dependencies = [ "aead", "chacha20", - "cipher 0.3.0", + "cipher", "poly1305", "zeroize", ] [[package]] name = "chrono" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" dependencies = [ "iana-time-zone", "js-sys", @@ -913,16 +938,6 @@ dependencies = [ "generic-array 0.14.6", ] -[[package]] -name = "cipher" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" -dependencies = [ - "crypto-common", - "inout", -] - [[package]] name = "ckb-merkle-mountain-range" version = "0.3.2" @@ -940,7 +955,7 @@ checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" dependencies = [ "glob", "libc", - "libloading 0.7.3", + "libloading", ] [[package]] @@ -950,32 +965,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "bitflags", - "textwrap 0.11.0", + "textwrap", "unicode-width", ] [[package]] name = "clap" -version = "3.2.23" +version = "4.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" +checksum = "0eb41c13df48950b20eb4cd0eefa618819469df1bffc49d11e8487c4ba0037e5" dependencies = [ "atty", "bitflags", "clap_derive", "clap_lex", - "indexmap", "once_cell", "strsim", "termcolor", - "textwrap 0.16.0", ] [[package]] name = "clap_derive" -version = "3.2.18" +version = "4.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" +checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" dependencies = [ "heck", "proc-macro-error", @@ -986,22 +999,13 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.2.4" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" dependencies = [ "os_str_bytes", ] -[[package]] -name = "cmake" -version = "0.1.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" -dependencies = [ - "cc", -] - [[package]] name = "codespan-reporting" version = "0.11.1" @@ -1032,6 +1036,15 @@ dependencies = [ "cache-padded", ] +[[package]] +name = "concurrent-queue" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "const-oid" version = "0.7.1" @@ -1117,11 +1130,11 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.85.3" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "749d0d6022c9038dccf480bdde2a38d435937335bf2bb0f14e815d94517cdce8" +checksum = "52056f6d0584484b57fa6c1a65c1fcb15f3780d8b6a758426d9e3084169b2ddd" dependencies = [ - "cranelift-entity 0.85.3", + "cranelift-entity 0.88.2", ] [[package]] @@ -1143,14 +1156,16 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.85.3" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94370cc7b37bf652ccd8bb8f09bd900997f7ccf97520edfc75554bb5c4abbea" +checksum = "18fed94c8770dc25d01154c3ffa64ed0b3ba9d583736f305fed7beebe5d9cf74" dependencies = [ - "cranelift-bforest 0.85.3", - "cranelift-codegen-meta 0.85.3", - "cranelift-codegen-shared 0.85.3", - "cranelift-entity 0.85.3", + "arrayvec 0.7.2", + "bumpalo", + "cranelift-bforest 0.88.2", + "cranelift-codegen-meta 0.88.2", + "cranelift-codegen-shared 0.88.2", + "cranelift-entity 0.88.2", "cranelift-isle", "gimli", "log", @@ -1170,11 +1185,11 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.85.3" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a3cea8fdab90e44018c5b9a1dfd460d8ee265ac354337150222a354628bdb6" +checksum = "1c451b81faf237d11c7e4f3165eeb6bac61112762c5cfe7b4c0fb7241474358f" dependencies = [ - "cranelift-codegen-shared 0.85.3", + "cranelift-codegen-shared 0.88.2", ] [[package]] @@ -1185,9 +1200,9 @@ checksum = "01fd0d9f288cc1b42d9333b7a776b17e278fc888c28e6a0f09b5573d45a150bc" [[package]] name = "cranelift-codegen-shared" -version = "0.85.3" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac72f76f2698598951ab26d8c96eaa854810e693e7dd52523958b5909fde6b2" +checksum = "e7c940133198426d26128f08be2b40b0bd117b84771fd36798969c4d712d81fc" [[package]] name = "cranelift-entity" @@ -1197,9 +1212,9 @@ checksum = "9e3bfe172b83167604601faf9dc60453e0d0a93415b57a9c4d1a7ae6849185cf" [[package]] name = "cranelift-entity" -version = "0.85.3" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09eaeacfcd2356fe0e66b295e8f9d59fdd1ac3ace53ba50de14d628ec902f72d" +checksum = "87a0f1b2fdc18776956370cf8d9b009ded3f855350c480c1c52142510961f352" dependencies = [ "serde", ] @@ -1218,11 +1233,11 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.85.3" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba69c9980d5ffd62c18a2bde927855fcd7c8dc92f29feaf8636052662cbd99c" +checksum = "34897538b36b216cc8dd324e73263596d51b8cf610da6498322838b2546baf8a" dependencies = [ - "cranelift-codegen 0.85.3", + "cranelift-codegen 0.88.2", "log", "smallvec", "target-lexicon", @@ -1230,34 +1245,34 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.85.3" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2920dc1e05cac40304456ed3301fde2c09bd6a9b0210bcfa2f101398d628d5b" +checksum = "1b2629a569fae540f16a76b70afcc87ad7decb38dc28fa6c648ac73b51e78470" [[package]] name = "cranelift-native" -version = "0.85.3" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04dfa45f9b2a6f587c564d6b63388e00cd6589d2df6ea2758cf79e1a13285e6" +checksum = "20937dab4e14d3e225c5adfc9c7106bafd4ac669bdb43027b911ff794c6fb318" dependencies = [ - "cranelift-codegen 0.85.3", + "cranelift-codegen 0.88.2", "libc", "target-lexicon", ] [[package]] name = "cranelift-wasm" -version = "0.85.3" +version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31a46513ae6f26f3f267d8d75b5373d555fbbd1e68681f348d99df43f747ec54" +checksum = "80fc2288957a94fd342a015811479de1837850924166d1f1856d8406e6f3609b" dependencies = [ - "cranelift-codegen 0.85.3", - "cranelift-entity 0.85.3", - "cranelift-frontend 0.85.3", + "cranelift-codegen 0.88.2", + "cranelift-entity 0.88.2", + "cranelift-frontend 0.88.2", "itertools 0.10.5", "log", "smallvec", - "wasmparser 0.85.0", + "wasmparser 0.89.1", "wasmtime-types", ] @@ -1435,18 +1450,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" dependencies = [ - "cipher 0.3.0", -] - -[[package]] -name = "cuckoofilter" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b810a8449931679f64cd7eef1bbd0fa315801b6d5d9cdc1ace2804d6529eee18" -dependencies = [ - "byteorder", - "fnv", - "rand 0.7.3", + "cipher", ] [[package]] @@ -1490,9 +1494,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b7d4e43b25d3c994662706a1d4fcfc32aaa6afd287502c111b237093bb23f3a" +checksum = "97abf9f0eca9e52b7f81b945524e76710e6cb2366aead23b7d4fbf72e281f888" dependencies = [ "cc", "cxxbridge-flags", @@ -1502,9 +1506,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84f8829ddc213e2c1368e51a2564c552b65a8cb6a28f31e576270ac81d5e5827" +checksum = "7cc32cc5fea1d894b77d269ddb9f192110069a8a9c1f1d441195fba90553dea3" dependencies = [ "cc", "codespan-reporting", @@ -1517,15 +1521,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e72537424b474af1460806647c41d4b6d35d09ef7fe031c5c2fa5766047cc56a" +checksum = "8ca220e4794c934dc6b1207c3b42856ad4c302f2df1712e9f8d2eec5afaacf1f" [[package]] name = "cxxbridge-macro" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "309e4fb93eed90e1e14bea0da16b209f81813ba9fc7830c20ed151dd7bc0a4d7" +checksum = "b846f081361125bfc8dc9d3940c84e1fd83ba54bbca7b17cd29483c828be0704" dependencies = [ "proc-macro2", "quote", @@ -1631,6 +1635,12 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + [[package]] name = "digest" version = "0.8.1" @@ -1717,6 +1727,12 @@ dependencies = [ "quick-error", ] +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + [[package]] name = "downcast-rs" version = "1.2.0" @@ -1857,9 +1873,9 @@ dependencies = [ [[package]] name = "enum-as-inner" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73" +checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" dependencies = [ "heck", "proc-macro2", @@ -1930,9 +1946,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c90bf5f19754d10198ccb95b70664fc925bd1fc090a0fd9a6ebc54acc8cd6272" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" dependencies = [ "atty", "humantime", @@ -2079,9 +2095,9 @@ dependencies = [ [[package]] name = "fixed-hash" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", "rand 0.8.5", @@ -2106,6 +2122,15 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + [[package]] name = "fnv" version = "1.0.7" @@ -2128,14 +2153,20 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + [[package]] name = "frame-benchmarking" version = "4.0.0-dev" dependencies = [ + "array-bytes", "frame-support", "frame-system", "futures", - "hex-literal", "linregress", "log", "parity-scale-codec", @@ -2159,8 +2190,9 @@ name = "frame-benchmarking-cli" version = "4.0.0-dev" dependencies = [ "Inflector", + "array-bytes", "chrono", - "clap 3.2.23", + "clap 4.0.23", "comfy-table", "frame-benchmarking", "frame-support", @@ -2169,7 +2201,6 @@ dependencies = [ "gethostname", "handlebars", "hash-db", - "hex", "itertools 0.10.5", "kvdb", "lazy_static", @@ -2249,7 +2280,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 3.2.23", + "clap 4.0.23", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -2267,6 +2298,7 @@ name = "frame-executive" version = "4.0.0-dev" dependencies = [ "aquamarine", + "array-bytes", "extrinsic-shuffler", "frame-support", "frame-system", @@ -2335,6 +2367,7 @@ dependencies = [ "sp-state-machine", "sp-std", "sp-tracing", + "sp-weights", "tt-call", ] @@ -2434,6 +2467,7 @@ dependencies = [ "sp-std", "sp-ver", "sp-version", + "sp-weights", "substrate-test-runtime-client", ] @@ -2471,18 +2505,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "fs-swap" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d47dad3685eceed8488986cad3d5027165ea5edb164331770e2059555f10a5" -dependencies = [ - "lazy_static", - "libc", - "libloading 0.5.2", - "winapi", -] - [[package]] name = "fs2" version = "0.4.3" @@ -2636,6 +2658,20 @@ dependencies = [ "byteorder", ] +[[package]] +name = "generate-bags" +version = "4.0.0-dev" +dependencies = [ + "chrono", + "frame-election-provider-support", + "frame-support", + "frame-system", + "git2", + "num-format", + "pallet-staking", + "sp-io", +] + [[package]] name = "generic-array" version = "0.12.4" @@ -2710,6 +2746,19 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "git2" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0155506aab710a86160ddb504a480d2964d7ab5b9e62419be69e0032bc5931c" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "url", +] + [[package]] name = "glob" version = "0.3.0" @@ -2851,12 +2900,6 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" -[[package]] -name = "hex_fmt" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" - [[package]] name = "hmac" version = "0.8.1" @@ -2953,9 +2996,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.20" +version = "0.14.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" +checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" dependencies = [ "bytes", "futures-channel", @@ -2992,9 +3035,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.52" +version = "0.1.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c422fb4f6e80490d0afcacf5c3de2c22ab8e631e0cd7cb2d4a3baf844720a52a" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -3053,9 +3096,9 @@ dependencies = [ [[package]] name = "if-watch" -version = "1.1.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "015a7df1eb6dda30df37f34b63ada9b7b352984b0e84de2a20ed526345000791" +checksum = "065c008e570a43c00de6aed9714035e5ea6a498c255323db9091722af6ee67dd" dependencies = [ "async-io", "core-foundation", @@ -3080,9 +3123,9 @@ dependencies = [ [[package]] name = "impl-serde" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" dependencies = [ "serde", ] @@ -3109,15 +3152,6 @@ dependencies = [ "serde", ] -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array 0.14.6", -] - [[package]] name = "instant" version = "0.1.12" @@ -3138,15 +3172,19 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "0.5.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec58677acfea8a15352d42fc87d11d63596ade9239e0a7c9352914417515dbe6" +checksum = "59ce5ef949d49ee85593fc4d3f3f95ad61657076395cbbce23e2121fc5542074" [[package]] name = "io-lifetimes" -version = "0.7.4" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e481ccbe3dea62107216d0d1138bb8ad8e5e5c43009a098bd1990272c497b0" +checksum = "a7d367024b3f3414d8e01f437f704f41a9f64ab36f9067fa73e526ad4c763c87" +dependencies = [ + "libc", + "windows-sys 0.42.0", +] [[package]] name = "ip_network" @@ -3156,9 +3194,9 @@ checksum = "aa2f047c0a98b2f299aa5d6d7088443570faae494e9ae1305e48be000c9e0eb1" [[package]] name = "ipconfig" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723519edce41262b05d4143ceb95050e4c614f483e78e9fd9e39a8275a84ad98" +checksum = "bd302af1b90f2463a98fa5ad469fc212c8e3175a41c3068601bfa2727591c5be" dependencies = [ "socket2", "widestring", @@ -3168,9 +3206,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.5.0" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" +checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745" [[package]] name = "itertools" @@ -3405,7 +3443,6 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", "log", "node-primitives", "pallet-alliance", @@ -3421,12 +3458,12 @@ dependencies = [ "pallet-collective", "pallet-contracts", "pallet-contracts-primitives", - "pallet-contracts-rpc-runtime-api", "pallet-conviction-voting", "pallet-democracy", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", "pallet-elections-phragmen", + "pallet-fast-unstake", "pallet-gilt", "pallet-grandpa", "pallet-identity", @@ -3498,9 +3535,9 @@ dependencies = [ [[package]] name = "kvdb" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a301d8ecb7989d4a6e2c57a49baca77d353bdbf879909debe3f375fe25d61f86" +checksum = "585089ceadba0197ffe9af6740ab350b325e3c1f5fccfbc3522e0250c750409b" dependencies = [ "parity-util-mem", "smallvec", @@ -3508,9 +3545,9 @@ dependencies = [ [[package]] name = "kvdb-memorydb" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece7e668abd21387aeb6628130a6f4c802787f014fa46bc83221448322250357" +checksum = "40d109c87bfb7759edd2a49b2649c1afe25af785d930ad6a38479b4dc70dd873" dependencies = [ "kvdb", "parity-util-mem", @@ -3519,15 +3556,13 @@ dependencies = [ [[package]] name = "kvdb-rocksdb" -version = "0.15.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca7fbdfd71cd663dceb0faf3367a99f8cf724514933e9867cec4995b6027cbc1" +checksum = "c076cc2cdbac89b9910c853a36c957d3862a779f31c2661174222cefb49ee597" dependencies = [ - "fs-swap", "kvdb", "log", "num_cpus", - "owning_ref", "parity-util-mem", "parking_lot 0.12.1", "regex", @@ -3560,20 +3595,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" [[package]] -name = "libloading" -version = "0.5.2" +name = "libgit2-sys" +version = "0.13.4+1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" +checksum = "d0fa6563431ede25f5cc7f6d803c6afbc1c5d3ad3d4925d12c882bf2b526f5d1" dependencies = [ "cc", - "winapi", + "libc", + "libz-sys", + "pkg-config", ] [[package]] name = "libloading" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ "cfg-if 1.0.0", "winapi", @@ -3581,15 +3618,15 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "292a948cd991e376cf75541fe5b97a1081d713c618b4f1b9500f8844e49eb565" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" [[package]] name = "libp2p" -version = "0.46.1" +version = "0.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81327106887e42d004fbdab1fef93675be2e2e07c1b95fce45e2cc813485611d" +checksum = "ec878fda12ebec479186b3914ebc48ff180fa4c51847e11a1a68bf65249e02c1" dependencies = [ "bytes", "futures", @@ -3597,12 +3634,8 @@ dependencies = [ "getrandom 0.2.8", "instant", "lazy_static", - "libp2p-autonat", "libp2p-core", - "libp2p-deflate", "libp2p-dns", - "libp2p-floodsub", - "libp2p-gossipsub", "libp2p-identify", "libp2p-kad", "libp2p-mdns", @@ -3610,49 +3643,24 @@ dependencies = [ "libp2p-mplex", "libp2p-noise", "libp2p-ping", - "libp2p-plaintext", - "libp2p-pnet", - "libp2p-relay", - "libp2p-rendezvous", "libp2p-request-response", "libp2p-swarm", "libp2p-swarm-derive", "libp2p-tcp", - "libp2p-uds", "libp2p-wasm-ext", "libp2p-websocket", "libp2p-yamux", "multiaddr", "parking_lot 0.12.1", "pin-project", - "rand 0.7.3", "smallvec", ] -[[package]] -name = "libp2p-autonat" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4decc51f3573653a9f4ecacb31b1b922dd20c25a6322bb15318ec04287ec46f9" -dependencies = [ - "async-trait", - "futures", - "futures-timer", - "instant", - "libp2p-core", - "libp2p-request-response", - "libp2p-swarm", - "log", - "prost", - "prost-build", - "rand 0.8.5", -] - [[package]] name = "libp2p-core" -version = "0.34.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf9b94cefab7599b2d3dff2f93bee218c6621d68590b23ede4485813cbcece6" +checksum = "799676bb0807c788065e57551c6527d461ad572162b0519d1958946ff9e0539d" dependencies = [ "asn1_der", "bs58", @@ -3663,7 +3671,6 @@ dependencies = [ "futures-timer", "instant", "lazy_static", - "libsecp256k1", "log", "multiaddr", "multihash", @@ -3673,7 +3680,6 @@ dependencies = [ "prost", "prost-build", "rand 0.8.5", - "ring", "rw-stream-sink", "sha2 0.10.6", "smallvec", @@ -3683,22 +3689,11 @@ dependencies = [ "zeroize", ] -[[package]] -name = "libp2p-deflate" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0183dc2a3da1fbbf85e5b6cf51217f55b14f5daea0c455a9536eef646bfec71" -dependencies = [ - "flate2", - "futures", - "libp2p-core", -] - [[package]] name = "libp2p-dns" -version = "0.34.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cbf54723250fa5d521383be789bf60efdabe6bacfb443f87da261019a49b4b5" +checksum = "2322c9fb40d99101def6a01612ee30500c89abbbecb6297b3cd252903a4c1720" dependencies = [ "async-std-resolver", "futures", @@ -3710,116 +3705,69 @@ dependencies = [ ] [[package]] -name = "libp2p-floodsub" -version = "0.37.0" +name = "libp2p-identify" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98a4b6ffd53e355775d24b76f583fdda54b3284806f678499b57913adb94f231" +checksum = "dcf9a121f699e8719bda2e6e9e9b6ddafc6cff4602471d6481c1067930ccb29b" dependencies = [ - "cuckoofilter", - "fnv", + "asynchronous-codec", "futures", + "futures-timer", "libp2p-core", "libp2p-swarm", "log", + "lru 0.8.1", "prost", "prost-build", - "rand 0.7.3", + "prost-codec", "smallvec", + "thiserror", + "void", ] [[package]] -name = "libp2p-gossipsub" -version = "0.39.0" +name = "libp2p-kad" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b4b888cfbeb1f5551acd3aa1366e01bf88ede26cc3c4645d0d2d004d5ca7b0" +checksum = "6721c200e2021f6c3fab8b6cf0272ead8912d871610ee194ebd628cecf428f22" dependencies = [ + "arrayvec 0.7.2", "asynchronous-codec", - "base64", - "byteorder", "bytes", + "either", "fnv", "futures", - "hex_fmt", + "futures-timer", "instant", "libp2p-core", "libp2p-swarm", "log", - "prometheus-client", "prost", "prost-build", - "rand 0.7.3", - "regex", + "rand 0.8.5", "sha2 0.10.6", "smallvec", + "thiserror", + "uint", "unsigned-varint", - "wasm-timer", + "void", ] [[package]] -name = "libp2p-identify" -version = "0.37.0" +name = "libp2p-mdns" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50b585518f8efd06f93ac2f976bd672e17cdac794644b3117edd078e96bda06" +checksum = "761704e727f7d68d58d7bc2231eafae5fc1b9814de24290f126df09d4bd37a15" dependencies = [ - "asynchronous-codec", + "async-io", + "data-encoding", + "dns-parser", "futures", - "futures-timer", + "if-watch", "libp2p-core", "libp2p-swarm", "log", - "lru", - "prost", - "prost-build", - "prost-codec", - "smallvec", - "thiserror", - "void", -] - -[[package]] -name = "libp2p-kad" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740862893bb5f06ac24acc9d49bdeadc3a5e52e51818a30a25c1f3519da2c851" -dependencies = [ - "arrayvec 0.7.2", - "asynchronous-codec", - "bytes", - "either", - "fnv", - "futures", - "futures-timer", - "instant", - "libp2p-core", - "libp2p-swarm", - "log", - "prost", - "prost-build", - "rand 0.7.3", - "sha2 0.10.6", - "smallvec", - "thiserror", - "uint", - "unsigned-varint", - "void", -] - -[[package]] -name = "libp2p-mdns" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66e5e5919509603281033fd16306c61df7a4428ce274b67af5e14b07de5cdcb2" -dependencies = [ - "async-io", - "data-encoding", - "dns-parser", - "futures", - "if-watch", - "lazy_static", - "libp2p-core", - "libp2p-swarm", - "log", - "rand 0.8.5", + "rand 0.8.5", "smallvec", "socket2", "void", @@ -3827,25 +3775,23 @@ dependencies = [ [[package]] name = "libp2p-metrics" -version = "0.7.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8aff4a1abef42328fbb30b17c853fff9be986dc39af17ee39f9c5f755c5e0c" +checksum = "9ee31b08e78b7b8bfd1c4204a9dd8a87b4fcdf6dafc57eb51701c1c264a81cb9" dependencies = [ "libp2p-core", - "libp2p-gossipsub", "libp2p-identify", "libp2p-kad", "libp2p-ping", - "libp2p-relay", "libp2p-swarm", "prometheus-client", ] [[package]] name = "libp2p-mplex" -version = "0.34.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61fd1b20638ec209c5075dfb2e8ce6a7ea4ec3cd3ad7b77f7a477c06d53322e2" +checksum = "692664acfd98652de739a8acbb0a0d670f1d67190a49be6b4395e22c37337d89" dependencies = [ "asynchronous-codec", "bytes", @@ -3854,16 +3800,16 @@ dependencies = [ "log", "nohash-hasher", "parking_lot 0.12.1", - "rand 0.7.3", + "rand 0.8.5", "smallvec", "unsigned-varint", ] [[package]] name = "libp2p-noise" -version = "0.37.0" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "762408cb5d84b49a600422d7f9a42c18012d8da6ebcd570f9a4a4290ba41fb6f" +checksum = "048155686bd81fe6cb5efdef0c6290f25ad32a0a42e8f4f72625cf6a505a206f" dependencies = [ "bytes", "curve25519-dalek 3.2.0", @@ -3883,105 +3829,25 @@ dependencies = [ [[package]] name = "libp2p-ping" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "100a6934ae1dbf8a693a4e7dd1d730fd60b774dafc45688ed63b554497c6c925" -dependencies = [ - "futures", - "futures-timer", - "instant", - "libp2p-core", - "libp2p-swarm", - "log", - "rand 0.7.3", - "void", -] - -[[package]] -name = "libp2p-plaintext" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be27bf0820a6238a4e06365b096d428271cce85a129cf16f2fe9eb1610c4df86" -dependencies = [ - "asynchronous-codec", - "bytes", - "futures", - "libp2p-core", - "log", - "prost", - "prost-build", - "unsigned-varint", - "void", -] - -[[package]] -name = "libp2p-pnet" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5a702574223aa55d8878bdc8bf55c84a6086f87ddaddc28ce730b4caa81538" -dependencies = [ - "futures", - "log", - "pin-project", - "rand 0.8.5", - "salsa20", - "sha3", -] - -[[package]] -name = "libp2p-relay" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4931547ee0cce03971ccc1733ff05bb0c4349fd89120a39e9861e2bbe18843c3" -dependencies = [ - "asynchronous-codec", - "bytes", - "either", - "futures", - "futures-timer", - "instant", - "libp2p-core", - "libp2p-swarm", - "log", - "pin-project", - "prost", - "prost-build", - "prost-codec", - "rand 0.8.5", - "smallvec", - "static_assertions", - "thiserror", - "void", -] - -[[package]] -name = "libp2p-rendezvous" -version = "0.7.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9511c9672ba33284838e349623319c8cad2d18cfad243ae46c6b7e8a2982ea4e" +checksum = "7228b9318d34689521349a86eb39a3c3a802c9efc99a0568062ffb80913e3f91" dependencies = [ - "asynchronous-codec", - "bimap", "futures", "futures-timer", "instant", "libp2p-core", "libp2p-swarm", "log", - "prost", - "prost-build", "rand 0.8.5", - "sha2 0.10.6", - "thiserror", - "unsigned-varint", "void", ] [[package]] name = "libp2p-request-response" -version = "0.19.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "508a189e2795d892c8f5c1fa1e9e0b1845d32d7b0b249dbf7b05b18811361843" +checksum = "8827af16a017b65311a410bb626205a9ad92ec0473967618425039fa5231adc1" dependencies = [ "async-trait", "bytes", @@ -3990,16 +3856,16 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "rand 0.7.3", + "rand 0.8.5", "smallvec", "unsigned-varint", ] [[package]] name = "libp2p-swarm" -version = "0.37.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ac5be6c2de2d1ff3f7693fda6faf8a827b1f3e808202277783fea9f527d114" +checksum = "46d13df7c37807965d82930c0e4b04a659efcb6cca237373b206043db5398ecf" dependencies = [ "either", "fnv", @@ -4009,7 +3875,7 @@ dependencies = [ "libp2p-core", "log", "pin-project", - "rand 0.7.3", + "rand 0.8.5", "smallvec", "thiserror", "void", @@ -4017,48 +3883,36 @@ dependencies = [ [[package]] name = "libp2p-swarm-derive" -version = "0.28.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f54a64b6957249e0ce782f8abf41d97f69330d02bf229f0672d864f0650cc76" +checksum = "a0eddc4497a8b5a506013c40e8189864f9c3a00db2b25671f428ae9007f3ba32" dependencies = [ + "heck", "quote", "syn", ] [[package]] name = "libp2p-tcp" -version = "0.34.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a6771dc19aa3c65d6af9a8c65222bfc8fcd446630ddca487acd161fa6096f3b" +checksum = "9839d96761491c6d3e238e70554b856956fca0ab60feb9de2cd08eed4473fa92" dependencies = [ "async-io", "futures", "futures-timer", "if-watch", - "ipnet", "libc", "libp2p-core", "log", "socket2", ] -[[package]] -name = "libp2p-uds" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d125e3e5f0d58f3c6ac21815b20cf4b6a88b8db9dc26368ea821838f4161fd4d" -dependencies = [ - "async-std", - "futures", - "libp2p-core", - "log", -] - [[package]] name = "libp2p-wasm-ext" -version = "0.34.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec894790eec3c1608f8d1a8a0bdf0dbeb79ed4de2dce964222011c2896dfa05a" +checksum = "a17b5b8e7a73e379e47b1b77f8a82c4721e97eca01abcd18e9cd91a23ca6ce97" dependencies = [ "futures", "js-sys", @@ -4070,9 +3924,9 @@ dependencies = [ [[package]] name = "libp2p-websocket" -version = "0.36.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9808e57e81be76ff841c106b4c5974fb4d41a233a7bdd2afbf1687ac6def3818" +checksum = "3758ae6f89b2531a24b6d9f5776bda6a626b60a57600d7185d43dfa75ca5ecc4" dependencies = [ "either", "futures", @@ -4089,12 +3943,13 @@ dependencies = [ [[package]] name = "libp2p-yamux" -version = "0.38.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6dea686217a06072033dc025631932810e2f6ad784e4fafa42e27d311c7a81c" +checksum = "30f079097a21ad017fc8139460630286f02488c8c13b26affb46623aa20d8845" dependencies = [ "futures", "libp2p-core", + "log", "parking_lot 0.12.1", "thiserror", "yamux", @@ -4102,9 +3957,9 @@ dependencies = [ [[package]] name = "librocksdb-sys" -version = "0.6.1+6.28.2" +version = "0.8.0+7.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc587013734dadb7cf23468e531aa120788b87243648be42e2d3a072186291" +checksum = "611804e4666a25136fcc5f8cf425ab4d26c7f74ea245ffe92ea23b85b6420b5d" dependencies = [ "bindgen", "bzip2-sys", @@ -4170,6 +4025,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" dependencies = [ "cc", + "libc", "pkg-config", "vcpkg", ] @@ -4210,15 +4066,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.0.42" +version = "0.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5284f00d480e1c39af34e72f8ad60b94f47007e3481cd3b731c1d67190ddc7b7" +checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" [[package]] name = "linux-raw-sys" -version = "0.0.46" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" +checksum = "bb68f22743a3fb35785f1e7f844ca5a3de2dde5bd0c0ef5b372065814699b121" [[package]] name = "lite-json" @@ -4288,6 +4144,15 @@ dependencies = [ "hashbrown 0.12.3", ] +[[package]] +name = "lru" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909" +dependencies = [ + "hashbrown 0.12.3", +] + [[package]] name = "lru-cache" version = "0.1.2" @@ -4339,7 +4204,7 @@ dependencies = [ [[package]] name = "mangata-types" version = "0.1.0" -source = "git+https://github.com/mangata-finance/substrate?branch=mangata-dev#60c819124ade4c10f927d76f9031eb73d88934d0" +source = "git+https://github.com/mangata-finance/substrate?branch=mangata-dev-v0.9.31#c2f636752b38a5e5a183968fdb09b79e02e604e3" dependencies = [ "parity-scale-codec", "scale-info", @@ -4385,18 +4250,18 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memfd" -version = "0.4.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6627dc657574b49d6ad27105ed671822be56e0d2547d413bfbf3e8d8fa92e7a" +checksum = "b20a59d985586e4a5aef64564ac77299f8586d8be6cf9106a5a40207e8908efb" dependencies = [ - "libc", + "rustix 0.36.1", ] [[package]] name = "memmap2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498" +checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" dependencies = [ "libc", ] @@ -4412,9 +4277,9 @@ dependencies = [ [[package]] name = "memory-db" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6566c70c1016f525ced45d7b7f97730a2bafb037c788211d0c186ef5b2189f0a" +checksum = "34ac11bb793c28fa095b7554466f53b3a60a2cd002afdac01bcf135cbd73a269" dependencies = [ "hash-db", "hashbrown 0.12.3", @@ -4423,9 +4288,9 @@ dependencies = [ [[package]] name = "memory_units" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" [[package]] name = "merlin" @@ -4466,6 +4331,33 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "mockall" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e4a1c770583dac7ab5e2f6c139153b783a53a1bbee9729613f193e59828326" +dependencies = [ + "cfg-if 1.0.0", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "832663583d5fa284ca8810bf7015e46c9fff9622d3cf34bd1eea5003fec06dd0" +dependencies = [ + "cfg-if 1.0.0", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "more-asserts" version = "0.2.2" @@ -4540,9 +4432,9 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" [[package]] name = "multistream-select" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "363a84be6453a70e63513660f4894ef815daf88e3356bffcda9ca27d810ce83b" +checksum = "9bc41247ec209813e2fd414d6e16b9d94297dacf3cd613fa6ef09cd4d9755c10" dependencies = [ "bytes", "futures", @@ -4679,6 +4571,15 @@ dependencies = [ "sp-runtime", ] +[[package]] +name = "node-runtime-generate-bags" +version = "3.0.0" +dependencies = [ + "clap 4.0.23", + "generate-bags", + "kitchensink-runtime", +] + [[package]] name = "node-template-runtime" version = "4.0.0-dev" @@ -4690,7 +4591,6 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", "pallet-aura", "pallet-balances", "pallet-grandpa", @@ -4738,6 +4638,12 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + [[package]] name = "num-bigint" version = "0.2.6" @@ -4749,6 +4655,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-complex" version = "0.4.2" @@ -4785,7 +4702,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" dependencies = [ "autocfg", - "num-bigint", + "num-bigint 0.2.6", "num-integer", "num-traits", ] @@ -4797,6 +4714,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", + "num-bigint 0.4.3", "num-integer", "num-traits", ] @@ -4813,9 +4731,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" dependencies = [ "hermit-abi", "libc", @@ -4839,14 +4757,17 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" dependencies = [ + "crc32fast", + "hashbrown 0.12.3", + "indexmap", "memchr", ] [[package]] name = "once_cell" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "oorandom" @@ -4875,12 +4796,12 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "orml-tokens" version = "0.4.1-dev" -source = "git+https://github.com/mangata-finance//open-runtime-module-library?branch=mangata-dev#ebbad3d3b80fb1829bd01958da091a14d1ec76f1" +source = "git+https://github.com/mangata-finance//open-runtime-module-library?branch=mangata-dev-v0.9.31#dd9d7e6eec8e514a1492e4d477c78593e31ffa6f" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "mangata-types 0.1.0 (git+https://github.com/mangata-finance/substrate?branch=mangata-dev)", + "mangata-types 0.1.0 (git+https://github.com/mangata-finance/substrate?branch=mangata-dev-v0.9.31)", "orml-traits", "parity-scale-codec", "scale-info", @@ -4892,7 +4813,7 @@ dependencies = [ [[package]] name = "orml-traits" version = "0.4.1-dev" -source = "git+https://github.com/mangata-finance//open-runtime-module-library?branch=mangata-dev#ebbad3d3b80fb1829bd01958da091a14d1ec76f1" +source = "git+https://github.com/mangata-finance//open-runtime-module-library?branch=mangata-dev-v0.9.31#dd9d7e6eec8e514a1492e4d477c78593e31ffa6f" dependencies = [ "frame-support", "impl-trait-for-tuples", @@ -4910,7 +4831,7 @@ dependencies = [ [[package]] name = "orml-utilities" version = "0.4.1-dev" -source = "git+https://github.com/mangata-finance//open-runtime-module-library?branch=mangata-dev#ebbad3d3b80fb1829bd01958da091a14d1ec76f1" +source = "git+https://github.com/mangata-finance//open-runtime-module-library?branch=mangata-dev-v0.9.31#dd9d7e6eec8e514a1492e4d477c78593e31ffa6f" dependencies = [ "frame-support", "parity-scale-codec", @@ -4923,9 +4844,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.3.1" +version = "6.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9" +checksum = "7b5bf27447411e9ee3ff51186bf7a08e16c341efdde93f4d823e8844429bed7e" [[package]] name = "output_vt100" @@ -4936,24 +4857,14 @@ dependencies = [ "winapi", ] -[[package]] -name = "owning_ref" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" -dependencies = [ - "stable_deref_trait", -] - [[package]] name = "pallet-alliance" version = "4.0.0-dev" dependencies = [ + "array-bytes", "frame-benchmarking", "frame-support", "frame-system", - "hex", - "hex-literal", "log", "pallet-balances", "pallet-collective", @@ -4988,27 +4899,6 @@ dependencies = [ "sp-storage", ] -[[package]] -name = "pallet-asset-tx-payment-mangata" -version = "4.0.0-dev" -dependencies = [ - "frame-support", - "frame-system", - "pallet-assets", - "pallet-authorship", - "pallet-balances", - "pallet-transaction-payment-mangata", - "parity-scale-codec", - "scale-info", - "serde", - "serde_json", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", - "sp-storage", -] - [[package]] name = "pallet-assets" version = "4.0.0-dev" @@ -5205,12 +5095,11 @@ dependencies = [ name = "pallet-beefy-mmr" version = "4.0.0-dev" dependencies = [ + "array-bytes", "beefy-merkle-tree", "beefy-primitives", "frame-support", "frame-system", - "hex", - "hex-literal", "log", "pallet-beefy", "pallet-mmr", @@ -5298,13 +5187,13 @@ dependencies = [ name = "pallet-contracts" version = "4.0.0-dev" dependencies = [ + "array-bytes", "assert_matches", "bitflags", "env_logger", "frame-benchmarking", "frame-support", "frame-system", - "hex-literal", "impl-trait-for-tuples", "log", "pallet-balances", @@ -5320,6 +5209,7 @@ dependencies = [ "scale-info", "serde", "smallvec", + "sp-api", "sp-core", "sp-io", "sp-keystore", @@ -5337,12 +5227,9 @@ version = "6.0.0" dependencies = [ "bitflags", "parity-scale-codec", - "scale-info", - "serde", - "sp-core", - "sp-rpc", "sp-runtime", "sp-std", + "sp-weights", ] [[package]] @@ -5354,35 +5241,6 @@ dependencies = [ "syn", ] -[[package]] -name = "pallet-contracts-rpc" -version = "4.0.0-dev" -dependencies = [ - "jsonrpsee", - "pallet-contracts-primitives", - "pallet-contracts-rpc-runtime-api", - "parity-scale-codec", - "serde", - "serde_json", - "sp-api", - "sp-blockchain", - "sp-core", - "sp-rpc", - "sp-runtime", -] - -[[package]] -name = "pallet-contracts-rpc-runtime-api" -version = "4.0.0-dev" -dependencies = [ - "pallet-contracts-primitives", - "parity-scale-codec", - "scale-info", - "sp-api", - "sp-runtime", - "sp-std", -] - [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" @@ -5409,7 +5267,9 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", "pallet-balances", + "pallet-preimage", "pallet-scheduler", "parity-scale-codec", "scale-info", @@ -5527,6 +5387,30 @@ dependencies = [ "sp-tasks", ] +[[package]] +name = "pallet-fast-unstake" +version = "4.0.0-dev" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-balances", + "pallet-staking", + "pallet-staking-reward-curve", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std", + "sp-tracing", + "substrate-test-utils", +] + [[package]] name = "pallet-gilt" version = "4.0.0-dev" @@ -5665,12 +5549,12 @@ dependencies = [ name = "pallet-mmr" version = "4.0.0-dev" dependencies = [ + "array-bytes", "ckb-merkle-mountain-range", "env_logger", "frame-benchmarking", "frame-support", "frame-system", - "hex-literal", "itertools 0.10.5", "parity-scale-codec", "scale-info", @@ -5703,6 +5587,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", "pallet-balances", "parity-scale-codec", "scale-info", @@ -5751,6 +5636,7 @@ dependencies = [ "log", "pallet-balances", "parity-scale-codec", + "rand 0.8.5", "scale-info", "sp-core", "sp-io", @@ -5779,6 +5665,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", + "sp-runtime-interface", "sp-staking", "sp-std", ] @@ -5867,6 +5754,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", "pallet-balances", "parity-scale-codec", "scale-info", @@ -6243,23 +6131,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "pallet-transaction-payment-mangata" -version = "4.0.0-dev" -dependencies = [ - "frame-support", - "frame-system", - "pallet-balances", - "parity-scale-codec", - "scale-info", - "serde", - "serde_json", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", -] - [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" @@ -6274,20 +6145,6 @@ dependencies = [ "sp-runtime", ] -[[package]] -name = "pallet-transaction-payment-rpc-mangata" -version = "4.0.0-dev" -dependencies = [ - "jsonrpsee", - "pallet-transaction-payment-rpc-runtime-api-mangata", - "parity-scale-codec", - "sp-api", - "sp-blockchain", - "sp-core", - "sp-rpc", - "sp-runtime", -] - [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" @@ -6298,24 +6155,14 @@ dependencies = [ "sp-runtime", ] -[[package]] -name = "pallet-transaction-payment-rpc-runtime-api-mangata" -version = "4.0.0-dev" -dependencies = [ - "pallet-transaction-payment-mangata", - "parity-scale-codec", - "sp-api", - "sp-runtime", -] - [[package]] name = "pallet-transaction-storage" version = "4.0.0-dev" dependencies = [ + "array-bytes", "frame-benchmarking", "frame-support", "frame-system", - "hex-literal", "log", "pallet-balances", "parity-scale-codec", @@ -6487,9 +6334,9 @@ checksum = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" [[package]] name = "parity-util-mem" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c32561d248d352148124f036cac253a644685a21dc9fea383eb4907d7bd35a8f" +checksum = "0d32c34f4f5ca7f9196001c0aba5a1f9a5a12382c8944b8b0f90233282d1e8f8" dependencies = [ "cfg-if 1.0.0", "hashbrown 0.12.3", @@ -6523,9 +6370,9 @@ dependencies = [ [[package]] name = "parity-wasm" -version = "0.42.2" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be5e13c266502aadf83426d87d81a0f5d1ef45b8027f5a471c360abfe4bfae92" +checksum = "e1ad0aff30c1da14b1254fcb2af73e1fa9a28670e584a626f53a369d0e157304" [[package]] name = "parking" @@ -6638,9 +6485,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc7bc69c062e492337d74d59b120c274fd3d261b6bf6d3207d499b4b379c41a" +checksum = "a528564cc62c19a7acac4d81e01f39e53e25e17b934878f4c6d25cc2836e62f8" dependencies = [ "thiserror", "ucd-trie", @@ -6648,9 +6495,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b75706b9642ebcb34dab3bc7750f811609a0eb1dd8b88c2d15bf628c1c65b2" +checksum = "d5fd9bc6500181952d34bd0b2b0163a54d794227b498be0b7afa7698d0a7b18f" dependencies = [ "pest", "pest_generator", @@ -6658,9 +6505,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f9272122f5979a6511a749af9db9bfc810393f63119970d7085fed1c4ea0db" +checksum = "d2610d5ac5156217b4ff8e46ddcef7cdf44b273da2ac5bca2ecbfa86a330e7c4" dependencies = [ "pest", "pest_meta", @@ -6671,9 +6518,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8717927f9b79515e565a64fe46c38b8cd0427e64c40680b14a7365ab09ac8d" +checksum = "824749bf7e21dd66b36fbe26b3f45c713879cccd4a009a917ab8e045ca8246fe" dependencies = [ "once_cell", "pest", @@ -6728,6 +6575,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs8" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +dependencies = [ + "der", + "spki", + "zeroize", +] + [[package]] name = "pkg-config" version = "0.3.26" @@ -6807,9 +6665,39 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "predicates" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed6bd09a7f7e68f3f0bf710fb7ab9c4615a488b58b5f653382a687701e458c92" +dependencies = [ + "difflib", + "float-cmp", + "itertools 0.10.5", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f883590242d3c6fc5bf50299011695fa6590c2c70eac95ee1bdb9a733ad1a2" + +[[package]] +name = "predicates-tree" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54ff541861505aabf6ea722d2131ee980b8276e10a1297b94e896dd8b621850d" +dependencies = [ + "predicates-core", + "termtree", +] [[package]] name = "pretty_assertions" @@ -6823,11 +6711,21 @@ dependencies = [ "yansi", ] +[[package]] +name = "prettyplease" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c142c0e46b57171fe0c528bee8c5b7569e80f0c17e377cd0e30ea57dbc11bb51" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "primitive-types" -version = "0.11.1" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" dependencies = [ "fixed-hash", "impl-codec", @@ -6902,21 +6800,21 @@ dependencies = [ [[package]] name = "prometheus-client" -version = "0.16.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1abe0255c04d15f571427a2d1e00099016506cf3297b53853acd2b7eb87825" +checksum = "83cd1b99916654a69008fd66b4f9397fbe08e6e51dfe23d4417acf5d3b8cb87c" dependencies = [ "dtoa", "itoa 1.0.4", - "owning_ref", + "parking_lot 0.12.1", "prometheus-client-derive-text-encode", ] [[package]] name = "prometheus-client-derive-text-encode" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8e12d01b9d66ad9eb4529c57666b6263fc1993cb30261d83ead658fdd932652" +checksum = "66a455fbcb954c1a7decf3c586e860fd7889cddf4b8e164be736dbac95a953cd" dependencies = [ "proc-macro2", "quote", @@ -6925,9 +6823,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.10.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71adf41db68aa0daaefc69bb30bcd68ded9b9abaad5d1fbb6304c4fb390e083e" +checksum = "a0841812012b2d4a6145fae9a6af1534873c32aa67fff26bd09f8fa42c83f95a" dependencies = [ "bytes", "prost-derive", @@ -6935,31 +6833,31 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.10.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae5a4388762d5815a9fc0dea33c56b021cdc8dde0c55e0c9ca57197254b0cab" +checksum = "1d8b442418ea0822409d9e7d047cbf1e7e9e1760b172bf9982cf29d517c93511" dependencies = [ "bytes", - "cfg-if 1.0.0", - "cmake", "heck", "itertools 0.10.5", "lazy_static", "log", "multimap", "petgraph", + "prettyplease", "prost", "prost-types", "regex", + "syn", "tempfile", "which", ] [[package]] name = "prost-codec" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00af1e92c33b4813cc79fda3f2dbf56af5169709be0202df730e9ebc3e4cd007" +checksum = "011ae9ff8359df7915f97302d591cdd9e0e27fbd5a4ddc5bd13b71079bb20987" dependencies = [ "asynchronous-codec", "bytes", @@ -6970,9 +6868,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.10.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" +checksum = "164ae68b6587001ca506d3bf7f1000bfa248d0e1217b618108fba4ec1d0cc306" dependencies = [ "anyhow", "itertools 0.10.5", @@ -6983,9 +6881,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.10.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" +checksum = "747761bc3dc48f9a34553bf65605cf6cb6288ba219f3450b4275dbd81539551a" dependencies = [ "bytes", "prost", @@ -7213,18 +7111,18 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12a733f1746c929b4913fe48f8697fcf9c55e3304ba251a79ffb41adfeaf49c2" +checksum = "53b15debb4f9d60d767cd8ca9ef7abb2452922f3214671ff052defc7f3502c44" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5887de4a01acafd221861463be6113e6e87275e79804e56779f4cdc131c60368" +checksum = "abfa8511e9e94fd3de6585a3d3cd00e01ed556dc9814829280af0e8dc72a8f36" dependencies = [ "proc-macro2", "quote", @@ -7244,9 +7142,9 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.2.3" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a8d23b35d7177df3b9d31ed8a9ab4bf625c668be77a319d4f5efd4a5257701c" +checksum = "d43a209257d978ef079f3d446331d0f1794f5e0fc19b306a199983857833a779" dependencies = [ "fxhash", "log", @@ -7256,9 +7154,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" dependencies = [ "aho-corasick", "memchr", @@ -7274,23 +7172,11 @@ dependencies = [ "regex-syntax", ] -[[package]] -name = "regex-syntax" -version = "0.6.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" - -[[package]] -name = "region" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877e54ea2adcd70d80e9179344c97f93ef0dffd6b03e1f4529e6e83ab2fa9ae0" -dependencies = [ - "bitflags", - "libc", - "mach", - "winapi", -] +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] name = "region" @@ -7310,7 +7196,6 @@ version = "0.10.0-dev" dependencies = [ "env_logger", "frame-support", - "jsonrpsee", "log", "pallet-elections-phragmen", "parity-scale-codec", @@ -7320,6 +7205,7 @@ dependencies = [ "sp-io", "sp-runtime", "sp-version", + "substrate-rpc-client", "tokio", ] @@ -7404,9 +7290,9 @@ dependencies = [ [[package]] name = "rocksdb" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "620f4129485ff1a7128d184bc687470c21c7951b64779ebc9cfdad3dcd920290" +checksum = "7e9562ea1d70c0cc63a34a22d977753b50cca91cc6b6527750463bd5dd8697bc" dependencies = [ "libc", "librocksdb-sys", @@ -7475,30 +7361,30 @@ dependencies = [ [[package]] name = "rustix" -version = "0.33.7" +version = "0.35.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938a344304321a9da4973b9ff4f9f8db9caf4597dfd9dda6a60b523340a0fff0" +checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9" dependencies = [ "bitflags", "errno", - "io-lifetimes 0.5.3", + "io-lifetimes 0.7.5", "libc", - "linux-raw-sys 0.0.42", - "winapi", + "linux-raw-sys 0.0.46", + "windows-sys 0.42.0", ] [[package]] name = "rustix" -version = "0.35.12" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "985947f9b6423159c4726323f373be0a21bdb514c5af06a849cb3d2dce2d01e8" +checksum = "812a2ec2043c4d6bc6482f5be2ab8244613cac2493d128d36c0759e52a626ab3" dependencies = [ "bitflags", "errno", - "io-lifetimes 0.7.4", + "io-lifetimes 1.0.1", "libc", - "linux-raw-sys 0.0.46", - "windows-sys 0.36.1", + "linux-raw-sys 0.1.2", + "windows-sys 0.42.0", ] [[package]] @@ -7577,15 +7463,6 @@ dependencies = [ "rustc_version 0.2.3", ] -[[package]] -name = "salsa20" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" -dependencies = [ - "cipher 0.4.3", -] - [[package]] name = "same-file" version = "1.0.6" @@ -7756,11 +7633,11 @@ dependencies = [ name = "sc-cli" version = "0.10.0-dev" dependencies = [ + "array-bytes", "chrono", - "clap 3.2.23", + "clap 4.0.23", "fdlimit", "futures", - "hex", "libp2p", "log", "names", @@ -7772,6 +7649,7 @@ dependencies = [ "sc-client-db", "sc-keystore", "sc-network", + "sc-network-common", "sc-service", "sc-telemetry", "sc-tracing", @@ -7922,7 +7800,7 @@ dependencies = [ "futures", "log", "merlin", - "num-bigint", + "num-bigint 0.2.6", "num-rational 0.2.4", "num-traits", "parity-scale-codec", @@ -8104,11 +7982,11 @@ dependencies = [ name = "sc-executor" version = "0.10.0-dev" dependencies = [ + "array-bytes", "criterion", "env_logger", - "hex-literal", "lazy_static", - "lru", + "lru 0.7.8", "num_cpus", "parity-scale-codec", "parking_lot 0.12.1", @@ -8180,10 +8058,9 @@ dependencies = [ "log", "once_cell", "parity-scale-codec", - "parity-wasm 0.42.2", + "parity-wasm 0.45.0", "paste 1.0.9", - "rustix 0.33.7", - "rustix 0.35.12", + "rustix 0.35.13", "sc-allocator", "sc-executor-common", "sc-runtime-test", @@ -8201,6 +8078,7 @@ name = "sc-finality-grandpa" version = "0.10.0-dev" dependencies = [ "ahash", + "array-bytes", "assert_matches", "async-trait", "dyn-clone", @@ -8208,7 +8086,6 @@ dependencies = [ "fork-tree", "futures", "futures-timer", - "hex", "log", "parity-scale-codec", "parking_lot 0.12.1", @@ -8264,8 +8141,8 @@ dependencies = [ name = "sc-keystore" version = "4.0.0-dev" dependencies = [ + "array-bytes", "async-trait", - "hex", "parking_lot 0.12.1", "serde_json", "sp-application-crypto", @@ -8279,6 +8156,7 @@ dependencies = [ name = "sc-network" version = "0.10.0-dev" dependencies = [ + "array-bytes", "assert_matches", "async-std", "async-trait", @@ -8291,18 +8169,16 @@ dependencies = [ "fork-tree", "futures", "futures-timer", - "hex", "ip_network", "libp2p", "linked-hash-map", "linked_hash_set", "log", - "lru", + "lru 0.7.8", "parity-scale-codec", "parking_lot 0.12.1", "pin-project", "prost", - "prost-build", "rand 0.7.3", "sc-block-builder", "sc-client-api", @@ -8328,10 +8204,35 @@ dependencies = [ "tempfile", "thiserror", "unsigned-varint", - "void", "zeroize", ] +[[package]] +name = "sc-network-bitswap" +version = "0.10.0-dev" +dependencies = [ + "cid", + "futures", + "libp2p", + "log", + "prost", + "prost-build", + "sc-block-builder", + "sc-client-api", + "sc-consensus", + "sc-network-common", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-runtime", + "substrate-test-runtime", + "substrate-test-runtime-client", + "thiserror", + "tokio", + "unsigned-varint", + "void", +] + [[package]] name = "sc-network-common" version = "0.10.0-dev" @@ -8340,7 +8241,9 @@ dependencies = [ "bitflags", "bytes", "futures", + "futures-timer", "libp2p", + "linked_hash_set", "parity-scale-codec", "prost-build", "sc-consensus", @@ -8351,6 +8254,7 @@ dependencies = [ "sp-consensus", "sp-finality-grandpa", "sp-runtime", + "substrate-prometheus-endpoint", "thiserror", ] @@ -8364,7 +8268,7 @@ dependencies = [ "futures-timer", "libp2p", "log", - "lru", + "lru 0.7.8", "quickcheck", "sc-network-common", "sc-peerset", @@ -8378,8 +8282,8 @@ dependencies = [ name = "sc-network-light" version = "0.10.0-dev" dependencies = [ + "array-bytes", "futures", - "hex", "libp2p", "log", "parity-scale-codec", @@ -8398,12 +8302,14 @@ dependencies = [ name = "sc-network-sync" version = "0.10.0-dev" dependencies = [ + "array-bytes", + "async-std", "fork-tree", "futures", - "hex", "libp2p", "log", - "lru", + "lru 0.7.8", + "mockall", "parity-scale-codec", "prost", "prost-build", @@ -8413,6 +8319,7 @@ dependencies = [ "sc-consensus", "sc-network-common", "sc-peerset", + "sc-utils", "smallvec", "sp-arithmetic", "sp-blockchain", @@ -8456,15 +8363,33 @@ dependencies = [ "substrate-test-runtime-client", ] +[[package]] +name = "sc-network-transactions" +version = "0.10.0-dev" +dependencies = [ + "array-bytes", + "futures", + "hex", + "libp2p", + "log", + "parity-scale-codec", + "pin-project", + "sc-network-common", + "sc-peerset", + "sp-consensus", + "sp-runtime", + "substrate-prometheus-endpoint", +] + [[package]] name = "sc-offchain" version = "4.0.0-dev" dependencies = [ + "array-bytes", "bytes", "fnv", "futures", "futures-timer", - "hex", "hyper", "hyper-rustls", "lazy_static", @@ -8588,6 +8513,26 @@ dependencies = [ "tokio", ] +[[package]] +name = "sc-rpc-spec-v2" +version = "0.10.0-dev" +dependencies = [ + "futures", + "hex", + "jsonrpsee", + "parity-scale-codec", + "sc-chain-spec", + "sc-transaction-pool-api", + "serde", + "serde_json", + "sp-api", + "sp-blockchain", + "sp-core", + "sp-runtime", + "thiserror", + "tokio", +] + [[package]] name = "sc-runtime-test" version = "2.0.0" @@ -8630,12 +8575,15 @@ dependencies = [ "sc-informant", "sc-keystore", "sc-network", + "sc-network-bitswap", "sc-network-common", "sc-network-light", "sc-network-sync", + "sc-network-transactions", "sc-offchain", "sc-rpc", "sc-rpc-server", + "sc-rpc-spec-v2", "sc-sysinfo", "sc-telemetry", "sc-tracing", @@ -8662,6 +8610,7 @@ dependencies = [ "sp-transaction-storage-proof", "sp-trie", "sp-version", + "static_init", "substrate-prometheus-endpoint", "substrate-test-runtime", "substrate-test-runtime-client", @@ -8677,10 +8626,9 @@ dependencies = [ name = "sc-service-test" version = "2.0.0" dependencies = [ + "array-bytes", "fdlimit", "futures", - "hex", - "hex-literal", "log", "parity-scale-codec", "parking_lot 0.12.1", @@ -8821,11 +8769,12 @@ dependencies = [ name = "sc-transaction-pool" version = "4.0.0-dev" dependencies = [ + "array-bytes", "assert_matches", + "async-trait", "criterion", "futures", "futures-timer", - "hex", "linked-hash-map", "log", "parity-scale-codec", @@ -8854,9 +8803,11 @@ dependencies = [ name = "sc-transaction-pool-api" version = "4.0.0-dev" dependencies = [ + "async-trait", "futures", "log", "serde", + "serde_json", "sp-blockchain", "sp-runtime", "thiserror", @@ -8877,9 +8828,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "333af15b02563b8182cd863f925bd31ef8fa86a0e095d30c091956057d436153" +checksum = "88d8a765117b237ef233705cc2cc4c6a27fccd46eea6ef0c8c6dae5f3ef407f8" dependencies = [ "bitvec", "cfg-if 1.0.0", @@ -8891,9 +8842,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53f56acbd0743d29ffa08f911ab5397def774ad01bab3786804cf6ee057fb5e1" +checksum = "cdcd47b380d8c4541044e341dcd9475f55ba37ddc50c908d945fc036a8642496" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -8965,6 +8916,7 @@ checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" dependencies = [ "der", "generic-array 0.14.6", + "pkcs8", "subtle", "zeroize", ] @@ -9404,7 +9356,7 @@ name = "sp-arithmetic-fuzzer" version = "2.0.0" dependencies = [ "honggfuzz", - "num-bigint", + "num-bigint 0.2.6", "primitive-types", "sp-arithmetic", ] @@ -9449,7 +9401,7 @@ version = "4.0.0-dev" dependencies = [ "futures", "log", - "lru", + "lru 0.7.8", "parity-scale-codec", "parking_lot 0.12.1", "sp-api", @@ -9558,9 +9510,10 @@ dependencies = [ name = "sp-core" version = "6.0.0" dependencies = [ + "array-bytes", "base58", "bitflags", - "blake2-rfc", + "blake2", "byteorder", "criterion", "dyn-clonable", @@ -9568,8 +9521,6 @@ dependencies = [ "futures", "hash-db", "hash256-std-hasher", - "hex", - "hex-literal", "impl-serde", "lazy_static", "libsecp256k1", @@ -9750,9 +9701,10 @@ dependencies = [ name = "sp-mmr-primitives" version = "4.0.0-dev" dependencies = [ - "hex-literal", + "array-bytes", "log", "parity-scale-codec", + "scale-info", "serde", "sp-api", "sp-core", @@ -9780,7 +9732,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 3.2.23", + "clap 4.0.23", "honggfuzz", "parity-scale-codec", "rand 0.8.5", @@ -9840,6 +9792,7 @@ dependencies = [ "sp-state-machine", "sp-std", "sp-tracing", + "sp-weights", "substrate-test-runtime-client", "zstd", ] @@ -9967,9 +9920,9 @@ dependencies = [ name = "sp-state-machine" version = "0.12.0" dependencies = [ + "array-bytes", "assert_matches", "hash-db", - "hex-literal", "log", "num-traits", "parity-scale-codec", @@ -10084,12 +10037,12 @@ name = "sp-trie" version = "6.0.0" dependencies = [ "ahash", + "array-bytes", "criterion", "hash-db", "hashbrown 0.12.3", - "hex-literal", "lazy_static", - "lru", + "lru 0.7.8", "memory-db", "nohash-hasher", "parity-scale-codec", @@ -10129,7 +10082,7 @@ version = "5.0.0" dependencies = [ "impl-serde", "parity-scale-codec", - "parity-wasm 0.42.2", + "parity-wasm 0.45.0", "scale-info", "serde", "sp-core-hashing-proc-macro", @@ -10162,17 +10115,42 @@ dependencies = [ "wasmtime", ] +[[package]] +name = "sp-weights" +version = "4.0.0" +dependencies = [ + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "serde", + "smallvec", + "sp-arithmetic", + "sp-core", + "sp-debug-derive", + "sp-std", +] + [[package]] name = "spin" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spki" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "ss58-registry" -version = "1.33.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab7554f8a8b6f8d71cd5a8e6536ef116e2ce0504cf97ebf16311d58065dc8a6" +checksum = "37a9821878e1f13aba383aa40a86fb1b33c7265774ec91e32563cb1dd1577496" dependencies = [ "Inflector", "num-format", @@ -10195,6 +10173,34 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "static_init" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a2a1c578e98c1c16fc3b8ec1328f7659a500737d7a0c6d625e73e830ff9c1f6" +dependencies = [ + "bitflags", + "cfg_aliases", + "libc", + "parking_lot 0.11.2", + "parking_lot_core 0.8.5", + "static_init_macro", + "winapi", +] + +[[package]] +name = "static_init_macro" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a2595fc3aa78f2d0e45dd425b22282dd863273761cc77780914b2cf3003acf" +dependencies = [ + "cfg_aliases", + "memchr", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "statrs" version = "0.15.0" @@ -10260,7 +10266,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 3.2.23", + "clap 4.0.23", "frame-support", "frame-system", "sc-cli", @@ -10280,6 +10286,8 @@ dependencies = [ "sc-rpc-api", "scale-info", "serde", + "sp-core", + "sp-runtime", "sp-storage", "tokio", ] @@ -10321,6 +10329,20 @@ dependencies = [ "tokio", ] +[[package]] +name = "substrate-rpc-client" +version = "0.10.0-dev" +dependencies = [ + "async-trait", + "jsonrpsee", + "log", + "sc-rpc-api", + "serde", + "sp-core", + "sp-runtime", + "tokio", +] + [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" @@ -10346,9 +10368,9 @@ dependencies = [ name = "substrate-test-client" version = "2.0.1" dependencies = [ + "array-bytes", "async-trait", "futures", - "hex", "parity-scale-codec", "sc-client-api", "sc-client-db", @@ -10555,9 +10577,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1" +checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" [[package]] name = "tempfile" @@ -10582,6 +10604,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "termtree" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95059e91184749cb66be6dc994f67f182b6d897cb3df74a5bf66b5e709295fd8" + [[package]] name = "textwrap" version = "0.11.0" @@ -10591,12 +10619,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" - [[package]] name = "thiserror" version = "1.0.37" @@ -10643,9 +10665,9 @@ dependencies = [ [[package]] name = "tikv-jemalloc-sys" -version = "0.4.3+5.2.1-patched.2" +version = "0.5.2+5.3.0-patched" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1792ccb507d955b46af42c123ea8863668fae24d03721e40cad6a41773dbb49" +checksum = "ec45c14da997d0925c7835883e4d5c181f196fa142f8c19d7643d1e9af2592c3" dependencies = [ "cc", "fs_extra", @@ -10902,9 +10924,9 @@ dependencies = [ [[package]] name = "trie-bench" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5704f0d6130bd83608e4370c19e20c8a6ec03e80363e493d0234efca005265a" +checksum = "f0dae77b1daad50cd3ed94c506d2dab27e2e47f7b5153a6d4b1992bb3f6028cb" dependencies = [ "criterion", "hash-db", @@ -10950,9 +10972,9 @@ dependencies = [ [[package]] name = "trust-dns-proto" -version = "0.21.2" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d" +checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" dependencies = [ "async-trait", "cfg-if 1.0.0", @@ -10964,30 +10986,30 @@ dependencies = [ "idna 0.2.3", "ipnet", "lazy_static", - "log", "rand 0.8.5", "smallvec", "thiserror", "tinyvec", + "tracing", "url", ] [[package]] name = "trust-dns-resolver" -version = "0.21.2" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558" +checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe" dependencies = [ "cfg-if 1.0.0", "futures-util", "ipconfig", "lazy_static", - "log", "lru-cache", "parking_lot 0.12.1", "resolv-conf", "smallvec", "thiserror", + "tracing", "trust-dns-proto", ] @@ -11001,9 +11023,8 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ - "clap 3.2.23", + "clap 4.0.23", "frame-try-runtime", - "jsonrpsee", "log", "parity-scale-codec", "remote-externalities", @@ -11019,6 +11040,8 @@ dependencies = [ "sp-runtime", "sp-state-machine", "sp-version", + "sp-weights", + "substrate-rpc-client", "tokio", "zstd", ] @@ -11326,9 +11349,9 @@ checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] name = "wasm-encoder" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5816e88e8ea7335016aa62eb0485747f786136d505a9b3890f8c400211d9b5f" +checksum = "9424cdab516a16d4ea03c8f4a01b14e7b2d04a129dcc2bcdde5bcc5f68f06c41" dependencies = [ "leb128", ] @@ -11346,11 +11369,11 @@ dependencies = [ [[package]] name = "wasm-instrument" -version = "0.1.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "962e5b0401bbb6c887f54e69b8c496ea36f704df65db73e81fd5ff8dc3e63a9f" +checksum = "aa1dafb3e60065305741e83db35c6c2584bb3725b692b5b66148a38d72ace6cd" dependencies = [ - "parity-wasm 0.42.2", + "parity-wasm 0.45.0", ] [[package]] @@ -11511,7 +11534,7 @@ dependencies = [ "enum-iterator", "enumset", "leb128", - "libloading 0.7.3", + "libloading", "loupe", "object 0.28.4", "rkyv", @@ -11537,7 +11560,7 @@ dependencies = [ "enumset", "leb128", "loupe", - "region 3.0.0", + "region", "rkyv", "wasmer-compiler", "wasmer-engine", @@ -11609,7 +11632,7 @@ dependencies = [ "mach", "memoffset", "more-asserts", - "region 3.0.0", + "region", "rkyv", "scopeguard", "serde", @@ -11621,28 +11644,35 @@ dependencies = [ [[package]] name = "wasmi" -version = "0.9.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca00c5147c319a8ec91ec1a0edbec31e566ce2c9cc93b3f9bb86a9efd0eb795d" +checksum = "06c326c93fbf86419608361a2c925a31754cf109da1b8b55737070b4d6669422" dependencies = [ - "downcast-rs", - "errno", - "libc", - "libm", - "memory_units", - "num-rational 0.2.4", - "num-traits", - "parity-wasm 0.42.2", + "parity-wasm 0.45.0", "wasmi-validation", + "wasmi_core", ] [[package]] name = "wasmi-validation" -version = "0.4.1" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ff416ad1ff0c42e5a926ed5d5fab74c0f098749aa0ad8b2a34b982ce0e867b" +dependencies = [ + "parity-wasm 0.45.0", +] + +[[package]] +name = "wasmi_core" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "165343ecd6c018fc09ebcae280752702c9a2ef3e6f8d02f1cfcbdb53ef6d7937" +checksum = "57d20cb3c59b788653d99541c646c561c9dd26506f25c0cebfe810659c54c6d7" dependencies = [ - "parity-wasm 0.42.2", + "downcast-rs", + "libm", + "memory_units", + "num-rational 0.4.1", + "num-traits", ] [[package]] @@ -11653,49 +11683,55 @@ checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a" [[package]] name = "wasmparser" -version = "0.85.0" +version = "0.89.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "570460c58b21e9150d2df0eaaedbb7816c34bcec009ae0dcc976e40ba81463e7" +checksum = "ab5d3e08b13876f96dd55608d03cd4883a0545884932d5adf11925876c96daef" dependencies = [ "indexmap", ] [[package]] name = "wasmtime" -version = "0.38.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f50eadf868ab6a04b7b511460233377d0bfbb92e417b2f6a98b98fef2e098f5" +checksum = "4ad5af6ba38311282f2a21670d96e78266e8c8e2f38cbcd52c254df6ccbc7731" dependencies = [ "anyhow", - "backtrace", "bincode", "cfg-if 1.0.0", "indexmap", - "lazy_static", "libc", "log", - "object 0.28.4", + "object 0.29.0", "once_cell", "paste 1.0.9", "psm", "rayon", - "region 2.2.0", "serde", "target-lexicon", - "wasmparser 0.85.0", + "wasmparser 0.89.1", "wasmtime-cache", "wasmtime-cranelift", "wasmtime-environ", "wasmtime-jit", "wasmtime-runtime", - "winapi", + "windows-sys 0.36.1", +] + +[[package]] +name = "wasmtime-asm-macros" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45de63ddfc8b9223d1adc8f7b2ee5f35d1f6d112833934ad7ea66e4f4339e597" +dependencies = [ + "cfg-if 1.0.0", ] [[package]] name = "wasmtime-cache" -version = "0.38.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1df23c642e1376892f3b72f311596976979cbf8b85469680cdd3a8a063d12a2" +checksum = "bcd849399d17d2270141cfe47fa0d91ee52d5f8ea9b98cf7ddde0d53e5f79882" dependencies = [ "anyhow", "base64", @@ -11703,61 +11739,59 @@ dependencies = [ "directories-next", "file-per-thread-logger", "log", - "rustix 0.33.7", + "rustix 0.35.13", "serde", "sha2 0.9.9", "toml", - "winapi", + "windows-sys 0.36.1", "zstd", ] [[package]] name = "wasmtime-cranelift" -version = "0.38.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f264ff6b4df247d15584f2f53d009fbc90032cfdc2605b52b961bffc71b6eccd" +checksum = "4bd91339b742ff20bfed4532a27b73c86b5bcbfedd6bea2dcdf2d64471e1b5c6" dependencies = [ "anyhow", - "cranelift-codegen 0.85.3", - "cranelift-entity 0.85.3", - "cranelift-frontend 0.85.3", + "cranelift-codegen 0.88.2", + "cranelift-entity 0.88.2", + "cranelift-frontend 0.88.2", "cranelift-native", "cranelift-wasm", "gimli", "log", - "more-asserts", - "object 0.28.4", + "object 0.29.0", "target-lexicon", "thiserror", - "wasmparser 0.85.0", + "wasmparser 0.89.1", "wasmtime-environ", ] [[package]] name = "wasmtime-environ" -version = "0.38.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "839d2820e4b830f4b9e7aa08d4c0acabf4a5036105d639f6dfa1c6891c73bdc6" +checksum = "ebb881c61f4f627b5d45c54e629724974f8a8890d455bcbe634330cc27309644" dependencies = [ "anyhow", - "cranelift-entity 0.85.3", + "cranelift-entity 0.88.2", "gimli", "indexmap", "log", - "more-asserts", - "object 0.28.4", + "object 0.29.0", "serde", "target-lexicon", "thiserror", - "wasmparser 0.85.0", + "wasmparser 0.89.1", "wasmtime-types", ] [[package]] name = "wasmtime-jit" -version = "0.38.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef0a0bcbfa18b946d890078ba0e1bc76bcc53eccfb40806c0020ec29dcd1bd49" +checksum = "1985c628011fe26adf5e23a5301bdc79b245e0e338f14bb58b39e4e25e4d8681" dependencies = [ "addr2line", "anyhow", @@ -11766,38 +11800,36 @@ dependencies = [ "cpp_demangle", "gimli", "log", - "object 0.28.4", - "region 2.2.0", + "object 0.29.0", "rustc-demangle", - "rustix 0.33.7", + "rustix 0.35.13", "serde", "target-lexicon", "thiserror", "wasmtime-environ", "wasmtime-jit-debug", "wasmtime-runtime", - "winapi", + "windows-sys 0.36.1", ] [[package]] name = "wasmtime-jit-debug" -version = "0.38.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4779d976206c458edd643d1ac622b6c37e4a0800a8b1d25dfbf245ac2f2cac" +checksum = "f671b588486f5ccec8c5a3dba6b4c07eac2e66ab8c60e6f4e53717c77f709731" dependencies = [ - "lazy_static", - "object 0.28.4", - "rustix 0.33.7", + "object 0.29.0", + "once_cell", + "rustix 0.35.13", ] [[package]] name = "wasmtime-runtime" -version = "0.38.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7eb6ffa169eb5dcd18ac9473c817358cd57bc62c244622210566d473397954a" +checksum = "ee8f92ad4b61736339c29361da85769ebc200f184361959d1792832e592a1afd" dependencies = [ "anyhow", - "backtrace", "cc", "cfg-if 1.0.0", "indexmap", @@ -11806,33 +11838,33 @@ dependencies = [ "mach", "memfd", "memoffset", - "more-asserts", + "paste 1.0.9", "rand 0.8.5", - "region 2.2.0", - "rustix 0.33.7", + "rustix 0.35.13", "thiserror", + "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-jit-debug", - "winapi", + "windows-sys 0.36.1", ] [[package]] name = "wasmtime-types" -version = "0.38.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d932b0ac5336f7308d869703dd225610a6a3aeaa8e968c52b43eed96cefb1c2" +checksum = "d23d61cb4c46e837b431196dd06abb11731541021916d03476a178b54dc07aeb" dependencies = [ - "cranelift-entity 0.85.3", + "cranelift-entity 0.88.2", "serde", "thiserror", - "wasmparser 0.85.0", + "wasmparser 0.89.1", ] [[package]] name = "wast" -version = "48.0.0" +version = "49.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84825b5ac7164df8260c9e2b2e814075334edbe7ac426f2469b93a5eeac23cce" +checksum = "05ef81fcd60d244cafffeafac3d17615fdb2fddda6aca18f34a8ae233353587c" dependencies = [ "leb128", "memchr", @@ -11842,9 +11874,9 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "129da4a03ec6d2a815f42c88f641824e789d5be0d86d2f90aa8a218c7068e0be" +checksum = "4c347c4460ffb311e95aafccd8c29e4888f241b9e4b3bb0e0ccbd998de2c8c0d" dependencies = [ "wast", ] @@ -12123,9 +12155,9 @@ checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" [[package]] name = "winreg" -version = "0.7.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] @@ -12152,8 +12184,8 @@ dependencies = [ [[package]] name = "xcm" -version = "0.9.29" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.29#94078b44fb6c9767bf60ffcaaa3be40681be5a76" +version = "0.9.31" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.31#32dd0c9cfcd1a1bda821747f6ab334f0e3577558" dependencies = [ "derivative", "impl-trait-for-tuples", @@ -12166,8 +12198,8 @@ dependencies = [ [[package]] name = "xcm-procedural" -version = "0.9.29" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.29#94078b44fb6c9767bf60ffcaaa3be40681be5a76" +version = "0.9.31" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.31#32dd0c9cfcd1a1bda821747f6ab334f0e3577558" dependencies = [ "Inflector", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 5abc8eeea8a23..72eeb58dd5cb6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ members = [ "client/keystore", "client/network", "client/network-gossip", + "client/network/bitswap", "client/network/common", "client/network/light", "client/network/sync", @@ -58,6 +59,7 @@ members = [ "client/rpc", "client/rpc-api", "client/rpc-servers", + "client/rpc-spec-v2", "client/service", "client/service/test", "client/state-db", @@ -89,10 +91,10 @@ members = [ "frame/collective", "frame/collective-mangata", "frame/contracts", - "frame/contracts/rpc", - "frame/contracts/rpc/runtime-api", + "frame/contracts/primitives", "frame/conviction-voting", "frame/democracy", + "frame/fast-unstake", "frame/try-runtime", "frame/election-provider-multi-phase", "frame/election-provider-support", @@ -160,10 +162,6 @@ members = [ "frame/vesting", "frame/whitelist", "frame/vesting-mangata", - "frame/transaction-payment-mangata", - "frame/transaction-payment-mangata/asset-tx-payment", - "frame/transaction-payment-mangata/rpc", - "frame/transaction-payment-mangata/rpc/runtime-api", "primitives/api", "primitives/api/proc-macro", "primitives/api/test", @@ -226,6 +224,7 @@ members = [ "primitives/ver", "primitives/version/proc-macro", "primitives/wasm-interface", + "primitives/weights", "test-utils/client", "test-utils/derive", "test-utils/runtime", @@ -241,8 +240,9 @@ members = [ "utils/frame/rpc/state-trie-migration-rpc", "utils/frame/rpc/support", "utils/frame/rpc/system", - # "utils/frame/generate-bags", - #"utils/frame/generate-bags/node-runtime", + "utils/frame/generate-bags", + "utils/frame/generate-bags/node-runtime", + "utils/frame/rpc/client", "utils/prometheus", "utils/wasm-builder", ] diff --git a/README.md b/README.md index c609641af7ce2..02f8a7591acc5 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,24 @@ -# Substrate · [![GitHub license](https://img.shields.io/badge/license-GPL3%2FApache2-blue)](#LICENSE) [![GitLab Status](https://gitlab.parity.io/parity/substrate/badges/master/pipeline.svg)](https://gitlab.parity.io/parity/substrate/pipelines) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](docs/CONTRIBUTING.adoc) [![Matrix](https://img.shields.io/matrix/substrate-technical:matrix.org)](https://matrix.to/#/#substrate-technical:matrix.org) - +# Substrate · [![GitHub license](https://img.shields.io/badge/license-GPL3%2FApache2-blue)](#LICENSE) [![GitLab Status](https://gitlab.parity.io/parity/substrate/badges/master/pipeline.svg)](https://gitlab.parity.io/parity/substrate/pipelines) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](docs/CONTRIBUTING.adoc) [![Stack Exchange](https://img.shields.io/badge/Substrate-Community%20&%20Support-24CC85?logo=stackexchange)](https://substrate.stackexchange.com/)

Substrate is a next-generation framework for blockchain innovation 🚀. -## Trying it out +## Getting Started + +Head to [docs.substrate.io](https://docs.substrate.io) and follow the [installation](https://docs.substrate.io/install/) instructions. +Then try out one of the [tutorials](https://docs.substrate.io/tutorials/). + +## Community & Support -Simply go to [docs.substrate.io](https://docs.substrate.io) and follow the -[installation](https://docs.substrate.io/main-docs/install/) instructions. You can -also try out one of the [tutorials](https://docs.substrate.io/tutorials/). +Join the highly active and supportive community on the [Susbstrate Stack Exchange](https://substrate.stackexchange.com/) to ask questions about use and problems you run into using this software. +Please do report bugs and [issues here](https://github.com/paritytech/substrate/issues) for anything you suspect requires action in the source. ## Contributions & Code of Conduct -Please follow the contributions guidelines as outlined in [`docs/CONTRIBUTING.adoc`](docs/CONTRIBUTING.adoc). In all communications and contributions, this project follows the [Contributor Covenant Code of Conduct](docs/CODE_OF_CONDUCT.md). +Please follow the contributions guidelines as outlined in [`docs/CONTRIBUTING.adoc`](docs/CONTRIBUTING.adoc). +In all communications and contributions, this project follows the [Contributor Covenant Code of Conduct](docs/CODE_OF_CONDUCT.md). ## Security diff --git a/bin/node-template/node/Cargo.toml b/bin/node-template/node/Cargo.toml index eeba198da8212..c60018e14969c 100644 --- a/bin/node-template/node/Cargo.toml +++ b/bin/node-template/node/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] name = "node-template" [dependencies] -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli", features = ["wasmtime"] } sp-core = { version = "6.0.0", path = "../../../primitives/core" } @@ -67,7 +67,12 @@ substrate-build-script-utils = { version = "3.0.0", path = "../../../utils/build [features] default = [] -runtime-benchmarks = ["node-template-runtime/runtime-benchmarks"] +# Dependencies that are only required if runtime benchmarking should be build. +runtime-benchmarks = [ + "node-template-runtime/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-benchmarking-cli/runtime-benchmarks", +] # Enable features that allow the runtime to be tried and debugged. Name might be subject to change # in the near future. try-runtime = ["node-template-runtime/try-runtime", "try-runtime-cli"] diff --git a/bin/node-template/node/src/benchmarking.rs b/bin/node-template/node/src/benchmarking.rs index f0e32104cd3ee..90fe06edf04b8 100644 --- a/bin/node-template/node/src/benchmarking.rs +++ b/bin/node-template/node/src/benchmarking.rs @@ -119,7 +119,7 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder { pub fn create_benchmark_extrinsic( client: &FullClient, sender: sp_core::sr25519::Pair, - call: runtime::Call, + call: runtime::RuntimeCall, nonce: u32, ) -> runtime::UncheckedExtrinsic { let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); diff --git a/bin/node-template/node/src/cli.rs b/bin/node-template/node/src/cli.rs index 4ab4d34210c98..dd610477ac469 100644 --- a/bin/node-template/node/src/cli.rs +++ b/bin/node-template/node/src/cli.rs @@ -2,7 +2,7 @@ use sc_cli::RunCmd; #[derive(Debug, clap::Parser)] pub struct Cli { - #[clap(subcommand)] + #[command(subcommand)] pub subcommand: Option, #[clap(flatten)] @@ -12,7 +12,7 @@ pub struct Cli { #[derive(Debug, clap::Subcommand)] pub enum Subcommand { /// Key management cli utilities - #[clap(subcommand)] + #[command(subcommand)] Key(sc_cli::KeySubcommand), /// Build a chain specification. @@ -37,7 +37,7 @@ pub enum Subcommand { Revert(sc_cli::RevertCmd), /// Sub-commands concerned with benchmarking. - #[clap(subcommand)] + #[command(subcommand)] Benchmark(frame_benchmarking_cli::BenchmarkCmd), /// Try some command against runtime state. diff --git a/bin/node-template/node/src/command.rs b/bin/node-template/node/src/command.rs index f8f02ed8fc2dd..6d293b7b85fcc 100644 --- a/bin/node-template/node/src/command.rs +++ b/bin/node-template/node/src/command.rs @@ -127,6 +127,12 @@ pub fn run() -> sc_cli::Result<()> { let PartialComponents { client, .. } = service::new_partial(&config)?; cmd.run(client) }, + #[cfg(not(feature = "runtime-benchmarks"))] + BenchmarkCmd::Storage(_) => Err( + "Storage benchmarking can be enabled with `--features runtime-benchmarks`." + .into(), + ), + #[cfg(feature = "runtime-benchmarks")] BenchmarkCmd::Storage(cmd) => { let PartialComponents { client, backend, .. } = service::new_partial(&config)?; diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index ffb2440caa0ed..96de6e17f3bfd 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -1,7 +1,7 @@ //! Service and ServiceFactory implementation. Specialized wrapper over substrate service. use node_template_runtime::{self, opaque::Block, RuntimeApi}; -use sc_client_api::{BlockBackend, ExecutorProvider}; +use sc_client_api::BlockBackend; use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; pub use sc_executor::NativeElseWasmExecutor; use sc_finality_grandpa::SharedVoterState; @@ -113,7 +113,7 @@ pub fn new_partial( let slot_duration = sc_consensus_aura::slot_duration(&*client)?; let import_queue = - sc_consensus_aura::import_queue::(ImportQueueParams { + sc_consensus_aura::import_queue::(ImportQueueParams { block_import: grandpa_block_import.clone(), justification_import: Some(Box::new(grandpa_block_import.clone())), client: client.clone(), @@ -126,12 +126,9 @@ pub fn new_partial( slot_duration, ); - Ok((timestamp, slot)) + Ok((slot, timestamp)) }, spawner: &task_manager.spawn_essential_handle(), - can_author_with: sp_consensus::CanAuthorWithNativeVersion::new( - client.executor().clone(), - ), registry: config.prometheus_registry(), check_for_equivocation: Default::default(), telemetry: telemetry.as_ref().map(|x| x.handle()), @@ -194,7 +191,7 @@ pub fn new_full(mut config: Configuration) -> Result Vec::default(), )); - let (network, system_rpc_tx, network_starter) = + let (network, system_rpc_tx, tx_handler_controller, network_starter) = sc_service::build_network(sc_service::BuildNetworkParams { config: &config, client: client.clone(), @@ -241,6 +238,7 @@ pub fn new_full(mut config: Configuration) -> Result rpc_builder: rpc_extensions_builder, backend, system_rpc_tx, + tx_handler_controller, config, telemetry: telemetry.as_mut(), })?; @@ -254,12 +252,9 @@ pub fn new_full(mut config: Configuration) -> Result telemetry.as_ref().map(|x| x.handle()), ); - let can_author_with = - sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()); - let slot_duration = sc_consensus_aura::slot_duration(&*client)?; - let aura = sc_consensus_aura::start_aura::( + let aura = sc_consensus_aura::start_aura::( StartAuraParams { slot_duration, client, @@ -275,12 +270,11 @@ pub fn new_full(mut config: Configuration) -> Result slot_duration, ); - Ok((timestamp, slot)) + Ok((slot, timestamp)) }, force_authoring, backoff_authoring_blocks, keystore: keystore_container.sync_keystore(), - can_author_with, sync_oracle: network.clone(), justification_sync_link: network.clone(), block_proposal_slot_portion: SlotProportion::new(2f32 / 3f32), diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml index 6f7a4b1d25841..3cfcef9d902ce 100644 --- a/bin/node-template/pallets/template/Cargo.toml +++ b/bin/node-template/pallets/template/Cargo.toml @@ -30,7 +30,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../ default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "scale-info/std", diff --git a/bin/node-template/pallets/template/src/lib.rs b/bin/node-template/pallets/template/src/lib.rs index a9209a9040b6d..0b55d7ae86fcf 100644 --- a/bin/node-template/pallets/template/src/lib.rs +++ b/bin/node-template/pallets/template/src/lib.rs @@ -27,7 +27,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// Because this pallet emits events, it depends on the runtime's definition of an event. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; } // The pallet's runtime storage items. diff --git a/bin/node-template/pallets/template/src/mock.rs b/bin/node-template/pallets/template/src/mock.rs index e03f37b2eea69..989681fa59a00 100644 --- a/bin/node-template/pallets/template/src/mock.rs +++ b/bin/node-template/pallets/template/src/mock.rs @@ -27,8 +27,8 @@ impl system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -36,7 +36,7 @@ impl system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -50,7 +50,7 @@ impl system::Config for Test { } impl pallet_template::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; } // Build genesis storage according to the mock runtime. diff --git a/bin/node-template/pallets/template/src/tests.rs b/bin/node-template/pallets/template/src/tests.rs index 2205658601721..527aec8ed00c0 100644 --- a/bin/node-template/pallets/template/src/tests.rs +++ b/bin/node-template/pallets/template/src/tests.rs @@ -5,7 +5,7 @@ use frame_support::{assert_noop, assert_ok}; fn it_works_for_default_value() { new_test_ext().execute_with(|| { // Dispatch a signed extrinsic. - assert_ok!(TemplateModule::do_something(Origin::signed(1), 42)); + assert_ok!(TemplateModule::do_something(RuntimeOrigin::signed(1), 42)); // Read pallet storage and assert an expected result. assert_eq!(TemplateModule::something(), Some(42)); }); @@ -15,6 +15,9 @@ fn it_works_for_default_value() { fn correct_error_for_none_value() { new_test_ext().execute_with(|| { // Ensure the expected error is thrown when no value is present. - assert_noop!(TemplateModule::cause_error(Origin::signed(1)), Error::::NoneValue); + assert_noop!( + TemplateModule::cause_error(RuntimeOrigin::signed(1)), + Error::::NoneValue + ); }); } diff --git a/bin/node-template/runtime/Cargo.toml b/bin/node-template/runtime/Cargo.toml index bbe3e8eef7d3c..45ab4939e311c 100644 --- a/bin/node-template/runtime/Cargo.toml +++ b/bin/node-template/runtime/Cargo.toml @@ -46,7 +46,6 @@ pallet-transaction-payment-rpc-runtime-api = { version = "4.0.0-dev", default-fe # Used for runtime benchmarking frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/benchmarking", optional = true } frame-system-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/system/benchmarking", optional = true } -hex-literal = { version = "0.3.4", optional = true } # Local Dependencies pallet-template = { version = "4.0.0-dev", default-features = false, path = "../pallets/template" } @@ -57,6 +56,9 @@ substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-bu [features] default = ["std"] std = [ + "frame-try-runtime?/std", + "frame-system-benchmarking?/std", + "frame-benchmarking?/std", "codec/std", "scale-info/std", "frame-executive/std", @@ -88,9 +90,8 @@ std = [ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", - "frame-system-benchmarking", + "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", - "hex-literal", "pallet-balances/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", "pallet-template/runtime-benchmarks", diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs index e28a3bb2adb9d..1d0e18d31bf80 100644 --- a/bin/node-template/runtime/src/lib.rs +++ b/bin/node-template/runtime/src/lib.rs @@ -14,7 +14,9 @@ use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, Verify}, + traits::{ + AccountIdLookup, BlakeTwo256, Block as BlockT, IdentifyAccount, NumberFor, One, Verify, + }, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, MultiSignature, }; @@ -38,7 +40,7 @@ pub use frame_support::{ pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; pub use pallet_timestamp::Call as TimestampCall; -use pallet_transaction_payment::CurrencyAdapter; +use pallet_transaction_payment::{ConstFeeMultiplier, CurrencyAdapter, Multiplier}; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; @@ -137,8 +139,11 @@ parameter_types! { pub const BlockHashCount: BlockNumber = 2400; pub const Version: RuntimeVersion = VERSION; /// We allow for 2 seconds of compute with a 6 second average block time. - pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights - ::with_sensible_defaults(2u64 * WEIGHT_PER_SECOND, NORMAL_DISPATCH_RATIO); + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::with_sensible_defaults( + (2u64 * WEIGHT_PER_SECOND).set_proof_size(u64::MAX), + NORMAL_DISPATCH_RATIO, + ); pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength ::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); pub const SS58Prefix: u8 = 42; @@ -156,7 +161,7 @@ impl frame_system::Config for Runtime { /// The identifier used to distinguish between accounts. type AccountId = AccountId; /// The aggregated dispatch type that is available for extrinsics. - type Call = Call; + type RuntimeCall = RuntimeCall; /// The lookup mechanism to get account ID from whatever is passed in dispatchers. type Lookup = AccountIdLookup; /// The index type for storing how many extrinsics an account has signed. @@ -170,9 +175,9 @@ impl frame_system::Config for Runtime { /// The header type. type Header = generic::Header; /// The ubiquitous event type. - type Event = Event; + type RuntimeEvent = RuntimeEvent; /// The ubiquitous origin type. - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; /// Maximum number of block number to block hash mappings to keep (oldest pruned first). type BlockHashCount = BlockHashCount; /// The weight of database operations that the runtime can invoke. @@ -207,8 +212,7 @@ impl pallet_aura::Config for Runtime { } impl pallet_grandpa::Config for Runtime { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; type KeyOwnerProofSystem = (); @@ -244,30 +248,34 @@ impl pallet_balances::Config for Runtime { /// The type for recording an account's balance. type Balance = Balance; /// The ubiquitous event type. - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU128; type AccountStore = System; type WeightInfo = pallet_balances::weights::SubstrateWeight; } +parameter_types! { + pub FeeMultiplier: Multiplier = Multiplier::one(); +} + impl pallet_transaction_payment::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; type LengthToFee = IdentityFee; - type FeeMultiplierUpdate = (); + type FeeMultiplierUpdate = ConstFeeMultiplier; } impl pallet_sudo::Config for Runtime { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; } /// Configure the pallet-template in pallets/template. impl pallet_template::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; } // Create the runtime by composing the FRAME pallets that were previously configured. @@ -308,10 +316,12 @@ pub type SignedExtra = ( frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, ); + /// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -467,17 +477,17 @@ impl_runtime_apis! { } } - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi for Runtime { fn query_call_info( - call: Call, + call: RuntimeCall, len: u32, ) -> pallet_transaction_payment::RuntimeDispatchInfo { TransactionPayment::query_call_info(call, len) } fn query_call_fee_details( - call: Call, + call: RuntimeCall, len: u32, ) -> pallet_transaction_payment::FeeDetails { TransactionPayment::query_call_fee_details(call, len) @@ -514,18 +524,8 @@ impl_runtime_apis! { impl frame_system_benchmarking::Config for Runtime {} impl baseline::Config for Runtime {} - let whitelist: Vec = vec![ - // Block Number - hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), - // Total Issuance - hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(), - // Execution Phase - hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(), - // Event Count - hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(), - // System Events - hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(), - ]; + use frame_support::traits::WhitelistedStorageKeys; + let whitelist: Vec = AllPalletsWithSystem::whitelisted_storage_keys(); let mut batches = Vec::::new(); let params = (&config, &whitelist); @@ -556,3 +556,40 @@ impl_runtime_apis! { } } } + +#[cfg(test)] +mod tests { + use super::*; + use frame_support::traits::WhitelistedStorageKeys; + use sp_core::hexdisplay::HexDisplay; + use std::collections::HashSet; + + #[test] + fn check_whitelist() { + let whitelist: HashSet = AllPalletsWithSystem::whitelisted_storage_keys() + .iter() + .map(|e| HexDisplay::from(&e.key).to_string()) + .collect(); + + // Block Number + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac") + ); + // Total Issuance + assert!( + whitelist.contains("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80") + ); + // Execution Phase + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a") + ); + // Event Count + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850") + ); + // System Events + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7") + ); + } +} diff --git a/bin/node/bench/Cargo.toml b/bin/node/bench/Cargo.toml index c7a747c30ed2e..54a1d4900c60b 100644 --- a/bin/node/bench/Cargo.toml +++ b/bin/node/bench/Cargo.toml @@ -5,11 +5,14 @@ authors = ["Parity Technologies "] description = "Substrate node integration benchmarks." edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = { version = "3.1.18", features = ["derive"] } +array-bytes = "4.1" +clap = { version = "4.0.9", features = ["derive"] } log = "0.4.17" node-primitives = { version = "2.0.0", path = "../primitives" } node-testing = { version = "3.0.0-dev", path = "../testing" } @@ -20,8 +23,8 @@ sp-state-machine = { version = "0.12.0", path = "../../../primitives/state-machi serde = "1.0.136" serde_json = "1.0.85" derive_more = { version = "0.99.17", default-features = false, features = ["display"] } -kvdb = "0.11.0" -kvdb-rocksdb = "0.15.1" +kvdb = "0.12.0" +kvdb-rocksdb = "0.16.0" sp-trie = { version = "6.0.0", path = "../../../primitives/trie" } sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } @@ -32,10 +35,9 @@ sp-tracing = { version = "5.0.0", path = "../../../primitives/tracing" } hash-db = "0.15.2" tempfile = "3.1.0" fs_extra = "1" -hex = "0.4.0" rand = { version = "0.7.2", features = ["small_rng"] } lazy_static = "1.4.0" -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } parity-db = { version = "0.3" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } diff --git a/bin/node/bench/src/core.rs b/bin/node/bench/src/core.rs index 3b3060a888349..b6ad3ecd80068 100644 --- a/bin/node/bench/src/core.rs +++ b/bin/node/bench/src/core.rs @@ -132,7 +132,7 @@ pub fn run_benchmark(benchmark: Box, mode: Mode) -> Be durations.push(duration.as_nanos()); } - durations.sort_unstable(); + durations.sort(); let raw_average = (durations.iter().sum::() / (durations.len() as u128)) as u64; let average = (durations.iter().skip(10).take(30).sum::() / 30) as u64; diff --git a/bin/node/bench/src/generator.rs b/bin/node/bench/src/generator.rs index 863928c719429..76bd3a3240c51 100644 --- a/bin/node/bench/src/generator.rs +++ b/bin/node/bench/src/generator.rs @@ -37,8 +37,10 @@ pub fn generate_trie( let (db, overlay) = { let mut overlay = HashMap::new(); overlay.insert( - hex::decode("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314") - .expect("null key is valid"), + array_bytes::hex2bytes( + "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314", + ) + .expect("null key is valid"), Some(vec![0]), ); let mut trie = SimpleTrie { db, overlay: &mut overlay }; diff --git a/bin/node/bench/src/import.rs b/bin/node/bench/src/import.rs index 47f630eb68700..26f9391800ceb 100644 --- a/bin/node/bench/src/import.rs +++ b/bin/node/bench/src/import.rs @@ -34,7 +34,7 @@ use std::borrow::Cow; use node_primitives::Block; use node_testing::bench::{BenchDb, BlockType, DatabaseType, KeyTypes, Profile}; -use sc_client_api::backend::Backend; +use sc_client_api::{backend::Backend, HeaderBackend}; use sp_runtime::generic::BlockId; use sp_state_machine::InspectState; @@ -127,10 +127,15 @@ impl core::Benchmark for ImportBenchmark { context.import_block(self.block.clone()); let elapsed = start.elapsed(); + let hash = context + .client + .expect_block_hash_from_id(&BlockId::number(1)) + .expect("Block 1 was imported; qed"); + // Sanity checks. context .client - .state_at(&BlockId::number(1)) + .state_at(&hash) .expect("state_at failed for block#1") .inspect_state(|| { match self.block_type { diff --git a/bin/node/bench/src/main.rs b/bin/node/bench/src/main.rs index d97c7af26535b..8a5d99640eb1b 100644 --- a/bin/node/bench/src/main.rs +++ b/bin/node/bench/src/main.rs @@ -43,18 +43,18 @@ use crate::{ }; #[derive(Debug, Parser)] -#[clap(name = "node-bench", about = "Node integration benchmarks")] +#[command(name = "node-bench", about = "Node integration benchmarks")] struct Opt { /// Show list of all available benchmarks. /// /// Will output ("name", "path"). Benchmarks can then be filtered by path. - #[clap(short, long)] + #[arg(short, long)] list: bool, /// Machine readable json output. /// /// This also suppresses all regular output (except to stderr) - #[clap(short, long)] + #[arg(short, long)] json: bool, /// Filter benchmarks. @@ -63,7 +63,7 @@ struct Opt { filter: Option, /// Number of transactions for block import with `custom` size. - #[clap(long)] + #[arg(long)] transactions: Option, /// Mode @@ -72,7 +72,7 @@ struct Opt { /// /// "profile" mode adds pauses between measurable runs, /// so that actual interval can be selected in the profiler of choice. - #[clap(short, long, default_value = "regular")] + #[arg(short, long, default_value = "regular")] mode: BenchmarkMode, } diff --git a/bin/node/bench/src/tempdb.rs b/bin/node/bench/src/tempdb.rs index 22c5980fd6524..eb3bb1d3fccd7 100644 --- a/bin/node/bench/src/tempdb.rs +++ b/bin/node/bench/src/tempdb.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use kvdb::{DBTransaction, KeyValueDB}; +use kvdb::{DBKeyValue, DBTransaction, KeyValueDB}; use kvdb_rocksdb::{Database, DatabaseConfig}; use std::{io, path::PathBuf, sync::Arc}; @@ -38,7 +38,7 @@ impl KeyValueDB for ParityDbWrapper { } /// Get a value by partial key. Only works for flushed data. - fn get_by_prefix(&self, _col: u32, _prefix: &[u8]) -> Option> { + fn get_by_prefix(&self, _col: u32, _prefix: &[u8]) -> io::Result>> { unimplemented!() } @@ -56,7 +56,7 @@ impl KeyValueDB for ParityDbWrapper { } /// Iterate over flushed data for a given column. - fn iter<'a>(&'a self, _col: u32) -> Box, Box<[u8]>)> + 'a> { + fn iter<'a>(&'a self, _col: u32) -> Box> + 'a> { unimplemented!() } @@ -65,12 +65,7 @@ impl KeyValueDB for ParityDbWrapper { &'a self, _col: u32, _prefix: &'a [u8], - ) -> Box, Box<[u8]>)> + 'a> { - unimplemented!() - } - - /// Attempt to replace this database with a new one located at the given path. - fn restore(&self, _new_db: &str) -> io::Result<()> { + ) -> Box> + 'a> { unimplemented!() } } diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index d84b8491cb162..4bf991f49320c 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -34,12 +34,12 @@ crate-type = ["cdylib", "rlib"] [dependencies] # third-party dependencies -clap = { version = "3.1.18", features = ["derive"], optional = true } +array-bytes = "4.1" +clap = { version = "4.0.9", features = ["derive"], optional = true } codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.136", features = ["derive"] } jsonrpsee = { version = "0.15.1", features = ["server"] } futures = "0.3.21" -hex-literal = "0.3.4" log = "0.4.17" rand = "0.8" @@ -132,12 +132,12 @@ soketto = "0.7.1" criterion = { version = "0.3.5", features = ["async_tokio"] } tokio = { version = "1.17.0", features = ["macros", "time", "parking_lot"] } wait-timeout = "0.2" -remote-externalities = { path = "../../../utils/frame/remote-externalities" } +substrate-rpc-client = { path = "../../../utils/frame/rpc/client" } pallet-timestamp = { version = "4.0.0-dev", path = "../../../frame/timestamp" } [build-dependencies] -clap = { version = "3.1.18", optional = true } -clap_complete = { version = "3.0", optional = true } +clap = { version = "4.0.9", optional = true } +clap_complete = { version = "4.0.2", optional = true } node-inspect = { version = "0.9.0-dev", optional = true, path = "../inspect" } frame-benchmarking-cli = { version = "4.0.0-dev", optional = true, path = "../../../utils/frame/benchmarking-cli" } substrate-build-script-utils = { version = "3.0.0", optional = true, path = "../../../utils/build-script-utils" } @@ -149,7 +149,6 @@ pallet-balances = { version = "4.0.0-dev", path = "../../../frame/balances" } [features] default = ["cli"] cli = [ - "node-executor/wasmi-errno", "node-inspect", "sc-cli", "frame-benchmarking-cli", @@ -160,7 +159,10 @@ cli = [ "substrate-build-script-utils", "try-runtime-cli", ] -runtime-benchmarks = ["kitchensink-runtime/runtime-benchmarks", "frame-benchmarking-cli"] +runtime-benchmarks = [ + "kitchensink-runtime/runtime-benchmarks", + "frame-benchmarking-cli/runtime-benchmarks" +] # Enable features that allow the runtime to be tried and debugged. Name might be subject to change # in the near future. try-runtime = ["kitchensink-runtime/try-runtime", "try-runtime-cli"] diff --git a/bin/node/cli/benches/block_production.rs b/bin/node/cli/benches/block_production.rs index c0f3b96e093cb..4fcebb123d9e3 100644 --- a/bin/node/cli/benches/block_production.rs +++ b/bin/node/cli/benches/block_production.rs @@ -74,7 +74,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, trie_cache_maximum_size: Some(64 * 1024 * 1024), state_pruning: Some(PruningMode::ArchiveAll), - blocks_pruning: BlocksPruning::All, + blocks_pruning: BlocksPruning::KeepAll, chain_spec: spec, wasm_method: WasmExecutionMethod::Compiled { instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, @@ -122,7 +122,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { fn extrinsic_set_time(now: u64) -> OpaqueExtrinsic { kitchensink_runtime::UncheckedExtrinsic { signature: None, - function: kitchensink_runtime::Call::Timestamp(pallet_timestamp::Call::set { now }), + function: kitchensink_runtime::RuntimeCall::Timestamp(pallet_timestamp::Call::set { now }), } .into() } diff --git a/bin/node/cli/benches/transaction_pool.rs b/bin/node/cli/benches/transaction_pool.rs index e6084fba8242a..a8839642ddc26 100644 --- a/bin/node/cli/benches/transaction_pool.rs +++ b/bin/node/cli/benches/transaction_pool.rs @@ -68,7 +68,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, trie_cache_maximum_size: Some(64 * 1024 * 1024), state_pruning: Some(PruningMode::ArchiveAll), - blocks_pruning: BlocksPruning::All, + blocks_pruning: BlocksPruning::KeepAll, chain_spec: spec, wasm_method: WasmExecutionMethod::Interpreted, // NOTE: we enforce the use of the native runtime to make the errors more debuggable diff --git a/bin/node/cli/build.rs b/bin/node/cli/build.rs index 6a3d13dda6a00..e8142b297f1b2 100644 --- a/bin/node/cli/build.rs +++ b/bin/node/cli/build.rs @@ -25,7 +25,7 @@ fn main() { mod cli { include!("src/cli.rs"); - use clap::{ArgEnum, CommandFactory}; + use clap::{CommandFactory, ValueEnum}; use clap_complete::{generate_to, Shell}; use std::{env, fs, path::Path}; use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; diff --git a/bin/node/cli/src/chain_spec.rs b/bin/node/cli/src/chain_spec.rs index 77e2f73dd6e18..8d74f2bde0f44 100644 --- a/bin/node/cli/src/chain_spec.rs +++ b/bin/node/cli/src/chain_spec.rs @@ -19,7 +19,6 @@ //! Substrate chain configurations. use grandpa_primitives::AuthorityId as GrandpaId; -use hex_literal::hex; use kitchensink_runtime::{ constants::currency::*, wasm_binary_unwrap, AuthorityDiscoveryConfig, BabeConfig, BalancesConfig, Block, CouncilConfig, DemocracyConfig, ElectionsConfig, GrandpaConfig, @@ -98,84 +97,83 @@ fn staging_testnet_config_genesis() -> GenesisConfig { )> = vec![ ( // 5Fbsd6WXDGiLTxunqeK5BATNiocfCqu9bS1yArVjCgeBLkVy - hex!["9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"].into(), + array_bytes::hex_n_into_unchecked("9c7a2ee14e565db0c69f78c7b4cd839fbf52b607d867e9e9c5a79042898a0d12"), // 5EnCiV7wSHeNhjW3FSUwiJNkcc2SBkPLn5Nj93FmbLtBjQUq - hex!["781ead1e2fa9ccb74b44c19d29cb2a7a4b5be3972927ae98cd3877523976a276"].into(), + array_bytes::hex_n_into_unchecked("781ead1e2fa9ccb74b44c19d29cb2a7a4b5be3972927ae98cd3877523976a276"), // 5Fb9ayurnxnaXj56CjmyQLBiadfRCqUbL2VWNbbe1nZU6wiC - hex!["9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332"] + array_bytes::hex2array_unchecked("9becad03e6dcac03cee07edebca5475314861492cdfc96a2144a67bbe9699332") .unchecked_into(), // 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8 - hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"] + array_bytes::hex2array_unchecked("6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106") .unchecked_into(), // 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8 - hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"] + array_bytes::hex2array_unchecked("6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106") .unchecked_into(), // 5EZaeQ8djPcq9pheJUhgerXQZt9YaHnMJpiHMRhwQeinqUW8 - hex!["6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106"] + array_bytes::hex2array_unchecked("6e7e4eb42cbd2e0ab4cae8708ce5509580b8c04d11f6758dbf686d50fe9f9106") .unchecked_into(), ), ( // 5ERawXCzCWkjVq3xz1W5KGNtVx2VdefvZ62Bw1FEuZW4Vny2 - hex!["68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"].into(), + array_bytes::hex_n_into_unchecked("68655684472b743e456907b398d3a44c113f189e56d1bbfd55e889e295dfde78"), // 5Gc4vr42hH1uDZc93Nayk5G7i687bAQdHHc9unLuyeawHipF - hex!["c8dc79e36b29395413399edaec3e20fcca7205fb19776ed8ddb25d6f427ec40e"].into(), + array_bytes::hex_n_into_unchecked("c8dc79e36b29395413399edaec3e20fcca7205fb19776ed8ddb25d6f427ec40e"), // 5EockCXN6YkiNCDjpqqnbcqd4ad35nU4RmA1ikM4YeRN4WcE - hex!["7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f"] + array_bytes::hex2array_unchecked("7932cff431e748892fa48e10c63c17d30f80ca42e4de3921e641249cd7fa3c2f") .unchecked_into(), // 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ - hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"] + array_bytes::hex2array_unchecked("482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e") .unchecked_into(), // 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ - hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"] + array_bytes::hex2array_unchecked("482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e") .unchecked_into(), // 5DhLtiaQd1L1LU9jaNeeu9HJkP6eyg3BwXA7iNMzKm7qqruQ - hex!["482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e"] + array_bytes::hex2array_unchecked("482dbd7297a39fa145c570552249c2ca9dd47e281f0c500c971b59c9dcdcd82e") .unchecked_into(), ), ( // 5DyVtKWPidondEu8iHZgi6Ffv9yrJJ1NDNLom3X9cTDi98qp - hex!["547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"].into(), + array_bytes::hex_n_into_unchecked("547ff0ab649283a7ae01dbc2eb73932eba2fb09075e9485ff369082a2ff38d65"), // 5FeD54vGVNpFX3PndHPXJ2MDakc462vBCD5mgtWRnWYCpZU9 - hex!["9e42241d7cd91d001773b0b616d523dd80e13c6c2cab860b1234ef1b9ffc1526"].into(), + array_bytes::hex_n_into_unchecked("9e42241d7cd91d001773b0b616d523dd80e13c6c2cab860b1234ef1b9ffc1526"), // 5E1jLYfLdUQKrFrtqoKgFrRvxM3oQPMbf6DfcsrugZZ5Bn8d - hex!["5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440"] + array_bytes::hex2array_unchecked("5633b70b80a6c8bb16270f82cca6d56b27ed7b76c8fd5af2986a25a4788ce440") .unchecked_into(), // 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH - hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"] + array_bytes::hex2array_unchecked("482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a") .unchecked_into(), // 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH - hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"] + array_bytes::hex2array_unchecked("482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a") .unchecked_into(), // 5DhKqkHRkndJu8vq7pi2Q5S3DfftWJHGxbEUNH43b46qNspH - hex!["482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a"] + array_bytes::hex2array_unchecked("482a3389a6cf42d8ed83888cfd920fec738ea30f97e44699ada7323f08c3380a") .unchecked_into(), ), ( // 5HYZnKWe5FVZQ33ZRJK1rG3WaLMztxWrrNDb1JRwaHHVWyP9 - hex!["f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c2663"].into(), + array_bytes::hex_n_into_unchecked("f26cdb14b5aec7b2789fd5ca80f979cef3761897ae1f37ffb3e154cbcc1c2663"), // 5EPQdAQ39WQNLCRjWsCk5jErsCitHiY5ZmjfWzzbXDoAoYbn - hex!["66bc1e5d275da50b72b15de072a2468a5ad414919ca9054d2695767cf650012f"].into(), + array_bytes::hex_n_into_unchecked("66bc1e5d275da50b72b15de072a2468a5ad414919ca9054d2695767cf650012f"), // 5DMa31Hd5u1dwoRKgC4uvqyrdK45RHv3CpwvpUC1EzuwDit4 - hex!["3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef"] + array_bytes::hex2array_unchecked("3919132b851ef0fd2dae42a7e734fe547af5a6b809006100f48944d7fae8e8ef") .unchecked_into(), // 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x - hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"] + array_bytes::hex2array_unchecked("00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378") .unchecked_into(), // 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x - hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"] + array_bytes::hex2array_unchecked("00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378") .unchecked_into(), // 5C4vDQxA8LTck2xJEy4Yg1hM9qjDt4LvTQaMo4Y8ne43aU6x - hex!["00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378"] + array_bytes::hex2array_unchecked("00299981a2b92f878baaf5dbeba5c18d4e70f2a1fcd9c61b32ea18daf38f4378") .unchecked_into(), ), ]; // generated with secret: subkey inspect "$secret"/fir - let root_key: AccountId = hex![ + let root_key: AccountId = array_bytes::hex_n_into_unchecked( // 5Ff3iXP75ruzroPWRP2FYBHWnmGGBSb63857BgnzCoXNxfPo - "9ee5e5bdc0ec239eb164f865ecc345ce4c88e76ee002e0f7e318097347471809" - ] - .into(); + "9ee5e5bdc0ec239eb164f865ecc345ce4c88e76ee002e0f7e318097347471809", + ); let endowed_accounts: Vec = vec![root_key.clone()]; diff --git a/bin/node/cli/src/cli.rs b/bin/node/cli/src/cli.rs index 5b2977599bab0..bb7f8a4c60aa9 100644 --- a/bin/node/cli/src/cli.rs +++ b/bin/node/cli/src/cli.rs @@ -20,7 +20,7 @@ #[derive(Debug, clap::Parser)] pub struct Cli { /// Possible subcommand with parameters. - #[clap(subcommand)] + #[command(subcommand)] pub subcommand: Option, #[allow(missing_docs)] @@ -34,7 +34,7 @@ pub struct Cli { /// /// The results are then printed out in the logs, and also sent as part of /// telemetry, if telemetry is enabled. - #[clap(long)] + #[arg(long)] pub no_hardware_benchmarks: bool, } @@ -42,7 +42,7 @@ pub struct Cli { #[derive(Debug, clap::Subcommand)] pub enum Subcommand { /// The custom inspect subcommmand for decoding blocks and extrinsics. - #[clap( + #[command( name = "inspect", about = "Decode given block or extrinsic using current native runtime." )] @@ -50,7 +50,7 @@ pub enum Subcommand { /// Sub-commands concerned with benchmarking. /// The pallet benchmarking moved to the `pallet` sub-command. - #[clap(subcommand)] + #[command(subcommand)] Benchmark(frame_benchmarking_cli::BenchmarkCmd), /// Try some command against runtime state. @@ -62,7 +62,7 @@ pub enum Subcommand { TryRuntime, /// Key management cli utilities - #[clap(subcommand)] + #[command(subcommand)] Key(sc_cli::KeySubcommand), /// Verify a signature for a message, provided on STDIN, with a given (public or secret) key. diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index 79abe8975f3b6..108d7743843b6 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -119,6 +119,12 @@ pub fn run() -> Result<()> { let partial = new_partial(&config)?; cmd.run(partial.client) }, + #[cfg(not(feature = "runtime-benchmarks"))] + BenchmarkCmd::Storage(_) => Err( + "Storage benchmarking can be enabled with `--features runtime-benchmarks`." + .into(), + ), + #[cfg(feature = "runtime-benchmarks")] BenchmarkCmd::Storage(cmd) => { // ensure that we keep the task manager alive let partial = new_partial(&config)?; diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 13003c1a7a41f..6c29f0c08ee13 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -26,7 +26,7 @@ use futures::prelude::*; use kitchensink_runtime::RuntimeApi; use node_executor::ExecutorDispatch; use node_primitives::Block; -use sc_client_api::{BlockBackend, ExecutorProvider}; +use sc_client_api::BlockBackend; use sc_consensus_babe::{self, SlotProportion}; use sc_executor::NativeElseWasmExecutor; use sc_network::NetworkService; @@ -69,7 +69,7 @@ pub fn fetch_nonce(client: &FullClient, account: sp_core::sr25519::Pair) -> u32 pub fn create_extrinsic( client: &FullClient, sender: sp_core::sr25519::Pair, - function: impl Into, + function: impl Into, nonce: Option, ) -> kitchensink_runtime::UncheckedExtrinsic { let function = function.into(); @@ -223,11 +223,10 @@ pub fn new_partial( let uncles = sp_authorship::InherentDataProvider::<::Header>::check_inherents(); - Ok((timestamp, slot, uncles)) + Ok((slot, timestamp, uncles)) }, &task_manager.spawn_essential_handle(), config.prometheus_registry(), - sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()), telemetry.as_ref().map(|x| x.handle()), )?; @@ -355,7 +354,7 @@ pub fn new_full_base( Vec::default(), )); - let (network, system_rpc_tx, network_starter) = + let (network, system_rpc_tx, tx_handler_controller, network_starter) = sc_service::build_network(sc_service::BuildNetworkParams { config: &config, client: client.clone(), @@ -393,6 +392,7 @@ pub fn new_full_base( transaction_pool: transaction_pool.clone(), task_manager: &mut task_manager, system_rpc_tx, + tx_handler_controller, telemetry: telemetry.as_mut(), })?; @@ -422,9 +422,6 @@ pub fn new_full_base( telemetry.as_ref().map(|x| x.handle()), ); - let can_author_with = - sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()); - let client_clone = client.clone(); let slot_duration = babe_link.config().slot_duration(); let babe_config = sc_consensus_babe::BabeParams { @@ -457,13 +454,12 @@ pub fn new_full_base( &parent, )?; - Ok((timestamp, slot, uncles, storage_proof)) + Ok((slot, timestamp, uncles, storage_proof)) } }, force_authoring, backoff_authoring_blocks, babe_link, - can_author_with, block_proposal_slot_portion: SlotProportion::new(0.5), max_block_proposal_slot_portion: None, telemetry: telemetry.as_ref().map(|x| x.handle()), @@ -570,7 +566,7 @@ mod tests { use codec::Encode; use kitchensink_runtime::{ constants::{currency::CENTS, time::SLOT_DURATION}, - Address, BalancesCall, Call, UncheckedExtrinsic, + Address, BalancesCall, RuntimeCall, UncheckedExtrinsic, }; use node_primitives::{Block, DigestItem, Signature}; use sc_client_api::BlockBackend; @@ -592,7 +588,7 @@ mod tests { RuntimeAppPublic, }; use sp_timestamp; - use std::{borrow::Cow, sync::Arc}; + use std::sync::Arc; type AccountPublic = ::Signer; @@ -738,9 +734,9 @@ mod tests { let mut params = BlockImportParams::new(BlockOrigin::File, new_header); params.post_digests.push(item); params.body = Some(new_body); - params.intermediates.insert( - Cow::from(INTERMEDIATE_KEY), - Box::new(BabeIntermediate:: { epoch_descriptor }) as Box<_>, + params.insert_intermediate( + INTERMEDIATE_KEY, + BabeIntermediate:: { epoch_descriptor }, ); params.fork_choice = Some(ForkChoiceStrategy::LongestChain); @@ -759,8 +755,10 @@ mod tests { }; let signer = charlie.clone(); - let function = - Call::Balances(BalancesCall::transfer { dest: to.into(), value: amount }); + let function = RuntimeCall::Balances(BalancesCall::transfer { + dest: to.into(), + value: amount, + }); let check_non_zero_sender = frame_system::CheckNonZeroSender::new(); let check_spec_version = frame_system::CheckSpecVersion::new(); diff --git a/bin/node/cli/tests/common.rs b/bin/node/cli/tests/common.rs index 3b83f4339611d..358c09779d59a 100644 --- a/bin/node/cli/tests/common.rs +++ b/bin/node/cli/tests/common.rs @@ -23,8 +23,7 @@ use nix::{ sys::signal::{kill, Signal::SIGINT}, unistd::Pid, }; -use node_primitives::Block; -use remote_externalities::rpc_api::RpcService; +use node_primitives::{Hash, Header}; use std::{ io::{BufRead, BufReader, Read}, ops::{Deref, DerefMut}, @@ -69,12 +68,14 @@ pub async fn wait_n_finalized_blocks( /// Wait for at least n blocks to be finalized from a specified node pub async fn wait_n_finalized_blocks_from(n: usize, url: &str) { + use substrate_rpc_client::{ws_client, ChainApi}; + let mut built_blocks = std::collections::HashSet::new(); let mut interval = tokio::time::interval(Duration::from_secs(2)); - let rpc_service = RpcService::new(url, false).await.unwrap(); + let rpc = ws_client(url).await.unwrap(); loop { - if let Ok(block) = rpc_service.get_finalized_head::().await { + if let Ok(block) = ChainApi::<(), Hash, Header, ()>::finalized_head(&rpc).await { built_blocks.insert(block); if built_blocks.len() > n { break diff --git a/bin/node/executor/Cargo.toml b/bin/node/executor/Cargo.toml index 71865783da8ac..651e4657dde32 100644 --- a/bin/node/executor/Cargo.toml +++ b/bin/node/executor/Cargo.toml @@ -46,7 +46,6 @@ sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } [features] wasmtime = ["sc-executor/wasmtime"] -wasmi-errno = ["sc-executor/wasmi-errno"] stress-test = [] [[bench]] diff --git a/bin/node/executor/benches/bench.rs b/bin/node/executor/benches/bench.rs index a1d31a5a966db..850be3e3c6281 100644 --- a/bin/node/executor/benches/bench.rs +++ b/bin/node/executor/benches/bench.rs @@ -19,8 +19,8 @@ use codec::{Decode, Encode}; use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; use frame_support::Hashable; use kitchensink_runtime::{ - constants::currency::*, Block, BuildStorage, Call, CheckedExtrinsic, GenesisConfig, Header, - UncheckedExtrinsic, + constants::currency::*, Block, BuildStorage, CheckedExtrinsic, GenesisConfig, Header, + RuntimeCall, UncheckedExtrinsic, }; use node_executor::ExecutorDispatch; use node_primitives::{BlockNumber, Hash}; @@ -31,7 +31,6 @@ use sc_executor::{Externalities, NativeElseWasmExecutor, RuntimeVersionOf, WasmE use sp_core::{ storage::well_known_keys, traits::{CodeExecutor, RuntimeCode}, - NativeOrEncoded, NeverNativeValue, }; use sp_runtime::traits::BlakeTwo256; use sp_state_machine::TestExternalities as CoreTestExternalities; @@ -112,46 +111,24 @@ fn construct_block( // execute the block to get the real header. executor - .call:: _>( - ext, - &runtime_code, - "Core_initialize_block", - &header.encode(), - true, - None, - ) + .call(ext, &runtime_code, "Core_initialize_block", &header.encode(), true) .0 .unwrap(); for i in extrinsics.iter() { executor - .call:: _>( - ext, - &runtime_code, - "BlockBuilder_apply_extrinsic", - &i.encode(), - true, - None, - ) + .call(ext, &runtime_code, "BlockBuilder_apply_extrinsic", &i.encode(), true) .0 .unwrap(); } - let header = match executor - .call:: _>( - ext, - &runtime_code, - "BlockBuilder_finalize_block", - &[0u8; 0], - true, - None, - ) - .0 - .unwrap() - { - NativeOrEncoded::Native(_) => unreachable!(), - NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(), - }; + let header = Header::decode( + &mut &executor + .call(ext, &runtime_code, "BlockBuilder_finalize_block", &[0u8; 0], true) + .0 + .unwrap()[..], + ) + .unwrap(); let hash = header.blake2_256(); (Block { header, extrinsics }.encode(), hash.into()) @@ -164,11 +141,11 @@ fn test_blocks( let mut test_ext = new_test_ext(genesis_config); let mut block1_extrinsics = vec![CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: 0 }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: 0 }), }]; block1_extrinsics.extend((0..20).map(|i| CheckedExtrinsic { signed: Some((alice(), signed_extra(i, 0))), - function: Call::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer { dest: bob().into(), value: 1 * DOLLARS, }), @@ -218,13 +195,12 @@ fn bench_execute_block(c: &mut Criterion) { |test_ext| { for block in blocks.iter() { executor - .call:: _>( + .call( &mut test_ext.ext(), &runtime_code, "Core_execute_block", &block.0, use_native, - None, ) .0 .unwrap(); diff --git a/bin/node/executor/tests/basic.rs b/bin/node/executor/tests/basic.rs index 3426df5872c35..fc4e138faafc2 100644 --- a/bin/node/executor/tests/basic.rs +++ b/bin/node/executor/tests/basic.rs @@ -17,19 +17,20 @@ use codec::{Decode, Encode, Joiner}; use frame_support::{ + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo}, traits::Currency, - weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Weight}, + weights::Weight, }; use frame_system::{self, AccountInfo, EventRecord, Phase}; -use sp_core::{storage::well_known_keys, traits::Externalities, NeverNativeValue}; +use sp_core::{storage::well_known_keys, traits::Externalities}; use sp_runtime::{ traits::Hash as HashT, transaction_validity::InvalidTransaction, ApplyExtrinsicResult, }; use kitchensink_runtime::{ constants::{currency::*, time::SLOT_DURATION}, - Balances, Call, CheckedExtrinsic, Event, Header, Runtime, System, TransactionPayment, - UncheckedExtrinsic, + Balances, CheckedExtrinsic, Header, Runtime, RuntimeCall, RuntimeEvent, System, + TransactionPayment, UncheckedExtrinsic, }; use node_primitives::{Balance, Hash}; use node_testing::keyring::*; @@ -67,7 +68,7 @@ fn transfer_fee(extrinsic: &E) -> Balance { fn xt() -> UncheckedExtrinsic { sign(CheckedExtrinsic { signed: Some((alice(), signed_extra(0, 0))), - function: Call::Balances(default_transfer_call()), + function: RuntimeCall::Balances(default_transfer_call()), }) } @@ -84,11 +85,11 @@ fn changes_trie_block() -> (Vec, Hash) { vec![ CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time }), }, CheckedExtrinsic { signed: Some((alice(), signed_extra(0, 0))), - function: Call::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer { dest: bob().into(), value: 69 * DOLLARS, }), @@ -111,11 +112,11 @@ fn blocks() -> ((Vec, Hash), (Vec, Hash)) { vec![ CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time1 }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time1 }), }, CheckedExtrinsic { signed: Some((alice(), signed_extra(0, 0))), - function: Call::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer { dest: bob().into(), value: 69 * DOLLARS, }), @@ -131,18 +132,18 @@ fn blocks() -> ((Vec, Hash), (Vec, Hash)) { vec![ CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time2 }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time2 }), }, CheckedExtrinsic { signed: Some((bob(), signed_extra(0, 0))), - function: Call::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer { dest: alice().into(), value: 5 * DOLLARS, }), }, CheckedExtrinsic { signed: Some((alice(), signed_extra(1, 0))), - function: Call::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer { dest: bob().into(), value: 15 * DOLLARS, }), @@ -166,11 +167,11 @@ fn block_with_size(time: u64, nonce: u32, size: usize) -> (Vec, Hash) { vec![ CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }), }, CheckedExtrinsic { signed: Some((alice(), signed_extra(nonce, 0))), - function: Call::System(frame_system::Call::remark { remark: vec![0; size] }), + function: RuntimeCall::System(frame_system::Call::remark { remark: vec![0; size] }), }, ], (time * 1000 / SLOT_DURATION).into(), @@ -187,25 +188,14 @@ fn panic_execution_with_foreign_code_gives_error() { t.insert(>::hashed_key().to_vec(), 69_u128.encode()); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = executor_call:: _>( - &mut t, - "Core_initialize_block", - &vec![].and(&from_block_number(1u32)), - true, - None, - ) - .0; + let r = + executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), true) + .0; assert!(r.is_ok()); - let v = executor_call:: _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt()), - true, - None, - ) - .0 - .unwrap(); - let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap(); + let v = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true) + .0 + .unwrap(); + let r = ApplyExtrinsicResult::decode(&mut &v[..]).unwrap(); assert_eq!(r, Err(InvalidTransaction::Payment.into())); } @@ -219,25 +209,14 @@ fn bad_extrinsic_with_native_equivalent_code_gives_error() { t.insert(>::hashed_key().to_vec(), 69_u128.encode()); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = executor_call:: _>( - &mut t, - "Core_initialize_block", - &vec![].and(&from_block_number(1u32)), - true, - None, - ) - .0; + let r = + executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), true) + .0; assert!(r.is_ok()); - let v = executor_call:: _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt()), - true, - None, - ) - .0 - .unwrap(); - let r = ApplyExtrinsicResult::decode(&mut &v.as_encoded()[..]).unwrap(); + let v = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true) + .0 + .unwrap(); + let r = ApplyExtrinsicResult::decode(&mut &v[..]).unwrap(); assert_eq!(r, Err(InvalidTransaction::Payment.into())); } @@ -266,26 +245,14 @@ fn successful_execution_with_native_equivalent_code_gives_ok() { ); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = executor_call:: _>( - &mut t, - "Core_initialize_block", - &vec![].and(&from_block_number(1u32)), - true, - None, - ) - .0; + let r = + executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), true) + .0; assert!(r.is_ok()); let fees = t.execute_with(|| transfer_fee(&xt())); - let r = executor_call:: _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt()), - true, - None, - ) - .0; + let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0; assert!(r.is_ok()); t.execute_with(|| { @@ -319,26 +286,14 @@ fn successful_execution_with_foreign_code_gives_ok() { ); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = executor_call:: _>( - &mut t, - "Core_initialize_block", - &vec![].and(&from_block_number(1u32)), - true, - None, - ) - .0; + let r = + executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), true) + .0; assert!(r.is_ok()); let fees = t.execute_with(|| transfer_fee(&xt())); - let r = executor_call:: _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt()), - true, - None, - ) - .0; + let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), true).0; assert!(r.is_ok()); t.execute_with(|| { @@ -356,20 +311,21 @@ fn full_native_block_import_works() { let mut alice_last_known_balance: Balance = Default::default(); let mut fees = t.execute_with(|| transfer_fee(&xt())); - let transfer_weight = default_transfer_call().get_dispatch_info().weight; + let transfer_weight = default_transfer_call().get_dispatch_info().weight.saturating_add( + ::BlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic, + ); let timestamp_weight = pallet_timestamp::Call::set:: { now: Default::default() } .get_dispatch_info() - .weight; + .weight + .saturating_add( + ::BlockWeights::get() + .get(DispatchClass::Mandatory) + .base_extrinsic, + ); - executor_call:: _>( - &mut t, - "Core_execute_block", - &block1.0, - true, - None, - ) - .0 - .unwrap(); + executor_call(&mut t, "Core_execute_block", &block1.0, true).0.unwrap(); t.execute_with(|| { assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); @@ -378,7 +334,7 @@ fn full_native_block_import_works() { let events = vec![ EventRecord { phase: Phase::ApplyExtrinsic(0), - event: Event::System(frame_system::Event::ExtrinsicSuccess { + event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, @@ -389,7 +345,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Withdraw { + event: RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who: alice().into(), amount: fees, }), @@ -397,7 +353,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: alice().into(), to: bob().into(), amount: 69 * DOLLARS, @@ -406,7 +362,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Deposit { + event: RuntimeEvent::Balances(pallet_balances::Event::Deposit { who: pallet_treasury::Pallet::::account_id(), amount: fees * 8 / 10, }), @@ -414,12 +370,14 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Treasury(pallet_treasury::Event::Deposit { value: fees * 8 / 10 }), + event: RuntimeEvent::Treasury(pallet_treasury::Event::Deposit { + value: fees * 8 / 10, + }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::TransactionPayment( + event: RuntimeEvent::TransactionPayment( pallet_transaction_payment::Event::TransactionFeePaid { who: alice().into(), actual_fee: fees, @@ -430,7 +388,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::System(frame_system::Event::ExtrinsicSuccess { + event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: transfer_weight, ..Default::default() }, }), topics: vec![], @@ -441,15 +399,7 @@ fn full_native_block_import_works() { fees = t.execute_with(|| transfer_fee(&xt())); - executor_call:: _>( - &mut t, - "Core_execute_block", - &block2.0, - true, - None, - ) - .0 - .unwrap(); + executor_call(&mut t, "Core_execute_block", &block2.0, true).0.unwrap(); t.execute_with(|| { assert_eq!( @@ -460,7 +410,7 @@ fn full_native_block_import_works() { let events = vec![ EventRecord { phase: Phase::ApplyExtrinsic(0), - event: Event::System(frame_system::Event::ExtrinsicSuccess { + event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, @@ -471,7 +421,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Withdraw { + event: RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who: bob().into(), amount: fees, }), @@ -479,7 +429,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: bob().into(), to: alice().into(), amount: 5 * DOLLARS, @@ -488,7 +438,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Balances(pallet_balances::Event::Deposit { + event: RuntimeEvent::Balances(pallet_balances::Event::Deposit { who: pallet_treasury::Pallet::::account_id(), amount: fees * 8 / 10, }), @@ -496,12 +446,14 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::Treasury(pallet_treasury::Event::Deposit { value: fees * 8 / 10 }), + event: RuntimeEvent::Treasury(pallet_treasury::Event::Deposit { + value: fees * 8 / 10, + }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::TransactionPayment( + event: RuntimeEvent::TransactionPayment( pallet_transaction_payment::Event::TransactionFeePaid { who: bob().into(), actual_fee: fees, @@ -512,14 +464,14 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(1), - event: Event::System(frame_system::Event::ExtrinsicSuccess { + event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: transfer_weight, ..Default::default() }, }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::Balances(pallet_balances::Event::Withdraw { + event: RuntimeEvent::Balances(pallet_balances::Event::Withdraw { who: alice().into(), amount: fees, }), @@ -527,7 +479,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: alice().into(), to: bob().into(), amount: 15 * DOLLARS, @@ -536,7 +488,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::Balances(pallet_balances::Event::Deposit { + event: RuntimeEvent::Balances(pallet_balances::Event::Deposit { who: pallet_treasury::Pallet::::account_id(), amount: fees * 8 / 10, }), @@ -544,12 +496,14 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::Treasury(pallet_treasury::Event::Deposit { value: fees * 8 / 10 }), + event: RuntimeEvent::Treasury(pallet_treasury::Event::Deposit { + value: fees * 8 / 10, + }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::TransactionPayment( + event: RuntimeEvent::TransactionPayment( pallet_transaction_payment::Event::TransactionFeePaid { who: alice().into(), actual_fee: fees, @@ -560,7 +514,7 @@ fn full_native_block_import_works() { }, EventRecord { phase: Phase::ApplyExtrinsic(2), - event: Event::System(frame_system::Event::ExtrinsicSuccess { + event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { dispatch_info: DispatchInfo { weight: transfer_weight, ..Default::default() }, }), topics: vec![], @@ -579,15 +533,7 @@ fn full_wasm_block_import_works() { let mut alice_last_known_balance: Balance = Default::default(); let mut fees = t.execute_with(|| transfer_fee(&xt())); - executor_call:: _>( - &mut t, - "Core_execute_block", - &block1.0, - false, - None, - ) - .0 - .unwrap(); + executor_call(&mut t, "Core_execute_block", &block1.0, false).0.unwrap(); t.execute_with(|| { assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); @@ -597,15 +543,7 @@ fn full_wasm_block_import_works() { fees = t.execute_with(|| transfer_fee(&xt())); - executor_call:: _>( - &mut t, - "Core_execute_block", - &block2.0, - false, - None, - ) - .0 - .unwrap(); + executor_call(&mut t, "Core_execute_block", &block2.0, false).0.unwrap(); t.execute_with(|| { assert_eq!( @@ -726,24 +664,24 @@ fn deploying_wasm_contract_should_work() { vec![ CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time }), }, CheckedExtrinsic { signed: Some((charlie(), signed_extra(0, 0))), - function: Call::Contracts( - pallet_contracts::Call::instantiate_with_code:: { - value: 0, - gas_limit: Weight::from_ref_time(500_000_000), - storage_deposit_limit: None, - code: transfer_code, - data: Vec::new(), - salt: Vec::new(), - }, - ), + function: RuntimeCall::Contracts(pallet_contracts::Call::instantiate_with_code::< + Runtime, + > { + value: 0, + gas_limit: Weight::from_ref_time(500_000_000), + storage_deposit_limit: None, + code: transfer_code, + data: Vec::new(), + salt: Vec::new(), + }), }, CheckedExtrinsic { signed: Some((charlie(), signed_extra(1, 0))), - function: Call::Contracts(pallet_contracts::Call::call:: { + function: RuntimeCall::Contracts(pallet_contracts::Call::call:: { dest: sp_runtime::MultiAddress::Id(addr.clone()), value: 10, gas_limit: Weight::from_ref_time(500_000_000), @@ -757,9 +695,7 @@ fn deploying_wasm_contract_should_work() { let mut t = new_test_ext(compact_code_unwrap()); - executor_call:: _>(&mut t, "Core_execute_block", &b.0, false, None) - .0 - .unwrap(); + executor_call(&mut t, "Core_execute_block", &b.0, false).0.unwrap(); t.execute_with(|| { // Verify that the contract does exist by querying some of its storage items @@ -778,14 +714,8 @@ fn wasm_big_block_import_fails() { set_heap_pages(&mut t.ext(), 4); - let result = executor_call:: _>( - &mut t, - "Core_execute_block", - &block_with_size(42, 0, 120_000).0, - false, - None, - ) - .0; + let result = + executor_call(&mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0, false).0; assert!(result.is_err()); // Err(Wasmi(Trap(Trap { kind: Host(AllocatorOutOfSpace) }))) } @@ -793,15 +723,9 @@ fn wasm_big_block_import_fails() { fn native_big_block_import_succeeds() { let mut t = new_test_ext(compact_code_unwrap()); - executor_call:: _>( - &mut t, - "Core_execute_block", - &block_with_size(42, 0, 120_000).0, - true, - None, - ) - .0 - .unwrap(); + executor_call(&mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0, true) + .0 + .unwrap(); } #[test] @@ -812,15 +736,11 @@ fn native_big_block_import_fails_on_fallback() { // block. set_heap_pages(&mut t.ext(), 8); - assert!(executor_call:: _>( - &mut t, - "Core_execute_block", - &block_with_size(42, 0, 120_000).0, - false, - None, - ) - .0 - .is_err()); + assert!( + executor_call(&mut t, "Core_execute_block", &block_with_size(42, 0, 120_000).0, false,) + .0 + .is_err() + ); } #[test] @@ -837,25 +757,17 @@ fn panic_execution_gives_error() { t.insert(>::hashed_key().to_vec(), 0_u128.encode()); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = executor_call:: _>( + let r = executor_call( &mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), false, - None, ) .0; assert!(r.is_ok()); - let r = executor_call:: _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt()), - false, - None, - ) - .0 - .unwrap() - .into_encoded(); + let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), false) + .0 + .unwrap(); let r = ApplyExtrinsicResult::decode(&mut &r[..]).unwrap(); assert_eq!(r, Err(InvalidTransaction::Payment.into())); } @@ -885,12 +797,11 @@ fn successful_execution_gives_ok() { ); t.insert(>::hashed_key_for(0), vec![0u8; 32]); - let r = executor_call:: _>( + let r = executor_call( &mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), false, - None, ) .0; assert!(r.is_ok()); @@ -900,16 +811,9 @@ fn successful_execution_gives_ok() { let fees = t.execute_with(|| transfer_fee(&xt())); - let r = executor_call:: _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt()), - false, - None, - ) - .0 - .unwrap() - .into_encoded(); + let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt()), false) + .0 + .unwrap(); ApplyExtrinsicResult::decode(&mut &r[..]) .unwrap() .expect("Extrinsic could not be applied") diff --git a/bin/node/executor/tests/common.rs b/bin/node/executor/tests/common.rs index 407a1e09f8efb..803ec78329eea 100644 --- a/bin/node/executor/tests/common.rs +++ b/bin/node/executor/tests/common.rs @@ -27,7 +27,6 @@ use sp_core::{ crypto::KeyTypeId, sr25519::Signature, traits::{CodeExecutor, RuntimeCode}, - NativeOrEncoded, NeverNativeValue, }; use sp_runtime::{ traits::{BlakeTwo256, Header as HeaderT}, @@ -99,17 +98,12 @@ pub fn executor() -> NativeElseWasmExecutor { NativeElseWasmExecutor::new(WasmExecutionMethod::Interpreted, None, 8, 2) } -pub fn executor_call< - R: Decode + Encode + PartialEq, - NC: FnOnce() -> std::result::Result> - + std::panic::UnwindSafe, ->( +pub fn executor_call( t: &mut TestExternalities, method: &str, data: &[u8], use_native: bool, - native_call: Option, -) -> (Result>, bool) { +) -> (Result>, bool) { let mut t = t.ext(); let code = t.storage(sp_core::storage::well_known_keys::CODE).unwrap(); @@ -120,7 +114,7 @@ pub fn executor_call< heap_pages: heap_pages.and_then(|hp| Decode::decode(&mut &hp[..]).ok()), }; sp_tracing::try_init_simple(); - executor().call::(&mut t, &runtime_code, method, data, use_native, native_call) + executor().call(&mut t, &runtime_code, method, data, use_native) } pub fn new_test_ext(code: &[u8]) -> TestExternalities { @@ -171,29 +165,15 @@ pub fn construct_block( }; // execute the block to get the real header. - executor_call:: _>( - env, - "Core_initialize_block", - &header.encode(), - true, - None, - ) - .0 - .unwrap(); + executor_call(env, "Core_initialize_block", &header.encode(), true).0.unwrap(); for extrinsic in extrinsics.iter() { // Try to apply the `extrinsic`. It should be valid, in the sense that it passes // all pre-inclusion checks. - let r = executor_call:: _>( - env, - "BlockBuilder_apply_extrinsic", - &extrinsic.encode(), - true, - None, - ) - .0 - .expect("application of an extrinsic failed") - .into_encoded(); + let r = executor_call(env, "BlockBuilder_apply_extrinsic", &extrinsic.encode(), true) + .0 + .expect("application of an extrinsic failed"); + match ApplyExtrinsicResult::decode(&mut &r[..]) .expect("apply result deserialization failed") { @@ -202,19 +182,10 @@ pub fn construct_block( } } - let header = match executor_call:: _>( - env, - "BlockBuilder_finalize_block", - &[0u8; 0], - true, - None, + let header = Header::decode( + &mut &executor_call(env, "BlockBuilder_finalize_block", &[0u8; 0], true).0.unwrap()[..], ) - .0 - .unwrap() - { - NativeOrEncoded::Native(_) => unreachable!(), - NativeOrEncoded::Encoded(h) => Header::decode(&mut &h[..]).unwrap(), - }; + .unwrap(); let hash = header.blake2_256(); (Block { header, extrinsics }.encode(), hash.into()) diff --git a/bin/node/executor/tests/fees.rs b/bin/node/executor/tests/fees.rs index dd1318254d9b7..6932cb2cea867 100644 --- a/bin/node/executor/tests/fees.rs +++ b/bin/node/executor/tests/fees.rs @@ -17,16 +17,17 @@ use codec::{Encode, Joiner}; use frame_support::{ + dispatch::GetDispatchInfo, traits::Currency, - weights::{constants::ExtrinsicBaseWeight, GetDispatchInfo, IdentityFee, WeightToFee}, + weights::{constants::ExtrinsicBaseWeight, IdentityFee, WeightToFee}, }; use kitchensink_runtime::{ constants::{currency::*, time::SLOT_DURATION}, - Balances, Call, CheckedExtrinsic, Multiplier, Runtime, TransactionByteFee, TransactionPayment, + Balances, CheckedExtrinsic, Multiplier, Runtime, RuntimeCall, TransactionByteFee, + TransactionPayment, }; use node_primitives::Balance; use node_testing::keyring::*; -use sp_core::NeverNativeValue; use sp_runtime::{traits::One, Perbill}; pub mod common; @@ -54,12 +55,12 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { vec![ CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time1 }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time1 }), }, CheckedExtrinsic { signed: Some((charlie(), signed_extra(0, 0))), - function: Call::Sudo(pallet_sudo::Call::sudo { - call: Box::new(Call::System(frame_system::Call::fill_block { + function: RuntimeCall::Sudo(pallet_sudo::Call::sudo { + call: Box::new(RuntimeCall::System(frame_system::Call::fill_block { ratio: Perbill::from_percent(60), })), }), @@ -77,11 +78,11 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { vec![ CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time2 }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time2 }), }, CheckedExtrinsic { signed: Some((charlie(), signed_extra(1, 0))), - function: Call::System(frame_system::Call::remark { remark: vec![0; 1] }), + function: RuntimeCall::System(frame_system::Call::remark { remark: vec![0; 1] }), }, ], (time2 / SLOT_DURATION).into(), @@ -94,15 +95,7 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { ); // execute a big block. - executor_call:: _>( - &mut t, - "Core_execute_block", - &block1.0, - true, - None, - ) - .0 - .unwrap(); + executor_call(&mut t, "Core_execute_block", &block1.0, true).0.unwrap(); // weight multiplier is increased for next block. t.execute_with(|| { @@ -113,15 +106,7 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { }); // execute a big block. - executor_call:: _>( - &mut t, - "Core_execute_block", - &block2.0, - true, - None, - ) - .0 - .unwrap(); + executor_call(&mut t, "Core_execute_block", &block2.0, true).0.unwrap(); // weight multiplier is increased for next block. t.execute_with(|| { @@ -163,27 +148,15 @@ fn transaction_fee_is_correct() { let tip = 1_000_000; let xt = sign(CheckedExtrinsic { signed: Some((alice(), signed_extra(0, tip))), - function: Call::Balances(default_transfer_call()), + function: RuntimeCall::Balances(default_transfer_call()), }); - let r = executor_call:: _>( - &mut t, - "Core_initialize_block", - &vec![].and(&from_block_number(1u32)), - true, - None, - ) - .0; + let r = + executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32)), true) + .0; assert!(r.is_ok()); - let r = executor_call:: _>( - &mut t, - "BlockBuilder_apply_extrinsic", - &vec![].and(&xt.clone()), - true, - None, - ) - .0; + let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt.clone()), true).0; assert!(r.is_ok()); t.execute_with(|| { @@ -241,7 +214,7 @@ fn block_weight_capacity_report() { let mut xts = (0..num_transfers) .map(|i| CheckedExtrinsic { signed: Some((charlie(), signed_extra(nonce + i as Index, 0))), - function: Call::Balances(pallet_balances::Call::transfer { + function: RuntimeCall::Balances(pallet_balances::Call::transfer { dest: bob().into(), value: 0, }), @@ -252,7 +225,7 @@ fn block_weight_capacity_report() { 0, CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }), }, ); @@ -274,14 +247,7 @@ fn block_weight_capacity_report() { len / 1024 / 1024, ); - let r = executor_call:: _>( - &mut t, - "Core_execute_block", - &block.0, - true, - None, - ) - .0; + let r = executor_call(&mut t, "Core_execute_block", &block.0, true).0; println!(" || Result = {:?}", r); assert!(r.is_ok()); @@ -322,11 +288,13 @@ fn block_length_capacity_report() { vec![ CheckedExtrinsic { signed: None, - function: Call::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }), + function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { + now: time * 1000, + }), }, CheckedExtrinsic { signed: Some((charlie(), signed_extra(nonce, 0))), - function: Call::System(frame_system::Call::remark { + function: RuntimeCall::System(frame_system::Call::remark { remark: vec![0u8; (block_number * factor) as usize], }), }, @@ -342,14 +310,7 @@ fn block_length_capacity_report() { len / 1024 / 1024, ); - let r = executor_call:: _>( - &mut t, - "Core_execute_block", - &block.0, - true, - None, - ) - .0; + let r = executor_call(&mut t, "Core_execute_block", &block.0, true).0; println!(" || Result = {:?}", r); assert!(r.is_ok()); diff --git a/bin/node/inspect/Cargo.toml b/bin/node/inspect/Cargo.toml index c41681d11be1e..b7eccf9c36bd2 100644 --- a/bin/node/inspect/Cargo.toml +++ b/bin/node/inspect/Cargo.toml @@ -2,6 +2,7 @@ name = "node-inspect" version = "0.9.0-dev" authors = ["Parity Technologies "] +description = "Substrate node block inspection tool." edition = "2021" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" homepage = "https://substrate.io" @@ -11,7 +12,7 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "3.1.6", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } thiserror = "1.0" sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } diff --git a/bin/node/inspect/src/cli.rs b/bin/node/inspect/src/cli.rs index cc1f232e1fe0f..fa6344ac346e9 100644 --- a/bin/node/inspect/src/cli.rs +++ b/bin/node/inspect/src/cli.rs @@ -46,7 +46,7 @@ pub enum InspectSubCmd { /// Can be either a block hash (no 0x prefix) or a number to retrieve existing block, /// or a 0x-prefixed bytes hex string, representing SCALE encoding of /// a block. - #[clap(value_name = "HASH or NUMBER or BYTES")] + #[arg(value_name = "HASH or NUMBER or BYTES")] input: String, }, /// Decode extrinsic with native version of runtime and print out the details. @@ -56,7 +56,7 @@ pub enum InspectSubCmd { /// Can be either a block hash (no 0x prefix) or number and the index, in the form /// of `{block}:{index}` or a 0x-prefixed bytes hex string, /// representing SCALE encoding of an extrinsic. - #[clap(value_name = "BLOCK:INDEX or BYTES")] + #[arg(value_name = "BLOCK:INDEX or BYTES")] input: String, }, } diff --git a/bin/node/inspect/src/lib.rs b/bin/node/inspect/src/lib.rs index b37c5aa7ca2e8..aacae0ff7a0d9 100644 --- a/bin/node/inspect/src/lib.rs +++ b/bin/node/inspect/src/lib.rs @@ -296,7 +296,7 @@ mod tests { let b2 = ExtrinsicAddress::from_str("0 0"); let b3 = ExtrinsicAddress::from_str("0x0012345f"); - assert_eq!(e0, Err("Extrinsic index missing: example \"5:0\"".into())); + assert_eq!(e0, Ok(ExtrinsicAddress::Bytes(vec![0x12, 0x34]))); assert_eq!( b0, Ok(ExtrinsicAddress::Block( @@ -305,7 +305,7 @@ mod tests { )) ); assert_eq!(b1, Ok(ExtrinsicAddress::Block(BlockAddress::Number(1234), 0))); - assert_eq!(b2, Ok(ExtrinsicAddress::Block(BlockAddress::Number(0), 0))); + assert_eq!(b2, Ok(ExtrinsicAddress::Bytes(vec![0, 0]))); assert_eq!(b3, Ok(ExtrinsicAddress::Bytes(vec![0, 0x12, 0x34, 0x5f]))); } } diff --git a/bin/node/primitives/Cargo.toml b/bin/node/primitives/Cargo.toml index bc6fa669ca4ea..65a4223a7fb9f 100644 --- a/bin/node/primitives/Cargo.toml +++ b/bin/node/primitives/Cargo.toml @@ -2,6 +2,7 @@ name = "node-primitives" version = "2.0.0" authors = ["Parity Technologies "] +description = "Substrate node low-level primitives." edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index 07b25085b9d10..1f93feabf2f1e 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -2,6 +2,7 @@ name = "node-rpc" version = "3.0.0-dev" authors = ["Parity Technologies "] +description = "Substrate node rpc methods." edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" @@ -13,7 +14,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] jsonrpsee = { version = "0.15.1", features = ["server"] } node-primitives = { version = "2.0.0", path = "../primitives" } -pallet-contracts-rpc = { version = "4.0.0-dev", path = "../../../frame/contracts/rpc/" } pallet-mmr-rpc = { version = "3.0.0", path = "../../../frame/merkle-mountain-range/rpc/" } pallet-transaction-payment-rpc = { version = "4.0.0-dev", path = "../../../frame/transaction-payment/rpc/" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" } @@ -25,6 +25,7 @@ sc-finality-grandpa = { version = "0.10.0-dev", path = "../../../client/finality sc-finality-grandpa-rpc = { version = "0.10.0-dev", path = "../../../client/finality-grandpa/rpc" } sc-rpc = { version = "4.0.0-dev", path = "../../../client/rpc" } sc-rpc-api = { version = "0.10.0-dev", path = "../../../client/rpc-api" } +sc-rpc-spec-v2 = { version = "0.10.0-dev", path = "../../../client/rpc-spec-v2" } sc-sync-state-rpc = { version = "0.10.0-dev", path = "../../../client/sync-state-rpc" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index 1c8b9cce1a744..8596fe23321ba 100644 --- a/bin/node/rpc/src/lib.rs +++ b/bin/node/rpc/src/lib.rs @@ -108,8 +108,11 @@ where + Send + 'static, C::Api: substrate_frame_rpc_system::AccountNonceApi, - C::Api: pallet_contracts_rpc::ContractsRuntimeApi, - C::Api: pallet_mmr_rpc::MmrRuntimeApi::Hash>, + C::Api: pallet_mmr_rpc::MmrRuntimeApi< + Block, + ::Hash, + BlockNumber, + >, C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, C::Api: BabeApi, C::Api: BlockBuilder, @@ -118,12 +121,12 @@ where B: sc_client_api::Backend + Send + Sync + 'static, B::State: sc_client_api::backend::StateBackend>, { - use pallet_contracts_rpc::{Contracts, ContractsApiServer}; use pallet_mmr_rpc::{Mmr, MmrApiServer}; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; use sc_consensus_babe_rpc::{Babe, BabeApiServer}; use sc_finality_grandpa_rpc::{Grandpa, GrandpaApiServer}; use sc_rpc::dev::{Dev, DevApiServer}; + use sc_rpc_spec_v2::chain_spec::{ChainSpec, ChainSpecApiServer}; use sc_sync_state_rpc::{SyncState, SyncStateApiServer}; use substrate_frame_rpc_system::{System, SystemApiServer}; use substrate_state_trie_migration_rpc::{StateMigration, StateMigrationApiServer}; @@ -140,11 +143,15 @@ where finality_provider, } = grandpa; + let chain_name = chain_spec.name().to_string(); + let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); + let properties = chain_spec.properties(); + io.merge(ChainSpec::new(chain_name, genesis_hash, properties).into_rpc())?; + io.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; // Making synchronous calls in light client freezes the browser currently, // more context: https://github.com/paritytech/substrate/pull/3480 // These RPCs should use an asynchronous caller instead. - io.merge(Contracts::new(client.clone()).into_rpc())?; io.merge(Mmr::new(client.clone()).into_rpc())?; io.merge(TransactionPayment::new(client.clone()).into_rpc())?; io.merge( diff --git a/bin/node/runtime/Cargo.toml b/bin/node/runtime/Cargo.toml index ebec9b8b755f6..6940e968e28e7 100644 --- a/bin/node/runtime/Cargo.toml +++ b/bin/node/runtime/Cargo.toml @@ -2,6 +2,7 @@ name = "kitchensink-runtime" version = "3.0.0-dev" authors = ["Parity Technologies "] +description = "Substrate node kitchensink runtime." edition = "2021" build = "build.rs" license = "Apache-2.0" @@ -20,7 +21,6 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } static_assertions = "1.1.0" -hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.17", default-features = false } # primitives @@ -61,13 +61,13 @@ pallet-bounties = { version = "4.0.0-dev", default-features = false, path = "../ pallet-child-bounties = { version = "4.0.0-dev", default-features = false, path = "../../../frame/child-bounties" } pallet-collective = { version = "4.0.0-dev", default-features = false, path = "../../../frame/collective" } pallet-contracts = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts" } -pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../../../frame/contracts/common/" } -pallet-contracts-rpc-runtime-api = { version = "4.0.0-dev", default-features = false, path = "../../../frame/contracts/rpc/runtime-api/" } +pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../../../frame/contracts/primitives/" } pallet-conviction-voting = { version = "4.0.0-dev", default-features = false, path = "../../../frame/conviction-voting" } pallet-democracy = { version = "4.0.0-dev", default-features = false, path = "../../../frame/democracy" } pallet-election-provider-multi-phase = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-multi-phase" } pallet-election-provider-support-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../../../frame/election-provider-support/benchmarking", optional = true } pallet-elections-phragmen = { version = "5.0.0-dev", default-features = false, path = "../../../frame/elections-phragmen" } +pallet-fast-unstake = { version = "4.0.0-dev", default-features = false, path = "../../../frame/fast-unstake" } pallet-gilt = { version = "4.0.0-dev", default-features = false, path = "../../../frame/gilt" } pallet-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../../frame/grandpa" } pallet-im-online = { version = "4.0.0-dev", default-features = false, path = "../../../frame/im-online" } @@ -116,6 +116,13 @@ substrate-wasm-builder = { version = "5.0.0-dev", path = "../../../utils/wasm-bu default = ["std"] with-tracing = ["frame-executive/with-tracing"] std = [ + "sp-sandbox/std", + "pallet-whitelist/std", + "pallet-offences-benchmarking?/std", + "pallet-election-provider-support-benchmarking?/std", + "pallet-asset-tx-payment/std", + "frame-system-benchmarking?/std", + "frame-election-provider-support/std", "sp-authority-discovery/std", "pallet-assets/std", "pallet-authority-discovery/std", @@ -131,10 +138,10 @@ std = [ "pallet-collective/std", "pallet-contracts/std", "pallet-contracts-primitives/std", - "pallet-contracts-rpc-runtime-api/std", "pallet-conviction-voting/std", "pallet-democracy/std", "pallet-elections-phragmen/std", + "pallet-fast-unstake/std", "frame-executive/std", "pallet-gilt/std", "pallet-grandpa/std", @@ -147,6 +154,7 @@ std = [ "pallet-multisig/std", "pallet-nomination-pools/std", "pallet-nomination-pools-runtime-api/std", + "pallet-nomination-pools-benchmarking?/std", "pallet-identity/std", "pallet-scheduler/std", "node-primitives/std", @@ -158,6 +166,7 @@ std = [ "pallet-randomness-collective-flip/std", "sp-std/std", "pallet-session/std", + "pallet-session-benchmarking?/std", "sp-api/std", "sp-runtime/std", "sp-staking/std", @@ -166,7 +175,7 @@ std = [ "sp-session/std", "pallet-sudo/std", "frame-support/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-system-rpc-runtime-api/std", "frame-system/std", "pallet-election-provider-multi-phase/std", @@ -187,7 +196,7 @@ std = [ "pallet-uniques/std", "pallet-vesting/std", "log/std", - "frame-try-runtime/std", + "frame-try-runtime?/std", "sp-io/std", "pallet-child-bounties/std", "pallet-alliance/std", @@ -211,6 +220,7 @@ runtime-benchmarks = [ "pallet-election-provider-multi-phase/runtime-benchmarks", "pallet-election-provider-support-benchmarking/runtime-benchmarks", "pallet-elections-phragmen/runtime-benchmarks", + "pallet-fast-unstake/runtime-benchmarks", "pallet-gilt/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", "pallet-identity/runtime-benchmarks", @@ -220,8 +230,8 @@ runtime-benchmarks = [ "pallet-membership/runtime-benchmarks", "pallet-mmr/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", - "pallet-nomination-pools-benchmarking", - "pallet-offences-benchmarking", + "pallet-nomination-pools-benchmarking/runtime-benchmarks", + "pallet-offences-benchmarking/runtime-benchmarks", "pallet-preimage/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", @@ -229,7 +239,7 @@ runtime-benchmarks = [ "pallet-referenda/runtime-benchmarks", "pallet-recovery/runtime-benchmarks", "pallet-remark/runtime-benchmarks", - "pallet-session-benchmarking", + "pallet-session-benchmarking/runtime-benchmarks", "pallet-society/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-state-trie-migration/runtime-benchmarks", @@ -241,8 +251,7 @@ runtime-benchmarks = [ "pallet-uniques/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", "pallet-whitelist/runtime-benchmarks", - "frame-system-benchmarking", - "hex-literal", + "frame-system-benchmarking/runtime-benchmarks", ] try-runtime = [ "frame-try-runtime", @@ -264,6 +273,7 @@ try-runtime = [ "pallet-democracy/try-runtime", "pallet-election-provider-multi-phase/try-runtime", "pallet-elections-phragmen/try-runtime", + "pallet-fast-unstake/try-runtime", "pallet-gilt/try-runtime", "pallet-grandpa/try-runtime", "pallet-im-online/try-runtime", diff --git a/bin/node/runtime/src/impls.rs b/bin/node/runtime/src/impls.rs index cedc945b0af7e..0a5c797ba729f 100644 --- a/bin/node/runtime/src/impls.rs +++ b/bin/node/runtime/src/impls.rs @@ -18,7 +18,8 @@ //! Some configurable implementations as associated type for the substrate runtime. use crate::{ - AccountId, AllianceMotion, Assets, Authorship, Balances, Call, Hash, NegativeImbalance, Runtime, + AccountId, AllianceMotion, Assets, Authorship, Balances, Hash, NegativeImbalance, Runtime, + RuntimeCall, }; use frame_support::{ pallet_prelude::*, @@ -77,11 +78,11 @@ impl IdentityVerifier for AllianceIdentityVerifier { } pub struct AllianceProposalProvider; -impl ProposalProvider for AllianceProposalProvider { +impl ProposalProvider for AllianceProposalProvider { fn propose_proposal( who: AccountId, threshold: u32, - proposal: Box, + proposal: Box, length_bound: u32, ) -> Result<(u32, u32), DispatchError> { AllianceMotion::do_propose_proposed(who, threshold, proposal, length_bound) @@ -109,7 +110,7 @@ impl ProposalProvider for AllianceProposalProvider { AllianceMotion::do_close(proposal_hash, proposal_index, proposal_weight_bound, length_bound) } - fn proposal_of(proposal_hash: Hash) -> Option { + fn proposal_of(proposal_hash: Hash) -> Option { AllianceMotion::proposal_of(proposal_hash) } } @@ -125,10 +126,13 @@ mod multiplier_tests { use crate::{ constants::{currency::*, time::*}, - AdjustmentVariable, MinimumMultiplier, Runtime, RuntimeBlockWeights as BlockWeights, - System, TargetBlockFullness, TransactionPayment, + AdjustmentVariable, MaximumMultiplier, MinimumMultiplier, Runtime, + RuntimeBlockWeights as BlockWeights, System, TargetBlockFullness, TransactionPayment, + }; + use frame_support::{ + dispatch::DispatchClass, + weights::{Weight, WeightToFee}, }; - use frame_support::weights::{DispatchClass, Weight, WeightToFee}; fn max_normal() -> Weight { BlockWeights::get() @@ -152,6 +156,7 @@ mod multiplier_tests { TargetBlockFullness, AdjustmentVariable, MinimumMultiplier, + MaximumMultiplier, >::convert(fm) } @@ -220,7 +225,7 @@ mod multiplier_tests { fn multiplier_can_grow_from_zero() { // if the min is too small, then this will not change, and we are doomed forever. // the weight is 1/100th bigger than target. - run_with_system_weight(target() * 101 / 100, || { + run_with_system_weight(target().set_ref_time(target().ref_time() * 101 / 100), || { let next = runtime_multiplier_update(min_multiplier()); assert!(next > min_multiplier(), "{:?} !>= {:?}", next, min_multiplier()); }) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 64a6b95d1c5c2..06b8daf7c51e4 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -28,16 +28,17 @@ use frame_election_provider_support::{ }; use frame_support::{ construct_runtime, + dispatch::DispatchClass, pallet_prelude::Get, parameter_types, traits::{ AsEnsureOriginWithArg, ConstU128, ConstU16, ConstU32, Currency, EitherOfDiverse, EqualPrivilegeOnly, Everything, Imbalance, InstanceFilter, KeyOwnerProofSystem, - LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, + LockIdentifier, Nothing, OnUnbalanced, U128CurrencyToVote, WithdrawReasons, }, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, - ConstantMultiplier, DispatchClass, IdentityFee, Weight, + ConstantMultiplier, IdentityFee, Weight, }, PalletId, RuntimeDebug, }; @@ -64,7 +65,7 @@ use sp_runtime::{ curve::PiecewiseLinear, generic, impl_opaque_keys, traits::{ - self, BlakeTwo256, Block as BlockT, ConvertInto, NumberFor, OpaqueKeys, + self, BlakeTwo256, Block as BlockT, Bounded, ConvertInto, NumberFor, OpaqueKeys, SaturatedConversion, StaticLookup, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, @@ -168,8 +169,8 @@ const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); /// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used /// by Operational extrinsics. const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); -/// We allow for 2 seconds of compute with a 6 second average block time. -const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND.saturating_mul(2); +/// We allow for 2 seconds of compute with a 6 second average block time, with maximum proof size. +const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND.saturating_mul(2).set_proof_size(u64::MAX); parameter_types! { pub const BlockHashCount: BlockNumber = 2400; @@ -203,8 +204,8 @@ impl frame_system::Config for Runtime { type BlockWeights = RuntimeBlockWeights; type BlockLength = RuntimeBlockLength; type DbWeight = RocksDbWeight; - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = Index; type BlockNumber = BlockNumber; type Hash = Hash; @@ -212,7 +213,7 @@ impl frame_system::Config for Runtime { type AccountId = AccountId; type Lookup = Indices; type Header = generic::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = BlockHashCount; type Version = Version; type PalletInfo = PalletInfo; @@ -228,8 +229,8 @@ impl frame_system::Config for Runtime { impl pallet_randomness_collective_flip::Config for Runtime {} impl pallet_utility::Config for Runtime { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; type WeightInfo = pallet_utility::weights::SubstrateWeight; } @@ -242,8 +243,8 @@ parameter_types! { } impl pallet_multisig::Config for Runtime { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type Currency = Balances; type DepositBase = DepositBase; type DepositFactor = DepositFactor; @@ -285,25 +286,28 @@ impl Default for ProxyType { Self::Any } } -impl InstanceFilter for ProxyType { - fn filter(&self, c: &Call) -> bool { +impl InstanceFilter for ProxyType { + fn filter(&self, c: &RuntimeCall) -> bool { match self { ProxyType::Any => true, ProxyType::NonTransfer => !matches!( c, - Call::Balances(..) | - Call::Assets(..) | Call::Uniques(..) | - Call::Vesting(pallet_vesting::Call::vested_transfer { .. }) | - Call::Indices(pallet_indices::Call::transfer { .. }) + RuntimeCall::Balances(..) | + RuntimeCall::Assets(..) | + RuntimeCall::Uniques(..) | + RuntimeCall::Vesting(pallet_vesting::Call::vested_transfer { .. }) | + RuntimeCall::Indices(pallet_indices::Call::transfer { .. }) ), ProxyType::Governance => matches!( c, - Call::Democracy(..) | - Call::Council(..) | Call::Society(..) | - Call::TechnicalCommittee(..) | - Call::Elections(..) | Call::Treasury(..) + RuntimeCall::Democracy(..) | + RuntimeCall::Council(..) | + RuntimeCall::Society(..) | + RuntimeCall::TechnicalCommittee(..) | + RuntimeCall::Elections(..) | + RuntimeCall::Treasury(..) ), - ProxyType::Staking => matches!(c, Call::Staking(..)), + ProxyType::Staking => matches!(c, RuntimeCall::Staking(..)), } } fn is_superset(&self, o: &Self) -> bool { @@ -318,8 +322,8 @@ impl InstanceFilter for ProxyType { } impl pallet_proxy::Config for Runtime { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type Currency = Balances; type ProxyType = ProxyType; type ProxyDepositBase = ProxyDepositBase; @@ -335,22 +339,19 @@ impl pallet_proxy::Config for Runtime { parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block; - // Retry a scheduled item every 10 blocks (1 minute) until the preimage exists. - pub const NoPreimagePostponement: Option = Some(10); } impl pallet_scheduler::Config for Runtime { - type Event = Event; - type Origin = Origin; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; type PalletsOrigin = OriginCaller; - type Call = Call; + type RuntimeCall = RuntimeCall; type MaximumWeight = MaximumSchedulerWeight; type ScheduleOrigin = EnsureRoot; - type MaxScheduledPerBlock = ConstU32<50>; + type MaxScheduledPerBlock = ConstU32<512>; type WeightInfo = pallet_scheduler::weights::SubstrateWeight; type OriginPrivilegeCmp = EqualPrivilegeOnly; - type PreimageProvider = Preimage; - type NoPreimagePostponement = NoPreimagePostponement; + type Preimages = Preimage; } parameter_types! { @@ -362,10 +363,9 @@ parameter_types! { impl pallet_preimage::Config for Runtime { type WeightInfo = pallet_preimage::weights::SubstrateWeight; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureRoot; - type MaxSize = PreimageMaxSize; type BaseDeposit = PreimageBaseDeposit; type ByteDeposit = PreimageByteDeposit; } @@ -412,7 +412,7 @@ impl pallet_indices::Config for Runtime { type AccountIndex = AccountIndex; type Currency = Balances; type Deposit = IndexDeposit; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = pallet_indices::weights::SubstrateWeight; } @@ -430,7 +430,7 @@ impl pallet_balances::Config for Runtime { type ReserveIdentifier = [u8; 8]; type Balance = Balance; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ExistentialDeposit; type AccountStore = frame_system::Pallet; type WeightInfo = pallet_balances::weights::SubstrateWeight; @@ -442,20 +442,26 @@ parameter_types! { pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25); pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(1, 100_000); pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000_000u128); + pub MaximumMultiplier: Multiplier = Bounded::max_value(); } impl pallet_transaction_payment::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter; type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = IdentityFee; type LengthToFee = ConstantMultiplier; - type FeeMultiplierUpdate = - TargetedFeeAdjustment; + type FeeMultiplierUpdate = TargetedFeeAdjustment< + Self, + TargetBlockFullness, + AdjustmentVariable, + MinimumMultiplier, + MaximumMultiplier, + >; } impl pallet_asset_tx_payment::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Fungibles = Assets; type OnChargeAssetTransaction = pallet_asset_tx_payment::FungiblesAdapter< pallet_assets::BalanceToAssetBalance, @@ -495,7 +501,7 @@ impl_opaque_keys! { } impl pallet_session::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = ::AccountId; type ValidatorIdOf = pallet_staking::StashOf; type ShouldEndSession = Babe; @@ -530,6 +536,7 @@ parameter_types! { pub const MaxNominatorRewardedPerValidator: u32 = 256; pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17); pub OffchainRepeat: BlockNumber = 5; + pub HistoryDepth: u32 = 84; } pub struct StakingBenchmarkingConfig; @@ -545,7 +552,7 @@ impl pallet_staking::Config for Runtime { type UnixTime = Timestamp; type CurrencyToVote = U128CurrencyToVote; type RewardRemainder = Treasury; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Slash = Treasury; // send the slashed funds to the treasury. type Reward = (); // rewards are minted from the void type SessionsPerEra = SessionsPerEra; @@ -563,13 +570,24 @@ impl pallet_staking::Config for Runtime { type OffendingValidatorsThreshold = OffendingValidatorsThreshold; type ElectionProvider = ElectionProviderMultiPhase; type GenesisElectionProvider = onchain::UnboundedExecution; - type VoterList = BagsList; + type VoterList = VoterList; + // This a placeholder, to be introduced in the next PR as an instance of bags-list + type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = HistoryDepth; type OnStakerSlash = NominationPools; type WeightInfo = pallet_staking::weights::SubstrateWeight; type BenchmarkingConfig = StakingBenchmarkingConfig; } +impl pallet_fast_unstake::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ControlOrigin = frame_system::EnsureRoot; + type Deposit = ConstU128<{ DOLLARS }>; + type DepositCurrency = Balances; + type WeightInfo = (); +} + parameter_types! { // phase durations. 1/4 of the last session for each. pub const SignedPhase: u32 = EPOCH_DURATION_IN_BLOCKS / 4; @@ -685,7 +703,7 @@ impl pallet_election_provider_multi_phase::MinerConfig for Runtime { } impl pallet_election_provider_multi_phase::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type EstimateCallFee = TransactionPayment; type SignedPhase = SignedPhase; @@ -719,12 +737,15 @@ parameter_types! { pub const BagThresholds: &'static [u64] = &voter_bags::THRESHOLDS; } -impl pallet_bags_list::Config for Runtime { - type Event = Event; +type VoterBagsListInstance = pallet_bags_list::Instance1; +impl pallet_bags_list::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + /// The voter bags-list is loosely kept up to date, and the real source of truth for the score + /// of each node is the staking pallet. type ScoreProvider = Staking; - type WeightInfo = pallet_bags_list::weights::SubstrateWeight; type BagThresholds = BagThresholds; type Score = VoteWeight; + type WeightInfo = pallet_bags_list::weights::SubstrateWeight; } parameter_types! { @@ -749,7 +770,7 @@ impl Convert for U256ToBalance { impl pallet_nomination_pools::Config for Runtime { type WeightInfo = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type CurrencyBalance = Balance; type RewardCounter = FixedU128; @@ -769,7 +790,7 @@ parameter_types! { impl pallet_conviction_voting::Config for Runtime { type WeightInfo = pallet_conviction_voting::weights::SubstrateWeight; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type VoteLockingPeriod = VoteLockingPeriod; type MaxVotes = ConstU32<512>; @@ -786,7 +807,7 @@ parameter_types! { pub struct TracksInfo; impl pallet_referenda::TracksInfo for TracksInfo { type Id = u16; - type Origin = ::PalletsOrigin; + type RuntimeOrigin = ::PalletsOrigin; fn tracks() -> &'static [(Self::Id, pallet_referenda::TrackInfo)] { static DATA: [(u16, pallet_referenda::TrackInfo); 1] = [( 0u16, @@ -812,7 +833,7 @@ impl pallet_referenda::TracksInfo for TracksInfo { )]; &DATA[..] } - fn track_for(id: &Self::Origin) -> Result { + fn track_for(id: &Self::RuntimeOrigin) -> Result { if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { match system_origin { frame_system::RawOrigin::Root => Ok(0), @@ -823,11 +844,12 @@ impl pallet_referenda::TracksInfo for TracksInfo { } } } +pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); impl pallet_referenda::Config for Runtime { type WeightInfo = pallet_referenda::weights::SubstrateWeight; - type Call = Call; - type Event = Event; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type Scheduler = Scheduler; type Currency = pallet_balances::Pallet; type SubmitOrigin = EnsureSigned; @@ -841,12 +863,13 @@ impl pallet_referenda::Config for Runtime { type UndecidingTimeout = UndecidingTimeout; type AlarmInterval = AlarmInterval; type Tracks = TracksInfo; + type Preimages = Preimage; } impl pallet_referenda::Config for Runtime { type WeightInfo = pallet_referenda::weights::SubstrateWeight; - type Call = Call; - type Event = Event; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type Scheduler = Scheduler; type Currency = pallet_balances::Pallet; type SubmitOrigin = EnsureSigned; @@ -860,11 +883,12 @@ impl pallet_referenda::Config for Runtime { type UndecidingTimeout = UndecidingTimeout; type AlarmInterval = AlarmInterval; type Tracks = TracksInfo; + type Preimages = Preimage; } impl pallet_ranked_collective::Config for Runtime { type WeightInfo = pallet_ranked_collective::weights::SubstrateWeight; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PromoteOrigin = EnsureRootWithSuccess>; type DemoteOrigin = EnsureRootWithSuccess>; type Polls = RankedPolls; @@ -874,7 +898,7 @@ impl pallet_ranked_collective::Config for Runtime { impl pallet_remark::Config for Runtime { type WeightInfo = pallet_remark::weights::SubstrateWeight; - type Event = Event; + type RuntimeEvent = RuntimeEvent; } parameter_types! { @@ -888,8 +912,7 @@ parameter_types! { } impl pallet_democracy::Config for Runtime { - type Proposal = Call; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type EnactmentPeriod = EnactmentPeriod; type LaunchPeriod = LaunchPeriod; @@ -928,14 +951,15 @@ impl pallet_democracy::Config for Runtime { // only do it once and it lasts only for the cool-off period. type VetoOrigin = pallet_collective::EnsureMember; type CooloffPeriod = CooloffPeriod; - type PreimageByteDeposit = PreimageByteDeposit; - type OperationalPreimageOrigin = pallet_collective::EnsureMember; type Slash = Treasury; type Scheduler = Scheduler; type PalletsOrigin = OriginCaller; type MaxVotes = ConstU32<100>; type WeightInfo = pallet_democracy::weights::SubstrateWeight; type MaxProposals = MaxProposals; + type Preimages = Preimage; + type MaxDeposits = ConstU32<100>; + type MaxBlacklisted = ConstU32<100>; } parameter_types! { @@ -946,9 +970,9 @@ parameter_types! { type CouncilCollective = pallet_collective::Instance1; impl pallet_collective::Config for Runtime { - type Origin = Origin; - type Proposal = Call; - type Event = Event; + type RuntimeOrigin = RuntimeOrigin; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type MotionDuration = CouncilMotionDuration; type MaxProposals = CouncilMaxProposals; type MaxMembers = CouncilMaxMembers; @@ -974,7 +998,7 @@ parameter_types! { const_assert!(DesiredMembers::get() <= CouncilMaxMembers::get()); impl pallet_elections_phragmen::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PalletId = ElectionsPhragmenPalletId; type Currency = Balances; type ChangeMembers = Council; @@ -1003,9 +1027,9 @@ parameter_types! { type TechnicalCollective = pallet_collective::Instance2; impl pallet_collective::Config for Runtime { - type Origin = Origin; - type Proposal = Call; - type Event = Event; + type RuntimeOrigin = RuntimeOrigin; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type MotionDuration = TechnicalMotionDuration; type MaxProposals = TechnicalMaxProposals; type MaxMembers = TechnicalMaxMembers; @@ -1018,7 +1042,7 @@ type EnsureRootOrHalfCouncil = EitherOfDiverse< pallet_collective::EnsureProportionMoreThan, >; impl pallet_membership::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type AddOrigin = EnsureRootOrHalfCouncil; type RemoveOrigin = EnsureRootOrHalfCouncil; type SwapOrigin = EnsureRootOrHalfCouncil; @@ -1055,7 +1079,7 @@ impl pallet_treasury::Config for Runtime { EnsureRoot, pallet_collective::EnsureProportionMoreThan, >; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ProposalBondMinimum; @@ -1081,7 +1105,7 @@ parameter_types! { } impl pallet_bounties::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BountyDepositBase = BountyDepositBase; type BountyDepositPayoutDelay = BountyDepositPayoutDelay; type BountyUpdatePeriod = BountyUpdatePeriod; @@ -1100,14 +1124,14 @@ parameter_types! { } impl pallet_child_bounties::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type MaxActiveChildBountyCount = ConstU32<5>; type ChildBountyValueMinimum = ChildBountyValueMinimum; type WeightInfo = pallet_child_bounties::weights::SubstrateWeight; } impl pallet_tips::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DataDepositPerByte = DataDepositPerByte; type MaximumReasonLength = MaximumReasonLength; type Tippers = Elections; @@ -1135,8 +1159,8 @@ impl pallet_contracts::Config for Runtime { type Time = Timestamp; type Randomness = RandomnessCollectiveFlip; type Currency = Balances; - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; /// The safest default is to allow no calls at all. /// /// Runtimes should whitelist dispatchables that are allowed to be called from contracts @@ -1154,15 +1178,13 @@ impl pallet_contracts::Config for Runtime { type DeletionWeightLimit = DeletionWeightLimit; type Schedule = Schedule; type AddressGenerator = pallet_contracts::DefaultAddressGenerator; - type ContractAccessWeight = pallet_contracts::DefaultContractAccessWeight; type MaxCodeLen = ConstU32<{ 128 * 1024 }>; - type RelaxedMaxCodeLen = ConstU32<{ 256 * 1024 }>; type MaxStorageKeyLen = ConstU32<128>; } impl pallet_sudo::Config for Runtime { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; } parameter_types! { @@ -1177,14 +1199,14 @@ parameter_types! { impl frame_system::offchain::CreateSignedTransaction for Runtime where - Call: From, + RuntimeCall: From, { fn create_transaction>( - call: Call, + call: RuntimeCall, public: ::Signer, account: AccountId, nonce: Index, - ) -> Option<(Call, ::SignaturePayload)> { + ) -> Option<(RuntimeCall, ::SignaturePayload)> { let tip = 0; // take the biggest period possible. let period = @@ -1224,15 +1246,15 @@ impl frame_system::offchain::SigningTypes for Runtime { impl frame_system::offchain::SendTransactionTypes for Runtime where - Call: From, + RuntimeCall: From, { type Extrinsic = UncheckedExtrinsic; - type OverarchingCall = Call; + type OverarchingCall = RuntimeCall; } impl pallet_im_online::Config for Runtime { type AuthorityId = ImOnlineId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type NextSessionRotation = Babe; type ValidatorSet = Historical; type ReportUnresponsiveness = Offences; @@ -1244,7 +1266,7 @@ impl pallet_im_online::Config for Runtime { } impl pallet_offences::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type IdentificationTuple = pallet_session::historical::IdentificationTuple; type OnOffenceHandler = Staking; } @@ -1254,8 +1276,7 @@ impl pallet_authority_discovery::Config for Runtime { } impl pallet_grandpa::Config for Runtime { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; type KeyOwnerProofSystem = Historical; @@ -1287,7 +1308,7 @@ parameter_types! { } impl pallet_identity::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type BasicDeposit = BasicDeposit; type FieldDeposit = FieldDeposit; @@ -1309,9 +1330,9 @@ parameter_types! { } impl pallet_recovery::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = pallet_recovery::weights::SubstrateWeight; - type Call = Call; + type RuntimeCall = RuntimeCall; type Currency = Balances; type ConfigDepositBase = ConfigDepositBase; type FriendDepositFactor = FriendDepositFactor; @@ -1332,7 +1353,7 @@ parameter_types! { } impl pallet_society::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PalletId = SocietyPalletId; type Currency = Balances; type Randomness = RandomnessCollectiveFlip; @@ -1352,14 +1373,17 @@ impl pallet_society::Config for Runtime { parameter_types! { pub const MinVestedTransfer: Balance = 100 * DOLLARS; + pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons = + WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); } impl pallet_vesting::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type BlockNumberToBalance = ConvertInto; type MinVestedTransfer = MinVestedTransfer; type WeightInfo = pallet_vesting::weights::SubstrateWeight; + type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; // `VestingInfo` encode length is 36bytes. 28 schedules gets encoded as 1009 bytes, which is the // highest number of schedules that encodes less than 2^10. const MAX_VESTING_SCHEDULES: u32 = 28; @@ -1382,10 +1406,10 @@ parameter_types! { impl pallet_lottery::Config for Runtime { type PalletId = LotteryPalletId; - type Call = Call; + type RuntimeCall = RuntimeCall; type Currency = Balances; type Randomness = RandomnessCollectiveFlip; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ManagerOrigin = EnsureRoot; type MaxCalls = MaxCalls; type ValidateCall = Lottery; @@ -1402,7 +1426,7 @@ parameter_types! { } impl pallet_assets::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Balance = u128; type AssetId = u32; type Currency = Balances; @@ -1430,7 +1454,7 @@ parameter_types! { } impl pallet_gilt::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type CurrencyBalance = Balance; type AdminOrigin = frame_system::EnsureRoot; @@ -1455,7 +1479,7 @@ parameter_types! { } impl pallet_uniques::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type CollectionId = u32; type ItemId = u32; type Currency = Balances; @@ -1476,9 +1500,9 @@ impl pallet_uniques::Config for Runtime { } impl pallet_transaction_storage::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type Call = Call; + type RuntimeCall = RuntimeCall; type FeeDestination = (); type WeightInfo = pallet_transaction_storage::weights::SubstrateWeight; type MaxBlockTransactions = @@ -1488,8 +1512,8 @@ impl pallet_transaction_storage::Config for Runtime { } impl pallet_whitelist::Config for Runtime { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type WhitelistOrigin = EnsureRoot; type DispatchWhitelistedOrigin = EnsureRoot; type PreimageProvider = Preimage; @@ -1503,7 +1527,7 @@ parameter_types! { } impl pallet_state_trie_migration::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ControlOrigin = EnsureRoot; type Currency = Balances; type MaxKeyLen = MigrationMaxKeyLen; @@ -1527,9 +1551,9 @@ parameter_types! { type AllianceCollective = pallet_collective::Instance3; impl pallet_collective::Config for Runtime { - type Origin = Origin; - type Proposal = Call; - type Event = Event; + type RuntimeOrigin = RuntimeOrigin; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type MotionDuration = AllianceMotionDuration; type MaxProposals = AllianceMaxProposals; type MaxMembers = AllianceMaxMembers; @@ -1546,8 +1570,8 @@ parameter_types! { } impl pallet_alliance::Config for Runtime { - type Event = Event; - type Proposal = Call; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; type AdminOrigin = EitherOfDiverse< EnsureRoot, pallet_collective::EnsureProportionMoreThan, @@ -1632,7 +1656,7 @@ construct_runtime!( Gilt: pallet_gilt, Uniques: pallet_uniques, TransactionStorage: pallet_transaction_storage, - BagsList: pallet_bags_list, + VoterList: pallet_bags_list::, StateTrieMigration: pallet_state_trie_migration, ChildBounties: pallet_child_bounties, Referenda: pallet_referenda, @@ -1644,6 +1668,7 @@ construct_runtime!( NominationPools: pallet_nomination_pools, RankedPolls: pallet_referenda::, RankedCollective: pallet_ranked_collective, + FastUnstake: pallet_fast_unstake, } ); @@ -1672,12 +1697,14 @@ pub type SignedExtra = ( frame_system::CheckWeight, pallet_asset_tx_payment::ChargeAssetTxPayment, ); + /// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; /// Extrinsic type that has already been checked. -pub type CheckedExtrinsic = generic::CheckedExtrinsic; +pub type CheckedExtrinsic = generic::CheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -1693,6 +1720,7 @@ pub type Executive = frame_executive::Executive< type Migrations = ( pallet_nomination_pools::migration::v2::MigrateToV2, pallet_alliance::migration::Migration, + pallet_contracts::Migration, ); /// MMR helper types @@ -1716,7 +1744,7 @@ mod benches { [pallet_alliance, Alliance] [pallet_assets, Assets] [pallet_babe, Babe] - [pallet_bags_list, BagsList] + [pallet_bags_list, VoterList] [pallet_balances, Balances] [pallet_bounties, Bounties] [pallet_child_bounties, ChildBounties] @@ -1727,6 +1755,7 @@ mod benches { [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] [pallet_election_provider_support_benchmarking, EPSBench::] [pallet_elections_phragmen, Elections] + [pallet_fast_unstake, FastUnstake] [pallet_gilt, Gilt] [pallet_grandpa, Grandpa] [pallet_identity, Identity] @@ -1918,33 +1947,32 @@ impl_runtime_apis! { } } - impl pallet_contracts_rpc_runtime_api::ContractsApi< - Block, AccountId, Balance, BlockNumber, Hash, - > - for Runtime + impl pallet_contracts::ContractsApi for Runtime { fn call( origin: AccountId, dest: AccountId, value: Balance, - gas_limit: u64, + gas_limit: Option, storage_deposit_limit: Option, input_data: Vec, ) -> pallet_contracts_primitives::ContractExecResult { - Contracts::bare_call(origin, dest, value, Weight::from_ref_time(gas_limit), storage_deposit_limit, input_data, true) + let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block); + Contracts::bare_call(origin, dest, value, gas_limit, storage_deposit_limit, input_data, true) } fn instantiate( origin: AccountId, value: Balance, - gas_limit: u64, + gas_limit: Option, storage_deposit_limit: Option, code: pallet_contracts_primitives::Code, data: Vec, salt: Vec, ) -> pallet_contracts_primitives::ContractInstantiateResult { - Contracts::bare_instantiate(origin, value, Weight::from_ref_time(gas_limit), storage_deposit_limit, code, data, salt, true) + let gas_limit = gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block); + Contracts::bare_instantiate(origin, value, gas_limit, storage_deposit_limit, code, data, salt, true) } fn upload_code( @@ -1976,13 +2004,13 @@ impl_runtime_apis! { } } - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi for Runtime { - fn query_call_info(call: Call, len: u32) -> RuntimeDispatchInfo { + fn query_call_info(call: RuntimeCall, len: u32) -> RuntimeDispatchInfo { TransactionPayment::query_call_info(call, len) } - fn query_call_fee_details(call: Call, len: u32) -> FeeDetails { + fn query_call_fee_details(call: RuntimeCall, len: u32) -> FeeDetails { TransactionPayment::query_call_fee_details(call, len) } } @@ -1990,11 +2018,12 @@ impl_runtime_apis! { impl pallet_mmr::primitives::MmrApi< Block, mmr::Hash, + BlockNumber, > for Runtime { - fn generate_proof(leaf_index: pallet_mmr::primitives::LeafIndex) + fn generate_proof(block_number: BlockNumber) -> Result<(mmr::EncodableOpaqueLeaf, mmr::Proof), mmr::Error> { - Mmr::generate_batch_proof(vec![leaf_index]).and_then(|(leaves, proof)| + Mmr::generate_batch_proof(vec![block_number]).and_then(|(leaves, proof)| Ok(( mmr::EncodableOpaqueLeaf::from_leaf(&leaves[0]), mmr::BatchProof::into_single_leaf_proof(proof)? @@ -2025,11 +2054,35 @@ impl_runtime_apis! { Ok(Mmr::mmr_root()) } - fn generate_batch_proof(leaf_indices: Vec) - -> Result<(Vec, mmr::BatchProof), mmr::Error> - { - Mmr::generate_batch_proof(leaf_indices) - .map(|(leaves, proof)| (leaves.into_iter().map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf)).collect(), proof)) + fn generate_batch_proof( + block_numbers: Vec, + ) -> Result<(Vec, mmr::BatchProof), mmr::Error> { + Mmr::generate_batch_proof(block_numbers).map(|(leaves, proof)| { + ( + leaves + .into_iter() + .map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf)) + .collect(), + proof, + ) + }) + } + + fn generate_historical_batch_proof( + block_numbers: Vec, + best_known_block_number: BlockNumber, + ) -> Result<(Vec, mmr::BatchProof), mmr::Error> { + Mmr::generate_historical_batch_proof(block_numbers, best_known_block_number).map( + |(leaves, proof)| { + ( + leaves + .into_iter() + .map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf)) + .collect(), + proof, + ) + }, + ) } fn verify_batch_proof(leaves: Vec, proof: mmr::BatchProof) @@ -2141,22 +2194,14 @@ impl_runtime_apis! { impl baseline::Config for Runtime {} impl pallet_nomination_pools_benchmarking::Config for Runtime {} - let whitelist: Vec = vec![ - // Block Number - hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), - // Total Issuance - hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(), - // Execution Phase - hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(), - // Event Count - hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(), - // System Events - hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(), - // System BlockWeight - hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96").to_vec().into(), - // Treasury Account - hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da95ecffd7b6c0f78751baa9d281e0bfa3a6d6f646c70792f74727372790000000000000000000000000000000000000000").to_vec().into(), - ]; + use frame_support::traits::WhitelistedStorageKeys; + let mut whitelist: Vec = AllPalletsWithSystem::whitelisted_storage_keys(); + + // Treasury Account + // TODO: this is manual for now, someday we might be able to use a + // macro for this particular key + let treasury_key = frame_system::Account::::hashed_key_for(Treasury::account_id()); + whitelist.push(treasury_key.to_vec().into()); let mut batches = Vec::::new(); let params = (&config, &whitelist); @@ -2170,14 +2215,50 @@ impl_runtime_apis! { mod tests { use super::*; use frame_election_provider_support::NposSolution; + use frame_support::traits::WhitelistedStorageKeys; use frame_system::offchain::CreateSignedTransaction; + use sp_core::hexdisplay::HexDisplay; use sp_runtime::UpperOf; + use std::collections::HashSet; + + #[test] + fn check_whitelist() { + let whitelist: HashSet = AllPalletsWithSystem::whitelisted_storage_keys() + .iter() + .map(|e| HexDisplay::from(&e.key).to_string()) + .collect(); + + // Block Number + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac") + ); + // Total Issuance + assert!( + whitelist.contains("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80") + ); + // Execution Phase + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a") + ); + // Event Count + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850") + ); + // System Events + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7") + ); + // System BlockWeight + assert!( + whitelist.contains("26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96") + ); + } #[test] fn validate_transaction_submitter_bounds() { fn is_submit_signed_transaction() where - T: CreateSignedTransaction, + T: CreateSignedTransaction, { } @@ -2197,11 +2278,11 @@ mod tests { #[test] fn call_size() { - let size = core::mem::size_of::(); + let size = core::mem::size_of::(); assert!( size <= 208, - "size of Call {} is more than 208 bytes: some calls have too big arguments, use Box to reduce the - size of Call. + "size of RuntimeCall {} is more than 208 bytes: some calls have too big arguments, use Box to reduce the + size of RuntimeCall. If the limit is too strong, maybe consider increase the limit to 300.", size, ); diff --git a/bin/node/runtime/src/voter_bags.rs b/bin/node/runtime/src/voter_bags.rs index 93790f028f457..eb540c27abcc7 100644 --- a/bin/node/runtime/src/voter_bags.rs +++ b/bin/node/runtime/src/voter_bags.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,9 +15,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Autogenerated voter bag thresholds. +//! Autogenerated bag thresholds. //! -//! Generated on 2021-07-05T09:17:40.469754927+00:00 +//! Generated on 2022-08-15T19:26:59.939787+00:00 +//! Arguments +//! Total issuance: 100000000000000 +//! Minimum balance: 100000000000000 //! for the node runtime. /// Existential weight for this runtime. diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index 534f0a4f09732..59f1fa94c9b20 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -35,8 +35,8 @@ use crate::{ use codec::{Decode, Encode}; use futures::executor; use kitchensink_runtime::{ - constants::currency::DOLLARS, AccountId, BalancesCall, Call, CheckedExtrinsic, MinimumPeriod, - Signature, SystemCall, UncheckedExtrinsic, + constants::currency::DOLLARS, AccountId, BalancesCall, CheckedExtrinsic, MinimumPeriod, + RuntimeCall, Signature, SystemCall, UncheckedExtrinsic, }; use node_primitives::Block; use sc_block_builder::BlockBuilderProvider; @@ -308,12 +308,12 @@ impl<'a> Iterator for BlockContentIterator<'a> { )), function: match self.content.block_type { BlockType::RandomTransfersKeepAlive => - Call::Balances(BalancesCall::transfer_keep_alive { + RuntimeCall::Balances(BalancesCall::transfer_keep_alive { dest: sp_runtime::MultiAddress::Id(receiver), value: kitchensink_runtime::ExistentialDeposit::get() + 1, }), BlockType::RandomTransfersReaping => { - Call::Balances(BalancesCall::transfer { + RuntimeCall::Balances(BalancesCall::transfer { dest: sp_runtime::MultiAddress::Id(receiver), // Transfer so that ending balance would be 1 less than existential // deposit so that we kill the sender account. @@ -321,7 +321,8 @@ impl<'a> Iterator for BlockContentIterator<'a> { (kitchensink_runtime::ExistentialDeposit::get() - 1), }) }, - BlockType::Noop => Call::System(SystemCall::remark { remark: Vec::new() }), + BlockType::Noop => + RuntimeCall::System(SystemCall::remark { remark: Vec::new() }), }, }, self.runtime_version.spec_version, @@ -391,7 +392,7 @@ impl BenchDb { trie_cache_maximum_size: Some(16 * 1024 * 1024), state_pruning: Some(PruningMode::ArchiveAll), source: database_type.into_settings(dir.into()), - blocks_pruning: sc_client_db::BlocksPruning::All, + blocks_pruning: sc_client_db::BlocksPruning::KeepAll, }; let task_executor = TaskExecutor::new(); diff --git a/bin/utils/chain-spec-builder/Cargo.toml b/bin/utils/chain-spec-builder/Cargo.toml index e3deb54ea8ac9..dc53dc08ec6af 100644 --- a/bin/utils/chain-spec-builder/Cargo.toml +++ b/bin/utils/chain-spec-builder/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ansi_term = "0.12.1" -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } rand = "0.8" node-cli = { version = "3.0.0-dev", path = "../../node/cli" } sc-chain-spec = { version = "4.0.0-dev", path = "../../../client/chain-spec" } diff --git a/bin/utils/chain-spec-builder/src/main.rs b/bin/utils/chain-spec-builder/src/main.rs index 641416154115b..7dfcaed773f40 100644 --- a/bin/utils/chain-spec-builder/src/main.rs +++ b/bin/utils/chain-spec-builder/src/main.rs @@ -37,51 +37,51 @@ use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; /// A utility to easily create a testnet chain spec definition with a given set /// of authorities and endowed accounts and/or generate random accounts. #[derive(Parser)] -#[clap(rename_all = "kebab-case")] +#[command(rename_all = "kebab-case")] enum ChainSpecBuilder { /// Create a new chain spec with the given authorities, endowed and sudo /// accounts. New { /// Authority key seed. - #[clap(long, short, required = true)] + #[arg(long, short, required = true)] authority_seeds: Vec, /// Active nominators (SS58 format), each backing a random subset of the aforementioned /// authorities. - #[clap(long, short, default_value = "0")] + #[arg(long, short, default_value = "0")] nominator_accounts: Vec, /// Endowed account address (SS58 format). - #[clap(long, short)] + #[arg(long, short)] endowed_accounts: Vec, /// Sudo account address (SS58 format). - #[clap(long, short)] + #[arg(long, short)] sudo_account: String, /// The path where the chain spec should be saved. - #[clap(long, short, default_value = "./chain_spec.json")] + #[arg(long, short, default_value = "./chain_spec.json")] chain_spec_path: PathBuf, }, /// Create a new chain spec with the given number of authorities and endowed /// accounts. Random keys will be generated as required. Generate { /// The number of authorities. - #[clap(long, short)] + #[arg(long, short)] authorities: usize, /// The number of nominators backing the aforementioned authorities. /// /// Will nominate a random subset of `authorities`. - #[clap(long, short, default_value = "0")] + #[arg(long, short, default_value_t = 0)] nominators: usize, /// The number of endowed accounts. - #[clap(long, short, default_value = "0")] + #[arg(long, short, default_value_t = 0)] endowed: usize, /// The path where the chain spec should be saved. - #[clap(long, short, default_value = "./chain_spec.json")] + #[arg(long, short, default_value = "./chain_spec.json")] chain_spec_path: PathBuf, /// Path to use when saving generated keystores for each authority. /// /// At this path, a new folder will be created for each authority's /// keystore named `auth-$i` where `i` is the authority index, i.e. /// `auth-0`, `auth-1`, etc. - #[clap(long, short)] + #[arg(long, short)] keystore_path: Option, }, } diff --git a/bin/utils/subkey/Cargo.toml b/bin/utils/subkey/Cargo.toml index 4c4e47e702be6..77c323821a508 100644 --- a/bin/utils/subkey/Cargo.toml +++ b/bin/utils/subkey/Cargo.toml @@ -17,5 +17,5 @@ path = "src/main.rs" name = "subkey" [dependencies] -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } diff --git a/bin/utils/subkey/src/lib.rs b/bin/utils/subkey/src/lib.rs index 6773ba822340f..280b90848fbf5 100644 --- a/bin/utils/subkey/src/lib.rs +++ b/bin/utils/subkey/src/lib.rs @@ -23,7 +23,7 @@ use sc_cli::{ }; #[derive(Debug, Parser)] -#[clap( +#[command( name = "subkey", author = "Parity Team ", about = "Utility for generating and restoring with Substrate keys", diff --git a/client/api/src/backend.rs b/client/api/src/backend.rs index bcc7a9bff3b2d..f358385acd708 100644 --- a/client/api/src/backend.rs +++ b/client/api/src/backend.rs @@ -357,77 +357,77 @@ where /// Provides acess to storage primitives pub trait StorageProvider> { - /// Given a `BlockId` and a key, return the value under the key in that block. + /// Given a block's `Hash` and a key, return the value under the key in that block. fn storage( &self, - id: &BlockId, + hash: &Block::Hash, key: &StorageKey, ) -> sp_blockchain::Result>; - /// Given a `BlockId` and a key prefix, return the matching storage keys in that block. + /// Given a block's `Hash` and a key prefix, return the matching storage keys in that block. fn storage_keys( &self, - id: &BlockId, + hash: &Block::Hash, key_prefix: &StorageKey, ) -> sp_blockchain::Result>; - /// Given a `BlockId` and a key, return the value under the hash in that block. + /// Given a block's `Hash` and a key, return the value under the hash in that block. fn storage_hash( &self, - id: &BlockId, + hash: &Block::Hash, key: &StorageKey, ) -> sp_blockchain::Result>; - /// Given a `BlockId` and a key prefix, return the matching child storage keys and values in - /// that block. + /// Given a block's `Hash` and a key prefix, return the matching child storage keys and values + /// in that block. fn storage_pairs( &self, - id: &BlockId, + hash: &Block::Hash, key_prefix: &StorageKey, ) -> sp_blockchain::Result>; - /// Given a `BlockId` and a key prefix, return a `KeyIterator` iterates matching storage keys in - /// that block. + /// Given a block's `Hash` and a key prefix, return a `KeyIterator` iterates matching storage + /// keys in that block. fn storage_keys_iter<'a>( &self, - id: &BlockId, + hash: &Block::Hash, prefix: Option<&'a StorageKey>, start_key: Option<&StorageKey>, ) -> sp_blockchain::Result>; - /// Given a `BlockId`, a key and a child storage key, return the value under the key in that - /// block. + /// Given a block's `Hash`, a key and a child storage key, return the value under the key in + /// that block. fn child_storage( &self, - id: &BlockId, + hash: &Block::Hash, child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result>; - /// Given a `BlockId`, a key prefix, and a child storage key, return the matching child storage - /// keys. + /// Given a block's `Hash`, a key prefix, and a child storage key, return the matching child + /// storage keys. fn child_storage_keys( &self, - id: &BlockId, + hash: &Block::Hash, child_info: &ChildInfo, key_prefix: &StorageKey, ) -> sp_blockchain::Result>; - /// Given a `BlockId` and a key `prefix` and a child storage key, + /// Given a block's `Hash` and a key `prefix` and a child storage key, /// return a `KeyIterator` that iterates matching storage keys in that block. fn child_storage_keys_iter<'a>( &self, - id: &BlockId, + hash: &Block::Hash, child_info: ChildInfo, prefix: Option<&'a StorageKey>, start_key: Option<&StorageKey>, ) -> sp_blockchain::Result>; - /// Given a `BlockId`, a key and a child storage key, return the hash under the key in that + /// Given a block's `Hash`, a key and a child storage key, return the hash under the key in that /// block. fn child_storage_hash( &self, - id: &BlockId, + hash: &Block::Hash, child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result>; @@ -505,11 +505,11 @@ pub trait Backend: AuxStore + Send + Sync { /// Returns true if state for given block is available. fn have_state_at(&self, hash: &Block::Hash, _number: NumberFor) -> bool { - self.state_at(BlockId::Hash(*hash)).is_ok() + self.state_at(hash).is_ok() } /// Returns state backend with post-state of given block. - fn state_at(&self, block: BlockId) -> sp_blockchain::Result; + fn state_at(&self, hash: &Block::Hash) -> sp_blockchain::Result; /// Attempts to revert the chain by `n` blocks. If `revert_finalized` is set it will attempt to /// revert past any finalized block, this is unsafe and can potentially leave the node in an diff --git a/client/api/src/call_executor.rs b/client/api/src/call_executor.rs index 738f932a47bf0..949fd16a30704 100644 --- a/client/api/src/call_executor.rs +++ b/client/api/src/call_executor.rs @@ -18,13 +18,11 @@ //! A method call executor interface. -use codec::{Decode, Encode}; use sc_executor::{RuntimeVersion, RuntimeVersionOf}; -use sp_core::NativeOrEncoded; use sp_externalities::Extensions; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use sp_state_machine::{ExecutionManager, ExecutionStrategy, OverlayedChanges, StorageProof}; -use std::{cell::RefCell, panic::UnwindSafe, result}; +use std::cell::RefCell; use crate::execution_extensions::ExecutionExtensions; use sp_api::{ProofRecorder, StorageTransactionCache}; @@ -68,11 +66,9 @@ pub trait CallExecutor: RuntimeVersionOf { /// of the execution context. fn contextual_call< EM: Fn( - Result, Self::Error>, - Result, Self::Error>, - ) -> Result, Self::Error>, - R: Encode + Decode + PartialEq, - NC: FnOnce() -> result::Result + UnwindSafe, + Result, Self::Error>, + Result, Self::Error>, + ) -> Result, Self::Error>, >( &self, at: &BlockId, @@ -85,10 +81,9 @@ pub trait CallExecutor: RuntimeVersionOf { >, >, execution_manager: ExecutionManager, - native_call: Option, proof_recorder: &Option>, extensions: Option, - ) -> sp_blockchain::Result> + ) -> sp_blockchain::Result> where ExecutionManager: Clone; diff --git a/client/api/src/execution_extensions.rs b/client/api/src/execution_extensions.rs index 574687312c82b..07a483bc3eaf2 100644 --- a/client/api/src/execution_extensions.rs +++ b/client/api/src/execution_extensions.rs @@ -201,11 +201,11 @@ impl ExecutionExtensions { /// /// Based on the execution context and capabilities it produces /// the right manager and extensions object to support desired set of APIs. - pub fn manager_and_extensions( + pub fn manager_and_extensions( &self, at: &BlockId, context: ExecutionContext, - ) -> (ExecutionManager>, Extensions) { + ) -> (ExecutionManager>, Extensions) { let manager = match context { ExecutionContext::BlockConstruction => self.strategies.block_construction.get_manager(), ExecutionContext::Syncing => self.strategies.syncing.get_manager(), diff --git a/client/api/src/in_mem.rs b/client/api/src/in_mem.rs index 9000f62aa6cc3..99efdd3bf1d22 100644 --- a/client/api/src/in_mem.rs +++ b/client/api/src/in_mem.rs @@ -516,7 +516,7 @@ where ) -> sp_blockchain::Result { check_genesis_storage(&storage)?; - let child_delta = storage.children_default.iter().map(|(_storage_key, child_content)| { + let child_delta = storage.children_default.values().map(|child_content| { ( &child_content.child_info, child_content.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))), @@ -686,7 +686,7 @@ where type OffchainStorage = OffchainStorage; fn begin_operation(&self) -> sp_blockchain::Result { - let old_state = self.state_at(BlockId::Hash(Default::default()))?; + let old_state = self.state_at(&Default::default())?; Ok(BlockImportOperation { pending_block: None, old_state, @@ -702,7 +702,8 @@ where operation: &mut Self::BlockImportOperation, block: BlockId, ) -> sp_blockchain::Result<()> { - operation.old_state = self.state_at(block)?; + let hash = self.blockchain.expect_block_hash_from_id(&block)?; + operation.old_state = self.state_at(&hash)?; Ok(()) } @@ -768,16 +769,16 @@ where None } - fn state_at(&self, block: BlockId) -> sp_blockchain::Result { - match block { - BlockId::Hash(h) if h == Default::default() => return Ok(Self::State::default()), - _ => {}, + fn state_at(&self, hash: &Block::Hash) -> sp_blockchain::Result { + if *hash == Default::default() { + return Ok(Self::State::default()) } - self.blockchain - .id(block) - .and_then(|id| self.states.read().get(&id).cloned()) - .ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", block))) + self.states + .read() + .get(hash) + .cloned() + .ok_or_else(|| sp_blockchain::Error::UnknownBlock(format!("{}", hash))) } fn revert( diff --git a/client/authority-discovery/Cargo.toml b/client/authority-discovery/Cargo.toml index d9e9df4f2a97c..91c977d90a660 100644 --- a/client/authority-discovery/Cargo.toml +++ b/client/authority-discovery/Cargo.toml @@ -14,16 +14,16 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } futures = "0.3.21" futures-timer = "3.0.1" ip_network = "0.4.1" -libp2p = { version = "0.46.1", default-features = false, features = ["kad"] } +libp2p = { version = "0.49.0", default-features = false, features = ["kad"] } log = "0.4.17" -prost = "0.10" +prost = "0.11" rand = "0.7.2" thiserror = "1.0" prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } diff --git a/client/authority-discovery/src/tests.rs b/client/authority-discovery/src/tests.rs index 334b2638ca58c..208440b7ab1ea 100644 --- a/client/authority-discovery/src/tests.rs +++ b/client/authority-discovery/src/tests.rs @@ -91,10 +91,7 @@ fn cryptos_are_compatible() { let libp2p_public = libp2p_secret.public(); let sp_core_secret = { - let libp2p_ed_secret = match libp2p_secret.clone() { - libp2p::identity::Keypair::Ed25519(x) => x, - _ => panic!("generate_ed25519 should have generated an Ed25519 key ¯\\_(ツ)_/¯"), - }; + let libp2p::identity::Keypair::Ed25519(libp2p_ed_secret) = libp2p_secret.clone(); sp_core::ed25519::Pair::from_seed_slice(&libp2p_ed_secret.secret().as_ref()).unwrap() }; let sp_core_public = sp_core_secret.public(); diff --git a/client/basic-authorship-ver/src/basic_authorship.rs b/client/basic-authorship-ver/src/basic_authorship.rs index 2f03cac2aaf3e..a938637e5e5d8 100644 --- a/client/basic-authorship-ver/src/basic_authorship.rs +++ b/client/basic-authorship-ver/src/basic_authorship.rs @@ -546,7 +546,7 @@ where let pending_tx = if let Some(pending_tx) = pending_iterator.next() { pending_tx } else { - break EndProposingReason::NoMoreTransactions + break EndProposingReason::NoMoreTransactions; }; let now = (self.now)(); if now > deadline { @@ -554,7 +554,7 @@ where "Consensus deadline reached when pushing block transactions, \ proceeding with proposing." ); - break EndProposingReason::HitDeadline + break EndProposingReason::HitDeadline; } let pending_tx_data = pending_tx.data().clone(); @@ -572,17 +572,17 @@ where but will try {} more transactions before quitting.", MAX_SKIPPED_TRANSACTIONS - skipped, ); - continue + continue; } else if now < soft_deadline { debug!(target: "block_builder", "Transaction would overflow the block size limit, \ but we still have time before the soft deadline, so \ we will try a bit more." ); - continue + continue; } else { debug!(target: "block_builder","Reached block size limit, proceeding with proposing."); - break EndProposingReason::HitBlockSizeLimit + break EndProposingReason::HitBlockSizeLimit; } } @@ -615,7 +615,7 @@ where trace!(target:"block_builder", "soft_deadline : {:?}", soft_deadline.saturating_duration_since(now).as_secs_f64()); debug!(target: "block_builder", "Reached block weight limit, proceeding with proposing."); - break EndProposingReason::HitBlockWeightLimit + break EndProposingReason::HitBlockWeightLimit; } }, Err(e) if skipped > 0 => { diff --git a/client/basic-authorship/src/basic_authorship.rs b/client/basic-authorship/src/basic_authorship.rs index f5ccd9023a3db..da98ccab9cb07 100644 --- a/client/basic-authorship/src/basic_authorship.rs +++ b/client/basic-authorship/src/basic_authorship.rs @@ -736,7 +736,7 @@ mod tests { let api = client.runtime_api(); api.execute_block(&block_id, proposal.block).unwrap(); - let state = backend.state_at(block_id).unwrap(); + let state = backend.state_at(&genesis_hash).unwrap(); let storage_changes = api.into_storage_changes(&state, genesis_hash).unwrap(); diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index 5cc2952e26ba5..a125d4c8d4f07 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -9,12 +9,12 @@ description = "BEEFY Client gadget for substrate" homepage = "https://substrate.io" [dependencies] +array-bytes = "4.1" async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } fnv = "1.0.6" futures = "0.3" futures-timer = "3.0.1" -hex = "0.4.2" log = "0.4" parking_lot = "0.12.1" thiserror = "1.0" @@ -27,6 +27,7 @@ sc-consensus = { version = "0.10.0-dev", path = "../consensus/common" } sc-finality-grandpa = { version = "0.10.0-dev", path = "../../client/finality-grandpa" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sc-network = { version = "0.10.0-dev", path = "../network" } +sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-network-gossip = { version = "0.10.0-dev", path = "../network-gossip" } sc-utils = { version = "4.0.0-dev", path = "../utils" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } diff --git a/client/beefy/rpc/src/lib.rs b/client/beefy/rpc/src/lib.rs index 3be182ceb8f39..d29ed433c38db 100644 --- a/client/beefy/rpc/src/lib.rs +++ b/client/beefy/rpc/src/lib.rs @@ -35,7 +35,9 @@ use jsonrpsee::{ }; use log::warn; -use beefy_gadget::notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofStream}; +use beefy_gadget::communication::notification::{ + BeefyBestBlockStream, BeefyVersionedFinalityProofStream, +}; mod notification; @@ -82,7 +84,7 @@ impl From for JsonRpseeError { // Provides RPC methods for interacting with BEEFY. #[rpc(client, server)] pub trait BeefyApi { - /// Returns the block most recently finalized by BEEFY, alongside side its justification. + /// Returns the block most recently finalized by BEEFY, alongside its justification. #[subscription( name = "beefy_subscribeJustifications" => "beefy_justifications", unsubscribe = "beefy_unsubscribeJustifications", @@ -165,10 +167,10 @@ mod tests { use super::*; use beefy_gadget::{ + communication::notification::BeefyVersionedFinalityProofSender, justification::BeefyVersionedFinalityProof, - notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofSender}, }; - use beefy_primitives::{known_payload_ids, Payload, SignedCommitment}; + use beefy_primitives::{known_payloads, Payload, SignedCommitment}; use codec::{Decode, Encode}; use jsonrpsee::{types::EmptyParams, RpcModule}; use sp_runtime::traits::{BlakeTwo256, Hash}; @@ -264,7 +266,8 @@ mod tests { } fn create_finality_proof() -> BeefyVersionedFinalityProof { - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); + let payload = + Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); BeefyVersionedFinalityProof::::V1(SignedCommitment { commitment: beefy_primitives::Commitment { payload, diff --git a/client/beefy/src/gossip.rs b/client/beefy/src/communication/gossip.rs similarity index 93% rename from client/beefy/src/gossip.rs rename to client/beefy/src/communication/gossip.rs index 02d5efe9e0e58..520548b943f96 100644 --- a/client/beefy/src/gossip.rs +++ b/client/beefy/src/communication/gossip.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::{collections::BTreeMap, time::Duration}; +use std::{collections::BTreeMap, sync::Arc, time::Duration}; use sc_network::PeerId; use sc_network_gossip::{MessageIntent, ValidationResult, Validator, ValidatorContext}; @@ -28,13 +28,12 @@ use log::{debug, trace}; use parking_lot::{Mutex, RwLock}; use wasm_timer::Instant; +use crate::{communication::peers::KnownPeers, keystore::BeefyKeystore}; use beefy_primitives::{ crypto::{Public, Signature}, VoteMessage, }; -use crate::keystore::BeefyKeystore; - // Timeout for rebroadcasting messages. const REBROADCAST_AFTER: Duration = Duration::from_secs(60 * 5); @@ -103,17 +102,19 @@ where topic: B::Hash, known_votes: RwLock>, next_rebroadcast: Mutex, + known_peers: Arc>>, } impl GossipValidator where B: Block, { - pub fn new() -> GossipValidator { + pub fn new(known_peers: Arc>>) -> GossipValidator { GossipValidator { topic: topic::(), known_votes: RwLock::new(KnownVotes::new()), next_rebroadcast: Mutex::new(Instant::now() + REBROADCAST_AFTER), + known_peers, } } @@ -165,6 +166,7 @@ where if BeefyKeystore::verify(&msg.id, &msg.signature, &msg.commitment.encode()) { self.known_votes.write().add_known(&round, msg_hash); + self.known_peers.lock().note_vote_for(*sender, round); return ValidationResult::ProcessAndKeep(self.topic) } else { // TODO: report peer @@ -235,8 +237,7 @@ mod tests { use crate::keystore::{tests::Keyring, BeefyKeystore}; use beefy_primitives::{ - crypto::Signature, known_payload_ids, Commitment, MmrRootHash, Payload, VoteMessage, - KEY_TYPE, + crypto::Signature, known_payloads, Commitment, MmrRootHash, Payload, VoteMessage, KEY_TYPE, }; use super::*; @@ -271,7 +272,7 @@ mod tests { #[test] fn note_and_drop_round_works() { - let gv = GossipValidator::::new(); + let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); gv.note_round(1u64); @@ -298,7 +299,7 @@ mod tests { #[test] fn note_same_round_twice() { - let gv = GossipValidator::::new(); + let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); gv.note_round(3u64); gv.note_round(7u64); @@ -346,7 +347,10 @@ mod tests { } fn dummy_vote(block_number: u64) -> VoteMessage { - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, MmrRootHash::default().encode()); + let payload = Payload::from_single_entry( + known_payloads::MMR_ROOT_ID, + MmrRootHash::default().encode(), + ); let commitment = Commitment { payload, block_number, validator_set_id: 0 }; let signature = sign_commitment(&Keyring::Alice, &commitment); @@ -355,7 +359,7 @@ mod tests { #[test] fn should_avoid_verifying_signatures_twice() { - let gv = GossipValidator::::new(); + let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); let sender = sc_network::PeerId::random(); let mut context = TestContext; @@ -391,7 +395,7 @@ mod tests { #[test] fn messages_allowed_and_expired() { - let gv = GossipValidator::::new(); + let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); let sender = sc_network::PeerId::random(); let topic = Default::default(); let intent = MessageIntent::Broadcast; @@ -434,7 +438,7 @@ mod tests { #[test] fn messages_rebroadcast() { - let gv = GossipValidator::::new(); + let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); let sender = sc_network::PeerId::random(); let topic = Default::default(); diff --git a/client/beefy/src/communication/mod.rs b/client/beefy/src/communication/mod.rs new file mode 100644 index 0000000000000..91798d4ae0d33 --- /dev/null +++ b/client/beefy/src/communication/mod.rs @@ -0,0 +1,113 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Communication streams for the BEEFY networking protocols. + +pub mod notification; +pub mod request_response; + +pub(crate) mod gossip; +pub(crate) mod peers; + +pub(crate) mod beefy_protocol_name { + use array_bytes::bytes2hex; + use sc_network::ProtocolName; + + /// BEEFY votes gossip protocol name suffix. + const GOSSIP_NAME: &str = "/beefy/1"; + /// BEEFY justifications protocol name suffix. + const JUSTIFICATIONS_NAME: &str = "/beefy/justifications/1"; + + /// Name of the votes gossip protocol used by BEEFY. + /// + /// Must be registered towards the networking in order for BEEFY voter to properly function. + pub fn gossip_protocol_name>( + genesis_hash: Hash, + fork_id: Option<&str>, + ) -> ProtocolName { + let genesis_hash = genesis_hash.as_ref(); + if let Some(fork_id) = fork_id { + format!("/{}/{}{}", bytes2hex("", genesis_hash), fork_id, GOSSIP_NAME).into() + } else { + format!("/{}{}", bytes2hex("", genesis_hash), GOSSIP_NAME).into() + } + } + + /// Name of the BEEFY justifications request-response protocol. + pub fn justifications_protocol_name>( + genesis_hash: Hash, + fork_id: Option<&str>, + ) -> ProtocolName { + let genesis_hash = genesis_hash.as_ref(); + if let Some(fork_id) = fork_id { + format!("/{}/{}{}", bytes2hex("", genesis_hash), fork_id, JUSTIFICATIONS_NAME).into() + } else { + format!("/{}{}", bytes2hex("", genesis_hash), JUSTIFICATIONS_NAME).into() + } + } +} + +/// Returns the configuration value to put in +/// [`sc_network::config::NetworkConfiguration::extra_sets`]. +/// For standard protocol name see [`beefy_protocol_name::gossip_protocol_name`]. +pub fn beefy_peers_set_config( + gossip_protocol_name: sc_network::ProtocolName, +) -> sc_network_common::config::NonDefaultSetConfig { + let mut cfg = + sc_network_common::config::NonDefaultSetConfig::new(gossip_protocol_name, 1024 * 1024); + cfg.allow_non_reserved(25, 25); + cfg +} + +#[cfg(test)] +mod tests { + use super::*; + + use sp_core::H256; + + #[test] + fn beefy_protocols_names() { + use beefy_protocol_name::{gossip_protocol_name, justifications_protocol_name}; + // Create protocol name using random genesis hash. + let genesis_hash = H256::random(); + let genesis_hex = array_bytes::bytes2hex("", genesis_hash.as_ref()); + + let expected_gossip_name = format!("/{}/beefy/1", genesis_hex); + let gossip_proto_name = gossip_protocol_name(&genesis_hash, None); + assert_eq!(gossip_proto_name.to_string(), expected_gossip_name); + + let expected_justif_name = format!("/{}/beefy/justifications/1", genesis_hex); + let justif_proto_name = justifications_protocol_name(&genesis_hash, None); + assert_eq!(justif_proto_name.to_string(), expected_justif_name); + + // Create protocol name using hardcoded genesis hash. Verify exact representation. + let genesis_hash = [ + 50, 4, 60, 123, 58, 106, 216, 246, 194, 188, 139, 193, 33, 212, 202, 171, 9, 55, 123, + 94, 8, 43, 12, 251, 187, 57, 173, 19, 188, 74, 205, 147, + ]; + let genesis_hex = "32043c7b3a6ad8f6c2bc8bc121d4caab09377b5e082b0cfbbb39ad13bc4acd93"; + + let expected_gossip_name = format!("/{}/beefy/1", genesis_hex); + let gossip_proto_name = gossip_protocol_name(&genesis_hash, None); + assert_eq!(gossip_proto_name.to_string(), expected_gossip_name); + + let expected_justif_name = format!("/{}/beefy/justifications/1", genesis_hex); + let justif_proto_name = justifications_protocol_name(&genesis_hash, None); + assert_eq!(justif_proto_name.to_string(), expected_justif_name); + } +} diff --git a/client/beefy/src/notification.rs b/client/beefy/src/communication/notification.rs similarity index 100% rename from client/beefy/src/notification.rs rename to client/beefy/src/communication/notification.rs diff --git a/client/beefy/src/communication/peers.rs b/client/beefy/src/communication/peers.rs new file mode 100644 index 0000000000000..0e20a0f4e0ff6 --- /dev/null +++ b/client/beefy/src/communication/peers.rs @@ -0,0 +1,131 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Logic for keeping track of BEEFY peers. + +// TODO (issue #12296): replace this naive peer tracking with generic one that infers data +// from multiple network protocols. + +use sc_network::PeerId; +use sp_runtime::traits::{Block, NumberFor, Zero}; +use std::collections::{HashMap, VecDeque}; + +struct PeerData { + last_voted_on: NumberFor, +} + +impl Default for PeerData { + fn default() -> Self { + PeerData { last_voted_on: Zero::zero() } + } +} + +/// Keep a simple map of connected peers +/// and the most recent voting round they participated in. +pub struct KnownPeers { + live: HashMap>, +} + +impl KnownPeers { + pub fn new() -> Self { + Self { live: HashMap::new() } + } + + /// Add new connected `peer`. + pub fn add_new(&mut self, peer: PeerId) { + self.live.entry(peer).or_default(); + } + + /// Note vote round number for `peer`. + pub fn note_vote_for(&mut self, peer: PeerId, round: NumberFor) { + let data = self.live.entry(peer).or_default(); + data.last_voted_on = round.max(data.last_voted_on); + } + + /// Remove connected `peer`. + pub fn remove(&mut self, peer: &PeerId) { + self.live.remove(peer); + } + + /// Return _filtered and cloned_ list of peers that have voted on `block` or higher. + pub fn at_least_at_block(&self, block: NumberFor) -> VecDeque { + self.live + .iter() + .filter_map(|(k, v)| (v.last_voted_on >= block).then_some(k)) + .cloned() + .collect() + } + + /// Answer whether `peer` is part of `KnownPeers` set. + pub fn contains(&self, peer: &PeerId) -> bool { + self.live.contains_key(peer) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn should_track_known_peers_progress() { + let (alice, bob, charlie) = (PeerId::random(), PeerId::random(), PeerId::random()); + let mut peers = KnownPeers::::new(); + assert!(peers.live.is_empty()); + + // Alice and Bob new connected peers. + peers.add_new(alice); + peers.add_new(bob); + // 'Tracked' Bob seen voting for 5. + peers.note_vote_for(bob, 5); + // Previously unseen Charlie now seen voting for 10. + peers.note_vote_for(charlie, 10); + + assert_eq!(peers.live.len(), 3); + assert!(peers.contains(&alice)); + assert!(peers.contains(&bob)); + assert!(peers.contains(&charlie)); + + // Get peers at block >= 5 + let at_5 = peers.at_least_at_block(5); + // Should be Bob and Charlie + assert_eq!(at_5.len(), 2); + assert!(at_5.contains(&bob)); + assert!(at_5.contains(&charlie)); + + // 'Tracked' Alice seen voting for 10. + peers.note_vote_for(alice, 10); + + // Get peers at block >= 9 + let at_9 = peers.at_least_at_block(9); + // Should be Charlie and Alice + assert_eq!(at_9.len(), 2); + assert!(at_9.contains(&charlie)); + assert!(at_9.contains(&alice)); + + // Remove Alice + peers.remove(&alice); + assert_eq!(peers.live.len(), 2); + assert!(!peers.contains(&alice)); + + // Get peers at block >= 9 + let at_9 = peers.at_least_at_block(9); + // Now should be just Charlie + assert_eq!(at_9.len(), 1); + assert!(at_9.contains(&charlie)); + } +} diff --git a/client/beefy/src/communication/request_response/incoming_requests_handler.rs b/client/beefy/src/communication/request_response/incoming_requests_handler.rs new file mode 100644 index 0000000000000..c0910a60fba3b --- /dev/null +++ b/client/beefy/src/communication/request_response/incoming_requests_handler.rs @@ -0,0 +1,193 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Helper for handling (i.e. answering) BEEFY justifications requests from a remote peer. + +use beefy_primitives::BEEFY_ENGINE_ID; +use codec::Decode; +use futures::{ + channel::{mpsc, oneshot}, + StreamExt, +}; +use log::{debug, trace}; +use sc_client_api::BlockBackend; +use sc_network::{config as netconfig, config::RequestResponseConfig, PeerId, ReputationChange}; +use sc_network_common::protocol::ProtocolName; +use sp_runtime::{generic::BlockId, traits::Block}; +use std::{marker::PhantomData, sync::Arc}; + +use crate::communication::request_response::{ + on_demand_justifications_protocol_config, Error, JustificationRequest, +}; + +/// A request coming in, including a sender for sending responses. +#[derive(Debug)] +pub(crate) struct IncomingRequest { + /// `PeerId` of sending peer. + pub peer: PeerId, + /// The sent request. + pub payload: JustificationRequest, + /// Sender for sending response back. + pub pending_response: oneshot::Sender, +} + +impl IncomingRequest { + /// Create new `IncomingRequest`. + pub fn new( + peer: PeerId, + payload: JustificationRequest, + pending_response: oneshot::Sender, + ) -> Self { + Self { peer, payload, pending_response } + } + + /// Try building from raw network request. + /// + /// This function will fail if the request cannot be decoded and will apply passed in + /// reputation changes in that case. + /// + /// Params: + /// - The raw request to decode + /// - Reputation changes to apply for the peer in case decoding fails. + pub fn try_from_raw( + raw: netconfig::IncomingRequest, + reputation_changes: Vec, + ) -> Result { + let netconfig::IncomingRequest { payload, peer, pending_response } = raw; + let payload = match JustificationRequest::decode(&mut payload.as_ref()) { + Ok(payload) => payload, + Err(err) => { + let response = netconfig::OutgoingResponse { + result: Err(()), + reputation_changes, + sent_feedback: None, + }; + if let Err(_) = pending_response.send(response) { + return Err(Error::DecodingErrorNoReputationChange(peer, err)) + } + return Err(Error::DecodingError(peer, err)) + }, + }; + Ok(Self::new(peer, payload, pending_response)) + } +} + +/// Receiver for incoming BEEFY justifications requests. +/// +/// Takes care of decoding and handling of invalid encoded requests. +pub(crate) struct IncomingRequestReceiver { + raw: mpsc::Receiver, +} + +impl IncomingRequestReceiver { + pub fn new(inner: mpsc::Receiver) -> Self { + Self { raw: inner } + } + + /// Try to receive the next incoming request. + /// + /// Any received request will be decoded, on decoding errors the provided reputation changes + /// will be applied and an error will be reported. + pub async fn recv(&mut self, reputation_changes: F) -> Result, Error> + where + B: Block, + F: FnOnce() -> Vec, + { + let req = match self.raw.next().await { + None => return Err(Error::RequestChannelExhausted), + Some(raw) => IncomingRequest::::try_from_raw(raw, reputation_changes())?, + }; + Ok(req) + } +} + +/// Handler for incoming BEEFY justifications requests from a remote peer. +pub struct BeefyJustifsRequestHandler { + pub(crate) request_receiver: IncomingRequestReceiver, + pub(crate) justif_protocol_name: ProtocolName, + pub(crate) client: Arc, + pub(crate) _block: PhantomData, +} + +impl BeefyJustifsRequestHandler +where + B: Block, + Client: BlockBackend + Send + Sync, +{ + /// Create a new [`BeefyJustifsRequestHandler`]. + pub fn new>( + genesis_hash: Hash, + fork_id: Option<&str>, + client: Arc, + ) -> (Self, RequestResponseConfig) { + let (request_receiver, config) = + on_demand_justifications_protocol_config(genesis_hash, fork_id); + let justif_protocol_name = config.name.clone(); + + (Self { request_receiver, justif_protocol_name, client, _block: PhantomData }, config) + } + + /// Network request-response protocol name used by this handler. + pub fn protocol_name(&self) -> ProtocolName { + self.justif_protocol_name.clone() + } + + // Sends back justification response if justification found in client backend. + fn handle_request(&self, request: IncomingRequest) -> Result<(), Error> { + // TODO (issue #12293): validate `request` and change peer reputation for invalid requests. + + let maybe_encoded_proof = self + .client + .justifications(&BlockId::Number(request.payload.begin)) + .map_err(Error::Client)? + .and_then(|justifs| justifs.get(BEEFY_ENGINE_ID).cloned()) + // No BEEFY justification present. + .ok_or(()); + + request + .pending_response + .send(netconfig::OutgoingResponse { + result: maybe_encoded_proof, + reputation_changes: Vec::new(), + sent_feedback: None, + }) + .map_err(|_| Error::SendResponse) + } + + /// Run [`BeefyJustifsRequestHandler`]. + pub async fn run(mut self) { + trace!(target: "beefy::sync", "🥩 Running BeefyJustifsRequestHandler"); + + while let Ok(request) = self.request_receiver.recv(|| vec![]).await { + let peer = request.peer; + match self.handle_request(request) { + Ok(()) => { + debug!( + target: "beefy::sync", + "🥩 Handled BEEFY justification request from {:?}.", peer + ) + }, + Err(e) => { + // TODO (issue #12293): apply reputation changes here based on error type. + debug!( + target: "beefy::sync", + "🥩 Failed to handle BEEFY justification request from {:?}: {}", peer, e, + ) + }, + } + } + } +} diff --git a/client/beefy/src/communication/request_response/mod.rs b/client/beefy/src/communication/request_response/mod.rs new file mode 100644 index 0000000000000..c83bb9d57e91b --- /dev/null +++ b/client/beefy/src/communication/request_response/mod.rs @@ -0,0 +1,101 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Request/response protocol for syncing BEEFY justifications. + +mod incoming_requests_handler; +pub(crate) mod outgoing_requests_engine; + +pub use incoming_requests_handler::BeefyJustifsRequestHandler; + +use futures::channel::mpsc; +use std::time::Duration; + +use codec::{Decode, Encode, Error as CodecError}; +use sc_network::{config::RequestResponseConfig, PeerId}; +use sp_runtime::traits::{Block, NumberFor}; + +use crate::communication::beefy_protocol_name::justifications_protocol_name; +use incoming_requests_handler::IncomingRequestReceiver; + +// 10 seems reasonable, considering justifs are explicitly requested only +// for mandatory blocks, by nodes that are syncing/catching-up. +const JUSTIF_CHANNEL_SIZE: usize = 10; + +const MAX_RESPONSE_SIZE: u64 = 1024 * 1024; +const JUSTIF_REQUEST_TIMEOUT: Duration = Duration::from_secs(3); + +/// Get the configuration for the BEEFY justifications Request/response protocol. +/// +/// Returns a receiver for messages received on this protocol and the requested +/// `ProtocolConfig`. +/// +/// Consider using [`BeefyJustifsRequestHandler`] instead of this low-level function. +pub(crate) fn on_demand_justifications_protocol_config>( + genesis_hash: Hash, + fork_id: Option<&str>, +) -> (IncomingRequestReceiver, RequestResponseConfig) { + let name = justifications_protocol_name(genesis_hash, fork_id); + let fallback_names = vec![]; + let (tx, rx) = mpsc::channel(JUSTIF_CHANNEL_SIZE); + let rx = IncomingRequestReceiver::new(rx); + let cfg = RequestResponseConfig { + name, + fallback_names, + max_request_size: 32, + max_response_size: MAX_RESPONSE_SIZE, + // We are connected to all validators: + request_timeout: JUSTIF_REQUEST_TIMEOUT, + inbound_queue: Some(tx), + }; + (rx, cfg) +} + +/// BEEFY justification request. +#[derive(Debug, Clone, Encode, Decode)] +pub struct JustificationRequest { + /// Start collecting proofs from this block. + pub begin: NumberFor, +} + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error(transparent)] + Client(#[from] sp_blockchain::Error), + + #[error(transparent)] + RuntimeApi(#[from] sp_api::ApiError), + + /// Decoding failed, we were able to change the peer's reputation accordingly. + #[error("Decoding request failed for peer {0}.")] + DecodingError(PeerId, #[source] CodecError), + + /// Decoding failed, but sending reputation change failed. + #[error("Decoding request failed for peer {0}, and changing reputation failed.")] + DecodingErrorNoReputationChange(PeerId, #[source] CodecError), + + /// Incoming request stream exhausted. Should only happen on shutdown. + #[error("Incoming request channel got closed.")] + RequestChannelExhausted, + + #[error("Failed to send response.")] + SendResponse, + + #[error("Received invalid response.")] + InvalidResponse, +} diff --git a/client/beefy/src/communication/request_response/outgoing_requests_engine.rs b/client/beefy/src/communication/request_response/outgoing_requests_engine.rs new file mode 100644 index 0000000000000..c4d3c926190e6 --- /dev/null +++ b/client/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -0,0 +1,241 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Generating request logic for request/response protocol for syncing BEEFY justifications. + +use beefy_primitives::{crypto::AuthorityId, BeefyApi, ValidatorSet}; +use codec::Encode; +use futures::channel::{oneshot, oneshot::Canceled}; +use log::{debug, error, warn}; +use parking_lot::Mutex; +use sc_network::{PeerId, ProtocolName}; +use sc_network_common::{ + request_responses::{IfDisconnected, RequestFailure}, + service::NetworkRequest, +}; +use sp_api::ProvideRuntimeApi; +use sp_runtime::{ + generic::BlockId, + traits::{Block, NumberFor}, +}; +use std::{collections::VecDeque, result::Result, sync::Arc}; + +use crate::{ + communication::request_response::{Error, JustificationRequest}, + justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof}, + KnownPeers, +}; + +/// Response type received from network. +type Response = Result, RequestFailure>; +/// Used to receive a response from the network. +type ResponseReceiver = oneshot::Receiver; + +enum State { + Idle, + AwaitingResponse(PeerId, NumberFor, ResponseReceiver), +} + +pub struct OnDemandJustificationsEngine { + network: Arc, + runtime: Arc, + protocol_name: ProtocolName, + + live_peers: Arc>>, + peers_cache: VecDeque, + + state: State, +} + +impl OnDemandJustificationsEngine +where + B: Block, + R: ProvideRuntimeApi, + R::Api: BeefyApi, +{ + pub fn new( + network: Arc, + runtime: Arc, + protocol_name: ProtocolName, + live_peers: Arc>>, + ) -> Self { + Self { + network, + runtime, + protocol_name, + live_peers, + peers_cache: VecDeque::new(), + state: State::Idle, + } + } + + fn reset_peers_cache_for_block(&mut self, block: NumberFor) { + // TODO (issue #12296): replace peer selection with generic one that involves all protocols. + self.peers_cache = self.live_peers.lock().at_least_at_block(block); + } + + fn try_next_peer(&mut self) -> Option { + // TODO (issue #12296): replace peer selection with generic one that involves all protocols. + let live = self.live_peers.lock(); + while let Some(peer) = self.peers_cache.pop_front() { + if live.contains(&peer) { + return Some(peer) + } + } + None + } + + fn request_from_peer(&mut self, peer: PeerId, block: NumberFor) { + debug!(target: "beefy::sync", "🥩 requesting justif #{:?} from peer {:?}", block, peer); + + let payload = JustificationRequest:: { begin: block }.encode(); + + let (tx, rx) = oneshot::channel(); + + self.network.start_request( + peer, + self.protocol_name.clone(), + payload, + tx, + IfDisconnected::ImmediateError, + ); + + self.state = State::AwaitingResponse(peer, block, rx); + } + + /// If no other request is in progress, start new justification request for `block`. + pub fn request(&mut self, block: NumberFor) { + // ignore new requests while there's already one pending + if matches!(self.state, State::AwaitingResponse(_, _, _)) { + return + } + self.reset_peers_cache_for_block(block); + + // Start the requests engine - each unsuccessful received response will automatically + // trigger a new request to the next peer in the `peers_cache` until there are none left. + if let Some(peer) = self.try_next_peer() { + self.request_from_peer(peer, block); + } else { + debug!(target: "beefy::sync", "🥩 no good peers to request justif #{:?} from", block); + } + } + + /// Cancel any pending request for block numbers smaller or equal to `block`. + pub fn cancel_requests_older_than(&mut self, block: NumberFor) { + match &self.state { + State::AwaitingResponse(_, number, _) if *number <= block => { + debug!( + target: "beefy::sync", + "🥩 cancel pending request for justification #{:?}", + number + ); + self.state = State::Idle; + }, + _ => (), + } + } + + fn process_response( + &mut self, + peer: PeerId, + block: NumberFor, + validator_set: &ValidatorSet, + response: Result, + ) -> Result, Error> { + response + .map_err(|e| { + debug!( + target: "beefy::sync", + "🥩 for on demand justification #{:?}, peer {:?} hung up: {:?}", + block, peer, e + ); + Error::InvalidResponse + })? + .map_err(|e| { + debug!( + target: "beefy::sync", + "🥩 for on demand justification #{:?}, peer {:?} error: {:?}", + block, peer, e + ); + Error::InvalidResponse + }) + .and_then(|encoded| { + decode_and_verify_finality_proof::(&encoded[..], block, &validator_set).map_err( + |e| { + debug!( + target: "beefy::sync", + "🥩 for on demand justification #{:?}, peer {:?} responded with invalid proof: {:?}", + block, peer, e + ); + Error::InvalidResponse + }, + ) + }) + } + + pub async fn next(&mut self) -> Option> { + let (peer, block, resp) = match &mut self.state { + State::Idle => { + futures::pending!(); + // Doesn't happen as 'futures::pending!()' is an 'await' barrier that never passes. + return None + }, + State::AwaitingResponse(peer, block, receiver) => { + let resp = receiver.await; + (*peer, *block, resp) + }, + }; + // We received the awaited response. Our 'receiver' will never generate any other response, + // meaning we're done with current state. Move the engine to `State::Idle`. + self.state = State::Idle; + + let block_id = BlockId::number(block); + let validator_set = self + .runtime + .runtime_api() + .validator_set(&block_id) + .map_err(|e| { + error!(target: "beefy::sync", "🥩 Runtime API error {:?} in on-demand justif engine.", e); + e + }) + .ok()? + .or_else(|| { + error!(target: "beefy::sync", "🥩 BEEFY pallet not available for block {:?}.", block); + None + })?; + + self.process_response(peer, block, &validator_set, resp) + .map_err(|_| { + // No valid justification received, try next peer in our set. + if let Some(peer) = self.try_next_peer() { + self.request_from_peer(peer, block); + } else { + warn!(target: "beefy::sync", "🥩 ran out of peers to request justif #{:?} from", block); + } + }) + .map(|proof| { + debug!( + target: "beefy::sync", + "🥩 received valid on-demand justif #{:?} from {:?}", + block, peer + ); + proof + }) + .ok() + } +} diff --git a/client/beefy/src/import.rs b/client/beefy/src/import.rs index db4d8bfba7450..0ed50d0ec8c98 100644 --- a/client/beefy/src/import.rs +++ b/client/beefy/src/import.rs @@ -33,8 +33,8 @@ use sc_client_api::backend::Backend; use sc_consensus::{BlockCheckParams, BlockImport, BlockImportParams, ImportResult}; use crate::{ + communication::notification::BeefyVersionedFinalityProofSender, justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof}, - notification::BeefyVersionedFinalityProofSender, }; /// A block-import handler for BEEFY. @@ -78,7 +78,7 @@ where Block: BlockT, BE: Backend, Runtime: ProvideRuntimeApi, - Runtime::Api: BeefyApi + Send + Sync, + Runtime::Api: BeefyApi + Send, { fn decode_and_verify( &self, diff --git a/client/beefy/src/justification.rs b/client/beefy/src/justification.rs index d9be18593dac7..7243c692727f0 100644 --- a/client/beefy/src/justification.rs +++ b/client/beefy/src/justification.rs @@ -81,7 +81,7 @@ fn verify_with_validator_set( #[cfg(test)] pub(crate) mod tests { use beefy_primitives::{ - known_payload_ids, Commitment, Payload, SignedCommitment, VersionedFinalityProof, + known_payloads, Commitment, Payload, SignedCommitment, VersionedFinalityProof, }; use substrate_test_runtime_client::runtime::Block; @@ -94,7 +94,7 @@ pub(crate) mod tests { keys: &[Keyring], ) -> BeefyVersionedFinalityProof { let commitment = Commitment { - payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]), + payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), block_number: block_num, validator_set_id: validator_set.id(), }; diff --git a/client/beefy/src/keystore.rs b/client/beefy/src/keystore.rs index b0259a42075ea..886c00fc5d817 100644 --- a/client/beefy/src/keystore.rs +++ b/client/beefy/src/keystore.rs @@ -19,12 +19,13 @@ use sp_application_crypto::RuntimeAppPublic; use sp_core::keccak_256; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; +use sp_runtime::traits::Keccak256; use log::warn; use beefy_primitives::{ crypto::{Public, Signature}, - KEY_TYPE, + BeefyVerify, KEY_TYPE, }; use crate::error; @@ -98,11 +99,7 @@ impl BeefyKeystore { /// /// Return `true` if the signature is authentic, `false` otherwise. pub fn verify(public: &Public, sig: &Signature, message: &[u8]) -> bool { - let msg = keccak_256(message); - let sig = sig.as_ref(); - let public = public.as_ref(); - - sp_core::ecdsa::Pair::verify_prehashed(sig, &msg, public) + BeefyVerify::::verify(sig, message, public) } } diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index cdb7fca10320d..441f6e4248117 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -16,79 +16,52 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use beefy_primitives::{BeefyApi, MmrRootHash}; +use beefy_primitives::{BeefyApi, MmrRootHash, PayloadProvider}; +use parking_lot::Mutex; use prometheus::Registry; -use sc_client_api::{Backend, BlockchainEvents, Finalizer}; +use sc_client_api::{Backend, BlockBackend, BlockchainEvents, Finalizer}; use sc_consensus::BlockImport; use sc_network::ProtocolName; +use sc_network_common::service::NetworkRequest; use sc_network_gossip::Network as GossipNetwork; -use sp_api::ProvideRuntimeApi; +use sp_api::{NumberFor, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use sp_consensus::{Error as ConsensusError, SyncOracle}; use sp_keystore::SyncCryptoStorePtr; use sp_mmr_primitives::MmrApi; use sp_runtime::traits::Block; -use std::sync::Arc; +use std::{marker::PhantomData, sync::Arc}; mod error; -mod gossip; mod keystore; mod metrics; mod round; mod worker; +pub mod communication; pub mod import; pub mod justification; -pub mod notification; #[cfg(test)] mod tests; use crate::{ - import::BeefyBlockImport, - notification::{ - BeefyBestBlockSender, BeefyBestBlockStream, BeefyVersionedFinalityProofSender, - BeefyVersionedFinalityProofStream, + communication::{ + notification::{ + BeefyBestBlockSender, BeefyBestBlockStream, BeefyVersionedFinalityProofSender, + BeefyVersionedFinalityProofStream, + }, + peers::KnownPeers, + request_response::{ + outgoing_requests_engine::OnDemandJustificationsEngine, BeefyJustifsRequestHandler, + }, }, + import::BeefyBlockImport, }; -pub use beefy_protocol_name::standard_name as protocol_standard_name; - -pub(crate) mod beefy_protocol_name { - use sc_chain_spec::ChainSpec; - use sc_network::ProtocolName; - - const NAME: &str = "/beefy/1"; - /// Old names for the notifications protocol, used for backward compatibility. - pub(crate) const LEGACY_NAMES: [&str; 1] = ["/paritytech/beefy/1"]; - - /// Name of the notifications protocol used by BEEFY. - /// - /// Must be registered towards the networking in order for BEEFY to properly function. - pub fn standard_name>( - genesis_hash: &Hash, - chain_spec: &Box, - ) -> ProtocolName { - let chain_prefix = match chain_spec.fork_id() { - Some(fork_id) => format!("/{}/{}", hex::encode(genesis_hash), fork_id), - None => format!("/{}", hex::encode(genesis_hash)), - }; - format!("{}{}", chain_prefix, NAME).into() - } -} - -/// Returns the configuration value to put in -/// [`sc_network::config::NetworkConfiguration::extra_sets`]. -/// For standard protocol name see [`beefy_protocol_name::standard_name`]. -pub fn beefy_peers_set_config( - protocol_name: ProtocolName, -) -> sc_network::config::NonDefaultSetConfig { - let mut cfg = sc_network::config::NonDefaultSetConfig::new(protocol_name, 1024 * 1024); - - cfg.allow_non_reserved(25, 25); - cfg.add_fallback_names(beefy_protocol_name::LEGACY_NAMES.iter().map(|&n| n.into()).collect()); - cfg -} +pub use communication::beefy_protocol_name::{ + gossip_protocol_name, justifications_protocol_name as justifs_protocol_name, +}; /// A convenience BEEFY client trait that defines all the type bounds a BEEFY client /// has to satisfy. Ideally that should actually be a trait alias. Unfortunately as @@ -158,13 +131,13 @@ where { // Voter -> RPC links let (to_rpc_justif_sender, from_voter_justif_stream) = - notification::BeefyVersionedFinalityProofStream::::channel(); + BeefyVersionedFinalityProofStream::::channel(); let (to_rpc_best_block_sender, from_voter_best_beefy_stream) = - notification::BeefyBestBlockStream::::channel(); + BeefyBestBlockStream::::channel(); // BlockImport -> Voter links let (to_voter_justif_sender, from_block_import_justif_stream) = - notification::BeefyVersionedFinalityProofStream::::channel(); + BeefyVersionedFinalityProofStream::::channel(); // BlockImport let import = @@ -179,69 +152,90 @@ where (import, voter_links, rpc_links) } +/// BEEFY gadget network parameters. +pub struct BeefyNetworkParams { + /// Network implementing gossip, requests and sync-oracle. + pub network: Arc, + /// Chain specific BEEFY gossip protocol name. See + /// [`communication::beefy_protocol_name::gossip_protocol_name`]. + pub gossip_protocol_name: ProtocolName, + /// Chain specific BEEFY on-demand justifications protocol name. See + /// [`communication::beefy_protocol_name::justifications_protocol_name`]. + pub justifications_protocol_name: ProtocolName, + + pub _phantom: PhantomData, +} + /// BEEFY gadget initialization parameters. -pub struct BeefyParams -where - B: Block, - BE: Backend, - C: Client, - R: ProvideRuntimeApi, - R::Api: BeefyApi + MmrApi, - N: GossipNetwork + Clone + SyncOracle + Send + Sync + 'static, -{ +pub struct BeefyParams { /// BEEFY client pub client: Arc, /// Client Backend pub backend: Arc, + /// BEEFY Payload provider + pub payload_provider: P, /// Runtime Api Provider pub runtime: Arc, /// Local key store pub key_store: Option, - /// Gossip network - pub network: N, + /// BEEFY voter network params + pub network_params: BeefyNetworkParams, /// Minimal delta between blocks, BEEFY should vote for pub min_block_delta: u32, /// Prometheus metric registry pub prometheus_registry: Option, - /// Chain specific GRANDPA protocol name. See [`beefy_protocol_name::standard_name`]. - pub protocol_name: ProtocolName, /// Links between the block importer, the background voter and the RPC layer. pub links: BeefyVoterLinks, + /// Handler for incoming BEEFY justifications requests from a remote peer. + pub on_demand_justifications_handler: BeefyJustifsRequestHandler, } /// Start the BEEFY gadget. /// /// This is a thin shim around running and awaiting a BEEFY worker. -pub async fn start_beefy_gadget(beefy_params: BeefyParams) +pub async fn start_beefy_gadget(beefy_params: BeefyParams) where B: Block, BE: Backend, - C: Client, + C: Client + BlockBackend, + P: PayloadProvider, R: ProvideRuntimeApi, - R::Api: BeefyApi + MmrApi, - N: GossipNetwork + Clone + SyncOracle + Send + Sync + 'static, + R::Api: BeefyApi + MmrApi>, + N: GossipNetwork + NetworkRequest + SyncOracle + Send + Sync + 'static, { let BeefyParams { client, backend, + payload_provider, runtime, key_store, - network, + network_params, min_block_delta, prometheus_registry, - protocol_name, links, + on_demand_justifications_handler, } = beefy_params; - let sync_oracle = network.clone(); - let gossip_validator = Arc::new(gossip::GossipValidator::new()); + let BeefyNetworkParams { network, gossip_protocol_name, justifications_protocol_name, .. } = + network_params; + + let known_peers = Arc::new(Mutex::new(KnownPeers::new())); + let gossip_validator = + Arc::new(communication::gossip::GossipValidator::new(known_peers.clone())); let gossip_engine = sc_network_gossip::GossipEngine::new( - network, - protocol_name, + network.clone(), + gossip_protocol_name, gossip_validator.clone(), None, ); + let on_demand_justifications = OnDemandJustificationsEngine::new( + network.clone(), + runtime.clone(), + justifications_protocol_name, + known_peers.clone(), + ); + let metrics = prometheus_registry.as_ref().map(metrics::Metrics::register).and_then( |result| match result { @@ -259,17 +253,20 @@ where let worker_params = worker::WorkerParams { client, backend, + payload_provider, runtime, - sync_oracle, + network, key_store: key_store.into(), + known_peers, gossip_engine, gossip_validator, + on_demand_justifications, links, metrics, min_block_delta, }; - let worker = worker::BeefyWorker::<_, _, _, _, _>::new(worker_params); + let worker = worker::BeefyWorker::<_, _, _, _, _, _>::new(worker_params); - worker.run().await + futures::future::join(worker.run(), on_demand_justifications_handler.run()).await; } diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index c96613eb38a95..45d346ccd85eb 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -33,7 +33,7 @@ use sp_runtime::traits::{Block, NumberFor}; /// whether the local `self` validator has voted/signed. /// /// Does not do any validation on votes or signatures, layers above need to handle that (gossip). -#[derive(Default)] +#[derive(Debug, Default)] struct RoundTracker { self_vote: bool, votes: HashMap, @@ -69,6 +69,7 @@ pub fn threshold(authorities: usize) -> usize { /// Only round numbers > `best_done` are of interest, all others are considered stale. /// /// Does not do any validation on votes or signatures, layers above need to handle that (gossip). +#[derive(Debug)] pub(crate) struct Rounds { rounds: BTreeMap<(Payload, NumberFor), RoundTracker>, session_start: NumberFor, @@ -135,7 +136,7 @@ where } } - pub(crate) fn try_conclude( + pub(crate) fn should_conclude( &mut self, round: &(P, NumberFor), ) -> Option>> { @@ -148,7 +149,6 @@ where if done { let signatures = self.rounds.remove(round)?.votes; - self.conclude(round.1); Some( self.validators() .iter() @@ -279,7 +279,7 @@ mod tests { true )); // round not concluded - assert!(rounds.try_conclude(&round).is_none()); + assert!(rounds.should_conclude(&round).is_none()); // self vote already present, should not self vote assert!(!rounds.should_self_vote(&round)); @@ -296,7 +296,7 @@ mod tests { (Keyring::Dave.public(), Keyring::Dave.sign(b"I am committed")), false )); - assert!(rounds.try_conclude(&round).is_none()); + assert!(rounds.should_conclude(&round).is_none()); // add 2nd good vote assert!(rounds.add_vote( @@ -305,7 +305,7 @@ mod tests { false )); // round not concluded - assert!(rounds.try_conclude(&round).is_none()); + assert!(rounds.should_conclude(&round).is_none()); // add 3rd good vote assert!(rounds.add_vote( @@ -314,7 +314,8 @@ mod tests { false )); // round concluded - assert!(rounds.try_conclude(&round).is_some()); + assert!(rounds.should_conclude(&round).is_some()); + rounds.conclude(round.1); // Eve is a validator, but round was concluded, adding vote disallowed assert!(!rounds.add_vote( @@ -432,11 +433,12 @@ mod tests { assert_eq!(3, rounds.rounds.len()); // conclude unknown round - assert!(rounds.try_conclude(&(H256::from_low_u64_le(5), 5)).is_none()); + assert!(rounds.should_conclude(&(H256::from_low_u64_le(5), 5)).is_none()); assert_eq!(3, rounds.rounds.len()); // conclude round 2 - let signatures = rounds.try_conclude(&(H256::from_low_u64_le(2), 2)).unwrap(); + let signatures = rounds.should_conclude(&(H256::from_low_u64_le(2), 2)).unwrap(); + rounds.conclude(2); assert_eq!(1, rounds.rounds.len()); assert_eq!( diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index e8d32fe3e8127..89be1cac4f886 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -21,10 +21,9 @@ use futures::{future, stream::FuturesUnordered, Future, StreamExt}; use parking_lot::Mutex; use serde::{Deserialize, Serialize}; -use std::{collections::HashMap, sync::Arc, task::Poll}; +use std::{collections::HashMap, marker::PhantomData, sync::Arc, task::Poll}; use tokio::{runtime::Runtime, time::Duration}; -use sc_chain_spec::{ChainSpec, GenericChainSpec}; use sc_client_api::HeaderBackend; use sc_consensus::{ BlockImport, BlockImportParams, BoxJustificationImport, ForkChoiceStrategy, ImportResult, @@ -33,18 +32,18 @@ use sc_consensus::{ use sc_keystore::LocalKeystore; use sc_network_test::{ Block, BlockImportAdapter, FullPeerConfig, PassThroughVerifier, Peer, PeersClient, - TestNetFactory, + PeersFullClient, TestNetFactory, }; use sc_utils::notification::NotificationReceiver; use beefy_primitives::{ crypto::{AuthorityId, Signature}, + mmr::MmrRootProvider, BeefyApi, ConsensusLog, MmrRootHash, ValidatorSet, VersionedFinalityProof, BEEFY_ENGINE_ID, KEY_TYPE as BeefyKeyType, }; -use sp_mmr_primitives::{ - BatchProof, EncodableOpaqueLeaf, Error as MmrError, LeafIndex, MmrApi, Proof, -}; +use sc_network::{config::RequestResponseConfig, ProtocolName}; +use sp_mmr_primitives::{BatchProof, EncodableOpaqueLeaf, Error as MmrError, MmrApi, Proof}; use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_consensus::BlockOrigin; @@ -60,11 +59,21 @@ use sp_runtime::{ use substrate_test_runtime_client::{runtime::Header, ClientExt}; use crate::{ - beefy_block_import_and_links, beefy_protocol_name, justification::*, - keystore::tests::Keyring as BeefyKeyring, BeefyRPCLinks, BeefyVoterLinks, + beefy_block_import_and_links, + communication::request_response::{ + on_demand_justifications_protocol_config, BeefyJustifsRequestHandler, + }, + gossip_protocol_name, + justification::*, + keystore::tests::Keyring as BeefyKeyring, + BeefyRPCLinks, BeefyVoterLinks, }; -pub(crate) const BEEFY_PROTOCOL_NAME: &'static str = "/beefy/1"; +const GENESIS_HASH: H256 = H256::zero(); +fn beefy_gossip_proto_name() -> ProtocolName { + gossip_protocol_name(GENESIS_HASH, None) +} + const GOOD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0xbf); const BAD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0x42); @@ -89,35 +98,12 @@ impl BuildStorage for Genesis { } } -#[test] -fn beefy_protocol_name() { - let chain_spec = GenericChainSpec::::from_json_bytes( - &include_bytes!("../../chain-spec/res/chain_spec.json")[..], - ) - .unwrap() - .cloned_box(); - - // Create protocol name using random genesis hash. - let genesis_hash = H256::random(); - let expected = format!("/{}/beefy/1", hex::encode(genesis_hash)); - let proto_name = beefy_protocol_name::standard_name(&genesis_hash, &chain_spec); - assert_eq!(proto_name.to_string(), expected); - - // Create protocol name using hardcoded genesis hash. Verify exact representation. - let genesis_hash = [ - 50, 4, 60, 123, 58, 106, 216, 246, 194, 188, 139, 193, 33, 212, 202, 171, 9, 55, 123, 94, - 8, 43, 12, 251, 187, 57, 173, 19, 188, 74, 205, 147, - ]; - let expected = - "/32043c7b3a6ad8f6c2bc8bc121d4caab09377b5e082b0cfbbb39ad13bc4acd93/beefy/1".to_string(); - let proto_name = beefy_protocol_name::standard_name(&genesis_hash, &chain_spec); - assert_eq!(proto_name.to_string(), expected); -} - #[derive(Default)] pub(crate) struct PeerData { pub(crate) beefy_rpc_links: Mutex>>, pub(crate) beefy_voter_links: Mutex>>, + pub(crate) beefy_justif_req_handler: + Mutex>>, } #[derive(Default)] @@ -126,23 +112,34 @@ pub(crate) struct BeefyTestNet { } impl BeefyTestNet { - pub(crate) fn new(n_authority: usize, n_full: usize) -> Self { - let mut net = BeefyTestNet { peers: Vec::with_capacity(n_authority + n_full) }; - for _ in 0..n_authority { - net.add_authority_peer(); - } - for _ in 0..n_full { - net.add_full_peer(); + pub(crate) fn new(n_authority: usize) -> Self { + let mut net = BeefyTestNet { peers: Vec::with_capacity(n_authority) }; + + for i in 0..n_authority { + let (rx, cfg) = on_demand_justifications_protocol_config(GENESIS_HASH, None); + let justif_protocol_name = cfg.name.clone(); + + net.add_authority_peer(vec![cfg]); + + let client = net.peers[i].client().as_client(); + let justif_handler = BeefyJustifsRequestHandler { + request_receiver: rx, + justif_protocol_name, + client, + _block: PhantomData, + }; + *net.peers[i].data.beefy_justif_req_handler.lock() = Some(justif_handler); } net } - pub(crate) fn add_authority_peer(&mut self) { + pub(crate) fn add_authority_peer(&mut self, req_resp_cfgs: Vec) { self.add_full_peer_with_config(FullPeerConfig { - notifications_protocols: vec![BEEFY_PROTOCOL_NAME.into()], + notifications_protocols: vec![beefy_gossip_proto_name()], + request_response_protocols: req_resp_cfgs, is_authority: true, ..Default::default() - }) + }); } pub(crate) fn generate_blocks_and_sync( @@ -198,6 +195,7 @@ impl TestNetFactory for BeefyTestNet { let peer_data = PeerData { beefy_rpc_links: Mutex::new(Some(rpc_links)), beefy_voter_links: Mutex::new(Some(voter_links)), + ..Default::default() }; (BlockImportAdapter::new(block_import), None, peer_data) } @@ -215,11 +213,8 @@ impl TestNetFactory for BeefyTestNet { } fn add_full_peer(&mut self) { - self.add_full_peer_with_config(FullPeerConfig { - notifications_protocols: vec![BEEFY_PROTOCOL_NAME.into()], - is_authority: false, - ..Default::default() - }) + // `add_authority_peer()` used instead. + unimplemented!() } } @@ -250,8 +245,8 @@ macro_rules! create_test_api { } } - impl MmrApi for RuntimeApi { - fn generate_proof(_leaf_index: LeafIndex) + impl MmrApi> for RuntimeApi { + fn generate_proof(_block_number: u64) -> Result<(EncodableOpaqueLeaf, Proof), MmrError> { unimplemented!() } @@ -273,7 +268,14 @@ macro_rules! create_test_api { Ok($mmr_root) } - fn generate_batch_proof(_leaf_indices: Vec) -> Result<(Vec, BatchProof), MmrError> { + fn generate_batch_proof(_block_numbers: Vec) -> Result<(Vec, BatchProof), MmrError> { + unimplemented!() + } + + fn generate_historical_batch_proof( + _block_numbers: Vec, + _best_known_block_number: u64 + ) -> Result<(Vec, BatchProof), MmrError> { unimplemented!() } @@ -345,9 +347,9 @@ fn initialize_beefy( ) -> impl Future where API: ProvideRuntimeApi + Default + Sync + Send, - API::Api: BeefyApi + MmrApi, + API::Api: BeefyApi + MmrApi>, { - let voters = FuturesUnordered::new(); + let tasks = FuturesUnordered::new(); for (peer_id, key, api) in peers.into_iter() { let peer = &net.peers[peer_id]; @@ -355,31 +357,42 @@ where let keystore = create_beefy_keystore(*key); let (_, _, peer_data) = net.make_block_import(peer.client().clone()); - let PeerData { beefy_rpc_links, beefy_voter_links } = peer_data; + let PeerData { beefy_rpc_links, beefy_voter_links, .. } = peer_data; let beefy_voter_links = beefy_voter_links.lock().take(); *peer.data.beefy_rpc_links.lock() = beefy_rpc_links.lock().take(); *peer.data.beefy_voter_links.lock() = beefy_voter_links.clone(); + let on_demand_justif_handler = peer.data.beefy_justif_req_handler.lock().take().unwrap(); + + let network_params = crate::BeefyNetworkParams { + network: peer.network_service().clone(), + gossip_protocol_name: beefy_gossip_proto_name(), + justifications_protocol_name: on_demand_justif_handler.protocol_name(), + _phantom: PhantomData, + }; + let payload_provider = MmrRootProvider::new(api.clone()); + let beefy_params = crate::BeefyParams { client: peer.client().as_client(), backend: peer.client().as_backend(), + payload_provider, runtime: api.clone(), key_store: Some(keystore), - network: peer.network_service().clone(), + network_params, links: beefy_voter_links.unwrap(), min_block_delta, prometheus_registry: None, - protocol_name: BEEFY_PROTOCOL_NAME.into(), + on_demand_justifications_handler: on_demand_justif_handler, }; - let gadget = crate::start_beefy_gadget::<_, _, _, _, _>(beefy_params); + let task = crate::start_beefy_gadget::<_, _, _, _, _, _>(beefy_params); fn assert_send(_: &T) {} - assert_send(&gadget); - voters.push(gadget); + assert_send(&task); + tasks.push(task); } - voters.for_each(|_| async move {}) + tasks.for_each(|_| async move {}) } fn block_until(future: impl Future + Unpin, net: &Arc>, runtime: &mut Runtime) { @@ -397,18 +410,19 @@ fn run_for(duration: Duration, net: &Arc>, runtime: &mut Run pub(crate) fn get_beefy_streams( net: &mut BeefyTestNet, - peers: &[BeefyKeyring], + // peer index and key + peers: impl Iterator, ) -> (Vec>, Vec>>) { let mut best_block_streams = Vec::new(); let mut versioned_finality_proof_streams = Vec::new(); - for peer_id in 0..peers.len() { - let beefy_rpc_links = net.peer(peer_id).data.beefy_rpc_links.lock().clone().unwrap(); + peers.for_each(|(index, _)| { + let beefy_rpc_links = net.peer(index).data.beefy_rpc_links.lock().clone().unwrap(); let BeefyRPCLinks { from_voter_justif_stream, from_voter_best_beefy_stream } = beefy_rpc_links; best_block_streams.push(from_voter_best_beefy_stream.subscribe()); versioned_finality_proof_streams.push(from_voter_justif_stream.subscribe()); - } + }); (best_block_streams, versioned_finality_proof_streams) } @@ -486,18 +500,24 @@ fn streams_empty_after_timeout( fn finalize_block_and_wait_for_beefy( net: &Arc>, - peers: &[BeefyKeyring], + // peer index and key + peers: impl Iterator + Clone, runtime: &mut Runtime, finalize_targets: &[u64], expected_beefy: &[u64], ) { - let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); + let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); for block in finalize_targets { let finalize = BlockId::number(*block); - for i in 0..peers.len() { - net.lock().peer(i).client().as_client().finalize_block(finalize, None).unwrap(); - } + peers.clone().for_each(|(index, _)| { + net.lock() + .peer(index) + .client() + .as_client() + .finalize_block(finalize, None) + .unwrap(); + }) } if expected_beefy.is_empty() { @@ -517,12 +537,12 @@ fn beefy_finalizing_blocks() { sp_tracing::try_init_simple(); let mut runtime = Runtime::new().unwrap(); - let peers = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; - let validator_set = ValidatorSet::new(make_beefy_ids(peers), 0).unwrap(); + let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob]; + let validator_set = ValidatorSet::new(make_beefy_ids(&peers), 0).unwrap(); let session_len = 10; let min_block_delta = 4; - let mut net = BeefyTestNet::new(2, 0); + let mut net = BeefyTestNet::new(2); let api = Arc::new(two_validators::TestApi {}); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); @@ -535,17 +555,18 @@ fn beefy_finalizing_blocks() { // Minimum BEEFY block delta is 4. + let peers = peers.into_iter().enumerate(); // finalize block #5 -> BEEFY should finalize #1 (mandatory) and #5 from diff-power-of-two rule. - finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[5], &[1, 5]); + finalize_block_and_wait_for_beefy(&net, peers.clone(), &mut runtime, &[5], &[1, 5]); // GRANDPA finalize #10 -> BEEFY finalize #10 (mandatory) - finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[10], &[10]); + finalize_block_and_wait_for_beefy(&net, peers.clone(), &mut runtime, &[10], &[10]); // GRANDPA finalize #18 -> BEEFY finalize #14, then #18 (diff-power-of-two rule) - finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[18], &[14, 18]); + finalize_block_and_wait_for_beefy(&net, peers.clone(), &mut runtime, &[18], &[14, 18]); // GRANDPA finalize #20 -> BEEFY finalize #20 (mandatory) - finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[20], &[20]); + finalize_block_and_wait_for_beefy(&net, peers.clone(), &mut runtime, &[20], &[20]); // GRANDPA finalize #21 -> BEEFY finalize nothing (yet) because min delta is 4 finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[21], &[]); @@ -556,12 +577,12 @@ fn lagging_validators() { sp_tracing::try_init_simple(); let mut runtime = Runtime::new().unwrap(); - let peers = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; - let validator_set = ValidatorSet::new(make_beefy_ids(peers), 0).unwrap(); + let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob]; + let validator_set = ValidatorSet::new(make_beefy_ids(&peers), 0).unwrap(); let session_len = 30; let min_block_delta = 1; - let mut net = BeefyTestNet::new(2, 0); + let mut net = BeefyTestNet::new(2); let api = Arc::new(two_validators::TestApi {}); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); runtime.spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); @@ -571,13 +592,20 @@ fn lagging_validators() { let net = Arc::new(Mutex::new(net)); + let peers = peers.into_iter().enumerate(); // finalize block #15 -> BEEFY should finalize #1 (mandatory) and #9, #13, #14, #15 from // diff-power-of-two rule. - finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[15], &[1, 9, 13, 14, 15]); + finalize_block_and_wait_for_beefy( + &net, + peers.clone(), + &mut runtime, + &[15], + &[1, 9, 13, 14, 15], + ); // Alice finalizes #25, Bob lags behind let finalize = BlockId::number(25); - let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); + let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); // verify nothing gets finalized by BEEFY let timeout = Some(Duration::from_millis(250)); @@ -585,21 +613,21 @@ fn lagging_validators() { streams_empty_after_timeout(versioned_finality_proof, &net, &mut runtime, None); // Bob catches up and also finalizes #25 - let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); + let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); // expected beefy finalizes block #17 from diff-power-of-two wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[23, 24, 25]); wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &mut runtime, &[23, 24, 25]); // Both finalize #30 (mandatory session) and #32 -> BEEFY finalize #30 (mandatory), #31, #32 - finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[30, 32], &[30, 31, 32]); + finalize_block_and_wait_for_beefy(&net, peers.clone(), &mut runtime, &[30, 32], &[30, 31, 32]); // Verify that session-boundary votes get buffered by client and only processed once // session-boundary block is GRANDPA-finalized (this guarantees authenticity for the new session // validator set). // Alice finalizes session-boundary mandatory block #60, Bob lags behind - let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); + let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); let finalize = BlockId::number(60); net.lock().peer(0).client().as_client().finalize_block(finalize, None).unwrap(); // verify nothing gets finalized by BEEFY @@ -610,7 +638,7 @@ fn lagging_validators() { // Bob catches up and also finalizes #60 (and should have buffered Alice's vote on #60) let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers); net.lock().peer(1).client().as_client().finalize_block(finalize, None).unwrap(); - // verify beefy skips intermediary votes, and successfully finalizes mandatory block #40 + // verify beefy skips intermediary votes, and successfully finalizes mandatory block #60 wait_for_best_beefy_blocks(best_blocks, &net, &mut runtime, &[60]); wait_for_beefy_signed_commitments(versioned_finality_proof, &net, &mut runtime, &[60]); } @@ -620,13 +648,12 @@ fn correct_beefy_payload() { sp_tracing::try_init_simple(); let mut runtime = Runtime::new().unwrap(); - let peers = - &[BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie, BeefyKeyring::Dave]; - let validator_set = ValidatorSet::new(make_beefy_ids(peers), 0).unwrap(); + let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie, BeefyKeyring::Dave]; + let validator_set = ValidatorSet::new(make_beefy_ids(&peers), 0).unwrap(); let session_len = 20; let min_block_delta = 2; - let mut net = BeefyTestNet::new(4, 0); + let mut net = BeefyTestNet::new(4); // Alice, Bob, Charlie will vote on good payloads let good_api = Arc::new(four_validators::TestApi {}); @@ -642,15 +669,16 @@ fn correct_beefy_payload() { let bad_peers = vec![(3, &BeefyKeyring::Dave, bad_api)]; runtime.spawn(initialize_beefy(&mut net, bad_peers, min_block_delta)); - // push 10 blocks + // push 12 blocks net.generate_blocks_and_sync(12, session_len, &validator_set, false); let net = Arc::new(Mutex::new(net)); + let peers = peers.into_iter().enumerate(); // with 3 good voters and 1 bad one, consensus should happen and best blocks produced. finalize_block_and_wait_for_beefy(&net, peers, &mut runtime, &[10], &[1, 9]); let (best_blocks, versioned_finality_proof) = - get_beefy_streams(&mut net.lock(), &[BeefyKeyring::Alice]); + get_beefy_streams(&mut net.lock(), [(0, BeefyKeyring::Alice)].into_iter()); // now 2 good validators and 1 bad one are voting net.lock() @@ -679,7 +707,7 @@ fn correct_beefy_payload() { // 3rd good validator catches up and votes as well let (best_blocks, versioned_finality_proof) = - get_beefy_streams(&mut net.lock(), &[BeefyKeyring::Alice]); + get_beefy_streams(&mut net.lock(), [(0, BeefyKeyring::Alice)].into_iter()); net.lock() .peer(2) .client() @@ -700,11 +728,11 @@ fn beefy_importing_blocks() { sp_tracing::try_init_simple(); - let mut net = BeefyTestNet::new(2, 0); + let mut net = BeefyTestNet::new(2); let client = net.peer(0).client().clone(); let (mut block_import, _, peer_data) = net.make_block_import(client.clone()); - let PeerData { beefy_rpc_links: _, beefy_voter_links } = peer_data; + let PeerData { beefy_voter_links, .. } = peer_data; let justif_stream = beefy_voter_links.lock().take().unwrap().from_block_import_justif_stream; let params = |block: Block, justifications: Option| { @@ -811,3 +839,118 @@ fn beefy_importing_blocks() { })); } } + +#[test] +fn voter_initialization() { + sp_tracing::try_init_simple(); + // Regression test for voter initialization where finality notifications were dropped + // after waiting for BEEFY pallet availability. + + let mut runtime = Runtime::new().unwrap(); + let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob]; + let validator_set = ValidatorSet::new(make_beefy_ids(&peers), 0).unwrap(); + let session_len = 5; + // Should vote on all mandatory blocks no matter the `min_block_delta`. + let min_block_delta = 10; + + let mut net = BeefyTestNet::new(2); + let api = Arc::new(two_validators::TestApi {}); + let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); + runtime.spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); + + // push 26 blocks + net.generate_blocks_and_sync(26, session_len, &validator_set, false); + let net = Arc::new(Mutex::new(net)); + + // Finalize multiple blocks at once to get a burst of finality notifications right from start. + // Need to finalize at least one block in each session, choose randomly. + // Expect voters to pick up all of them and BEEFY-finalize the mandatory blocks of each session. + finalize_block_and_wait_for_beefy( + &net, + peers.into_iter().enumerate(), + &mut runtime, + &[1, 6, 10, 17, 24, 26], + &[1, 5, 10, 15, 20, 25], + ); +} + +#[test] +fn on_demand_beefy_justification_sync() { + sp_tracing::try_init_simple(); + + let mut runtime = Runtime::new().unwrap(); + let all_peers = + [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie, BeefyKeyring::Dave]; + let validator_set = ValidatorSet::new(make_beefy_ids(&all_peers), 0).unwrap(); + let session_len = 5; + let min_block_delta = 5; + + let mut net = BeefyTestNet::new(4); + + // Alice, Bob, Charlie start first and make progress through voting. + let api = Arc::new(four_validators::TestApi {}); + let fast_peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie]; + let voting_peers = + fast_peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); + runtime.spawn(initialize_beefy(&mut net, voting_peers, min_block_delta)); + + // Dave will start late and have to catch up using on-demand justification requests (since + // in this test there is no block import queue to automatically import justifications). + let dave = vec![(3, &BeefyKeyring::Dave, api)]; + // Instantiate but don't run Dave, yet. + let dave_task = initialize_beefy(&mut net, dave, min_block_delta); + let dave_index = 3; + + // push 30 blocks + net.generate_blocks_and_sync(30, session_len, &validator_set, false); + + let fast_peers = fast_peers.into_iter().enumerate(); + let net = Arc::new(Mutex::new(net)); + // With 3 active voters and one inactive, consensus should happen and blocks BEEFY-finalized. + // Need to finalize at least one block in each session, choose randomly. + finalize_block_and_wait_for_beefy( + &net, + fast_peers.clone(), + &mut runtime, + &[1, 6, 10, 17, 24], + &[1, 5, 10, 15, 20], + ); + + // Spawn Dave, he's now way behind voting and can only catch up through on-demand justif sync. + runtime.spawn(dave_task); + // give Dave a chance to spawn and init. + run_for(Duration::from_millis(400), &net, &mut runtime); + + let (dave_best_blocks, _) = + get_beefy_streams(&mut net.lock(), [(dave_index, BeefyKeyring::Dave)].into_iter()); + net.lock() + .peer(dave_index) + .client() + .as_client() + .finalize_block(BlockId::number(1), None) + .unwrap(); + // Give Dave task some cpu cycles to process the finality notification, + run_for(Duration::from_millis(100), &net, &mut runtime); + // freshly spun up Dave now needs to listen for gossip to figure out the state of his peers. + + // Have the other peers do some gossip so Dave finds out about their progress. + finalize_block_and_wait_for_beefy(&net, fast_peers, &mut runtime, &[25], &[25]); + + // Now verify Dave successfully finalized #1 (through on-demand justification request). + wait_for_best_beefy_blocks(dave_best_blocks, &net, &mut runtime, &[1]); + + // Give Dave all tasks some cpu cycles to burn through their events queues, + run_for(Duration::from_millis(100), &net, &mut runtime); + // then verify Dave catches up through on-demand justification requests. + finalize_block_and_wait_for_beefy( + &net, + [(dave_index, BeefyKeyring::Dave)].into_iter(), + &mut runtime, + &[6, 10, 17, 24, 26], + &[5, 10, 15, 20, 25], + ); + + let all_peers = all_peers.into_iter().enumerate(); + // Now that Dave has caught up, sanity check voting works for all of them. + finalize_block_and_wait_for_beefy(&net, all_peers, &mut runtime, &[30], &[30]); +} diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 9f54a300472de..4381081f74ebd 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -24,10 +24,15 @@ use std::{ }; use codec::{Codec, Decode, Encode}; -use futures::StreamExt; +use futures::{stream::Fuse, FutureExt, StreamExt}; use log::{debug, error, info, log_enabled, trace, warn}; +use parking_lot::Mutex; -use sc_client_api::{Backend, FinalityNotification, HeaderBackend}; +use sc_client_api::{Backend, FinalityNotification, FinalityNotifications, HeaderBackend}; +use sc_network_common::{ + protocol::event::Event as NetEvent, + service::{NetworkEventStream, NetworkRequest}, +}; use sc_network_gossip::GossipEngine; use sp_api::{BlockId, ProvideRuntimeApi}; @@ -43,19 +48,22 @@ use sp_runtime::{ use beefy_primitives::{ crypto::{AuthorityId, Signature}, - known_payload_ids, BeefyApi, Commitment, ConsensusLog, MmrRootHash, Payload, SignedCommitment, + BeefyApi, Commitment, ConsensusLog, MmrRootHash, Payload, PayloadProvider, SignedCommitment, ValidatorSet, VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, GENESIS_AUTHORITY_SET_ID, }; use crate::{ + communication::{ + gossip::{topic, GossipValidator}, + request_response::outgoing_requests_engine::OnDemandJustificationsEngine, + }, error::Error, - gossip::{topic, GossipValidator}, justification::BeefyVersionedFinalityProof, keystore::BeefyKeystore, metric_inc, metric_set, metrics::Metrics, round::Rounds, - BeefyVoterLinks, Client, + BeefyVoterLinks, Client, KnownPeers, }; enum RoundAction { @@ -113,6 +121,17 @@ impl VoterOracle { } } + /// Return current pending mandatory block, if any. + pub fn mandatory_pending(&self) -> Option> { + self.sessions.front().and_then(|round| { + if round.mandatory_done() { + None + } else { + Some(round.session_start()) + } + }) + } + /// Return `(A, B)` tuple representing inclusive [A, B] interval of votes to accept. pub fn accepted_interval( &self, @@ -175,29 +194,37 @@ impl VoterOracle { } } -pub(crate) struct WorkerParams { +pub(crate) struct WorkerParams { pub client: Arc, pub backend: Arc, + pub payload_provider: P, pub runtime: Arc, - pub sync_oracle: SO, + pub network: N, pub key_store: BeefyKeystore, + pub known_peers: Arc>>, pub gossip_engine: GossipEngine, pub gossip_validator: Arc>, + pub on_demand_justifications: OnDemandJustificationsEngine, pub links: BeefyVoterLinks, pub metrics: Option, pub min_block_delta: u32, } /// A BEEFY worker plays the BEEFY protocol -pub(crate) struct BeefyWorker { +pub(crate) struct BeefyWorker { // utilities client: Arc, backend: Arc, + payload_provider: P, runtime: Arc, - sync_oracle: SO, + network: N, key_store: BeefyKeystore, + + // communication + known_peers: Arc>>, gossip_engine: GossipEngine, gossip_validator: Arc>, + on_demand_justifications: OnDemandJustificationsEngine, // channels /// Links between the block importer, the background voter and the RPC layer. @@ -218,14 +245,15 @@ pub(crate) struct BeefyWorker { voting_oracle: VoterOracle, } -impl BeefyWorker +impl BeefyWorker where B: Block + Codec, BE: Backend, C: Client, + P: PayloadProvider, R: ProvideRuntimeApi, - R::Api: BeefyApi + MmrApi, - SO: SyncOracle + Send + Sync + Clone + 'static, + R::Api: BeefyApi + MmrApi>, + N: NetworkEventStream + NetworkRequest + SyncOracle + Send + Sync + Clone + 'static, { /// Return a new BEEFY worker instance. /// @@ -233,15 +261,18 @@ where /// BEEFY pallet has been deployed on-chain. /// /// The BEEFY pallet is needed in order to keep track of the BEEFY authority set. - pub(crate) fn new(worker_params: WorkerParams) -> Self { + pub(crate) fn new(worker_params: WorkerParams) -> Self { let WorkerParams { client, backend, + payload_provider, runtime, key_store, - sync_oracle, + network, gossip_engine, gossip_validator, + on_demand_justifications, + known_peers, links, metrics, min_block_delta, @@ -255,11 +286,14 @@ where BeefyWorker { client: client.clone(), backend, + payload_provider, runtime, - sync_oracle, + network, + known_peers, key_store, gossip_engine, gossip_validator, + on_demand_justifications, links, metrics, best_grandpa_block_header: last_finalized_header, @@ -270,17 +304,6 @@ where } } - /// Simple wrapper that gets MMR root from header digests or from client state. - fn get_mmr_root_digest(&self, header: &B::Header) -> Option { - find_mmr_root_digest::(header).or_else(|| { - self.runtime - .runtime_api() - .mmr_root(&BlockId::hash(header.hash())) - .ok() - .and_then(|r| r.ok()) - }) - } - /// Verify `active` validator set for `block` against the key store /// /// We want to make sure that we have _at least one_ key in our keystore that @@ -366,8 +389,6 @@ where { if let Some(new_validator_set) = find_authorities_change::(&header) { self.init_session_at(new_validator_set, *header.number()); - // TODO (grandpa-bridge-gadget/issues/20): when adding SYNC protocol, - // fire up a request for justification for this mandatory block here. } } } @@ -408,7 +429,10 @@ where let block_num = signed_commitment.commitment.block_number; let best_grandpa = *self.best_grandpa_block_header.number(); match self.voting_oracle.triage_round(block_num, best_grandpa)? { - RoundAction::Process => self.finalize(justification)?, + RoundAction::Process => { + debug!(target: "beefy", "🥩 Process justification for round: {:?}.", block_num); + self.finalize(justification)? + }, RoundAction::Enqueue => { debug!(target: "beefy", "🥩 Buffer justification for round: {:?}.", block_num); self.pending_justifications.entry(block_num).or_insert(justification); @@ -429,7 +453,7 @@ where let rounds = self.voting_oracle.rounds_mut().ok_or(Error::UninitSession)?; if rounds.add_vote(&round, vote, self_vote) { - if let Some(signatures) = rounds.try_conclude(&round) { + if let Some(signatures) = rounds.should_conclude(&round) { self.gossip_validator.conclude_round(round.1); let block_num = round.1; @@ -474,9 +498,11 @@ where self.best_beefy_block = Some(block_num); metric_set!(self, beefy_best_block, block_num); + self.on_demand_justifications.cancel_requests_older_than(block_num); + if let Err(e) = self.backend.append_justification( BlockId::Number(block_num), - (BEEFY_ENGINE_ID, finality_proof.clone().encode()), + (BEEFY_ENGINE_ID, finality_proof.encode()), ) { error!(target: "beefy", "🥩 Error {:?} on appending justification: {:?}", e, finality_proof); } @@ -589,13 +615,12 @@ where }; let target_hash = target_header.hash(); - let mmr_root = if let Some(hash) = self.get_mmr_root_digest(&target_header) { + let payload = if let Some(hash) = self.payload_provider.payload(&target_header) { hash } else { warn!(target: "beefy", "🥩 No MMR root digest found for: {:?}", target_hash); return Ok(()) }; - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, mmr_root.encode()); let rounds = self.voting_oracle.rounds_mut().ok_or(Error::UninitSession)?; if !rounds.should_self_vote(&(payload.clone(), target_number)) { @@ -723,12 +748,11 @@ where /// Wait for BEEFY runtime pallet to be available. /// Should be called only once during worker initialization. - async fn wait_for_runtime_pallet(&mut self) { + async fn wait_for_runtime_pallet(&mut self, finality: &mut Fuse>) { let mut gossip_engine = &mut self.gossip_engine; - let mut finality_stream = self.client.finality_notification_stream().fuse(); loop { futures::select! { - notif = finality_stream.next() => { + notif = finality.next() => { let notif = match notif { Some(notif) => notif, None => break @@ -736,7 +760,7 @@ where let at = BlockId::hash(notif.header.hash()); if let Some(active) = self.runtime.runtime_api().validator_set(&at).ok().flatten() { self.initialize_voter(¬if.header, active); - if !self.sync_oracle.is_major_syncing() { + if !self.network.is_major_syncing() { if let Err(err) = self.try_to_vote() { debug!(target: "beefy", "🥩 {}", err); } @@ -762,11 +786,14 @@ where pub(crate) async fn run(mut self) { info!(target: "beefy", "🥩 run BEEFY worker, best grandpa: #{:?}.", self.best_grandpa_block_header.number()); let mut block_import_justif = self.links.from_block_import_justif_stream.subscribe().fuse(); + // Subscribe to finality notifications before waiting for runtime pallet and reuse stream, + // so we process notifications for all finalized blocks after pallet is available. + let mut finality_notifications = self.client.finality_notification_stream().fuse(); - self.wait_for_runtime_pallet().await; + self.wait_for_runtime_pallet(&mut finality_notifications).await; trace!(target: "beefy", "🥩 BEEFY pallet available, starting voter."); - let mut finality_notifications = self.client.finality_notification_stream().fuse(); + let mut network_events = self.network.event_stream("network-gossip").fuse(); let mut votes = Box::pin( self.gossip_engine .messages_for(topic::()) @@ -787,15 +814,38 @@ where // The branches below only change 'state', actual voting happen afterwards, // based on the new resulting 'state'. futures::select_biased! { + // Use `select_biased!` to prioritize order below. + // Make sure to pump gossip engine. + _ = gossip_engine => { + error!(target: "beefy", "🥩 Gossip engine has terminated, closing worker."); + return; + }, + // Keep track of connected peers. + net_event = network_events.next() => { + if let Some(net_event) = net_event { + self.handle_network_event(net_event); + } else { + error!(target: "beefy", "🥩 Network events stream terminated, closing worker."); + return; + } + }, + // Process finality notifications first since these drive the voter. notification = finality_notifications.next() => { if let Some(notification) = notification { self.handle_finality_notification(¬ification); } else { + error!(target: "beefy", "🥩 Finality stream terminated, closing worker."); return; } }, - // TODO: when adding SYNC protocol, join the on-demand justifications stream to - // this one, and handle them both here. + // Process incoming justifications as these can make some in-flight votes obsolete. + justif = self.on_demand_justifications.next().fuse() => { + if let Some(justif) = justif { + if let Err(err) = self.triage_incoming_justif(justif) { + debug!(target: "beefy", "🥩 {}", err); + } + } + }, justif = block_import_justif.next() => { if let Some(justif) = justif { // Block import justifications have already been verified to be valid @@ -804,9 +854,11 @@ where debug!(target: "beefy", "🥩 {}", err); } } else { + error!(target: "beefy", "🥩 Block import stream terminated, closing worker."); return; } }, + // Finally process incoming votes. vote = votes.next() => { if let Some(vote) = vote { // Votes have already been verified to be valid by the gossip validator. @@ -814,13 +866,10 @@ where debug!(target: "beefy", "🥩 {}", err); } } else { + error!(target: "beefy", "🥩 Votes gossiping stream terminated, closing worker."); return; } }, - _ = gossip_engine => { - error!(target: "beefy", "🥩 Gossip engine has terminated."); - return; - } } // Handle pending justifications and/or votes for now GRANDPA finalized blocks. @@ -828,8 +877,14 @@ where debug!(target: "beefy", "🥩 {}", err); } - // Don't bother voting during major sync. - if !self.sync_oracle.is_major_syncing() { + // Don't bother voting or requesting justifications during major sync. + if !self.network.is_major_syncing() { + // If the current target is a mandatory block, + // make sure there's also an on-demand justification request out for it. + if let Some(block) = self.voting_oracle.mandatory_pending() { + // This only starts new request if there isn't already an active one. + self.on_demand_justifications.request(block); + } // There were external events, 'state' is changed, author a vote if needed/possible. if let Err(err) = self.try_to_vote() { debug!(target: "beefy", "🥩 {}", err); @@ -839,20 +894,20 @@ where } } } -} -/// Extract the MMR root hash from a digest in the given header, if it exists. -fn find_mmr_root_digest(header: &B::Header) -> Option -where - B: Block, -{ - let id = OpaqueDigestItemId::Consensus(&BEEFY_ENGINE_ID); - - let filter = |log: ConsensusLog| match log { - ConsensusLog::MmrRoot(root) => Some(root), - _ => None, - }; - header.digest().convert_first(|l| l.try_to(id).and_then(filter)) + /// Update known peers based on network events. + fn handle_network_event(&mut self, event: NetEvent) { + match event { + NetEvent::SyncConnected { remote } => { + self.known_peers.lock().add_new(remote); + }, + NetEvent::SyncDisconnected { remote } => { + self.known_peers.lock().remove(&remote); + }, + // We don't care about other events. + _ => (), + } + } } /// Scan the `header` digest log for a BEEFY validator set change. Return either the new @@ -931,17 +986,17 @@ where pub(crate) mod tests { use super::*; use crate::{ + communication::notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofStream}, keystore::tests::Keyring, - notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofStream}, tests::{ create_beefy_keystore, get_beefy_streams, make_beefy_ids, two_validators::TestApi, - BeefyPeer, BeefyTestNet, BEEFY_PROTOCOL_NAME, + BeefyPeer, BeefyTestNet, }, BeefyRPCLinks, }; + use beefy_primitives::{known_payloads, mmr::MmrRootProvider}; use futures::{executor::block_on, future::poll_fn, task::Poll}; - use sc_client_api::{Backend as BackendT, HeaderBackend}; use sc_network::NetworkService; use sc_network_test::{PeersFullClient, TestNetFactory}; @@ -956,7 +1011,14 @@ pub(crate) mod tests { peer: &BeefyPeer, key: &Keyring, min_block_delta: u32, - ) -> BeefyWorker>> { + ) -> BeefyWorker< + Block, + Backend, + PeersFullClient, + MmrRootProvider, + TestApi, + Arc>, + > { let keystore = create_beefy_keystore(*key); let (to_rpc_justif_sender, from_voter_justif_stream) = @@ -978,23 +1040,33 @@ pub(crate) mod tests { let api = Arc::new(TestApi {}); let network = peer.network_service().clone(); - let sync_oracle = network.clone(); - let gossip_validator = Arc::new(crate::gossip::GossipValidator::new()); + let known_peers = Arc::new(Mutex::new(KnownPeers::new())); + let gossip_validator = Arc::new(GossipValidator::new(known_peers.clone())); let gossip_engine = - GossipEngine::new(network, BEEFY_PROTOCOL_NAME, gossip_validator.clone(), None); + GossipEngine::new(network.clone(), "/beefy/1", gossip_validator.clone(), None); + let on_demand_justifications = OnDemandJustificationsEngine::new( + network.clone(), + api.clone(), + "/beefy/justifs/1".into(), + known_peers.clone(), + ); + let payload_provider = MmrRootProvider::new(api.clone()); let worker_params = crate::worker::WorkerParams { client: peer.client().as_client(), backend: peer.client().as_backend(), + payload_provider, runtime: api, key_store: Some(keystore).into(), + known_peers, links, gossip_engine, gossip_validator, min_block_delta, metrics: None, - sync_oracle, + network, + on_demand_justifications, }; - BeefyWorker::<_, _, _, _, _>::new(worker_params) + BeefyWorker::<_, _, _, _, _, _>::new(worker_params) } #[test] @@ -1216,35 +1288,11 @@ pub(crate) mod tests { assert_eq!(extracted, Some(validator_set)); } - #[test] - fn extract_mmr_root_digest() { - let mut header = Header::new( - 1u32.into(), - Default::default(), - Default::default(), - Default::default(), - Digest::default(), - ); - - // verify empty digest shows nothing - assert!(find_mmr_root_digest::(&header).is_none()); - - let mmr_root_hash = H256::random(); - header.digest_mut().push(DigestItem::Consensus( - BEEFY_ENGINE_ID, - ConsensusLog::::MmrRoot(mmr_root_hash).encode(), - )); - - // verify validator set is correctly extracted from digest - let extracted = find_mmr_root_digest::(&header); - assert_eq!(extracted, Some(mmr_root_hash)); - } - #[test] fn keystore_vs_validator_set() { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1, 0); + let mut net = BeefyTestNet::new(1); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); // keystore doesn't contain other keys than validators' @@ -1265,19 +1313,21 @@ pub(crate) mod tests { #[test] fn should_finalize_correctly() { - let keys = &[Keyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1, 0); + let keys = [Keyring::Alice]; + let validator_set = ValidatorSet::new(make_beefy_ids(&keys), 0).unwrap(); + let mut net = BeefyTestNet::new(1); let backend = net.peer(0).client().as_backend(); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); - let (mut best_block_streams, mut finality_proofs) = get_beefy_streams(&mut net, keys); + let keys = keys.iter().cloned().enumerate(); + let (mut best_block_streams, mut finality_proofs) = + get_beefy_streams(&mut net, keys.clone()); let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); let mut finality_proof = finality_proofs.drain(..).next().unwrap(); let create_finality_proof = |block_num: NumberFor| { let commitment = Commitment { - payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]), + payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), block_number: block_num, validator_set_id: validator_set.id(), }; @@ -1293,7 +1343,8 @@ pub(crate) mod tests { })); // unknown hash for block #1 - let (mut best_block_streams, mut finality_proofs) = get_beefy_streams(&mut net, keys); + let (mut best_block_streams, mut finality_proofs) = + get_beefy_streams(&mut net, keys.clone()); let mut best_block_stream = best_block_streams.drain(..).next().unwrap(); let mut finality_proof = finality_proofs.drain(..).next().unwrap(); let justif = create_finality_proof(1); @@ -1354,7 +1405,7 @@ pub(crate) mod tests { fn should_init_session() { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1, 0); + let mut net = BeefyTestNet::new(1); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); assert!(worker.voting_oracle.sessions.is_empty()); @@ -1388,14 +1439,14 @@ pub(crate) mod tests { fn should_triage_votes_and_process_later() { let keys = &[Keyring::Alice, Keyring::Bob]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1, 0); + let mut net = BeefyTestNet::new(1); let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1); fn new_vote( block_number: NumberFor, ) -> VoteMessage, AuthorityId, Signature> { let commitment = Commitment { - payload: Payload::new(*b"BF", vec![]), + payload: Payload::from_single_entry(*b"BF", vec![]), block_number, validator_set_id: 0, }; @@ -1449,7 +1500,7 @@ pub(crate) mod tests { fn should_initialize_correct_voter() { let keys = &[Keyring::Alice]; let validator_set = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap(); - let mut net = BeefyTestNet::new(1, 0); + let mut net = BeefyTestNet::new(1); let backend = net.peer(0).client().as_backend(); // push 15 blocks with `AuthorityChange` digests every 10 blocks @@ -1487,7 +1538,7 @@ pub(crate) mod tests { // import/append BEEFY justification for session boundary block 10 let commitment = Commitment { - payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]), + payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), block_number: 10, validator_set_id: validator_set.id(), }; @@ -1521,7 +1572,7 @@ pub(crate) mod tests { // import/append BEEFY justification for block 12 let commitment = Commitment { - payload: Payload::new(known_payload_ids::MMR_ROOT_ID, vec![]), + payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), block_number: 12, validator_set_id: validator_set.id(), }; diff --git a/client/block-builder-ver/src/lib.rs b/client/block-builder-ver/src/lib.rs index 55fd559a5e611..13b984f237c28 100644 --- a/client/block-builder-ver/src/lib.rs +++ b/client/block-builder-ver/src/lib.rs @@ -305,7 +305,7 @@ where let proof = self.api.extract_proof(); - let state = self.backend.state_at(self.block_id)?; + let state = self.backend.state_at(&self.parent_hash)?; let parent_hash = self.parent_hash; let storage_changes = self .api diff --git a/client/block-builder/src/lib.rs b/client/block-builder/src/lib.rs index 803e9c1e8bf26..cd5e62e264200 100644 --- a/client/block-builder/src/lib.rs +++ b/client/block-builder/src/lib.rs @@ -258,12 +258,11 @@ where let proof = self.api.extract_proof(); - let state = self.backend.state_at(self.block_id)?; - let parent_hash = self.parent_hash; + let state = self.backend.state_at(&self.parent_hash)?; let storage_changes = self .api - .into_storage_changes(&state, parent_hash) + .into_storage_changes(&state, self.parent_hash) .map_err(sp_blockchain::Error::StorageChanges)?; Ok(BuiltBlock { diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 50d110d40eabd..04824859ce8ab 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -13,12 +13,12 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +array-bytes = "4.1" chrono = "0.4.10" -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive", "string"] } fdlimit = "0.2.1" futures = "0.3.21" -hex = "0.4.2" -libp2p = "0.46.1" +libp2p = "0.49.0" log = "0.4.17" names = { version = "0.13.0", default-features = false } parity-scale-codec = "3.0.0" @@ -34,6 +34,7 @@ sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-client-db = { version = "0.10.0-dev", default-features = false, path = "../db" } sc-keystore = { version = "4.0.0-dev", path = "../keystore" } sc-network = { version = "0.10.0-dev", path = "../network" } +sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-service = { version = "0.10.0-dev", default-features = false, path = "../service" } sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" } sc-tracing = { version = "4.0.0-dev", path = "../tracing" } @@ -50,6 +51,6 @@ sp-version = { version = "5.0.0", path = "../../primitives/version" } tempfile = "3.1.0" [features] -default = ["rocksdb"] +default = ["rocksdb", "wasmtime"] rocksdb = ["sc-client-db/rocksdb"] wasmtime = ["sc-service/wasmtime"] diff --git a/client/cli/src/arg_enums.rs b/client/cli/src/arg_enums.rs index 283fef985dfb9..d761c854a6f0d 100644 --- a/client/cli/src/arg_enums.rs +++ b/client/cli/src/arg_enums.rs @@ -16,13 +16,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Definitions of [`ArgEnum`] types. +//! Definitions of [`ValueEnum`] types. -use clap::ArgEnum; +use clap::{builder::PossibleValue, ValueEnum}; /// The instantiation strategy to use in compiled mode. -#[derive(Debug, Clone, Copy, ArgEnum)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Clone, Copy, ValueEnum)] +#[value(rename_all = "kebab-case")] pub enum WasmtimeInstantiationStrategy { /// Pool the instances to avoid initializing everything from scratch /// on each instantiation. Use copy-on-write memory when possible. @@ -59,20 +59,22 @@ pub enum WasmExecutionMethod { Compiled, } -impl std::fmt::Display for WasmExecutionMethod { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Interpreted => write!(f, "Interpreted"), - Self::Compiled => write!(f, "Compiled"), +const INTERPRETED_NAME: &str = "interpreted-i-know-what-i-do"; + +impl clap::ValueEnum for WasmExecutionMethod { + /// All possible argument values, in display order. + fn value_variants<'a>() -> &'a [Self] { + let variants = &[Self::Interpreted, Self::Compiled]; + if cfg!(feature = "wasmtime") { + variants + } else { + &variants[..1] } } -} - -impl std::str::FromStr for WasmExecutionMethod { - type Err = String; - fn from_str(s: &str) -> Result { - if s.eq_ignore_ascii_case("interpreted-i-know-what-i-do") { + /// Parse an argument into `Self`. + fn from_str(s: &str, _: bool) -> Result { + if s.eq_ignore_ascii_case(INTERPRETED_NAME) { Ok(Self::Interpreted) } else if s.eq_ignore_ascii_case("compiled") { #[cfg(feature = "wasmtime")] @@ -84,19 +86,29 @@ impl std::str::FromStr for WasmExecutionMethod { Err("`Compiled` variant requires the `wasmtime` feature to be enabled".into()) } } else { - Err(format!("Unknown variant `{}`, known variants: {:?}", s, Self::variants())) + Err(format!("Unknown variant `{}`", s)) + } + } + + /// The canonical argument value. + /// + /// The value is `None` for skipped variants. + fn to_possible_value(&self) -> Option { + match self { + #[cfg(feature = "wasmtime")] + WasmExecutionMethod::Compiled => Some(PossibleValue::new("compiled")), + #[cfg(not(feature = "wasmtime"))] + WasmExecutionMethod::Compiled => None, + WasmExecutionMethod::Interpreted => Some(PossibleValue::new(INTERPRETED_NAME)), } } } -impl WasmExecutionMethod { - /// Returns all the variants of this enum to be shown in the cli. - pub fn variants() -> &'static [&'static str] { - let variants = &["interpreted-i-know-what-i-do", "compiled"]; - if cfg!(feature = "wasmtime") { - variants - } else { - &variants[..1] +impl std::fmt::Display for WasmExecutionMethod { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Interpreted => write!(f, "Interpreted"), + Self::Compiled => write!(f, "Compiled"), } } } @@ -133,15 +145,15 @@ pub fn execution_method_from_cli( /// The default [`WasmExecutionMethod`]. #[cfg(feature = "wasmtime")] -pub const DEFAULT_WASM_EXECUTION_METHOD: &str = "compiled"; +pub const DEFAULT_WASM_EXECUTION_METHOD: WasmExecutionMethod = WasmExecutionMethod::Compiled; /// The default [`WasmExecutionMethod`]. #[cfg(not(feature = "wasmtime"))] -pub const DEFAULT_WASM_EXECUTION_METHOD: &str = "interpreted-i-know-what-i-do"; +pub const DEFAULT_WASM_EXECUTION_METHOD: WasmExecutionMethod = WasmExecutionMethod::Interpreted; #[allow(missing_docs)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueEnum)] +#[value(rename_all = "kebab-case")] pub enum TracingReceiver { /// Output the tracing records using the log. Log, @@ -156,16 +168,16 @@ impl Into for TracingReceiver { } /// The type of the node key. -#[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueEnum)] +#[value(rename_all = "kebab-case")] pub enum NodeKeyType { /// Use ed25519. Ed25519, } /// The crypto scheme to use. -#[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueEnum)] +#[value(rename_all = "kebab-case")] pub enum CryptoScheme { /// Use ed25519. Ed25519, @@ -176,8 +188,8 @@ pub enum CryptoScheme { } /// The type of the output format. -#[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueEnum)] +#[value(rename_all = "kebab-case")] pub enum OutputType { /// Output as json. Json, @@ -186,8 +198,8 @@ pub enum OutputType { } /// How to execute blocks -#[derive(Debug, Copy, Clone, PartialEq, Eq, ArgEnum)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Copy, Clone, PartialEq, Eq, ValueEnum)] +#[value(rename_all = "kebab-case")] pub enum ExecutionStrategy { /// Execute with native build (if available, WebAssembly otherwise). Native, @@ -212,8 +224,8 @@ impl Into for ExecutionStrategy { /// Available RPC methods. #[allow(missing_docs)] -#[derive(Debug, Copy, Clone, PartialEq, ArgEnum)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Copy, Clone, PartialEq, ValueEnum)] +#[value(rename_all = "kebab-case")] pub enum RpcMethods { /// Expose every RPC method only when RPC is listening on `localhost`, /// otherwise serve only safe RPC methods. @@ -235,7 +247,8 @@ impl Into for RpcMethods { } /// Database backend -#[derive(Debug, Clone, PartialEq, Copy)] +#[derive(Debug, Clone, PartialEq, Copy, clap::ValueEnum)] +#[value(rename_all = "lower")] pub enum Database { /// Facebooks RocksDB #[cfg(feature = "rocksdb")] @@ -246,29 +259,10 @@ pub enum Database { /// instance of ParityDb Auto, /// ParityDb. + #[value(name = "paritydb-experimental")] ParityDbDeprecated, } -impl std::str::FromStr for Database { - type Err = String; - - fn from_str(s: &str) -> Result { - #[cfg(feature = "rocksdb")] - if s.eq_ignore_ascii_case("rocksdb") { - return Ok(Self::RocksDb) - } - if s.eq_ignore_ascii_case("paritydb-experimental") { - return Ok(Self::ParityDbDeprecated) - } else if s.eq_ignore_ascii_case("paritydb") { - return Ok(Self::ParityDb) - } else if s.eq_ignore_ascii_case("auto") { - Ok(Self::Auto) - } else { - Err(format!("Unknown variant `{}`, known variants: {:?}", s, Self::variants())) - } - } -} - impl Database { /// Returns all the variants of this enum to be shown in the cli. pub const fn variants() -> &'static [&'static str] { @@ -284,8 +278,8 @@ impl Database { /// Whether off-chain workers are enabled. #[allow(missing_docs)] -#[derive(Debug, Clone, ArgEnum)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Clone, ValueEnum)] +#[value(rename_all = "kebab-case")] pub enum OffchainWorkerEnabled { /// Always have offchain worker enabled. Always, @@ -296,8 +290,8 @@ pub enum OffchainWorkerEnabled { } /// Syncing mode. -#[derive(Debug, Clone, Copy, ArgEnum, PartialEq)] -#[clap(rename_all = "kebab-case")] +#[derive(Debug, Clone, Copy, ValueEnum, PartialEq)] +#[value(rename_all = "kebab-case")] pub enum SyncMode { /// Full sync. Download end verify all blocks. Full, diff --git a/client/cli/src/commands/build_spec_cmd.rs b/client/cli/src/commands/build_spec_cmd.rs index 3196a3e7b915f..5ab3ce9e88a09 100644 --- a/client/cli/src/commands/build_spec_cmd.rs +++ b/client/cli/src/commands/build_spec_cmd.rs @@ -34,14 +34,14 @@ use std::io::Write; #[derive(Debug, Clone, Parser)] pub struct BuildSpecCmd { /// Force raw genesis storage output. - #[clap(long)] + #[arg(long)] pub raw: bool, /// Disable adding the default bootnode to the specification. /// /// By default the `/ip4/127.0.0.1/tcp/30333/p2p/NODE_PEER_ID` bootnode is added to the /// specification when no bootnode exists. - #[clap(long)] + #[arg(long)] pub disable_default_bootnode: bool, #[allow(missing_docs)] diff --git a/client/cli/src/commands/check_block_cmd.rs b/client/cli/src/commands/check_block_cmd.rs index b7e69b1360a0a..3e25eab2c4350 100644 --- a/client/cli/src/commands/check_block_cmd.rs +++ b/client/cli/src/commands/check_block_cmd.rs @@ -30,13 +30,13 @@ use std::{fmt::Debug, str::FromStr, sync::Arc}; #[derive(Debug, Clone, Parser)] pub struct CheckBlockCmd { /// Block hash or number - #[clap(value_name = "HASH or NUMBER")] + #[arg(value_name = "HASH or NUMBER")] pub input: BlockNumberOrHash, /// The default number of 64KB pages to ever allocate for Wasm execution. /// /// Don't alter this unless you know what you're doing. - #[clap(long, value_name = "COUNT")] + #[arg(long, value_name = "COUNT")] pub default_heap_pages: Option, #[allow(missing_docs)] diff --git a/client/cli/src/commands/export_blocks_cmd.rs b/client/cli/src/commands/export_blocks_cmd.rs index ff35b5a51fcad..e2f83200e511c 100644 --- a/client/cli/src/commands/export_blocks_cmd.rs +++ b/client/cli/src/commands/export_blocks_cmd.rs @@ -32,23 +32,23 @@ use std::{fmt::Debug, fs, io, path::PathBuf, str::FromStr, sync::Arc}; #[derive(Debug, Clone, Parser)] pub struct ExportBlocksCmd { /// Output file name or stdout if unspecified. - #[clap(parse(from_os_str))] + #[arg()] pub output: Option, /// Specify starting block number. /// /// Default is 1. - #[clap(long, value_name = "BLOCK")] + #[arg(long, value_name = "BLOCK")] pub from: Option, /// Specify last block number. /// /// Default is best block. - #[clap(long, value_name = "BLOCK")] + #[arg(long, value_name = "BLOCK")] pub to: Option, /// Use binary output rather than JSON. - #[clap(long)] + #[arg(long)] pub binary: bool, #[allow(missing_docs)] diff --git a/client/cli/src/commands/export_state_cmd.rs b/client/cli/src/commands/export_state_cmd.rs index b76724caf0fef..1bcf21f388a62 100644 --- a/client/cli/src/commands/export_state_cmd.rs +++ b/client/cli/src/commands/export_state_cmd.rs @@ -23,7 +23,7 @@ use crate::{ }; use clap::Parser; use log::info; -use sc_client_api::{StorageProvider, UsageProvider}; +use sc_client_api::{HeaderBackend, StorageProvider, UsageProvider}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use std::{fmt::Debug, io::Write, str::FromStr, sync::Arc}; @@ -32,7 +32,7 @@ use std::{fmt::Debug, io::Write, str::FromStr, sync::Arc}; #[derive(Debug, Clone, Parser)] pub struct ExportStateCmd { /// Block hash or number. - #[clap(value_name = "HASH or NUMBER")] + #[arg(value_name = "HASH or NUMBER")] pub input: Option, #[allow(missing_docs)] @@ -57,7 +57,7 @@ impl ExportStateCmd { ) -> error::Result<()> where B: BlockT, - C: UsageProvider + StorageProvider, + C: UsageProvider + StorageProvider + HeaderBackend, BA: sc_client_api::backend::Backend, B::Hash: FromStr, ::Err: Debug, @@ -65,7 +65,11 @@ impl ExportStateCmd { { info!("Exporting raw state..."); let block_id = self.input.as_ref().map(|b| b.parse()).transpose()?; - let raw_state = sc_service::chain_ops::export_raw_state(client, block_id)?; + let hash = match block_id { + Some(id) => client.expect_block_hash_from_id(&id)?, + None => client.usage_info().chain.best_hash, + }; + let raw_state = sc_service::chain_ops::export_raw_state(client, &hash)?; input_spec.set_storage(raw_state); info!("Generating new chain spec..."); diff --git a/client/cli/src/commands/generate.rs b/client/cli/src/commands/generate.rs index 5b1b708f8669c..461cb98bc2e51 100644 --- a/client/cli/src/commands/generate.rs +++ b/client/cli/src/commands/generate.rs @@ -25,10 +25,10 @@ use clap::Parser; /// The `generate` command #[derive(Debug, Clone, Parser)] -#[clap(name = "generate", about = "Generate a random account")] +#[command(name = "generate", about = "Generate a random account")] pub struct GenerateCmd { /// The number of words in the phrase to generate. One of 12 (default), 15, 18, 21 and 24. - #[clap(short = 'w', long, value_name = "WORDS")] + #[arg(short = 'w', long, value_name = "WORDS")] words: Option, #[allow(missing_docs)] diff --git a/client/cli/src/commands/generate_node_key.rs b/client/cli/src/commands/generate_node_key.rs index 6b2f12531458c..e84b4a71d6d72 100644 --- a/client/cli/src/commands/generate_node_key.rs +++ b/client/cli/src/commands/generate_node_key.rs @@ -28,7 +28,7 @@ use std::{ /// The `generate-node-key` command #[derive(Debug, Parser)] -#[clap( +#[command( name = "generate-node-key", about = "Generate a random node key, write it to a file or stdout \ and write the corresponding peer-id to stderr" @@ -37,13 +37,13 @@ pub struct GenerateNodeKeyCmd { /// Name of file to save secret key to. /// /// If not given, the secret key is printed to stdout. - #[clap(long)] + #[arg(long)] file: Option, /// The output is in raw binary format. /// /// If not given, the output is written as an hex encoded string. - #[clap(long)] + #[arg(long)] bin: bool, } @@ -57,7 +57,7 @@ impl GenerateNodeKeyCmd { let file_data = if self.bin { secret.as_ref().to_owned() } else { - hex::encode(secret.as_ref()).into_bytes() + array_bytes::bytes2hex("", secret.as_ref()).into_bytes() }; match &self.file { @@ -85,6 +85,6 @@ mod tests { assert!(generate.run().is_ok()); let mut buf = String::new(); assert!(file.read_to_string(&mut buf).is_ok()); - assert!(hex::decode(buf).is_ok()); + assert!(array_bytes::hex2bytes(&buf).is_ok()); } } diff --git a/client/cli/src/commands/import_blocks_cmd.rs b/client/cli/src/commands/import_blocks_cmd.rs index 749824834bf7b..debc697242ddd 100644 --- a/client/cli/src/commands/import_blocks_cmd.rs +++ b/client/cli/src/commands/import_blocks_cmd.rs @@ -37,17 +37,17 @@ use std::{ #[derive(Debug, Parser)] pub struct ImportBlocksCmd { /// Input file or stdin if unspecified. - #[clap(parse(from_os_str))] + #[arg()] pub input: Option, /// The default number of 64KB pages to ever allocate for Wasm execution. /// /// Don't alter this unless you know what you're doing. - #[clap(long, value_name = "COUNT")] + #[arg(long, value_name = "COUNT")] pub default_heap_pages: Option, /// Try importing blocks from binary format rather than JSON. - #[clap(long)] + #[arg(long)] pub binary: bool, #[allow(missing_docs)] diff --git a/client/cli/src/commands/insert_key.rs b/client/cli/src/commands/insert_key.rs index 5029ecd29248c..7d66a680df8c0 100644 --- a/client/cli/src/commands/insert_key.rs +++ b/client/cli/src/commands/insert_key.rs @@ -29,16 +29,16 @@ use std::sync::Arc; /// The `insert` command #[derive(Debug, Clone, Parser)] -#[clap(name = "insert", about = "Insert a key to the keystore of a node.")] +#[command(name = "insert", about = "Insert a key to the keystore of a node.")] pub struct InsertKeyCmd { /// The secret key URI. /// If the value is a file, the file content is used as URI. /// If not given, you will be prompted for the URI. - #[clap(long)] + #[arg(long)] suri: Option, /// Key type, examples: "gran", or "imon" - #[clap(long)] + #[arg(long)] key_type: String, #[allow(missing_docs)] @@ -50,7 +50,7 @@ pub struct InsertKeyCmd { pub keystore_params: KeystoreParams, /// The cryptography scheme that should be used to generate the key out of the given URI. - #[clap(long, value_name = "SCHEME", arg_enum, ignore_case = true)] + #[arg(long, value_name = "SCHEME", value_enum, ignore_case = true)] pub scheme: CryptoScheme, } diff --git a/client/cli/src/commands/inspect_key.rs b/client/cli/src/commands/inspect_key.rs index 14bb059503df9..369fd10926dce 100644 --- a/client/cli/src/commands/inspect_key.rs +++ b/client/cli/src/commands/inspect_key.rs @@ -27,7 +27,7 @@ use std::str::FromStr; /// The `inspect` command #[derive(Debug, Parser)] -#[clap( +#[command( name = "inspect", about = "Gets a public key and a SS58 address from the provided Secret URI" )] @@ -44,7 +44,7 @@ pub struct InspectKeyCmd { uri: Option, /// Is the given `uri` a hex encoded public key? - #[clap(long)] + #[arg(long)] public: bool, #[allow(missing_docs)] @@ -72,7 +72,7 @@ pub struct InspectKeyCmd { /// /// If there is no derivation in `--uri`, the public key will be checked against the public key /// of `--uri` directly. - #[clap(long, conflicts_with = "public")] + #[arg(long, conflicts_with = "public")] pub expect_public: Option, } @@ -127,7 +127,7 @@ fn expect_public_from_phrase( ) -> Result<(), Error> { let secret_uri = SecretUri::from_str(suri).map_err(|e| format!("{:?}", e))?; let expected_public = if let Some(public) = expect_public.strip_prefix("0x") { - let hex_public = hex::decode(&public) + let hex_public = array_bytes::hex2bytes(public) .map_err(|_| format!("Invalid expected public key hex: `{}`", expect_public))?; Pair::Public::try_from(&hex_public) .map_err(|_| format!("Invalid expected public key: `{}`", expect_public))? @@ -208,7 +208,7 @@ mod tests { .expect("Valid") .0 .public(); - let valid_public_hex = format!("0x{}", hex::encode(valid_public.as_slice())); + let valid_public_hex = array_bytes::bytes2hex("0x", valid_public.as_slice()); let valid_accountid = format!("{}", valid_public.into_account()); // It should fail with the invalid public key @@ -226,7 +226,7 @@ mod tests { .0 .public(); let valid_public_hex_with_password = - format!("0x{}", hex::encode(&valid_public_with_password.as_slice())); + array_bytes::bytes2hex("0x", valid_public_with_password.as_slice()); let valid_accountid_with_password = format!("{}", &valid_public_with_password.into_account()); @@ -248,7 +248,7 @@ mod tests { .0 .public(); let valid_public_hex_with_password_and_derivation = - format!("0x{}", hex::encode(&valid_public_with_password_and_derivation.as_slice())); + array_bytes::bytes2hex("0x", valid_public_with_password_and_derivation.as_slice()); // They should still be valid, because we check the base secret key. check_cmd(&seed_with_password_and_derivation, &valid_public_hex_with_password, true); diff --git a/client/cli/src/commands/inspect_node_key.rs b/client/cli/src/commands/inspect_node_key.rs index e1617c1d085df..9300007cb6bf2 100644 --- a/client/cli/src/commands/inspect_node_key.rs +++ b/client/cli/src/commands/inspect_node_key.rs @@ -28,7 +28,7 @@ use std::{ /// The `inspect-node-key` command #[derive(Debug, Parser)] -#[clap( +#[command( name = "inspect-node-key", about = "Load a node key from a file or stdin and print the corresponding peer-id." )] @@ -36,18 +36,18 @@ pub struct InspectNodeKeyCmd { /// Name of file to read the secret key from. /// /// If not given, the secret key is read from stdin (up to EOF). - #[clap(long)] + #[arg(long)] file: Option, /// The input is in raw binary format. /// /// If not given, the input is read as an hex encoded string. - #[clap(long)] + #[arg(long)] bin: bool, /// This argument is deprecated and has no effect for this command. #[deprecated(note = "Network identifier is not used for node-key inspection")] - #[clap(short = 'n', long = "network", value_name = "NETWORK", ignore_case = true)] + #[arg(short = 'n', long = "network", value_name = "NETWORK", ignore_case = true)] pub network_scheme: Option, } @@ -66,7 +66,8 @@ impl InspectNodeKeyCmd { if !self.bin { // With hex input, give to the user a bit of tolerance about whitespaces let keyhex = String::from_utf8_lossy(&file_data); - file_data = hex::decode(keyhex.trim()).map_err(|_| "failed to decode secret as hex")?; + file_data = array_bytes::hex2bytes(keyhex.trim()) + .map_err(|_| "failed to decode secret as hex")?; } let secret = diff --git a/client/cli/src/commands/purge_chain_cmd.rs b/client/cli/src/commands/purge_chain_cmd.rs index b89487a18f779..9a3aeee50e944 100644 --- a/client/cli/src/commands/purge_chain_cmd.rs +++ b/client/cli/src/commands/purge_chain_cmd.rs @@ -33,7 +33,7 @@ use std::{ #[derive(Debug, Clone, Parser)] pub struct PurgeChainCmd { /// Skip interactive prompt by answering yes automatically. - #[clap(short = 'y')] + #[arg(short = 'y')] pub yes: bool, #[allow(missing_docs)] diff --git a/client/cli/src/commands/revert_cmd.rs b/client/cli/src/commands/revert_cmd.rs index f65e348b37b89..8477630cf9404 100644 --- a/client/cli/src/commands/revert_cmd.rs +++ b/client/cli/src/commands/revert_cmd.rs @@ -31,7 +31,7 @@ use std::{fmt::Debug, str::FromStr, sync::Arc}; #[derive(Debug, Parser)] pub struct RevertCmd { /// Number of blocks to revert. - #[clap(default_value = "256")] + #[arg(default_value = "256")] pub num: GenericNumber, #[allow(missing_docs)] diff --git a/client/cli/src/commands/run_cmd.rs b/client/cli/src/commands/run_cmd.rs index 11cfb9d0ff651..35181d83f805f 100644 --- a/client/cli/src/commands/run_cmd.rs +++ b/client/cli/src/commands/run_cmd.rs @@ -42,12 +42,12 @@ pub struct RunCmd { /// The node will be started with the authority role and actively /// participate in any consensus task that it can (e.g. depending on /// availability of local keys). - #[clap(long)] + #[arg(long)] pub validator: bool, /// Disable GRANDPA voter when running in validator mode, otherwise disable the GRANDPA /// observer. - #[clap(long)] + #[arg(long)] pub no_grandpa: bool, /// Listen to all RPC interfaces. @@ -56,13 +56,13 @@ pub struct RunCmd { /// proxy server to filter out dangerous methods. More details: /// . /// Use `--unsafe-rpc-external` to suppress the warning if you understand the risks. - #[clap(long)] + #[arg(long)] pub rpc_external: bool, /// Listen to all RPC interfaces. /// /// Same as `--rpc-external`. - #[clap(long)] + #[arg(long)] pub unsafe_rpc_external: bool, /// RPC methods to expose. @@ -71,12 +71,12 @@ pub struct RunCmd { /// - `safe`: Exposes only a safe subset of RPC methods, denying unsafe RPC methods. /// - `auto`: Acts as `safe` if RPC is served externally, e.g. when `--{rpc,ws}-external` is /// passed, otherwise acts as `unsafe`. - #[clap( + #[arg( long, value_name = "METHOD SET", - arg_enum, + value_enum, ignore_case = true, - default_value = "auto", + default_value_t = RpcMethods::Auto, verbatim_doc_comment )] pub rpc_methods: RpcMethods, @@ -87,59 +87,59 @@ pub struct RunCmd { /// proxy server to filter out dangerous methods. More details: /// . /// Use `--unsafe-ws-external` to suppress the warning if you understand the risks. - #[clap(long)] + #[arg(long)] pub ws_external: bool, /// Listen to all Websocket interfaces. /// /// Same as `--ws-external` but doesn't warn you about it. - #[clap(long)] + #[arg(long)] pub unsafe_ws_external: bool, /// DEPRECATED, this has no affect anymore. Use `rpc_max_request_size` or /// `rpc_max_response_size` instead. - #[clap(long)] + #[arg(long)] pub rpc_max_payload: Option, /// Set the the maximum RPC request payload size for both HTTP and WS in megabytes. /// Default is 15MiB. - #[clap(long)] + #[arg(long)] pub rpc_max_request_size: Option, /// Set the the maximum RPC response payload size for both HTTP and WS in megabytes. /// Default is 15MiB. - #[clap(long)] + #[arg(long)] pub rpc_max_response_size: Option, /// Set the the maximum concurrent subscriptions per connection. /// Default is 1024. - #[clap(long)] + #[arg(long)] pub rpc_max_subscriptions_per_connection: Option, /// Expose Prometheus exporter on all interfaces. /// /// Default is local. - #[clap(long)] + #[arg(long)] pub prometheus_external: bool, /// DEPRECATED, IPC support has been removed. - #[clap(long, value_name = "PATH")] + #[arg(long, value_name = "PATH")] pub ipc_path: Option, /// Specify HTTP RPC server TCP port. - #[clap(long, value_name = "PORT")] + #[arg(long, value_name = "PORT")] pub rpc_port: Option, /// Specify WebSockets RPC server TCP port. - #[clap(long, value_name = "PORT")] + #[arg(long, value_name = "PORT")] pub ws_port: Option, /// Maximum number of WS RPC server connections. - #[clap(long, value_name = "COUNT")] + #[arg(long, value_name = "COUNT")] pub ws_max_connections: Option, /// DEPRECATED, this has no affect anymore. Use `rpc_max_response_size` instead. - #[clap(long)] + #[arg(long)] pub ws_max_out_buffer_capacity: Option, /// Specify browser Origins allowed to access the HTTP & WS RPC servers. @@ -148,29 +148,29 @@ pub struct RunCmd { /// value). Value of `all` will disable origin validation. Default is to /// allow localhost and origins. When running in /// --dev mode the default is to allow all origins. - #[clap(long, value_name = "ORIGINS", parse(from_str = parse_cors))] + #[arg(long, value_name = "ORIGINS", value_parser = parse_cors)] pub rpc_cors: Option, /// Specify Prometheus exporter TCP Port. - #[clap(long, value_name = "PORT")] + #[arg(long, value_name = "PORT")] pub prometheus_port: Option, /// Do not expose a Prometheus exporter endpoint. /// /// Prometheus metric endpoint is enabled by default. - #[clap(long)] + #[arg(long)] pub no_prometheus: bool, /// The human-readable name for this node. /// /// The node name will be reported to the telemetry server, if enabled. - #[clap(long, value_name = "NAME")] + #[arg(long, value_name = "NAME")] pub name: Option, /// Disable connecting to the Substrate telemetry server. /// /// Telemetry is on by default on global chains. - #[clap(long)] + #[arg(long)] pub no_telemetry: bool, /// The URL of the telemetry server to connect to. @@ -179,7 +179,7 @@ pub struct RunCmd { /// telemetry endpoints. Verbosity levels range from 0-9, with 0 denoting /// the least verbosity. /// Expected format is 'URL VERBOSITY', e.g. `--telemetry-url 'wss://foo/bar 0'`. - #[clap(long = "telemetry-url", value_name = "URL VERBOSITY", parse(try_from_str = parse_telemetry_endpoints))] + #[arg(long = "telemetry-url", value_name = "URL VERBOSITY", value_parser = parse_telemetry_endpoints)] pub telemetry_endpoints: Vec<(String, u8)>, #[allow(missing_docs)] @@ -203,40 +203,40 @@ pub struct RunCmd { pub pool_config: TransactionPoolParams, /// Shortcut for `--name Alice --validator` with session keys for `Alice` added to keystore. - #[clap(long, conflicts_with_all = &["bob", "charlie", "dave", "eve", "ferdie", "one", "two"])] + #[arg(long, conflicts_with_all = &["bob", "charlie", "dave", "eve", "ferdie", "one", "two"])] pub alice: bool, /// Shortcut for `--name Bob --validator` with session keys for `Bob` added to keystore. - #[clap(long, conflicts_with_all = &["alice", "charlie", "dave", "eve", "ferdie", "one", "two"])] + #[arg(long, conflicts_with_all = &["alice", "charlie", "dave", "eve", "ferdie", "one", "two"])] pub bob: bool, /// Shortcut for `--name Charlie --validator` with session keys for `Charlie` added to /// keystore. - #[clap(long, conflicts_with_all = &["alice", "bob", "dave", "eve", "ferdie", "one", "two"])] + #[arg(long, conflicts_with_all = &["alice", "bob", "dave", "eve", "ferdie", "one", "two"])] pub charlie: bool, /// Shortcut for `--name Dave --validator` with session keys for `Dave` added to keystore. - #[clap(long, conflicts_with_all = &["alice", "bob", "charlie", "eve", "ferdie", "one", "two"])] + #[arg(long, conflicts_with_all = &["alice", "bob", "charlie", "eve", "ferdie", "one", "two"])] pub dave: bool, /// Shortcut for `--name Eve --validator` with session keys for `Eve` added to keystore. - #[clap(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "ferdie", "one", "two"])] + #[arg(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "ferdie", "one", "two"])] pub eve: bool, /// Shortcut for `--name Ferdie --validator` with session keys for `Ferdie` added to keystore. - #[clap(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "one", "two"])] + #[arg(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "one", "two"])] pub ferdie: bool, /// Shortcut for `--name One --validator` with session keys for `One` added to keystore. - #[clap(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "ferdie", "two"])] + #[arg(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "ferdie", "two"])] pub one: bool, /// Shortcut for `--name Two --validator` with session keys for `Two` added to keystore. - #[clap(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "ferdie", "one"])] + #[arg(long, conflicts_with_all = &["alice", "bob", "charlie", "dave", "eve", "ferdie", "one"])] pub two: bool, /// Enable authoring even when offline. - #[clap(long)] + #[arg(long)] pub force_authoring: bool, #[allow(missing_docs)] @@ -246,11 +246,11 @@ pub struct RunCmd { /// The size of the instances cache for each runtime. /// /// The default value is 8 and the values higher than 256 are ignored. - #[clap(long)] + #[arg(long)] pub max_runtime_instances: Option, /// Maximum number of different runtimes that can be cached. - #[clap(long, default_value = "2")] + #[arg(long, default_value_t = 2)] pub runtime_cache_size: u8, /// Run a temporary node. @@ -262,7 +262,7 @@ pub struct RunCmd { /// which includes: database, node key and keystore. /// /// When `--dev` is given and no explicit `--base-path`, this option is implied. - #[clap(long, conflicts_with = "base-path")] + #[arg(long, conflicts_with = "base_path")] pub tmp: bool, } @@ -597,7 +597,7 @@ impl From for Option> { } /// Parse cors origins. -fn parse_cors(s: &str) -> Cors { +fn parse_cors(s: &str) -> Result { let mut is_all = false; let mut origins = Vec::new(); for part in s.split(',') { @@ -611,9 +611,9 @@ fn parse_cors(s: &str) -> Cors { } if is_all { - Cors::All + Ok(Cors::All) } else { - Cors::List(origins) + Ok(Cors::List(origins)) } } diff --git a/client/cli/src/commands/sign.rs b/client/cli/src/commands/sign.rs index e0a5fce353ef4..2c3ff3a1575fd 100644 --- a/client/cli/src/commands/sign.rs +++ b/client/cli/src/commands/sign.rs @@ -23,21 +23,21 @@ use sp_core::crypto::SecretString; /// The `sign` command #[derive(Debug, Clone, Parser)] -#[clap(name = "sign", about = "Sign a message, with a given (secret) key")] +#[command(name = "sign", about = "Sign a message, with a given (secret) key")] pub struct SignCmd { /// The secret key URI. /// If the value is a file, the file content is used as URI. /// If not given, you will be prompted for the URI. - #[clap(long)] + #[arg(long)] suri: Option, /// Message to sign, if not provided you will be prompted to /// pass the message via STDIN - #[clap(long)] + #[arg(long)] message: Option, /// The message on STDIN is hex-encoded data - #[clap(long)] + #[arg(long)] hex: bool, #[allow(missing_docs)] @@ -70,7 +70,7 @@ fn sign( message: Vec, ) -> error::Result { let pair = utils::pair_from_suri::

(suri, password)?; - Ok(hex::encode(pair.sign(&message))) + Ok(array_bytes::bytes2hex("", pair.sign(&message).as_ref())) } #[cfg(test)] diff --git a/client/cli/src/commands/utils.rs b/client/cli/src/commands/utils.rs index 95849065471b4..1ce2b23221691 100644 --- a/client/cli/src/commands/utils.rs +++ b/client/cli/src/commands/utils.rs @@ -203,7 +203,7 @@ where Pair: sp_core::Pair, Pair::Public: Into, { - let public = decode_hex(public_str)?; + let public = array_bytes::hex2bytes(public_str)?; let public_key = Pair::Public::try_from(&public) .map_err(|_| "Failed to construct public key from given hex")?; @@ -273,26 +273,17 @@ where format!("0x{}", HexDisplay::from(&public_key.into().into_account().as_ref())) } -/// helper method for decoding hex -pub fn decode_hex>(message: T) -> Result, Error> { - let mut message = message.as_ref(); - if message[..2] == [b'0', b'x'] { - message = &message[2..] - } - Ok(hex::decode(message)?) -} - /// checks if message is Some, otherwise reads message from stdin and optionally decodes hex pub fn read_message(msg: Option<&String>, should_decode: bool) -> Result, Error> { let mut message = vec![]; match msg { Some(m) => { - message = decode_hex(m)?; + message = array_bytes::hex2bytes(m.as_str())?; }, None => { std::io::stdin().lock().read_to_end(&mut message)?; if should_decode { - message = decode_hex(&message)?; + message = array_bytes::hex2bytes(array_bytes::hex_bytes2hex_str(&message)?)?; } }, } diff --git a/client/cli/src/commands/vanity.rs b/client/cli/src/commands/vanity.rs index 6a1bf77f6c8b0..ae0007ac7964d 100644 --- a/client/cli/src/commands/vanity.rs +++ b/client/cli/src/commands/vanity.rs @@ -29,10 +29,10 @@ use utils::print_from_uri; /// The `vanity` command #[derive(Debug, Clone, Parser)] -#[clap(name = "vanity", about = "Generate a seed that provides a vanity address")] +#[command(name = "vanity", about = "Generate a seed that provides a vanity address")] pub struct VanityCmd { /// Desired pattern - #[clap(long, parse(try_from_str = assert_non_empty_string))] + #[arg(long, value_parser = assert_non_empty_string)] pattern: String, #[allow(missing_docs)] @@ -178,7 +178,7 @@ mod tests { #[test] fn test_generation_with_single_char() { let seed = generate_key::("ab", default_ss58_version()).unwrap(); - assert!(sr25519::Pair::from_seed_slice(&hex::decode(&seed[2..]).unwrap()) + assert!(sr25519::Pair::from_seed_slice(&array_bytes::hex2bytes_unchecked(&seed)) .unwrap() .public() .to_ss58check() @@ -190,7 +190,7 @@ mod tests { let seed = generate_key::("ab", Ss58AddressFormatRegistry::PolkadotAccount.into()) .unwrap(); - assert!(sr25519::Pair::from_seed_slice(&hex::decode(&seed[2..]).unwrap()) + assert!(sr25519::Pair::from_seed_slice(&array_bytes::hex2bytes_unchecked(&seed)) .unwrap() .public() .to_ss58check_with_version(Ss58AddressFormatRegistry::PolkadotAccount.into()) diff --git a/client/cli/src/commands/verify.rs b/client/cli/src/commands/verify.rs index b004a948a7a48..82554fbf268fa 100644 --- a/client/cli/src/commands/verify.rs +++ b/client/cli/src/commands/verify.rs @@ -24,7 +24,7 @@ use sp_core::crypto::{ByteArray, Ss58Codec}; /// The `verify` command #[derive(Debug, Clone, Parser)] -#[clap( +#[command( name = "verify", about = "Verify a signature for a message, provided on STDIN, with a given (public or secret) key" )] @@ -39,11 +39,11 @@ pub struct VerifyCmd { /// Message to verify, if not provided you will be prompted to /// pass the message via STDIN - #[clap(long)] + #[arg(long)] message: Option, /// The message on STDIN is hex-encoded data - #[clap(long)] + #[arg(long)] hex: bool, #[allow(missing_docs)] @@ -55,7 +55,7 @@ impl VerifyCmd { /// Run the command pub fn run(&self) -> error::Result<()> { let message = utils::read_message(self.message.as_ref(), self.hex)?; - let sig_data = utils::decode_hex(&self.sig)?; + let sig_data = array_bytes::hex2bytes(&self.sig)?; let uri = utils::read_uri(self.uri.as_ref())?; let uri = if let Some(uri) = uri.strip_prefix("0x") { uri } else { &uri }; @@ -71,7 +71,7 @@ where let signature = Pair::Signature::try_from(&sig_data).map_err(|_| error::Error::SignatureFormatInvalid)?; - let pubkey = if let Ok(pubkey_vec) = hex::decode(uri) { + let pubkey = if let Ok(pubkey_vec) = array_bytes::hex2bytes(uri) { Pair::Public::from_slice(pubkey_vec.as_slice()) .map_err(|_| error::Error::KeyFormatInvalid)? } else { diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index bc5941914de89..77689708a231f 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -251,11 +251,11 @@ pub trait CliConfiguration: Sized { /// Get the block pruning mode. /// /// By default this is retrieved from `block_pruning` if it is available. Otherwise its - /// `BlocksPruning::All`. + /// `BlocksPruning::KeepFinalized`. fn blocks_pruning(&self) -> Result { self.pruning_params() .map(|x| x.blocks_pruning()) - .unwrap_or_else(|| Ok(BlocksPruning::All)) + .unwrap_or_else(|| Ok(BlocksPruning::KeepFinalized)) } /// Get the chain ID (string). @@ -659,17 +659,6 @@ pub trait CliConfiguration: Sized { } } - if self.import_params().map_or(false, |p| { - #[allow(deprecated)] - p.unsafe_pruning - }) { - // according to https://github.com/substrate/issues/8103; - warn!( - "WARNING: \"--unsafe-pruning\" CLI-flag is deprecated and has no effect. \ - In future builds it will be removed, and providing this flag will lead to an error." - ); - } - Ok(()) } } diff --git a/client/cli/src/error.rs b/client/cli/src/error.rs index f38a95e0115f1..a0f843e73bf53 100644 --- a/client/cli/src/error.rs +++ b/client/cli/src/error.rs @@ -69,8 +69,8 @@ pub enum Error { #[error("Key storage issue encountered")] KeyStorage(#[from] sc_keystore::Error), - #[error("Invalid hexadecimal string data")] - HexDataConversion(#[from] hex::FromHexError), + #[error("Invalid hexadecimal string data, {0:?}")] + HexDataConversion(array_bytes::Error), /// Application specific error chain sequence forwarder. #[error(transparent)] @@ -97,3 +97,9 @@ impl From for Error { Error::InvalidUri(e) } } + +impl From for Error { + fn from(e: array_bytes::Error) -> Error { + Error::HexDataConversion(e) + } +} diff --git a/client/cli/src/lib.rs b/client/cli/src/lib.rs index e01befbef41a2..b6d0d47e52c1f 100644 --- a/client/cli/src/lib.rs +++ b/client/cli/src/lib.rs @@ -129,9 +129,9 @@ pub trait SubstrateCli: Sized { let about = Self::description(); let app = app .name(name) - .author(author.as_str()) - .about(about.as_str()) - .version(full_version.as_str()) + .author(author) + .about(about) + .version(full_version) .propagate_version(true) .args_conflicts_with_subcommands(true) .subcommand_negates_reqs(true); @@ -153,9 +153,9 @@ pub trait SubstrateCli: Sized { /// /// **NOTE:** This method WILL NOT exit when `--help` or `--version` (or short versions) are /// used. It will return a [`clap::Error`], where the [`clap::Error::kind`] is a - /// [`clap::ErrorKind::DisplayHelp`] or [`clap::ErrorKind::DisplayVersion`] respectively. - /// You must call [`clap::Error::exit`] or perform a [`std::process::exit`]. - fn try_from_iter(iter: I) -> clap::Result + /// [`clap::error::ErrorKind::DisplayHelp`] or [`clap::error::ErrorKind::DisplayVersion`] + /// respectively. You must call [`clap::Error::exit`] or perform a [`std::process::exit`]. + fn try_from_iter(iter: I) -> clap::error::Result where Self: Parser + Sized, I: IntoIterator, @@ -169,11 +169,7 @@ pub trait SubstrateCli: Sized { let name = Self::executable_name(); let author = Self::author(); let about = Self::description(); - let app = app - .name(name) - .author(author.as_str()) - .about(about.as_str()) - .version(full_version.as_str()); + let app = app.name(name).author(author).about(about).version(full_version); let matches = app.try_get_matches_from(iter)?; diff --git a/client/cli/src/params/database_params.rs b/client/cli/src/params/database_params.rs index e954b8cc3bc20..3c9ae09e9ab42 100644 --- a/client/cli/src/params/database_params.rs +++ b/client/cli/src/params/database_params.rs @@ -23,17 +23,11 @@ use clap::Args; #[derive(Debug, Clone, PartialEq, Args)] pub struct DatabaseParams { /// Select database backend to use. - #[clap( - long, - alias = "db", - value_name = "DB", - ignore_case = true, - possible_values = Database::variants(), - )] + #[arg(long, alias = "db", value_name = "DB", value_enum)] pub database: Option, /// Limit the memory the database cache can use. - #[clap(long = "db-cache", value_name = "MiB")] + #[arg(long = "db-cache", value_name = "MiB")] pub database_cache_size: Option, } diff --git a/client/cli/src/params/import_params.rs b/client/cli/src/params/import_params.rs index c851050838965..b7ccbf1c8ed55 100644 --- a/client/cli/src/params/import_params.rs +++ b/client/cli/src/params/import_params.rs @@ -41,25 +41,13 @@ pub struct ImportParams { #[clap(flatten)] pub database_params: DatabaseParams, - /// THIS IS A DEPRECATED CLI-ARGUMENT. - /// - /// It has been preserved in order to not break the compatibility with the existing scripts. - /// Enabling this option will lead to a runtime warning. - /// In future this option will be removed completely, thus specifying it will lead to a start - /// up error. - /// - /// Details: - #[clap(long)] - #[deprecated = "According to https://github.com/paritytech/substrate/issues/8103"] - pub unsafe_pruning: bool, - /// Method for executing Wasm runtime code. - #[clap( + #[arg( long = "wasm-execution", value_name = "METHOD", - possible_values = WasmExecutionMethod::variants(), + value_enum, ignore_case = true, - default_value = DEFAULT_WASM_EXECUTION_METHOD, + default_value_t = DEFAULT_WASM_EXECUTION_METHOD, )] pub wasm_method: WasmExecutionMethod, @@ -76,18 +64,18 @@ pub struct ImportParams { /// The `legacy-instance-reuse` strategy is deprecated and will /// be removed in the future. It should only be used in case of /// issues with the default instantiation strategy. - #[clap( + #[arg( long, value_name = "STRATEGY", default_value_t = DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, - arg_enum, + value_enum, )] pub wasmtime_instantiation_strategy: WasmtimeInstantiationStrategy, /// Specify the path where local WASM runtimes are stored. /// /// These runtimes will override on-chain runtimes when the version matches. - #[clap(long, value_name = "PATH", parse(from_os_str))] + #[arg(long, value_name = "PATH")] pub wasm_runtime_overrides: Option, #[allow(missing_docs)] @@ -97,13 +85,13 @@ pub struct ImportParams { /// Specify the state cache size. /// /// Providing `0` will disable the cache. - #[clap(long, value_name = "Bytes", default_value = "67108864")] + #[arg(long, value_name = "Bytes", default_value_t = 67108864)] pub trie_cache_size: usize, /// DEPRECATED /// /// Switch to `--trie-cache-size`. - #[clap(long)] + #[arg(long)] state_cache_size: Option, } @@ -168,39 +156,39 @@ impl ImportParams { pub struct ExecutionStrategiesParams { /// The means of execution used when calling into the runtime for importing blocks as /// part of an initial sync. - #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] + #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)] pub execution_syncing: Option, /// The means of execution used when calling into the runtime for general block import /// (including locally authored blocks). - #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] + #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)] pub execution_import_block: Option, /// The means of execution used when calling into the runtime while constructing blocks. - #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] + #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)] pub execution_block_construction: Option, /// The means of execution used when calling into the runtime while using an off-chain worker. - #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] + #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)] pub execution_offchain_worker: Option, /// The means of execution used when calling into the runtime while not syncing, importing or /// constructing blocks. - #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] + #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)] pub execution_other: Option, /// The execution strategy that should be used by all execution contexts. - #[clap( + #[arg( long, value_name = "STRATEGY", - arg_enum, + value_enum, ignore_case = true, conflicts_with_all = &[ - "execution-other", - "execution-offchain-worker", - "execution-block-construction", - "execution-import-block", - "execution-syncing", + "execution_other", + "execution_offchain_worker", + "execution_block_construction", + "execution_import_block", + "execution_syncing", ] )] pub execution: Option, diff --git a/client/cli/src/params/keystore_params.rs b/client/cli/src/params/keystore_params.rs index 386d1791dd805..d6c3c35d82418 100644 --- a/client/cli/src/params/keystore_params.rs +++ b/client/cli/src/params/keystore_params.rs @@ -32,32 +32,31 @@ const DEFAULT_KEYSTORE_CONFIG_PATH: &str = "keystore"; #[derive(Debug, Clone, Args)] pub struct KeystoreParams { /// Specify custom URIs to connect to for keystore-services - #[clap(long)] + #[arg(long)] pub keystore_uri: Option, /// Specify custom keystore path. - #[clap(long, value_name = "PATH", parse(from_os_str))] + #[arg(long, value_name = "PATH")] pub keystore_path: Option, /// Use interactive shell for entering the password used by the keystore. - #[clap(long, conflicts_with_all = &["password", "password-filename"])] + #[arg(long, conflicts_with_all = &["password", "password_filename"])] pub password_interactive: bool, /// Password used by the keystore. This allows appending an extra user-defined secret to the /// seed. - #[clap( + #[arg( long, - parse(try_from_str = secret_string_from_str), - conflicts_with_all = &["password-interactive", "password-filename"] + value_parser = secret_string_from_str, + conflicts_with_all = &["password_interactive", "password_filename"] )] pub password: Option, /// File that contains the password used by the keystore. - #[clap( + #[arg( long, value_name = "PATH", - parse(from_os_str), - conflicts_with_all = &["password-interactive", "password"] + conflicts_with_all = &["password_interactive", "password"] )] pub password_filename: Option, } diff --git a/client/cli/src/params/mod.rs b/client/cli/src/params/mod.rs index 9fccce606b4e4..3197deb101bcc 100644 --- a/client/cli/src/params/mod.rs +++ b/client/cli/src/params/mod.rs @@ -27,7 +27,7 @@ mod transaction_pool_params; use crate::arg_enums::{CryptoScheme, OutputType}; use clap::Args; -use sp_core::crypto::Ss58AddressFormat; +use sp_core::crypto::{Ss58AddressFormat, Ss58AddressFormatRegistry}; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, NumberFor}, @@ -40,6 +40,17 @@ pub use crate::params::{ transaction_pool_params::*, }; +/// Parse Ss58AddressFormat +pub fn parse_ss58_address_format(x: &str) -> Result { + match Ss58AddressFormatRegistry::try_from(x) { + Ok(format_registry) => Ok(format_registry.into()), + Err(_) => Err(format!( + "Unable to parse variant. Known variants: {:?}", + Ss58AddressFormat::all_names() + )), + } +} + /// Wrapper type of `String` that holds an unsigned integer of arbitrary size, formatted as a /// decimal. #[derive(Debug, Clone)] @@ -118,7 +129,7 @@ impl BlockNumberOrHash { #[derive(Debug, Clone, Args)] pub struct CryptoSchemeFlag { /// cryptography scheme - #[clap(long, value_name = "SCHEME", arg_enum, ignore_case = true, default_value = "sr25519")] + #[arg(long, value_name = "SCHEME", value_enum, ignore_case = true, default_value_t = CryptoScheme::Sr25519)] pub scheme: CryptoScheme, } @@ -126,7 +137,7 @@ pub struct CryptoSchemeFlag { #[derive(Debug, Clone, Args)] pub struct OutputTypeFlag { /// output format - #[clap(long, value_name = "FORMAT", arg_enum, ignore_case = true, default_value = "text")] + #[arg(long, value_name = "FORMAT", value_enum, ignore_case = true, default_value_t = OutputType::Text)] pub output_type: OutputType, } @@ -134,13 +145,12 @@ pub struct OutputTypeFlag { #[derive(Debug, Clone, Args)] pub struct NetworkSchemeFlag { /// network address format - #[clap( + #[arg( short = 'n', long, value_name = "NETWORK", - possible_values = &Ss58AddressFormat::all_names()[..], ignore_case = true, - parse(try_from_str = Ss58AddressFormat::try_from), + value_parser = parse_ss58_address_format, )] pub network: Option, } diff --git a/client/cli/src/params/network_params.rs b/client/cli/src/params/network_params.rs index 74c2db92c3215..5580dea45bde6 100644 --- a/client/cli/src/params/network_params.rs +++ b/client/cli/src/params/network_params.rs @@ -19,11 +19,10 @@ use crate::{arg_enums::SyncMode, params::node_key_params::NodeKeyParams}; use clap::Args; use sc_network::{ - config::{ - NetworkConfiguration, NodeKeyConfig, NonReservedPeerMode, SetConfig, TransportConfig, - }, + config::{NetworkConfiguration, NodeKeyConfig}, multiaddr::Protocol, }; +use sc_network_common::config::{NonReservedPeerMode, SetConfig, TransportConfig}; use sc_service::{ config::{Multiaddr, MultiaddrWithPeerId}, ChainSpec, ChainType, @@ -34,11 +33,11 @@ use std::{borrow::Cow, path::PathBuf}; #[derive(Debug, Clone, Args)] pub struct NetworkParams { /// Specify a list of bootnodes. - #[clap(long, value_name = "ADDR", multiple_values(true))] + #[arg(long, value_name = "ADDR", num_args = 1..)] pub bootnodes: Vec, /// Specify a list of reserved node addresses. - #[clap(long, value_name = "ADDR", multiple_values(true))] + #[arg(long, value_name = "ADDR", num_args = 1..)] pub reserved_nodes: Vec, /// Whether to only synchronize the chain with reserved nodes. @@ -49,12 +48,12 @@ pub struct NetworkParams { /// In particular, if you are a validator your node might still connect to other /// validator nodes and collator nodes regardless of whether they are defined as /// reserved nodes. - #[clap(long)] + #[arg(long)] pub reserved_only: bool, /// The public address that other nodes will use to connect to it. /// This can be used if there's a proxy in front of this node. - #[clap(long, value_name = "PUBLIC_ADDR", multiple_values(true))] + #[arg(long, value_name = "PUBLIC_ADDR", num_args = 1..)] pub public_addr: Vec, /// Listen on this multiaddress. @@ -62,49 +61,50 @@ pub struct NetworkParams { /// By default: /// If `--validator` is passed: `/ip4/0.0.0.0/tcp/` and `/ip6/[::]/tcp/`. /// Otherwise: `/ip4/0.0.0.0/tcp//ws` and `/ip6/[::]/tcp//ws`. - #[clap(long, value_name = "LISTEN_ADDR", multiple_values(true))] + #[arg(long, value_name = "LISTEN_ADDR", num_args = 1..)] pub listen_addr: Vec, /// Specify p2p protocol TCP port. - #[clap(long, value_name = "PORT", conflicts_with_all = &[ "listen-addr" ])] + #[arg(long, value_name = "PORT", conflicts_with_all = &[ "listen_addr" ])] pub port: Option, /// Always forbid connecting to private IPv4 addresses (as specified in /// [RFC1918](https://tools.ietf.org/html/rfc1918)), unless the address was passed with /// `--reserved-nodes` or `--bootnodes`. Enabled by default for chains marked as "live" in /// their chain specifications. - #[clap(long, conflicts_with_all = &["allow-private-ipv4"])] + #[arg(long, conflicts_with_all = &["allow_private_ipv4"])] pub no_private_ipv4: bool, /// Always accept connecting to private IPv4 addresses (as specified in /// [RFC1918](https://tools.ietf.org/html/rfc1918)). Enabled by default for chains marked as /// "local" in their chain specifications, or when `--dev` is passed. - #[clap(long, conflicts_with_all = &["no-private-ipv4"])] + #[arg(long, conflicts_with_all = &["no_private_ipv4"])] pub allow_private_ipv4: bool, /// Specify the number of outgoing connections we're trying to maintain. - #[clap(long, value_name = "COUNT", default_value = "25")] + #[arg(long, value_name = "COUNT", default_value_t = 15)] pub out_peers: u32, /// Maximum number of inbound full nodes peers. - #[clap(long, value_name = "COUNT", default_value = "25")] + #[arg(long, value_name = "COUNT", default_value_t = 25)] pub in_peers: u32, + /// Maximum number of inbound light nodes peers. - #[clap(long, value_name = "COUNT", default_value = "100")] + #[arg(long, value_name = "COUNT", default_value_t = 100)] pub in_peers_light: u32, /// Disable mDNS discovery. /// /// By default, the network will use mDNS to discover other nodes on the /// local network. This disables it. Automatically implied when using --dev. - #[clap(long)] + #[arg(long)] pub no_mdns: bool, /// Maximum number of peers from which to ask for the same blocks in parallel. /// /// This allows downloading announced blocks from multiple peers. Decrease to save /// traffic and risk increased latency. - #[clap(long, value_name = "COUNT", default_value = "5")] + #[arg(long, value_name = "COUNT", default_value_t = 5)] pub max_parallel_downloads: u32, #[allow(missing_docs)] @@ -115,7 +115,7 @@ pub struct NetworkParams { /// /// By default this option is `true` for `--dev` or when the chain type is /// `Local`/`Development` and false otherwise. - #[clap(long)] + #[arg(long)] pub discover_local: bool, /// Require iterative Kademlia DHT queries to use disjoint paths for increased resiliency in @@ -123,11 +123,11 @@ pub struct NetworkParams { /// /// See the S/Kademlia paper for more information on the high level design as well as its /// security improvements. - #[clap(long)] + #[arg(long)] pub kademlia_disjoint_query_paths: bool, /// Join the IPFS network and serve transactions over bitswap protocol. - #[clap(long)] + #[arg(long)] pub ipfs_server: bool, /// Blockchain syncing mode. @@ -136,11 +136,11 @@ pub struct NetworkParams { /// - `fast`: Download blocks and the latest state only. /// - `fast-unsafe`: Same as `fast`, but skip downloading state proofs. /// - `warp`: Download the latest state and proof. - #[clap( + #[arg( long, - arg_enum, + value_enum, value_name = "SYNC_MODE", - default_value = "full", + default_value_t = SyncMode::Full, ignore_case = true, verbatim_doc_comment )] diff --git a/client/cli/src/params/node_key_params.rs b/client/cli/src/params/node_key_params.rs index d51b6143ed393..2346455c26a37 100644 --- a/client/cli/src/params/node_key_params.rs +++ b/client/cli/src/params/node_key_params.rs @@ -46,7 +46,7 @@ pub struct NodeKeyParams { /// WARNING: Secrets provided as command-line arguments are easily exposed. /// Use of this option should be limited to development and testing. To use /// an externally managed secret key, use `--node-key-file` instead. - #[clap(long, value_name = "KEY")] + #[arg(long, value_name = "KEY")] pub node_key: Option, /// The type of secret key to use for libp2p networking. @@ -66,7 +66,7 @@ pub struct NodeKeyParams { /// /// The node's secret key determines the corresponding public key and hence the /// node's peer ID in the context of libp2p. - #[clap(long, value_name = "TYPE", arg_enum, ignore_case = true, default_value = "ed25519")] + #[arg(long, value_name = "TYPE", value_enum, ignore_case = true, default_value_t = NodeKeyType::Ed25519)] pub node_key_type: NodeKeyType, /// The file from which to read the node's secret key to use for libp2p networking. @@ -79,7 +79,7 @@ pub struct NodeKeyParams { /// /// If the file does not exist, it is created with a newly generated secret key of /// the chosen type. - #[clap(long, value_name = "FILE")] + #[arg(long, value_name = "FILE")] pub node_key_file: Option, } @@ -122,7 +122,7 @@ fn parse_ed25519_secret(hex: &str) -> error::Result, - /// Specify the number of finalized blocks to keep in the database. + /// Specify the blocks pruning mode, a number of blocks to keep or 'archive'. /// - /// Default is to keep all blocks. + /// Default is to keep all finalized blocks. + /// otherwise, all blocks can be kept (i.e 'archive'), + /// or for all canonical blocks (i.e 'archive-canonical'), + /// or for the last N blocks (i.e a number). /// /// NOTE: only finalized blocks are subject for removal! - #[clap(alias = "keep-blocks", long, value_name = "COUNT")] - pub blocks_pruning: Option, + #[arg(alias = "keep-blocks", long, value_name = "COUNT")] + pub blocks_pruning: Option, } impl PruningParams { @@ -46,9 +49,12 @@ impl PruningParams { .as_ref() .map(|s| match s.as_str() { "archive" => Ok(PruningMode::ArchiveAll), + "archive-canonical" => Ok(PruningMode::ArchiveCanonical), bc => bc .parse() - .map_err(|_| error::Error::Input("Invalid pruning mode specified".to_string())) + .map_err(|_| { + error::Error::Input("Invalid state pruning mode specified".to_string()) + }) .map(PruningMode::blocks_pruning), }) .transpose() @@ -56,9 +62,18 @@ impl PruningParams { /// Get the block pruning value from the parameters pub fn blocks_pruning(&self) -> error::Result { - Ok(match self.blocks_pruning { - Some(n) => BlocksPruning::Some(n), - None => BlocksPruning::All, - }) + match self.blocks_pruning.as_ref() { + Some(bp) => match bp.as_str() { + "archive" => Ok(BlocksPruning::KeepAll), + "archive-canonical" => Ok(BlocksPruning::KeepFinalized), + bc => bc + .parse() + .map_err(|_| { + error::Error::Input("Invalid blocks pruning mode specified".to_string()) + }) + .map(BlocksPruning::Some), + }, + None => Ok(BlocksPruning::KeepFinalized), + } } } diff --git a/client/cli/src/params/shared_params.rs b/client/cli/src/params/shared_params.rs index 4a8fc4bcfffdd..6c03ac2c4ec23 100644 --- a/client/cli/src/params/shared_params.rs +++ b/client/cli/src/params/shared_params.rs @@ -28,25 +28,25 @@ pub struct SharedParams { /// /// It can be one of the predefined ones (dev, local, or staging) or it can be a path to a file /// with the chainspec (such as one exported by the `build-spec` subcommand). - #[clap(long, value_name = "CHAIN_SPEC")] + #[arg(long, value_name = "CHAIN_SPEC")] pub chain: Option, /// Specify the development chain. /// /// This flag sets `--chain=dev`, `--force-authoring`, `--rpc-cors=all`, /// `--alice`, and `--tmp` flags, unless explicitly overridden. - #[clap(long, conflicts_with_all = &["chain"])] + #[arg(long, conflicts_with_all = &["chain"])] pub dev: bool, /// Specify custom base path. - #[clap(long, short = 'd', value_name = "PATH", parse(from_os_str))] + #[arg(long, short = 'd', value_name = "PATH")] pub base_path: Option, /// Sets a custom logging filter. Syntax is =, e.g. -lsync=debug. /// /// Log levels (least to most verbose) are error, warn, info, debug, and trace. /// By default, all targets log `info`. The global log level can be set with -l. - #[clap(short = 'l', long, value_name = "LOG_PATTERN", multiple_values(true))] + #[arg(short = 'l', long, value_name = "LOG_PATTERN", num_args = 1..)] pub log: Vec, /// Enable detailed log output. @@ -54,11 +54,11 @@ pub struct SharedParams { /// This includes displaying the log target, log level and thread name. /// /// This is automatically enabled when something is logged with any higher level than `info`. - #[clap(long)] + #[arg(long)] pub detailed_log_output: bool, /// Disable log color output. - #[clap(long)] + #[arg(long)] pub disable_log_color: bool, /// Enable feature to dynamically update and reload the log filter. @@ -68,15 +68,15 @@ pub struct SharedParams { /// /// The `system_addLogFilter` and `system_resetLogFilter` RPCs will have no effect with this /// option not being set. - #[clap(long)] + #[arg(long)] pub enable_log_reloading: bool, /// Sets a custom profiling filter. Syntax is the same as for logging: = - #[clap(long, value_name = "TARGETS")] + #[arg(long, value_name = "TARGETS")] pub tracing_targets: Option, /// Receiver to process tracing messages. - #[clap(long, value_name = "RECEIVER", arg_enum, ignore_case = true, default_value = "log")] + #[arg(long, value_name = "RECEIVER", value_enum, ignore_case = true, default_value_t = TracingReceiver::Log)] pub tracing_receiver: TracingReceiver, } diff --git a/client/cli/src/params/transaction_pool_params.rs b/client/cli/src/params/transaction_pool_params.rs index 6429dfec3f908..6b3a2d8a97a01 100644 --- a/client/cli/src/params/transaction_pool_params.rs +++ b/client/cli/src/params/transaction_pool_params.rs @@ -23,15 +23,15 @@ use sc_service::config::TransactionPoolOptions; #[derive(Debug, Clone, Args)] pub struct TransactionPoolParams { /// Maximum number of transactions in the transaction pool. - #[clap(long, value_name = "COUNT", default_value = "8192")] + #[arg(long, value_name = "COUNT", default_value_t = 8192)] pub pool_limit: usize, /// Maximum number of kilobytes of all transactions stored in the pool. - #[clap(long, value_name = "COUNT", default_value = "20480")] + #[arg(long, value_name = "COUNT", default_value_t = 20480)] pub pool_kbytes: usize, /// How long a transaction is banned for, if it is considered invalid. Defaults to 1800s. - #[clap(long, value_name = "SECONDS")] + #[arg(long, value_name = "SECONDS")] pub tx_ban_seconds: Option, } diff --git a/client/consensus/aura/src/import_queue.rs b/client/consensus/aura/src/import_queue.rs index 30554006732c0..90f15fef1b34b 100644 --- a/client/consensus/aura/src/import_queue.rs +++ b/client/consensus/aura/src/import_queue.rs @@ -35,7 +35,7 @@ use sp_blockchain::{ well_known_cache_keys::{self, Id as CacheKeyId}, HeaderBackend, }; -use sp_consensus::{CanAuthorWith, Error as ConsensusError}; +use sp_consensus::Error as ConsensusError; use sp_consensus_aura::{ digests::CompatibleDigestItem, inherents::AuraInherentData, AuraApi, ConsensusLog, AURA_ENGINE_ID, @@ -109,27 +109,24 @@ where } /// A verifier for Aura blocks. -pub struct AuraVerifier { +pub struct AuraVerifier { client: Arc, phantom: PhantomData

, create_inherent_data_providers: CIDP, - can_author_with: CAW, check_for_equivocation: CheckForEquivocation, telemetry: Option, } -impl AuraVerifier { +impl AuraVerifier { pub(crate) fn new( client: Arc, create_inherent_data_providers: CIDP, - can_author_with: CAW, check_for_equivocation: CheckForEquivocation, telemetry: Option, ) -> Self { Self { client, create_inherent_data_providers, - can_author_with, check_for_equivocation, telemetry, phantom: PhantomData, @@ -137,10 +134,9 @@ impl AuraVerifier { } } -impl AuraVerifier +impl AuraVerifier where P: Send + Sync + 'static, - CAW: Send + Sync + 'static, CIDP: Send, { async fn check_inherents( @@ -154,19 +150,8 @@ where where C: ProvideRuntimeApi, C::Api: BlockBuilderApi, - CAW: CanAuthorWith, CIDP: CreateInherentDataProviders, { - if let Err(e) = self.can_author_with.can_author_with(&block_id) { - debug!( - target: "aura", - "Skipping `check_inherents` as authoring version is not compatible: {}", - e, - ); - - return Ok(()) - } - let inherent_res = self .client .runtime_api() @@ -187,14 +172,13 @@ where } #[async_trait::async_trait] -impl Verifier for AuraVerifier +impl Verifier for AuraVerifier where C: ProvideRuntimeApi + Send + Sync + sc_client_api::backend::AuxStore + BlockOf, C::Api: BlockBuilderApi + AuraApi> + ApiExt, P: Pair + Send + Sync + 'static, P::Public: Send + Sync + Hash + Eq + Clone + Decode + Encode + Debug + 'static, P::Signature: Encode + Decode, - CAW: CanAuthorWith + Send + Sync + 'static, CIDP: CreateInherentDataProviders + Send + Sync, CIDP::InherentDataProviders: InherentDataProviderExt + Send + Sync, { @@ -241,15 +225,16 @@ where inherent_data.aura_replace_inherent_data(slot); - // skip the inherents verification if the runtime API is old. - if self - .client - .runtime_api() - .has_api_with::, _>( - &BlockId::Hash(parent_hash), - |v| v >= 2, - ) - .map_err(|e| e.to_string())? + // skip the inherents verification if the runtime API is old or not expected to + // exist. + if !block.state_action.skip_execution_checks() && + self.client + .runtime_api() + .has_api_with::, _>( + &BlockId::Hash(parent_hash), + |v| v >= 2, + ) + .map_err(|e| e.to_string())? { self.check_inherents( new_block.clone(), @@ -338,7 +323,7 @@ impl Default for CheckForEquivocation { } /// Parameters of [`import_queue`]. -pub struct ImportQueueParams<'a, Block, I, C, S, CAW, CIDP> { +pub struct ImportQueueParams<'a, Block, I, C, S, CIDP> { /// The block import to use. pub block_import: I, /// The justification import. @@ -351,8 +336,6 @@ pub struct ImportQueueParams<'a, Block, I, C, S, CAW, CIDP> { pub spawner: &'a S, /// The prometheus registry. pub registry: Option<&'a Registry>, - /// Can we author with the current node? - pub can_author_with: CAW, /// Should we check for equivocation? pub check_for_equivocation: CheckForEquivocation, /// Telemetry instance used to report telemetry metrics. @@ -360,7 +343,7 @@ pub struct ImportQueueParams<'a, Block, I, C, S, CAW, CIDP> { } /// Start an import queue for the Aura consensus algorithm. -pub fn import_queue( +pub fn import_queue( ImportQueueParams { block_import, justification_import, @@ -368,10 +351,9 @@ pub fn import_queue( create_inherent_data_providers, spawner, registry, - can_author_with, check_for_equivocation, telemetry, - }: ImportQueueParams, + }: ImportQueueParams, ) -> Result, sp_consensus::Error> where Block: BlockT, @@ -392,14 +374,12 @@ where P::Public: Clone + Eq + Send + Sync + Hash + Debug + Encode + Decode, P::Signature: Encode + Decode, S: sp_core::traits::SpawnEssentialNamed, - CAW: CanAuthorWith + Send + Sync + 'static, CIDP: CreateInherentDataProviders + Sync + Send + 'static, CIDP::InherentDataProviders: InherentDataProviderExt + Send + Sync, { - let verifier = build_verifier::(BuildVerifierParams { + let verifier = build_verifier::(BuildVerifierParams { client, create_inherent_data_providers, - can_author_with, check_for_equivocation, telemetry, }); @@ -408,13 +388,11 @@ where } /// Parameters of [`build_verifier`]. -pub struct BuildVerifierParams { +pub struct BuildVerifierParams { /// The client to interact with the chain. pub client: Arc, /// Something that can create the inherent data providers. pub create_inherent_data_providers: CIDP, - /// Can we author with the current node? - pub can_author_with: CAW, /// Should we check for equivocation? pub check_for_equivocation: CheckForEquivocation, /// Telemetry instance used to report telemetry metrics. @@ -422,19 +400,17 @@ pub struct BuildVerifierParams { } /// Build the [`AuraVerifier`] -pub fn build_verifier( +pub fn build_verifier( BuildVerifierParams { client, create_inherent_data_providers, - can_author_with, check_for_equivocation, telemetry, - }: BuildVerifierParams, -) -> AuraVerifier { - AuraVerifier::<_, P, _, _>::new( + }: BuildVerifierParams, +) -> AuraVerifier { + AuraVerifier::<_, P, _>::new( client, create_inherent_data_providers, - can_author_with, check_for_equivocation, telemetry, ) diff --git a/client/consensus/aura/src/lib.rs b/client/consensus/aura/src/lib.rs index b29ecf8fef57a..76419f8488e61 100644 --- a/client/consensus/aura/src/lib.rs +++ b/client/consensus/aura/src/lib.rs @@ -47,9 +47,7 @@ use sc_telemetry::TelemetryHandle; use sp_api::ProvideRuntimeApi; use sp_application_crypto::{AppKey, AppPublic}; use sp_blockchain::{HeaderBackend, Result as CResult}; -use sp_consensus::{ - BlockOrigin, CanAuthorWith, Environment, Error as ConsensusError, Proposer, SelectChain, -}; +use sp_consensus::{BlockOrigin, Environment, Error as ConsensusError, Proposer, SelectChain}; use sp_consensus_slots::Slot; use sp_core::crypto::{ByteArray, Pair, Public}; use sp_inherents::CreateInherentDataProviders; @@ -108,7 +106,7 @@ fn slot_author(slot: Slot, authorities: &[AuthorityId

]) -> Option<&A } /// Parameters of [`start_aura`]. -pub struct StartAuraParams { +pub struct StartAuraParams { /// The duration of a slot. pub slot_duration: SlotDuration, /// The client to interact with the chain. @@ -131,8 +129,6 @@ pub struct StartAuraParams { pub backoff_authoring_blocks: Option, /// The keystore used by the node. pub keystore: SyncCryptoStorePtr, - /// Can we author a block with this node? - pub can_author_with: CAW, /// The proportion of the slot dedicated to proposing. /// /// The block proposing will be limited to this proportion of the slot from the starting of the @@ -147,7 +143,7 @@ pub struct StartAuraParams { } /// Start the aura worker. The returned future should be run in a futures executor. -pub fn start_aura( +pub fn start_aura( StartAuraParams { slot_duration, client, @@ -160,11 +156,10 @@ pub fn start_aura( force_authoring, backoff_authoring_blocks, keystore, - can_author_with, block_proposal_slot_portion, max_block_proposal_slot_portion, telemetry, - }: StartAuraParams, + }: StartAuraParams, ) -> Result, sp_consensus::Error> where P: Pair + Send + Sync, @@ -182,7 +177,6 @@ where CIDP: CreateInherentDataProviders + Send, CIDP::InherentDataProviders: InherentDataProviderExt + Send, BS: BackoffAuthoringBlocksStrategy> + Send + Sync + 'static, - CAW: CanAuthorWith + Send, Error: std::error::Error + Send + From + 'static, { let worker = build_aura_worker::(BuildAuraWorkerParams { @@ -205,7 +199,6 @@ where SimpleSlotWorkerToSlotWorker(worker), sync_oracle, create_inherent_data_providers, - can_author_with, )) } @@ -264,7 +257,7 @@ pub fn build_aura_worker( SyncOracle = SO, JustificationSyncLink = L, Claim = P::Public, - EpochData = Vec>, + AuxData = Vec>, > where B: BlockT, @@ -337,7 +330,7 @@ where Pin> + Send + 'static>>; type Proposer = E::Proposer; type Claim = P::Public; - type EpochData = Vec>; + type AuxData = Vec>; fn logging_target(&self) -> &'static str { "aura" @@ -347,15 +340,15 @@ where &mut self.block_import } - fn epoch_data( + fn aux_data( &self, header: &B::Header, _slot: Slot, - ) -> Result { + ) -> Result { authorities(self.client.as_ref(), &BlockId::Hash(header.hash())) } - fn authorities_len(&self, epoch_data: &Self::EpochData) -> Option { + fn authorities_len(&self, epoch_data: &Self::AuxData) -> Option { Some(epoch_data.len()) } @@ -363,7 +356,7 @@ where &self, _header: &B::Header, slot: Slot, - epoch_data: &Self::EpochData, + epoch_data: &Self::AuxData, ) -> Option { let expected_author = slot_author::

(slot, epoch_data); expected_author.and_then(|p| { @@ -389,7 +382,7 @@ where body: Vec, storage_changes: StorageChanges<>::Transaction, B>, public: Self::Claim, - _epoch: Self::EpochData, + _epoch: Self::AuxData, ) -> Result< sc_consensus::BlockImportParams>::Transaction>, sp_consensus::Error, @@ -576,9 +569,7 @@ mod tests { use sc_keystore::LocalKeystore; use sc_network_test::{Block as TestBlock, *}; use sp_application_crypto::key_types::AURA; - use sp_consensus::{ - AlwaysCanAuthor, DisableProofRecording, NoNetwork as DummyOracle, Proposal, - }; + use sp_consensus::{DisableProofRecording, NoNetwork as DummyOracle, Proposal}; use sp_consensus_aura::sr25519::AuthorityPair; use sp_inherents::InherentData; use sp_keyring::sr25519::Keyring; @@ -586,7 +577,7 @@ mod tests { traits::{Block as BlockT, Header as _}, Digest, }; - use sp_timestamp::InherentDataProvider as TimestampInherentDataProvider; + use sp_timestamp::Timestamp; use std::{ task::Poll, time::{Duration, Instant}, @@ -596,6 +587,8 @@ mod tests { TestClient, }; + const SLOT_DURATION_MS: u64 = 1000; + type Error = sp_blockchain::Error; struct DummyFactory(Arc); @@ -636,17 +629,14 @@ mod tests { } } - const SLOT_DURATION: u64 = 1000; - type AuraVerifier = import_queue::AuraVerifier< PeersFullClient, AuthorityPair, - AlwaysCanAuthor, Box< dyn CreateInherentDataProviders< TestBlock, (), - InherentDataProviders = (TimestampInherentDataProvider, InherentDataProvider), + InherentDataProviders = (InherentDataProvider,), >, >, >; @@ -666,19 +656,16 @@ mod tests { let client = client.as_client(); let slot_duration = slot_duration(&*client).expect("slot duration available"); - assert_eq!(slot_duration.as_millis() as u64, SLOT_DURATION); + assert_eq!(slot_duration.as_millis() as u64, SLOT_DURATION_MS); import_queue::AuraVerifier::new( client, Box::new(|_, _| async { - let timestamp = TimestampInherentDataProvider::from_system_time(); let slot = InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - SlotDuration::from_millis(6000), + Timestamp::current(), + SlotDuration::from_millis(SLOT_DURATION_MS), ); - - Ok((timestamp, slot)) + Ok((slot,)) }), - AlwaysCanAuthor, CheckForEquivocation::Yes, None, ) @@ -746,7 +733,7 @@ mod tests { let slot_duration = slot_duration(&*client).expect("slot duration available"); aura_futures.push( - start_aura::(StartAuraParams { + start_aura::(StartAuraParams { slot_duration, block_import: client.clone(), select_chain, @@ -755,20 +742,18 @@ mod tests { sync_oracle: DummyOracle, justification_sync_link: (), create_inherent_data_providers: |_, _| async { - let timestamp = TimestampInherentDataProvider::from_system_time(); let slot = InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - SlotDuration::from_millis(12000), + Timestamp::current(), + SlotDuration::from_millis(SLOT_DURATION_MS), ); - Ok((timestamp, slot)) + Ok((slot,)) }, force_authoring: false, backoff_authoring_blocks: Some( BackoffAuthoringOnFinalizedHeadLagging::default(), ), keystore, - can_author_with: sp_consensus::AlwaysCanAuthor, block_proposal_slot_portion: SlotProportion::new(0.5), max_block_proposal_slot_portion: None, telemetry: None, @@ -792,7 +777,7 @@ mod tests { assert_eq!(client.chain_info().best_number, 0); assert_eq!( - authorities(&client, &BlockId::Number(0)).unwrap(), + authorities(&client, &BlockId::Hash(client.chain_info().best_hash)).unwrap(), vec![ Keyring::Alice.public().into(), Keyring::Bob.public().into(), @@ -895,7 +880,6 @@ mod tests { let res = executor::block_on(worker.on_slot(SlotInfo { slot: 0.into(), - timestamp: 0.into(), ends_at: Instant::now() + Duration::from_secs(100), inherent_data: InherentData::new(), duration: Duration::from_millis(1000), diff --git a/client/consensus/babe/src/lib.rs b/client/consensus/babe/src/lib.rs index 24dd519c38ea6..7045518c1f1ca 100644 --- a/client/consensus/babe/src/lib.rs +++ b/client/consensus/babe/src/lib.rs @@ -67,7 +67,6 @@ #![warn(missing_docs)] use std::{ - borrow::Cow, collections::{HashMap, HashSet}, future::Future, pin::Pin, @@ -115,8 +114,7 @@ use sp_blockchain::{ Backend as _, Error as ClientError, HeaderBackend, HeaderMetadata, Result as ClientResult, }; use sp_consensus::{ - BlockOrigin, CacheKeyId, CanAuthorWith, Environment, Error as ConsensusError, Proposer, - SelectChain, + BlockOrigin, CacheKeyId, Environment, Error as ConsensusError, Proposer, SelectChain, }; use sp_consensus_babe::inherents::BabeInherentData; use sp_consensus_slots::Slot; @@ -370,7 +368,7 @@ where } /// Parameters for BABE. -pub struct BabeParams { +pub struct BabeParams { /// The keystore that manages the keys of the node. pub keystore: SyncCryptoStorePtr, @@ -406,9 +404,6 @@ pub struct BabeParams { /// The source of timestamps for relative slots pub babe_link: BabeLink, - /// Checks if the current native implementation can author with a runtime at a given block. - pub can_author_with: CAW, - /// The proportion of the slot dedicated to proposing. /// /// The block proposing will be limited to this proportion of the slot from the starting of the @@ -425,7 +420,7 @@ pub struct BabeParams { } /// Start the babe worker. -pub fn start_babe( +pub fn start_babe( BabeParams { keystore, client, @@ -438,11 +433,10 @@ pub fn start_babe( force_authoring, backoff_authoring_blocks, babe_link, - can_author_with, block_proposal_slot_portion, max_block_proposal_slot_portion, telemetry, - }: BabeParams, + }: BabeParams, ) -> Result, sp_consensus::Error> where B: BlockT, @@ -468,7 +462,6 @@ where CIDP: CreateInherentDataProviders + Send + Sync + 'static, CIDP::InherentDataProviders: InherentDataProviderExt + Send, BS: BackoffAuthoringBlocksStrategy> + Send + Sync + 'static, - CAW: CanAuthorWith + Send + Sync + 'static, Error: std::error::Error + Send + From + From + 'static, { const HANDLE_BUFFER_SIZE: usize = 1024; @@ -500,7 +493,6 @@ where sc_consensus_slots::SimpleSlotWorkerToSlotWorker(worker), sync_oracle, create_inherent_data_providers, - can_author_with, ); let (worker_tx, worker_rx) = channel(HANDLE_BUFFER_SIZE); @@ -737,7 +729,6 @@ where BS: BackoffAuthoringBlocksStrategy> + Sync, Error: std::error::Error + Send + From + From + 'static, { - type EpochData = ViableEpochDescriptor, Epoch>; type Claim = (PreDigest, AuthorityId); type SyncOracle = SO; type JustificationSyncLink = L; @@ -745,6 +736,7 @@ where Pin> + Send + 'static>>; type Proposer = E::Proposer; type BlockImport = I; + type AuxData = ViableEpochDescriptor, Epoch>; fn logging_target(&self) -> &'static str { "babe" @@ -754,11 +746,7 @@ where &mut self.block_import } - fn epoch_data( - &self, - parent: &B::Header, - slot: Slot, - ) -> Result { + fn aux_data(&self, parent: &B::Header, slot: Slot) -> Result { self.epoch_changes .shared_data() .epoch_descriptor_for_child_of( @@ -771,7 +759,7 @@ where .ok_or(sp_consensus::Error::InvalidAuthoritiesSet) } - fn authorities_len(&self, epoch_descriptor: &Self::EpochData) -> Option { + fn authorities_len(&self, epoch_descriptor: &Self::AuxData) -> Option { self.epoch_changes .shared_data() .viable_epoch(epoch_descriptor, |slot| Epoch::genesis(&self.config, slot)) @@ -831,7 +819,7 @@ where body: Vec, storage_changes: StorageChanges<>::Transaction, B>, (_, public): Self::Claim, - epoch_descriptor: Self::EpochData, + epoch_descriptor: Self::AuxData, ) -> Result< sc_consensus::BlockImportParams>::Transaction>, sp_consensus::Error, @@ -864,10 +852,8 @@ where import_block.body = Some(body); import_block.state_action = StateAction::ApplyChanges(sc_consensus::StorageChanges::Changes(storage_changes)); - import_block.intermediates.insert( - Cow::from(INTERMEDIATE_KEY), - Box::new(BabeIntermediate:: { epoch_descriptor }) as Box<_>, - ); + import_block + .insert_intermediate(INTERMEDIATE_KEY, BabeIntermediate:: { epoch_descriptor }); Ok(import_block) } @@ -1017,23 +1003,21 @@ impl BabeLink { } /// A verifier for Babe blocks. -pub struct BabeVerifier { +pub struct BabeVerifier { client: Arc, select_chain: SelectChain, create_inherent_data_providers: CIDP, config: BabeConfiguration, epoch_changes: SharedEpochChanges, - can_author_with: CAW, telemetry: Option, } -impl BabeVerifier +impl BabeVerifier where Block: BlockT, Client: AuxStore + HeaderBackend + HeaderMetadata + ProvideRuntimeApi, Client::Api: BlockBuilderApi + BabeApi, SelectChain: sp_consensus::SelectChain, - CAW: CanAuthorWith, CIDP: CreateInherentDataProviders, { async fn check_inherents( @@ -1044,16 +1028,6 @@ where create_inherent_data_providers: CIDP::InherentDataProviders, execution_context: ExecutionContext, ) -> Result<(), Error> { - if let Err(e) = self.can_author_with.can_author_with(&block_id) { - debug!( - target: "babe", - "Skipping `check_inherents` as authoring version is not compatible: {}", - e, - ); - - return Ok(()) - } - let inherent_res = self .client .runtime_api() @@ -1158,8 +1132,8 @@ type BlockVerificationResult = Result<(BlockImportParams, Option)>>), String>; #[async_trait::async_trait] -impl Verifier - for BabeVerifier +impl Verifier + for BabeVerifier where Block: BlockT, Client: HeaderMetadata @@ -1170,7 +1144,6 @@ where + AuxStore, Client::Api: BlockBuilderApi + BabeApi, SelectChain: sp_consensus::SelectChain, - CAW: CanAuthorWith + Send + Sync, CIDP: CreateInherentDataProviders + Send + Sync, CIDP::InherentDataProviders: InherentDataProviderExt + Send + Sync, { @@ -1265,24 +1238,26 @@ where warn!(target: "babe", "Error checking/reporting BABE equivocation: {}", err); } - // if the body is passed through, we need to use the runtime - // to check that the internally-set timestamp in the inherents - // actually matches the slot set in the seal. if let Some(inner_body) = block.body { - let mut inherent_data = create_inherent_data_providers - .create_inherent_data() - .map_err(Error::::CreateInherents)?; - inherent_data.babe_replace_inherent_data(slot); let new_block = Block::new(pre_header.clone(), inner_body); - - self.check_inherents( - new_block.clone(), - BlockId::Hash(parent_hash), - inherent_data, - create_inherent_data_providers, - block.origin.into(), - ) - .await?; + if !block.state_action.skip_execution_checks() { + // if the body is passed through and the block was executed, + // we need to use the runtime to check that the internally-set + // timestamp in the inherents actually matches the slot set in the seal. + let mut inherent_data = create_inherent_data_providers + .create_inherent_data() + .map_err(Error::::CreateInherents)?; + inherent_data.babe_replace_inherent_data(slot); + + self.check_inherents( + new_block.clone(), + BlockId::Hash(parent_hash), + inherent_data, + create_inherent_data_providers, + block.origin.into(), + ) + .await?; + } let (_, inner_body) = new_block.deconstruct(); block.body = Some(inner_body); @@ -1298,9 +1273,9 @@ where block.header = pre_header; block.post_digests.push(verified_info.seal); - block.intermediates.insert( - Cow::from(INTERMEDIATE_KEY), - Box::new(BabeIntermediate:: { epoch_descriptor }) as Box<_>, + block.insert_intermediate( + INTERMEDIATE_KEY, + BabeIntermediate:: { epoch_descriptor }, ); block.post_hash = Some(hash); @@ -1452,7 +1427,7 @@ where match self.client.status(BlockId::Hash(hash)) { Ok(sp_blockchain::BlockStatus::InChain) => { // When re-importing existing block strip away intermediates. - let _ = block.take_intermediate::>(INTERMEDIATE_KEY); + let _ = block.remove_intermediate::>(INTERMEDIATE_KEY); block.fork_choice = Some(ForkChoiceStrategy::Custom(false)); return self.inner.import_block(block, new_cache).await.map_err(Into::into) }, @@ -1521,7 +1496,7 @@ where }; let intermediate = - block.take_intermediate::>(INTERMEDIATE_KEY)?; + block.remove_intermediate::>(INTERMEDIATE_KEY)?; let epoch_descriptor = intermediate.epoch_descriptor; let first_in_epoch = parent_slot < epoch_descriptor.start_slot(); @@ -1781,7 +1756,7 @@ where /// /// The block import object provided must be the `BabeBlockImport` or a wrapper /// of it, otherwise crucial import logic will be omitted. -pub fn import_queue( +pub fn import_queue( babe_link: BabeLink, block_import: Inner, justification_import: Option>, @@ -1790,7 +1765,6 @@ pub fn import_queue( create_inherent_data_providers: CIDP, spawner: &impl sp_core::traits::SpawnEssentialNamed, registry: Option<&Registry>, - can_author_with: CAW, telemetry: Option, ) -> ClientResult> where @@ -1810,7 +1784,6 @@ where + 'static, Client::Api: BlockBuilderApi + BabeApi + ApiExt, SelectChain: sp_consensus::SelectChain + 'static, - CAW: CanAuthorWith + Send + Sync + 'static, CIDP: CreateInherentDataProviders + Send + Sync + 'static, CIDP::InherentDataProviders: InherentDataProviderExt + Send + Sync, { @@ -1819,7 +1792,6 @@ where create_inherent_data_providers, config: babe_link.config, epoch_changes: babe_link.epoch_changes, - can_author_with, telemetry, client, }; diff --git a/client/consensus/babe/src/tests.rs b/client/consensus/babe/src/tests.rs index 8a3b4237f198b..f2bb8baaaf730 100644 --- a/client/consensus/babe/src/tests.rs +++ b/client/consensus/babe/src/tests.rs @@ -31,7 +31,7 @@ use sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging; use sc_keystore::LocalKeystore; use sc_network_test::{Block as TestBlock, *}; use sp_application_crypto::key_types::BABE; -use sp_consensus::{AlwaysCanAuthor, DisableProofRecording, NoNetwork as DummyOracle, Proposal}; +use sp_consensus::{DisableProofRecording, NoNetwork as DummyOracle, Proposal}; use sp_consensus_babe::{ inherents::InherentDataProvider, make_transcript, make_transcript_data, AllowedSlots, AuthorityPair, Slot, @@ -43,7 +43,7 @@ use sp_runtime::{ generic::{Digest, DigestItem}, traits::Block as BlockT, }; -use sp_timestamp::InherentDataProvider as TimestampInherentDataProvider; +use sp_timestamp::Timestamp; use std::{cell::RefCell, task::Poll, time::Duration}; type Item = DigestItem; @@ -68,6 +68,8 @@ type Mutator = Arc; type BabeBlockImport = PanickingBlockImport>>; +const SLOT_DURATION_MS: u64 = 1000; + #[derive(Clone)] struct DummyFactory { client: Arc, @@ -235,12 +237,11 @@ pub struct TestVerifier { TestBlock, PeersFullClient, TestSelectChain, - AlwaysCanAuthor, Box< dyn CreateInherentDataProviders< TestBlock, (), - InherentDataProviders = (TimestampInherentDataProvider, InherentDataProvider), + InherentDataProviders = (InherentDataProvider,), >, >, >, @@ -322,17 +323,14 @@ impl TestNetFactory for BabeTestNet { client: client.clone(), select_chain: longest_chain, create_inherent_data_providers: Box::new(|_, _| async { - let timestamp = TimestampInherentDataProvider::from_system_time(); let slot = InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - SlotDuration::from_millis(6000), + Timestamp::current(), + SlotDuration::from_millis(SLOT_DURATION_MS), ); - - Ok((timestamp, slot)) + Ok((slot,)) }), config: data.link.config.clone(), epoch_changes: data.link.epoch_changes.clone(), - can_author_with: AlwaysCanAuthor, telemetry: None, }, mutator: MUTATOR.with(|m| m.borrow().clone()), @@ -435,19 +433,16 @@ fn run_one_test(mutator: impl Fn(&mut TestHeader, Stage) + Send + Sync + 'static env: environ, sync_oracle: DummyOracle, create_inherent_data_providers: Box::new(|_, _| async { - let timestamp = TimestampInherentDataProvider::from_system_time(); let slot = InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - SlotDuration::from_millis(6000), + Timestamp::current(), + SlotDuration::from_millis(SLOT_DURATION_MS), ); - - Ok((timestamp, slot)) + Ok((slot,)) }), force_authoring: false, backoff_authoring_blocks: Some(BackoffAuthoringOnFinalizedHeadLagging::default()), babe_link: data.link.clone(), keystore, - can_author_with: sp_consensus::AlwaysCanAuthor, justification_sync_link: (), block_proposal_slot_portion: SlotProportion::new(0.5), max_block_proposal_slot_portion: None, @@ -647,10 +642,8 @@ fn propose_and_import_block( let mut import = BlockImportParams::new(BlockOrigin::Own, block.header); import.post_digests.push(seal); import.body = Some(block.extrinsics); - import.intermediates.insert( - Cow::from(INTERMEDIATE_KEY), - Box::new(BabeIntermediate:: { epoch_descriptor }) as Box<_>, - ); + import + .insert_intermediate(INTERMEDIATE_KEY, BabeIntermediate:: { epoch_descriptor }); import.fork_choice = Some(ForkChoiceStrategy::LongestChain); let import_result = block_on(block_import.import_block(import, Default::default())).unwrap(); diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 180ad7c38008d..d5745665a79fd 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] async-trait = "0.1.57" futures = { version = "0.3.21", features = ["thread-pool"] } futures-timer = "3.0.1" -libp2p = { version = "0.46.1", default-features = false } +libp2p = { version = "0.49.0", default-features = false } log = "0.4.17" parking_lot = "0.12.1" serde = { version = "1.0", features = ["derive"] } diff --git a/client/consensus/common/src/block_import.rs b/client/consensus/common/src/block_import.rs index 10739f63ef779..f888176addd2d 100644 --- a/client/consensus/common/src/block_import.rs +++ b/client/consensus/common/src/block_import.rs @@ -153,6 +153,18 @@ pub enum StateAction { Skip, } +impl StateAction { + /// Check if execution checks that require runtime calls should be skipped. + pub fn skip_execution_checks(&self) -> bool { + match self { + StateAction::ApplyChanges(_) | + StateAction::Execute | + StateAction::ExecuteIfPossible => false, + StateAction::Skip => true, + } + } +} + /// Data required to import a Block. #[non_exhaustive] pub struct BlockImportParams { @@ -282,18 +294,23 @@ impl BlockImportParams { } } - /// Take intermediate by given key, and remove it from the processing list. - pub fn take_intermediate(&mut self, key: &[u8]) -> Result, Error> { + /// Insert intermediate by given key. + pub fn insert_intermediate(&mut self, key: &'static [u8], value: T) { + self.intermediates.insert(Cow::from(key), Box::new(value)); + } + + /// Remove and return intermediate by given key. + pub fn remove_intermediate(&mut self, key: &[u8]) -> Result { let (k, v) = self.intermediates.remove_entry(key).ok_or(Error::NoIntermediate)?; - v.downcast::().map_err(|v| { + v.downcast::().map(|v| *v).map_err(|v| { self.intermediates.insert(k, v); Error::InvalidIntermediate }) } /// Get a reference to a given intermediate. - pub fn intermediate(&self, key: &[u8]) -> Result<&T, Error> { + pub fn get_intermediate(&self, key: &[u8]) -> Result<&T, Error> { self.intermediates .get(key) .ok_or(Error::NoIntermediate)? @@ -302,7 +319,7 @@ impl BlockImportParams { } /// Get a mutable reference to a given intermediate. - pub fn intermediate_mut(&mut self, key: &[u8]) -> Result<&mut T, Error> { + pub fn get_intermediate_mut(&mut self, key: &[u8]) -> Result<&mut T, Error> { self.intermediates .get_mut(key) .ok_or(Error::NoIntermediate)? diff --git a/client/consensus/common/src/import_queue.rs b/client/consensus/common/src/import_queue.rs index c71e21ccd4b00..3741fa99663cd 100644 --- a/client/consensus/common/src/import_queue.rs +++ b/client/consensus/common/src/import_queue.rs @@ -62,8 +62,8 @@ pub type BoxBlockImport = pub type BoxJustificationImport = Box + Send + Sync>; -/// Maps to the Origin used by the network. -pub type Origin = libp2p::PeerId; +/// Maps to the RuntimeOrigin used by the network. +pub type RuntimeOrigin = libp2p::PeerId; /// Block data used by the queue. #[derive(Debug, PartialEq, Eq, Clone)] @@ -79,7 +79,7 @@ pub struct IncomingBlock { /// Justification(s) if requested. pub justifications: Option, /// The peer, we received this from - pub origin: Option, + pub origin: Option, /// Allow importing the block skipping state verification if parent state is missing. pub allow_missing_state: bool, /// Skip block execution and state verification. @@ -112,7 +112,7 @@ pub trait ImportQueue: Send { /// Import block justifications. fn import_justifications( &mut self, - who: Origin, + who: RuntimeOrigin, hash: B::Hash, number: NumberFor, justifications: Justifications, @@ -140,7 +140,7 @@ pub trait Link: Send { /// Justification import result. fn justification_imported( &mut self, - _who: Origin, + _who: RuntimeOrigin, _hash: &B::Hash, _number: NumberFor, _success: bool, @@ -155,9 +155,9 @@ pub trait Link: Send { #[derive(Debug, PartialEq)] pub enum BlockImportStatus { /// Imported known block. - ImportedKnown(N, Option), + ImportedKnown(N, Option), /// Imported unknown block. - ImportedUnknown(N, ImportedAux, Option), + ImportedUnknown(N, ImportedAux, Option), } impl BlockImportStatus { @@ -175,15 +175,15 @@ impl BlockImportStatus { pub enum BlockImportError { /// Block missed header, can't be imported #[error("block is missing a header (origin = {0:?})")] - IncompleteHeader(Option), + IncompleteHeader(Option), /// Block verification failed, can't be imported #[error("block verification failed (origin = {0:?}): {1}")] - VerificationFailed(Option, String), + VerificationFailed(Option, String), /// Block is known to be Bad #[error("bad block (origin = {0:?})")] - BadBlock(Option), + BadBlock(Option), /// Parent state is missing. #[error("block is missing parent state")] diff --git a/client/consensus/common/src/import_queue/basic_queue.rs b/client/consensus/common/src/import_queue/basic_queue.rs index 84ccba990e599..0e607159b75c3 100644 --- a/client/consensus/common/src/import_queue/basic_queue.rs +++ b/client/consensus/common/src/import_queue/basic_queue.rs @@ -34,7 +34,7 @@ use crate::{ import_queue::{ buffered_link::{self, BufferedLinkReceiver, BufferedLinkSender}, import_single_block_metered, BlockImportError, BlockImportStatus, BoxBlockImport, - BoxJustificationImport, ImportQueue, IncomingBlock, Link, Origin, Verifier, + BoxJustificationImport, ImportQueue, IncomingBlock, Link, RuntimeOrigin, Verifier, }, metrics::Metrics, }; @@ -120,7 +120,7 @@ impl ImportQueue for BasicQueue fn import_justifications( &mut self, - who: Origin, + who: RuntimeOrigin, hash: B::Hash, number: NumberFor, justifications: Justifications, @@ -152,7 +152,7 @@ mod worker_messages { pub struct ImportBlocks(pub BlockOrigin, pub Vec>); pub struct ImportJustification( - pub Origin, + pub RuntimeOrigin, pub B::Hash, pub NumberFor, pub Justification, @@ -289,7 +289,7 @@ impl BlockImportWorker { async fn import_justification( &mut self, - who: Origin, + who: RuntimeOrigin, hash: B::Hash, number: NumberFor, justification: Justification, @@ -530,7 +530,7 @@ mod tests { fn justification_imported( &mut self, - _who: Origin, + _who: RuntimeOrigin, hash: &Hash, _number: BlockNumber, _success: bool, diff --git a/client/consensus/common/src/import_queue/buffered_link.rs b/client/consensus/common/src/import_queue/buffered_link.rs index d3d91f5bd31c5..5d418dddf0853 100644 --- a/client/consensus/common/src/import_queue/buffered_link.rs +++ b/client/consensus/common/src/import_queue/buffered_link.rs @@ -38,7 +38,7 @@ //! }); //! ``` -use crate::import_queue::{Link, Origin}; +use crate::import_queue::{Link, RuntimeOrigin}; use futures::prelude::*; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_runtime::traits::{Block as BlockT, NumberFor}; @@ -82,7 +82,7 @@ impl Clone for BufferedLinkSender { /// Internal buffered message. enum BlockImportWorkerMsg { BlocksProcessed(usize, usize, Vec<(BlockImportResult, B::Hash)>), - JustificationImported(Origin, B::Hash, NumberFor, bool), + JustificationImported(RuntimeOrigin, B::Hash, NumberFor, bool), RequestJustification(B::Hash, NumberFor), } @@ -100,7 +100,7 @@ impl Link for BufferedLinkSender { fn justification_imported( &mut self, - who: Origin, + who: RuntimeOrigin, hash: &B::Hash, number: NumberFor, success: bool, diff --git a/client/consensus/manual-seal/src/consensus/babe.rs b/client/consensus/manual-seal/src/consensus/babe.rs index 300a96695c90a..206f5163a13cd 100644 --- a/client/consensus/manual-seal/src/consensus/babe.rs +++ b/client/consensus/manual-seal/src/consensus/babe.rs @@ -30,7 +30,7 @@ use sc_consensus_epochs::{ descendent_query, EpochHeader, SharedEpochChanges, ViableEpochDescriptor, }; use sp_keystore::SyncCryptoStorePtr; -use std::{borrow::Cow, marker::PhantomData, sync::Arc}; +use std::{marker::PhantomData, sync::Arc}; use sc_consensus::{BlockImportParams, ForkChoiceStrategy, Verifier}; use sp_api::{ProvideRuntimeApi, TransactionFor}; @@ -125,10 +125,8 @@ where // drop the lock drop(epoch_changes); - import_params.intermediates.insert( - Cow::from(INTERMEDIATE_KEY), - Box::new(BabeIntermediate:: { epoch_descriptor }) as Box<_>, - ); + import_params + .insert_intermediate(INTERMEDIATE_KEY, BabeIntermediate:: { epoch_descriptor }); Ok((import_params, None)) } @@ -315,10 +313,7 @@ where }; } - params.intermediates.insert( - Cow::from(INTERMEDIATE_KEY), - Box::new(BabeIntermediate:: { epoch_descriptor }) as Box<_>, - ); + params.insert_intermediate(INTERMEDIATE_KEY, BabeIntermediate:: { epoch_descriptor }); Ok(()) } diff --git a/client/consensus/manual-seal/src/lib.rs b/client/consensus/manual-seal/src/lib.rs index c5dd169e281f2..09ab139b91c73 100644 --- a/client/consensus/manual-seal/src/lib.rs +++ b/client/consensus/manual-seal/src/lib.rs @@ -247,13 +247,66 @@ pub async fn run_instant_seal( .await } +/// Runs the background authorship task for the instant seal engine. +/// instant-seal creates a new block for every transaction imported into +/// the transaction pool. +/// +/// This function will finalize the block immediately as well. If you don't +/// want this behavior use `run_instant_seal` instead. +pub async fn run_instant_seal_and_finalize( + InstantSealParams { + block_import, + env, + client, + pool, + select_chain, + consensus_data_provider, + create_inherent_data_providers, + }: InstantSealParams, +) where + B: BlockT + 'static, + BI: BlockImport> + + Send + + Sync + + 'static, + C: HeaderBackend + Finalizer + ProvideRuntimeApi + 'static, + CB: ClientBackend + 'static, + E: Environment + 'static, + E::Proposer: Proposer>, + SC: SelectChain + 'static, + TransactionFor: 'static, + TP: TransactionPool, + CIDP: CreateInherentDataProviders, + P: Send + Sync + 'static, +{ + // Creates and finalizes blocks as soon as transactions are imported + // into the transaction pool. + let commands_stream = pool.import_notification_stream().map(|_| EngineCommand::SealNewBlock { + create_empty: false, + finalize: true, + parent_hash: None, + sender: None, + }); + + run_manual_seal(ManualSealParams { + block_import, + env, + client, + pool, + commands_stream, + select_chain, + consensus_data_provider, + create_inherent_data_providers, + }) + .await +} + #[cfg(test)] mod tests { use super::*; use sc_basic_authorship::ProposerFactory; - use sc_client_api::BlockBackend; use sc_consensus::ImportedAux; - use sc_transaction_pool::{BasicPool, Options, RevalidationType}; + use sc_transaction_pool::{BasicPool, FullChainApi, Options, RevalidationType}; use sc_transaction_pool_api::{MaintainedTransactionPool, TransactionPool, TransactionSource}; use sp_inherents::InherentData; use sp_runtime::generic::{BlockId, Digest, DigestItem}; @@ -305,6 +358,7 @@ mod tests { let (client, select_chain) = builder.build_with_longest_chain(); let client = Arc::new(client); let spawner = sp_core::testing::TaskExecutor::new(); + let genesis_hash = client.header(&BlockId::Number(0)).unwrap().unwrap().hash(); let pool = Arc::new(BasicPool::with_revalidation_type( Options::default(), true.into(), @@ -313,6 +367,8 @@ mod tests { RevalidationType::Full, spawner.clone(), 0, + genesis_hash, + genesis_hash, )); let env = ProposerFactory::new(spawner.clone(), client.clone(), pool.clone(), None, None); // this test checks that blocks are created as soon as transactions are imported into the @@ -375,6 +431,7 @@ mod tests { let (client, select_chain) = builder.build_with_longest_chain(); let client = Arc::new(client); let spawner = sp_core::testing::TaskExecutor::new(); + let genesis_hash = client.header(&BlockId::Number(0)).unwrap().unwrap().hash(); let pool = Arc::new(BasicPool::with_revalidation_type( Options::default(), true.into(), @@ -383,6 +440,8 @@ mod tests { RevalidationType::Full, spawner.clone(), 0, + genesis_hash, + genesis_hash, )); let env = ProposerFactory::new(spawner.clone(), client.clone(), pool.clone(), None, None); // this test checks that blocks are created as soon as an engine command is sent over the @@ -451,8 +510,13 @@ mod tests { let builder = TestClientBuilder::new(); let (client, select_chain) = builder.build_with_longest_chain(); let client = Arc::new(client); - let pool_api = api(); + let pool_api = Arc::new(FullChainApi::new( + client.clone(), + None, + &sp_core::testing::TaskExecutor::new(), + )); let spawner = sp_core::testing::TaskExecutor::new(); + let genesis_hash = client.header(&BlockId::Number(0)).unwrap().unwrap().hash(); let pool = Arc::new(BasicPool::with_revalidation_type( Options::default(), true.into(), @@ -461,6 +525,8 @@ mod tests { RevalidationType::Full, spawner.clone(), 0, + genesis_hash, + genesis_hash, )); let env = ProposerFactory::new(spawner.clone(), client.clone(), pool.clone(), None, None); // this test checks that blocks are created as soon as an engine command is sent over the @@ -496,7 +562,6 @@ mod tests { .await .unwrap(); let created_block = rx.await.unwrap().unwrap(); - pool_api.increment_nonce(Alice.into()); // assert that the background task returns ok assert_eq!( @@ -512,8 +577,7 @@ mod tests { } } ); - let block = client.block(&BlockId::Number(1)).unwrap().unwrap().block; - pool_api.add_block(block, true); + assert!(pool.submit_one(&BlockId::Number(1), SOURCE, uxt(Alice, 1)).await.is_ok()); let header = client.header(&BlockId::Number(1)).expect("db error").expect("imported above"); @@ -534,9 +598,6 @@ mod tests { .await .is_ok()); assert_matches::assert_matches!(rx1.await.expect("should be no error receiving"), Ok(_)); - let block = client.block(&BlockId::Number(2)).unwrap().unwrap().block; - pool_api.add_block(block, true); - pool_api.increment_nonce(Alice.into()); assert!(pool.submit_one(&BlockId::Number(1), SOURCE, uxt(Bob, 0)).await.is_ok()); let (tx2, rx2) = futures::channel::oneshot::channel(); @@ -560,6 +621,7 @@ mod tests { let (client, select_chain) = builder.build_with_longest_chain(); let client = Arc::new(client); let spawner = sp_core::testing::TaskExecutor::new(); + let genesis_hash = client.header(&BlockId::Number(0)).unwrap().unwrap().hash(); let pool = Arc::new(BasicPool::with_revalidation_type( Options::default(), true.into(), @@ -568,6 +630,8 @@ mod tests { RevalidationType::Full, spawner.clone(), 0, + genesis_hash, + genesis_hash, )); let env = ProposerFactory::new(spawner.clone(), client.clone(), pool.clone(), None, None); diff --git a/client/consensus/pow/src/lib.rs b/client/consensus/pow/src/lib.rs index f63e453a48026..dcf069d617bab 100644 --- a/client/consensus/pow/src/lib.rs +++ b/client/consensus/pow/src/lib.rs @@ -56,9 +56,7 @@ use sc_consensus::{ use sp_api::ProvideRuntimeApi; use sp_block_builder::BlockBuilder as BlockBuilderApi; use sp_blockchain::{well_known_cache_keys::Id as CacheKeyId, HeaderBackend}; -use sp_consensus::{ - CanAuthorWith, Environment, Error as ConsensusError, Proposer, SelectChain, SyncOracle, -}; +use sp_consensus::{Environment, Error as ConsensusError, Proposer, SelectChain, SyncOracle}; use sp_consensus_pow::{Seal, TotalDifficulty, POW_ENGINE_ID}; use sp_core::ExecutionContext; use sp_inherents::{CreateInherentDataProviders, InherentDataProvider}; @@ -67,10 +65,7 @@ use sp_runtime::{ traits::{Block as BlockT, Header as HeaderT}, RuntimeString, }; -use std::{ - borrow::Cow, cmp::Ordering, collections::HashMap, marker::PhantomData, sync::Arc, - time::Duration, -}; +use std::{cmp::Ordering, collections::HashMap, marker::PhantomData, sync::Arc, time::Duration}; #[derive(Debug, thiserror::Error)] pub enum Error { @@ -214,18 +209,17 @@ pub trait PowAlgorithm { } /// A block importer for PoW. -pub struct PowBlockImport { +pub struct PowBlockImport { algorithm: Algorithm, inner: I, select_chain: S, client: Arc, create_inherent_data_providers: Arc, check_inherents_after: <::Header as HeaderT>::Number, - can_author_with: CAW, } -impl Clone - for PowBlockImport +impl Clone + for PowBlockImport { fn clone(&self) -> Self { Self { @@ -235,12 +229,11 @@ impl Clone client: self.client.clone(), create_inherent_data_providers: self.create_inherent_data_providers.clone(), check_inherents_after: self.check_inherents_after, - can_author_with: self.can_author_with.clone(), } } } -impl PowBlockImport +impl PowBlockImport where B: BlockT, I: BlockImport> + Send + Sync, @@ -248,7 +241,6 @@ where C: ProvideRuntimeApi + Send + Sync + HeaderBackend + AuxStore + BlockOf, C::Api: BlockBuilderApi, Algorithm: PowAlgorithm, - CAW: CanAuthorWith, CIDP: CreateInherentDataProviders, { /// Create a new block import suitable to be used in PoW @@ -259,7 +251,6 @@ where check_inherents_after: <::Header as HeaderT>::Number, select_chain: S, create_inherent_data_providers: CIDP, - can_author_with: CAW, ) -> Self { Self { inner, @@ -268,7 +259,6 @@ where check_inherents_after, select_chain, create_inherent_data_providers: Arc::new(create_inherent_data_providers), - can_author_with, } } @@ -283,16 +273,6 @@ where return Ok(()) } - if let Err(e) = self.can_author_with.can_author_with(&block_id) { - debug!( - target: "pow", - "Skipping `check_inherents` as authoring version is not compatible: {}", - e, - ); - - return Ok(()) - } - let inherent_data = inherent_data_providers .create_inherent_data() .map_err(|e| Error::CreateInherents(e))?; @@ -317,8 +297,7 @@ where } #[async_trait::async_trait] -impl BlockImport - for PowBlockImport +impl BlockImport for PowBlockImport where B: BlockT, I: BlockImport> + Send + Sync, @@ -328,7 +307,6 @@ where C::Api: BlockBuilderApi, Algorithm: PowAlgorithm + Send + Sync, Algorithm::Difficulty: 'static + Send, - CAW: CanAuthorWith + Send + Sync, CIDP: CreateInherentDataProviders + Send + Sync, { type Error = ConsensusError; @@ -360,23 +338,25 @@ where if let Some(inner_body) = block.body.take() { let check_block = B::new(block.header.clone(), inner_body); - self.check_inherents( - check_block.clone(), - BlockId::Hash(parent_hash), - self.create_inherent_data_providers - .create_inherent_data_providers(parent_hash, ()) - .await?, - block.origin.into(), - ) - .await?; + if !block.state_action.skip_execution_checks() { + self.check_inherents( + check_block.clone(), + BlockId::Hash(parent_hash), + self.create_inherent_data_providers + .create_inherent_data_providers(parent_hash, ()) + .await?, + block.origin.into(), + ) + .await?; + } block.body = Some(check_block.deconstruct().1); } let inner_seal = fetch_seal::(block.post_digests.last(), block.header.hash())?; - let intermediate = - block.take_intermediate::>(INTERMEDIATE_KEY)?; + let intermediate = block + .remove_intermediate::>(INTERMEDIATE_KEY)?; let difficulty = match intermediate.difficulty { Some(difficulty) => difficulty, @@ -472,9 +452,7 @@ where let intermediate = PowIntermediate:: { difficulty: None }; block.header = checked_header; block.post_digests.push(seal); - block - .intermediates - .insert(Cow::from(INTERMEDIATE_KEY), Box::new(intermediate) as Box<_>); + block.insert_intermediate(INTERMEDIATE_KEY, intermediate); block.post_hash = Some(hash); Ok((block, None)) @@ -512,7 +490,7 @@ where /// /// `pre_runtime` is a parameter that allows a custom additional pre-runtime digest to be inserted /// for blocks being built. This can encode authorship information, or just be a graffiti. -pub fn start_mining_worker( +pub fn start_mining_worker( block_import: BoxBlockImport>, client: Arc, select_chain: S, @@ -524,7 +502,6 @@ pub fn start_mining_worker( create_inherent_data_providers: CIDP, timeout: Duration, build_time: Duration, - can_author_with: CAW, ) -> ( MiningHandle>::Proof>, impl Future, @@ -541,7 +518,6 @@ where SO: SyncOracle + Clone + Send + Sync + 'static, L: sc_consensus::JustificationSyncLink, CIDP: CreateInherentDataProviders, - CAW: CanAuthorWith + Clone + Send + 'static, { let mut timer = UntilImportedOrTimeout::new(client.import_notification_stream(), timeout); let worker = MiningHandle::new(algorithm.clone(), block_import, justification_sync_link); @@ -573,16 +549,6 @@ where }; let best_hash = best_header.hash(); - if let Err(err) = can_author_with.can_author_with(&BlockId::Hash(best_hash)) { - warn!( - target: "pow", - "Skipping proposal `can_author_with` returned: {} \ - Probably a node update is required!", - err, - ); - continue - } - if worker.best_hash() == Some(best_hash) { continue } diff --git a/client/consensus/pow/src/worker.rs b/client/consensus/pow/src/worker.rs index 750e78cd9a038..a00da6e7022fb 100644 --- a/client/consensus/pow/src/worker.rs +++ b/client/consensus/pow/src/worker.rs @@ -32,7 +32,6 @@ use sp_runtime::{ DigestItem, }; use std::{ - borrow::Cow, collections::HashMap, pin::Pin, sync::{ @@ -212,10 +211,7 @@ where let intermediate = PowIntermediate:: { difficulty: Some(build.metadata.difficulty), }; - - import_block - .intermediates - .insert(Cow::from(INTERMEDIATE_KEY), Box::new(intermediate) as Box<_>); + import_block.insert_intermediate(INTERMEDIATE_KEY, intermediate); let header = import_block.post_header(); let mut block_import = self.block_import.lock(); diff --git a/client/consensus/slots/src/lib.rs b/client/consensus/slots/src/lib.rs index 28ffb740a0796..97931f195ee57 100644 --- a/client/consensus/slots/src/lib.rs +++ b/client/consensus/slots/src/lib.rs @@ -38,7 +38,7 @@ use log::{debug, info, warn}; use sc_consensus::{BlockImport, JustificationSyncLink}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO, CONSENSUS_WARN}; use sp_arithmetic::traits::BaseArithmetic; -use sp_consensus::{CanAuthorWith, Proposal, Proposer, SelectChain, SyncOracle}; +use sp_consensus::{Proposal, Proposer, SelectChain, SyncOracle}; use sp_consensus_slots::{Slot, SlotDuration}; use sp_core::{crypto::key_types::AURA, sr25519, ShufflingSeed}; use sp_inherents::{CreateInherentDataProviders, InherentDataProvider}; @@ -139,8 +139,8 @@ pub trait SimpleSlotWorker { /// Data associated with a slot claim. type Claim: Send + Sync + 'static; - /// Epoch data necessary for authoring. - type EpochData: Send + Sync + 'static; + /// Auxiliary data necessary for authoring. + type AuxData: Send + Sync + 'static; /// The logging target to use when logging messages. fn logging_target(&self) -> &'static str; @@ -148,24 +148,23 @@ pub trait SimpleSlotWorker { /// A handle to a `BlockImport`. fn block_import(&mut self) -> &mut Self::BlockImport; - /// Returns the epoch data necessary for authoring. For time-dependent epochs, - /// use the provided slot number as a canonical source of time. - fn epoch_data( + /// Returns the auxiliary data necessary for authoring. + fn aux_data( &self, header: &B::Header, slot: Slot, - ) -> Result; + ) -> Result; - /// Returns the number of authorities given the epoch data. + /// Returns the number of authorities. /// None indicate that the authorities information is incomplete. - fn authorities_len(&self, epoch_data: &Self::EpochData) -> Option; + fn authorities_len(&self, aux_data: &Self::AuxData) -> Option; /// Tries to claim the given slot, returning an object with claim data if successful. async fn claim_slot( &self, header: &B::Header, slot: Slot, - epoch_data: &Self::EpochData, + aux_data: &Self::AuxData, ) -> Option; /// reads key required for signing shuffling seed @@ -173,7 +172,7 @@ pub trait SimpleSlotWorker { /// Notifies the given slot. Similar to `claim_slot`, but will be called no matter whether we /// need to author blocks or not. - fn notify_slot(&self, _header: &B::Header, _slot: Slot, _epoch_data: &Self::EpochData) {} + fn notify_slot(&self, _header: &B::Header, _slot: Slot, _aux_data: &Self::AuxData) {} /// Return the pre digest data to include in a block authored with the given claim. fn pre_digest_data(&self, slot: Slot, claim: &Self::Claim) -> Vec; @@ -186,7 +185,7 @@ pub trait SimpleSlotWorker { body: Vec, storage_changes: StorageChanges<>::Transaction, B>, public: Self::Claim, - epoch: Self::EpochData, + epoch: Self::AuxData, ) -> Result< sc_consensus::BlockImportParams>::Transaction>, sp_consensus::Error, @@ -292,8 +291,8 @@ pub trait SimpleSlotWorker { where Self: Sync, { + let slot = slot_info.slot; let keystore = self.keystore().clone(); - let (timestamp, slot) = (slot_info.timestamp, slot_info.slot); let telemetry = self.telemetry(); let logging_target = self.logging_target(); @@ -310,12 +309,12 @@ pub trait SimpleSlotWorker { Delay::new(proposing_remaining_duration) }; - let epoch_data = match self.epoch_data(&slot_info.chain_head, slot) { - Ok(epoch_data) => epoch_data, + let aux_data = match self.aux_data(&slot_info.chain_head, slot) { + Ok(aux_data) => aux_data, Err(err) => { warn!( target: logging_target, - "Unable to fetch epoch data at block {:?}: {}", + "Unable to fetch auxiliary data for block {:?}: {}", slot_info.chain_head.hash(), err, ); @@ -332,9 +331,9 @@ pub trait SimpleSlotWorker { }, }; - self.notify_slot(&slot_info.chain_head, slot, &epoch_data); + self.notify_slot(&slot_info.chain_head, slot, &aux_data); - let authorities_len = self.authorities_len(&epoch_data); + let authorities_len = self.authorities_len(&aux_data); if !self.force_authoring() && self.sync_oracle().is_offline() && @@ -351,7 +350,8 @@ pub trait SimpleSlotWorker { return None } - let claim = self.claim_slot(&slot_info.chain_head, slot, &epoch_data).await?; + let claim = self.claim_slot(&slot_info.chain_head, slot, &aux_data).await?; + let key = self.get_key(&claim); inject_inherents(keystore, &key, &mut slot_info).ok()?; @@ -359,23 +359,14 @@ pub trait SimpleSlotWorker { return None } - debug!( - target: logging_target, - "Starting authorship at slot {}; timestamp = {}", slot, *timestamp, - ); + debug!(target: logging_target, "Starting authorship at slot: {slot}"); - telemetry!( - telemetry; - CONSENSUS_DEBUG; - "slots.starting_authorship"; - "slot_num" => *slot, - "timestamp" => *timestamp, - ); + telemetry!(telemetry; CONSENSUS_DEBUG; "slots.starting_authorship"; "slot_num" => slot); let proposer = match self.proposer(&slot_info.chain_head).await { Ok(p) => p, Err(err) => { - warn!(target: logging_target, "Unable to author block in slot {:?}: {}", slot, err,); + warn!(target: logging_target, "Unable to author block in slot {slot:?}: {err}"); telemetry!( telemetry; @@ -404,7 +395,7 @@ pub trait SimpleSlotWorker { body.clone(), proposal.storage_changes, claim, - epoch_data, + aux_data, ) .await { @@ -486,56 +477,46 @@ impl + Send + Sync, B: BlockT> /// Slot specific extension that the inherent data provider needs to implement. pub trait InherentDataProviderExt { - /// The current timestamp that will be found in the - /// [`InherentData`](`sp_inherents::InherentData`). - fn timestamp(&self) -> Timestamp; - /// The current slot that will be found in the [`InherentData`](`sp_inherents::InherentData`). fn slot(&self) -> Slot; } /// Small macro for implementing `InherentDataProviderExt` for inherent data provider tuple. macro_rules! impl_inherent_data_provider_ext_tuple { - ( T, S $(, $TN:ident)* $( , )?) => { - impl InherentDataProviderExt for (T, S, $($TN),*) + ( S $(, $TN:ident)* $( , )?) => { + impl InherentDataProviderExt for (S, $($TN),*) where - T: Deref, S: Deref, { - fn timestamp(&self) -> Timestamp { - *self.0.deref() - } - fn slot(&self) -> Slot { - *self.1.deref() + *self.0.deref() } } } } -impl_inherent_data_provider_ext_tuple!(T, S); -impl_inherent_data_provider_ext_tuple!(T, S, A); -impl_inherent_data_provider_ext_tuple!(T, S, A, B); -impl_inherent_data_provider_ext_tuple!(T, S, A, B, C); -impl_inherent_data_provider_ext_tuple!(T, S, A, B, C, D); -impl_inherent_data_provider_ext_tuple!(T, S, A, B, C, D, E); -impl_inherent_data_provider_ext_tuple!(T, S, A, B, C, D, E, F); -impl_inherent_data_provider_ext_tuple!(T, S, A, B, C, D, E, F, G); -impl_inherent_data_provider_ext_tuple!(T, S, A, B, C, D, E, F, G, H); -impl_inherent_data_provider_ext_tuple!(T, S, A, B, C, D, E, F, G, H, I); -impl_inherent_data_provider_ext_tuple!(T, S, A, B, C, D, E, F, G, H, I, J); +impl_inherent_data_provider_ext_tuple!(S); +impl_inherent_data_provider_ext_tuple!(S, A); +impl_inherent_data_provider_ext_tuple!(S, A, B); +impl_inherent_data_provider_ext_tuple!(S, A, B, C); +impl_inherent_data_provider_ext_tuple!(S, A, B, C, D); +impl_inherent_data_provider_ext_tuple!(S, A, B, C, D, E); +impl_inherent_data_provider_ext_tuple!(S, A, B, C, D, E, F); +impl_inherent_data_provider_ext_tuple!(S, A, B, C, D, E, F, G); +impl_inherent_data_provider_ext_tuple!(S, A, B, C, D, E, F, G, H); +impl_inherent_data_provider_ext_tuple!(S, A, B, C, D, E, F, G, H, I); +impl_inherent_data_provider_ext_tuple!(S, A, B, C, D, E, F, G, H, I, J); /// Start a new slot worker. /// /// Every time a new slot is triggered, `worker.on_slot` is called and the future it returns is /// polled until completion, unless we are major syncing. -pub async fn start_slot_worker( +pub async fn start_slot_worker( slot_duration: SlotDuration, client: C, mut worker: W, sync_oracle: SO, create_inherent_data_providers: CIDP, - can_author_with: CAW, ) where B: BlockT, C: SelectChain, @@ -543,7 +524,6 @@ pub async fn start_slot_worker( SO: SyncOracle + Send, CIDP: CreateInherentDataProviders + Send, CIDP::InherentDataProviders: InherentDataProviderExt + Send, - CAW: CanAuthorWith + Send, { let mut slots = Slots::new(slot_duration.as_duration(), create_inherent_data_providers, client); @@ -561,19 +541,7 @@ pub async fn start_slot_worker( continue } - if let Err(err) = - can_author_with.can_author_with(&BlockId::Hash(slot_info.chain_head.hash())) - { - warn!( - target: "slots", - "Unable to author block in slot {},. `can_author_with` returned: {} \ - Probably a node update is required!", - slot_info.slot, - err, - ); - } else { - let _ = worker.on_slot(slot_info).await; - } + let _ = worker.on_slot(slot_info).await; } } @@ -866,7 +834,6 @@ mod test { super::slots::SlotInfo { slot: slot.into(), duration: SLOT_DURATION, - timestamp: Default::default(), inherent_data: Default::default(), ends_at: Instant::now() + SLOT_DURATION, chain_head: Header::new( @@ -1199,7 +1166,7 @@ mod test { // But lets assert all distances, which we expect to grow linearly until `max_interval + 1` let expected_intervals: Vec<_> = - (0..497).map(|i| (i / 2).max(1).min(expected_distance)).collect(); + (0..497).map(|i| (i / 2).clamp(1, expected_distance)).collect(); assert_eq!(intervals, expected_intervals); } diff --git a/client/consensus/slots/src/slots.rs b/client/consensus/slots/src/slots.rs index accf24b6b4e78..f3dc485a8e819 100644 --- a/client/consensus/slots/src/slots.rs +++ b/client/consensus/slots/src/slots.rs @@ -50,8 +50,6 @@ pub fn time_until_next_slot(slot_duration: Duration) -> Duration { pub struct SlotInfo { /// The slot number as found in the inherent data. pub slot: Slot, - /// Current timestamp as found in the inherent data. - pub timestamp: sp_timestamp::Timestamp, /// The instant at which the slot ends. pub ends_at: Instant, /// The inherent data. @@ -72,7 +70,6 @@ impl SlotInfo { /// `ends_at` is calculated using `timestamp` and `duration`. pub fn new( slot: Slot, - timestamp: sp_timestamp::Timestamp, inherent_data: InherentData, duration: Duration, chain_head: B::Header, @@ -80,7 +77,6 @@ impl SlotInfo { ) -> Self { Self { slot, - timestamp, inherent_data, duration, chain_head, @@ -175,7 +171,6 @@ where ); } - let timestamp = inherent_data_providers.timestamp(); let slot = inherent_data_providers.slot(); let inherent_data = inherent_data_providers.create_inherent_data()?; @@ -183,14 +178,7 @@ where if slot > self.last_slot { self.last_slot = slot; - break Ok(SlotInfo::new( - slot, - timestamp, - inherent_data, - self.slot_duration, - chain_head, - None, - )) + break Ok(SlotInfo::new(slot, inherent_data, self.slot_duration, chain_head, None)) } } } diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 7f564ae642433..b21038b77564f 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -17,9 +17,9 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } hash-db = "0.15.2" -kvdb = "0.11.0" -kvdb-memorydb = "0.11.0" -kvdb-rocksdb = { version = "0.15.2", optional = true } +kvdb = "0.12.0" +kvdb-memorydb = "0.12.0" +kvdb-rocksdb = { version = "0.16.0", optional = true } linked-hash-map = "0.5.4" log = "0.4.17" parity-db = "0.3.16" @@ -36,7 +36,7 @@ sp-trie = { version = "6.0.0", path = "../../primitives/trie" } [dev-dependencies] criterion = "0.3.3" -kvdb-rocksdb = "0.15.1" +kvdb-rocksdb = "0.16.0" rand = "0.8.4" tempfile = "3.1.0" quickcheck = { version = "1.0.3", default-features = false } diff --git a/client/db/benches/state_access.rs b/client/db/benches/state_access.rs index 78aed7858e342..912a9b028f638 100644 --- a/client/db/benches/state_access.rs +++ b/client/db/benches/state_access.rs @@ -84,7 +84,7 @@ fn insert_blocks(db: &Backend, storage: Vec<(Vec, Vec)>) -> H256 .map(|(k, v)| (k.clone(), Some(v.clone()))) .collect::>(); - let (state_root, tx) = db.state_at(BlockId::Number(number - 1)).unwrap().storage_root( + let (state_root, tx) = db.state_at(&parent_hash).unwrap().storage_root( changes.iter().map(|(k, v)| (k.as_slice(), v.as_deref())), StateVersion::V1, ); @@ -122,7 +122,7 @@ fn create_backend(config: BenchmarkConfig, temp_dir: &TempDir) -> Backend trie_cache_maximum_size, state_pruning: Some(PruningMode::ArchiveAll), source: DatabaseSource::ParityDb { path }, - blocks_pruning: BlocksPruning::All, + blocks_pruning: BlocksPruning::KeepAll, }; Backend::new(settings, 100).expect("Creates backend") @@ -176,7 +176,7 @@ fn state_access_benchmarks(c: &mut Criterion) { group.bench_function(desc, |b| { b.iter_batched( - || backend.state_at(BlockId::Hash(block_hash)).expect("Creates state"), + || backend.state_at(&block_hash).expect("Creates state"), |state| { for key in keys.iter().cycle().take(keys.len() * multiplier) { let _ = state.storage(&key).expect("Doesn't fail").unwrap(); @@ -214,7 +214,7 @@ fn state_access_benchmarks(c: &mut Criterion) { group.bench_function(desc, |b| { b.iter_batched( - || backend.state_at(BlockId::Hash(block_hash)).expect("Creates state"), + || backend.state_at(&block_hash).expect("Creates state"), |state| { for key in keys.iter().take(1).cycle().take(multiplier) { let _ = state.storage(&key).expect("Doesn't fail").unwrap(); @@ -252,7 +252,7 @@ fn state_access_benchmarks(c: &mut Criterion) { group.bench_function(desc, |b| { b.iter_batched( - || backend.state_at(BlockId::Hash(block_hash)).expect("Creates state"), + || backend.state_at(&block_hash).expect("Creates state"), |state| { for key in keys.iter().take(1).cycle().take(multiplier) { let _ = state.storage_hash(&key).expect("Doesn't fail").unwrap(); @@ -290,7 +290,7 @@ fn state_access_benchmarks(c: &mut Criterion) { group.bench_function(desc, |b| { b.iter_batched( - || backend.state_at(BlockId::Hash(block_hash)).expect("Creates state"), + || backend.state_at(&block_hash).expect("Creates state"), |state| { let _ = state .storage_hash(sp_core::storage::well_known_keys::CODE) diff --git a/client/db/src/bench.rs b/client/db/src/bench.rs index b1f4e3b6c0af5..13d91fff0b555 100644 --- a/client/db/src/bench.rs +++ b/client/db/src/bench.rs @@ -116,7 +116,7 @@ impl BenchmarkingState { state.add_whitelist_to_tracker(); state.reopen()?; - let child_delta = genesis.children_default.iter().map(|(_storage_key, child_content)| { + let child_delta = genesis.children_default.values().map(|child_content| { ( &child_content.child_info, child_content.data.iter().map(|(k, v)| (k.as_ref(), Some(v.as_ref()))), diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index 79ef7e9b6625d..1a80c16c4e59d 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -320,10 +320,12 @@ pub struct DatabaseSettings { } /// Block pruning settings. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum BlocksPruning { - /// Keep full block history. - All, + /// Keep full block history, of every block that was ever imported. + KeepAll, + /// Keep full finalized block history. + KeepFinalized, /// Keep N recent finalized blocks. Some(u32), } @@ -796,7 +798,7 @@ impl BlockImportOperation { return Err(sp_blockchain::Error::InvalidState) } - let child_delta = storage.children_default.iter().map(|(_storage_key, child_content)| { + let child_delta = storage.children_default.values().map(|child_content| { ( &child_content.child_info, child_content.data.iter().map(|(k, v)| (&k[..], Some(&v[..]))), @@ -1061,19 +1063,27 @@ impl Backend { /// Create new memory-backed client backend for tests. #[cfg(any(test, feature = "test-helpers"))] pub fn new_test(blocks_pruning: u32, canonicalization_delay: u64) -> Self { - Self::new_test_with_tx_storage(blocks_pruning, canonicalization_delay) + Self::new_test_with_tx_storage(BlocksPruning::Some(blocks_pruning), canonicalization_delay) } /// Create new memory-backed client backend for tests. #[cfg(any(test, feature = "test-helpers"))] - pub fn new_test_with_tx_storage(blocks_pruning: u32, canonicalization_delay: u64) -> Self { + pub fn new_test_with_tx_storage( + blocks_pruning: BlocksPruning, + canonicalization_delay: u64, + ) -> Self { let db = kvdb_memorydb::create(crate::utils::NUM_COLUMNS); let db = sp_database::as_database(db); + let state_pruning = match blocks_pruning { + BlocksPruning::KeepAll => PruningMode::ArchiveAll, + BlocksPruning::KeepFinalized => PruningMode::ArchiveCanonical, + BlocksPruning::Some(n) => PruningMode::blocks_pruning(n), + }; let db_setting = DatabaseSettings { trie_cache_maximum_size: Some(16 * 1024 * 1024), - state_pruning: Some(PruningMode::blocks_pruning(blocks_pruning)), + state_pruning: Some(state_pruning), source: DatabaseSource::Custom { db, require_create_flag: true }, - blocks_pruning: BlocksPruning::Some(blocks_pruning), + blocks_pruning, }; Self::new(db_setting, canonicalization_delay).expect("failed to create test-db") @@ -1707,32 +1717,47 @@ impl Backend { finalized: NumberFor, displaced: &FinalizationOutcome>, ) -> ClientResult<()> { - if let BlocksPruning::Some(blocks_pruning) = self.blocks_pruning { - // Always keep the last finalized block - let keep = std::cmp::max(blocks_pruning, 1); - if finalized >= keep.into() { - let number = finalized.saturating_sub(keep.into()); - self.prune_block(transaction, BlockId::::number(number))?; - } + match self.blocks_pruning { + BlocksPruning::KeepAll => {}, + BlocksPruning::Some(blocks_pruning) => { + // Always keep the last finalized block + let keep = std::cmp::max(blocks_pruning, 1); + if finalized >= keep.into() { + let number = finalized.saturating_sub(keep.into()); + self.prune_block(transaction, BlockId::::number(number))?; + } + self.prune_displaced_branches(transaction, finalized, displaced)?; + }, + BlocksPruning::KeepFinalized => { + self.prune_displaced_branches(transaction, finalized, displaced)?; + }, + } + Ok(()) + } - // Also discard all blocks from displaced branches - for h in displaced.leaves() { - let mut number = finalized; - let mut hash = *h; - // Follow displaced chains back until we reach a finalized block. - // Since leaves are discarded due to finality, they can't have parents - // that are canonical, but not yet finalized. So we stop deleting as soon as - // we reach canonical chain. - while self.blockchain.hash(number)? != Some(hash) { - let id = BlockId::::hash(hash); - match self.blockchain.header(id)? { - Some(header) => { - self.prune_block(transaction, id)?; - number = header.number().saturating_sub(One::one()); - hash = *header.parent_hash(); - }, - None => break, - } + fn prune_displaced_branches( + &self, + transaction: &mut Transaction, + finalized: NumberFor, + displaced: &FinalizationOutcome>, + ) -> ClientResult<()> { + // Discard all blocks from displaced branches + for h in displaced.leaves() { + let mut number = finalized; + let mut hash = *h; + // Follow displaced chains back until we reach a finalized block. + // Since leaves are discarded due to finality, they can't have parents + // that are canonical, but not yet finalized. So we stop deleting as soon as + // we reach canonical chain. + while self.blockchain.hash(number)? != Some(hash) { + let id = BlockId::::hash(hash); + match self.blockchain.header(id)? { + Some(header) => { + self.prune_block(transaction, id)?; + number = header.number().saturating_sub(One::one()); + hash = *header.parent_hash(); + }, + None => break, } } } @@ -1752,6 +1777,13 @@ impl Backend { columns::BODY, id, )?; + utils::remove_from_db( + transaction, + &*self.storage.db, + columns::KEY_LOOKUP, + columns::JUSTIFICATIONS, + id, + )?; if let Some(index) = read_db(&*self.storage.db, columns::KEY_LOOKUP, columns::BODY_INDEX, id)? { @@ -1931,10 +1963,11 @@ impl sc_client_api::backend::Backend for Backend { operation: &mut Self::BlockImportOperation, block: BlockId, ) -> ClientResult<()> { + let hash = self.blockchain.expect_block_hash_from_id(&block)?; if block.is_pre_genesis() { operation.old_state = self.empty_state()?; } else { - operation.old_state = self.state_at(block)?; + operation.old_state = self.state_at(&hash)?; } operation.commit_state = true; @@ -2270,15 +2303,8 @@ impl sc_client_api::backend::Backend for Backend { &self.blockchain } - fn state_at(&self, block: BlockId) -> ClientResult { - use sc_client_api::blockchain::HeaderBackend as BcHeaderBackend; - - let is_genesis = match &block { - BlockId::Number(n) if n.is_zero() => true, - BlockId::Hash(h) if h == &self.blockchain.meta.read().genesis_hash => true, - _ => false, - }; - if is_genesis { + fn state_at(&self, hash: &Block::Hash) -> ClientResult { + if hash == &self.blockchain.meta.read().genesis_hash { if let Some(genesis_state) = &*self.genesis_state.read() { let root = genesis_state.root; let db_state = DbStateBuilder::::new(genesis_state.clone(), root) @@ -2290,14 +2316,7 @@ impl sc_client_api::backend::Backend for Backend { } } - let hash = match block { - BlockId::Hash(h) => h, - BlockId::Number(n) => self.blockchain.hash(n)?.ok_or_else(|| { - sp_blockchain::Error::UnknownBlock(format!("Unknown block number {}", n)) - })?, - }; - - match self.blockchain.header_metadata(hash) { + match self.blockchain.header_metadata(*hash) { Ok(ref hdr) => { let hint = || { sc_state_db::NodeDb::get(self.storage.as_ref(), hdr.state_root.as_ref()) @@ -2305,7 +2324,7 @@ impl sc_client_api::backend::Backend for Backend { .is_some() }; if let Ok(()) = - self.storage.state_db.pin(&hash, hdr.number.saturated_into::(), hint) + self.storage.state_db.pin(hash, hdr.number.saturated_into::(), hint) { let root = hdr.state_root; let db_state = DbStateBuilder::::new(self.storage.clone(), root) @@ -2313,12 +2332,12 @@ impl sc_client_api::backend::Backend for Backend { self.shared_trie_cache.as_ref().map(|c| c.local_cache()), ) .build(); - let state = RefTrackingState::new(db_state, self.storage.clone(), Some(hash)); - Ok(RecordStatsState::new(state, Some(hash), self.state_usage.clone())) + let state = RefTrackingState::new(db_state, self.storage.clone(), Some(*hash)); + Ok(RecordStatsState::new(state, Some(*hash), self.state_usage.clone())) } else { Err(sp_blockchain::Error::UnknownBlock(format!( "State already discarded for {:?}", - block + hash ))) } }, @@ -2506,7 +2525,7 @@ pub(crate) mod tests { trie_cache_maximum_size: Some(16 * 1024 * 1024), state_pruning: Some(PruningMode::blocks_pruning(1)), source: DatabaseSource::Custom { db: backing, require_create_flag: false }, - blocks_pruning: BlocksPruning::All, + blocks_pruning: BlocksPruning::KeepFinalized, }, 0, ) @@ -2556,7 +2575,7 @@ pub(crate) mod tests { db.commit_operation(op).unwrap(); - let state = db.state_at(BlockId::Number(0)).unwrap(); + let state = db.state_at(&hash).unwrap(); assert_eq!(state.storage(&[1, 3, 5]).unwrap(), Some(vec![2, 4, 6])); assert_eq!(state.storage(&[1, 2, 3]).unwrap(), Some(vec![9, 9, 9])); @@ -2591,7 +2610,8 @@ pub(crate) mod tests { db.commit_operation(op).unwrap(); - let state = db.state_at(BlockId::Number(1)).unwrap(); + let hash = db.blockchain().expect_block_hash_from_id(&BlockId::Number(1)).unwrap(); + let state = db.state_at(&hash).unwrap(); assert_eq!(state.storage(&[1, 3, 5]).unwrap(), None); assert_eq!(state.storage(&[1, 2, 3]).unwrap(), Some(vec![9, 9, 9])); @@ -3107,11 +3127,7 @@ pub(crate) mod tests { hash }; - let block0_hash = backend - .state_at(BlockId::Hash(hash0)) - .unwrap() - .storage_hash(&b"test"[..]) - .unwrap(); + let block0_hash = backend.state_at(&hash0).unwrap().storage_hash(&b"test"[..]).unwrap(); let hash1 = { let mut op = backend.begin_operation().unwrap(); @@ -3150,11 +3166,7 @@ pub(crate) mod tests { backend.commit_operation(op).unwrap(); } - let block1_hash = backend - .state_at(BlockId::Hash(hash1)) - .unwrap() - .storage_hash(&b"test"[..]) - .unwrap(); + let block1_hash = backend.state_at(&hash1).unwrap().storage_hash(&b"test"[..]).unwrap(); assert_ne!(block0_hash, block1_hash); } @@ -3176,7 +3188,7 @@ pub(crate) mod tests { #[test] fn prune_blocks_on_finalize() { - let backend = Backend::::new_test_with_tx_storage(2, 0); + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(2), 0); let mut blocks = Vec::new(); let mut prev_hash = Default::default(); for i in 0..5 { @@ -3210,9 +3222,114 @@ pub(crate) mod tests { assert_eq!(Some(vec![4.into()]), bc.body(BlockId::hash(blocks[4])).unwrap()); } + #[test] + fn prune_blocks_on_finalize_in_keep_all() { + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::KeepAll, 0); + let mut blocks = Vec::new(); + let mut prev_hash = Default::default(); + for i in 0..5 { + let hash = insert_block( + &backend, + i, + prev_hash, + None, + Default::default(), + vec![i.into()], + None, + ) + .unwrap(); + blocks.push(hash); + prev_hash = hash; + } + + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); + for i in 1..3 { + op.mark_finalized(BlockId::Hash(blocks[i]), None).unwrap(); + } + backend.commit_operation(op).unwrap(); + + let bc = backend.blockchain(); + assert_eq!(Some(vec![0.into()]), bc.body(BlockId::hash(blocks[0])).unwrap()); + assert_eq!(Some(vec![1.into()]), bc.body(BlockId::hash(blocks[1])).unwrap()); + assert_eq!(Some(vec![2.into()]), bc.body(BlockId::hash(blocks[2])).unwrap()); + assert_eq!(Some(vec![3.into()]), bc.body(BlockId::hash(blocks[3])).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(BlockId::hash(blocks[4])).unwrap()); + } + + #[test] + fn prune_blocks_on_finalize_with_fork_in_keep_all() { + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::KeepAll, 10); + let mut blocks = Vec::new(); + let mut prev_hash = Default::default(); + for i in 0..5 { + let hash = insert_block( + &backend, + i, + prev_hash, + None, + Default::default(), + vec![i.into()], + None, + ) + .unwrap(); + blocks.push(hash); + prev_hash = hash; + } + + // insert a fork at block 2 + let fork_hash_root = insert_block( + &backend, + 2, + blocks[1], + None, + sp_core::H256::random(), + vec![2.into()], + None, + ) + .unwrap(); + insert_block( + &backend, + 3, + fork_hash_root, + None, + H256::random(), + vec![3.into(), 11.into()], + None, + ) + .unwrap(); + + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); + op.mark_head(BlockId::Hash(blocks[4])).unwrap(); + backend.commit_operation(op).unwrap(); + + let bc = backend.blockchain(); + assert_eq!(Some(vec![2.into()]), bc.body(BlockId::hash(fork_hash_root)).unwrap()); + + for i in 1..5 { + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, BlockId::Hash(blocks[i])).unwrap(); + op.mark_finalized(BlockId::Hash(blocks[i]), None).unwrap(); + backend.commit_operation(op).unwrap(); + } + + assert_eq!(Some(vec![0.into()]), bc.body(BlockId::hash(blocks[0])).unwrap()); + assert_eq!(Some(vec![1.into()]), bc.body(BlockId::hash(blocks[1])).unwrap()); + assert_eq!(Some(vec![2.into()]), bc.body(BlockId::hash(blocks[2])).unwrap()); + assert_eq!(Some(vec![3.into()]), bc.body(BlockId::hash(blocks[3])).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(BlockId::hash(blocks[4])).unwrap()); + + assert_eq!(Some(vec![2.into()]), bc.body(BlockId::hash(fork_hash_root)).unwrap()); + assert_eq!(bc.info().best_number, 4); + for i in 0..5 { + assert!(bc.hash(i).unwrap().is_some()); + } + } + #[test] fn prune_blocks_on_finalize_with_fork() { - let backend = Backend::::new_test_with_tx_storage(2, 10); + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(2), 10); let mut blocks = Vec::new(); let mut prev_hash = Default::default(); for i in 0..5 { @@ -3273,7 +3390,7 @@ pub(crate) mod tests { #[test] fn indexed_data_block_body() { - let backend = Backend::::new_test_with_tx_storage(1, 10); + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(1), 10); let x0 = ExtrinsicWrapper::from(0u64).encode(); let x1 = ExtrinsicWrapper::from(1u64).encode(); @@ -3315,7 +3432,7 @@ pub(crate) mod tests { #[test] fn index_invalid_size() { - let backend = Backend::::new_test_with_tx_storage(1, 10); + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(1), 10); let x0 = ExtrinsicWrapper::from(0u64).encode(); let x1 = ExtrinsicWrapper::from(1u64).encode(); @@ -3350,7 +3467,7 @@ pub(crate) mod tests { #[test] fn renew_transaction_storage() { - let backend = Backend::::new_test_with_tx_storage(2, 10); + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(2), 10); let mut blocks = Vec::new(); let mut prev_hash = Default::default(); let x1 = ExtrinsicWrapper::from(0u64).encode(); @@ -3397,7 +3514,7 @@ pub(crate) mod tests { #[test] fn remove_leaf_block_works() { - let backend = Backend::::new_test_with_tx_storage(2, 10); + let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(2), 10); let mut blocks = Vec::new(); let mut prev_hash = Default::default(); for i in 0..2 { diff --git a/client/db/src/upgrade.rs b/client/db/src/upgrade.rs index 292905663a20b..51750bf689759 100644 --- a/client/db/src/upgrade.rs +++ b/client/db/src/upgrade.rs @@ -115,7 +115,7 @@ pub fn upgrade_db(db_path: &Path, db_type: DatabaseType) -> Upgra /// 2) transactions column is added; fn migrate_1_to_2(db_path: &Path, _db_type: DatabaseType) -> UpgradeResult<()> { let db_cfg = DatabaseConfig::with_columns(V1_NUM_COLUMNS); - let db = Database::open(&db_cfg, db_path)?; + let mut db = Database::open(&db_cfg, db_path)?; db.add_column().map_err(Into::into) } @@ -126,7 +126,10 @@ fn migrate_2_to_3(db_path: &Path, _db_type: DatabaseType) -> Upgr let db = Database::open(&db_cfg, db_path)?; // Get all the keys we need to update - let keys: Vec<_> = db.iter(columns::JUSTIFICATIONS).map(|entry| entry.0).collect(); + let keys: Vec<_> = db + .iter(columns::JUSTIFICATIONS) + .map(|r| r.map(|e| e.0)) + .collect::>()?; // Read and update each entry let mut transaction = db.transaction(); @@ -152,7 +155,7 @@ fn migrate_2_to_3(db_path: &Path, _db_type: DatabaseType) -> Upgr /// 2) BODY_INDEX column is added; fn migrate_3_to_4(db_path: &Path, _db_type: DatabaseType) -> UpgradeResult<()> { let db_cfg = DatabaseConfig::with_columns(V3_NUM_COLUMNS); - let db = Database::open(&db_cfg, db_path)?; + let mut db = Database::open(&db_cfg, db_path)?; db.add_column().map_err(Into::into) } diff --git a/client/executor/Cargo.toml b/client/executor/Cargo.toml index 6a4b2a44a2d44..264db0e89b1c8 100644 --- a/client/executor/Cargo.toml +++ b/client/executor/Cargo.toml @@ -18,7 +18,7 @@ lazy_static = "1.4.0" lru = "0.7.5" parking_lot = "0.12.1" tracing = "0.1.29" -wasmi = "0.9.1" +wasmi = "0.13" codec = { package = "parity-scale-codec", version = "3.0.0" } sc-executor-common = { version = "0.10.0-dev", path = "common" } @@ -37,8 +37,8 @@ sp-version = { version = "5.0.0", path = "../../primitives/version" } sp-wasm-interface = { version = "6.0.0", path = "../../primitives/wasm-interface" } [dev-dependencies] +array-bytes = "4.1" wat = "1.0" -hex-literal = "0.3.4" sc-runtime-test = { version = "2.0.0", path = "runtime-test" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } sp-state-machine = { version = "0.12.0", path = "../../primitives/state-machine" } @@ -63,5 +63,4 @@ default = ["std"] std = [] wasm-extern-trace = [] wasmtime = ["sc-executor-wasmtime"] -wasmi-errno = ["wasmi/errno"] wasmer-sandbox = ["sc-executor-common/wasmer-sandbox"] diff --git a/client/executor/common/Cargo.toml b/client/executor/common/Cargo.toml index b16ed7e8552ce..71a6f2c324591 100644 --- a/client/executor/common/Cargo.toml +++ b/client/executor/common/Cargo.toml @@ -17,9 +17,9 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0" } environmental = "1.1.3" thiserror = "1.0.30" -wasm-instrument = "0.1" +wasm-instrument = "0.3" wasmer = { version = "2.2", features = ["singlepass"], optional = true } -wasmi = "0.9.1" +wasmi = "0.13" sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sp-maybe-compressed-blob = { version = "4.1.0-dev", path = "../../../primitives/maybe-compressed-blob" } sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } diff --git a/client/executor/common/src/sandbox/wasmi_backend.rs b/client/executor/common/src/sandbox/wasmi_backend.rs index 03fa5dc06dea8..2ba133f5f15b1 100644 --- a/client/executor/common/src/sandbox/wasmi_backend.rs +++ b/client/executor/common/src/sandbox/wasmi_backend.rs @@ -18,14 +18,14 @@ //! Wasmi specific impls for sandbox -use std::rc::Rc; +use std::{fmt, rc::Rc}; use codec::{Decode, Encode}; use sp_sandbox::HostError; use sp_wasm_interface::{FunctionContext, Pointer, ReturnValue, Value, WordSize}; use wasmi::{ memory_units::Pages, ImportResolver, MemoryInstance, Module, ModuleInstance, RuntimeArgs, - RuntimeValue, Trap, TrapKind, + RuntimeValue, Trap, }; use crate::{ @@ -39,9 +39,20 @@ use crate::{ environmental::environmental!(SandboxContextStore: trait SandboxContext); +#[derive(Debug)] +struct CustomHostError(String); + +impl fmt::Display for CustomHostError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "HostError: {}", self.0) + } +} + +impl wasmi::HostError for CustomHostError {} + /// Construct trap error from specified message fn trap(msg: &'static str) -> Trap { - TrapKind::Host(Box::new(Error::Other(msg.into()))).into() + Trap::host(CustomHostError(msg.into())) } impl ImportResolver for Imports { diff --git a/client/executor/src/integration_tests/mod.rs b/client/executor/src/integration_tests/mod.rs index ba0c93630cf6c..9ffb7f502f5c6 100644 --- a/client/executor/src/integration_tests/mod.rs +++ b/client/executor/src/integration_tests/mod.rs @@ -21,7 +21,6 @@ mod linux; mod sandbox; use codec::{Decode, Encode}; -use hex_literal::hex; use sc_executor_common::{error::Error, runtime_blob::RuntimeBlob, wasm_runtime::WasmModule}; use sc_runtime_test::wasm_binary_unwrap; use sp_core::{ @@ -253,7 +252,7 @@ fn call_not_existing_function(wasm_method: WasmExecutionMethod) { match call_in_wasm("test_calling_missing_external", &[], wasm_method, &mut ext).unwrap_err() { Error::AbortedDueToTrap(error) => { let expected = match wasm_method { - WasmExecutionMethod::Interpreted => "Trap: Host(Other(\"Function `missing_external` is only a stub. Calling a stub is not allowed.\"))", + WasmExecutionMethod::Interpreted => "Other: Function `missing_external` is only a stub. Calling a stub is not allowed.", #[cfg(feature = "wasmtime")] WasmExecutionMethod::Compiled { .. } => "call to a missing function env:missing_external" }; @@ -273,7 +272,7 @@ fn call_yet_another_not_existing_function(wasm_method: WasmExecutionMethod) { { Error::AbortedDueToTrap(error) => { let expected = match wasm_method { - WasmExecutionMethod::Interpreted => "Trap: Host(Other(\"Function `yet_another_missing_external` is only a stub. Calling a stub is not allowed.\"))", + WasmExecutionMethod::Interpreted => "Other: Function `yet_another_missing_external` is only a stub. Calling a stub is not allowed.", #[cfg(feature = "wasmtime")] WasmExecutionMethod::Compiled { .. } => "call to a missing function env:yet_another_missing_external" }; @@ -391,16 +390,18 @@ fn sha2_256_should_work(wasm_method: WasmExecutionMethod) { let mut ext = ext.ext(); assert_eq!( call_in_wasm("test_sha2_256", &[0], wasm_method, &mut ext,).unwrap(), - hex!("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") - .to_vec() - .encode(), + array_bytes::hex2bytes_unchecked( + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + ) + .encode(), ); assert_eq!( call_in_wasm("test_sha2_256", &b"Hello world!".to_vec().encode(), wasm_method, &mut ext,) .unwrap(), - hex!("c0535e4be2b79ffd93291305436bf889314e4a3faec05ecffcbb7df31ad9e51a") - .to_vec() - .encode(), + array_bytes::hex2bytes_unchecked( + "c0535e4be2b79ffd93291305436bf889314e4a3faec05ecffcbb7df31ad9e51a" + ) + .encode(), ); } @@ -410,16 +411,18 @@ fn twox_256_should_work(wasm_method: WasmExecutionMethod) { let mut ext = ext.ext(); assert_eq!( call_in_wasm("test_twox_256", &[0], wasm_method, &mut ext,).unwrap(), - hex!("99e9d85137db46ef4bbea33613baafd56f963c64b1f3685a4eb4abd67ff6203a") - .to_vec() - .encode(), + array_bytes::hex2bytes_unchecked( + "99e9d85137db46ef4bbea33613baafd56f963c64b1f3685a4eb4abd67ff6203a" + ) + .encode(), ); assert_eq!( call_in_wasm("test_twox_256", &b"Hello world!".to_vec().encode(), wasm_method, &mut ext,) .unwrap(), - hex!("b27dfd7f223f177f2a13647b533599af0c07f68bda23d96d059da2b451a35a74") - .to_vec() - .encode(), + array_bytes::hex2bytes_unchecked( + "b27dfd7f223f177f2a13647b533599af0c07f68bda23d96d059da2b451a35a74" + ) + .encode(), ); } @@ -429,12 +432,12 @@ fn twox_128_should_work(wasm_method: WasmExecutionMethod) { let mut ext = ext.ext(); assert_eq!( call_in_wasm("test_twox_128", &[0], wasm_method, &mut ext,).unwrap(), - hex!("99e9d85137db46ef4bbea33613baafd5").to_vec().encode(), + array_bytes::hex2bytes_unchecked("99e9d85137db46ef4bbea33613baafd5").encode(), ); assert_eq!( call_in_wasm("test_twox_128", &b"Hello world!".to_vec().encode(), wasm_method, &mut ext,) .unwrap(), - hex!("b27dfd7f223f177f2a13647b533599af").to_vec().encode(), + array_bytes::hex2bytes_unchecked("b27dfd7f223f177f2a13647b533599af").encode(), ); } @@ -704,7 +707,7 @@ fn parallel_execution(wasm_method: WasmExecutionMethod) { &[0], ) .unwrap(), - hex!("99e9d85137db46ef4bbea33613baafd5").to_vec().encode(), + array_bytes::hex2bytes_unchecked("99e9d85137db46ef4bbea33613baafd5").encode() ); }) }) @@ -909,7 +912,7 @@ fn unreachable_intrinsic(wasm_method: WasmExecutionMethod) { match call_in_wasm("test_unreachable_intrinsic", &[], wasm_method, &mut ext).unwrap_err() { Error::AbortedDueToTrap(error) => { let expected = match wasm_method { - WasmExecutionMethod::Interpreted => "Trap: Unreachable", + WasmExecutionMethod::Interpreted => "unreachable", #[cfg(feature = "wasmtime")] WasmExecutionMethod::Compiled { .. } => "wasm trap: wasm `unreachable` instruction executed", }; diff --git a/client/executor/src/native_executor.rs b/client/executor/src/native_executor.rs index 7610c4c8f32e0..b164b427e306d 100644 --- a/client/executor/src/native_executor.rs +++ b/client/executor/src/native_executor.rs @@ -27,22 +27,18 @@ use std::{ marker::PhantomData, panic::{AssertUnwindSafe, UnwindSafe}, path::PathBuf, - result, sync::{ atomic::{AtomicU64, Ordering}, mpsc, Arc, }, }; -use codec::{Decode, Encode}; +use codec::Encode; use sc_executor_common::{ runtime_blob::RuntimeBlob, wasm_runtime::{AllocationStats, InvokeMethod, WasmInstance, WasmModule}, }; -use sp_core::{ - traits::{CodeExecutor, Externalities, RuntimeCode, RuntimeSpawn, RuntimeSpawnExt}, - NativeOrEncoded, -}; +use sp_core::traits::{CodeExecutor, Externalities, RuntimeCode, RuntimeSpawn, RuntimeSpawnExt}; use sp_externalities::ExternalitiesExt as _; use sp_tasks::new_async_externalities; use sp_version::{GetNativeVersion, NativeVersion, RuntimeVersion}; @@ -339,18 +335,14 @@ where { type Error = Error; - fn call< - R: Decode + Encode + PartialEq, - NC: FnOnce() -> result::Result> + UnwindSafe, - >( + fn call( &self, ext: &mut dyn Externalities, runtime_code: &RuntimeCode, method: &str, data: &[u8], _use_native: bool, - _native_call: Option, - ) -> (Result>, bool) { + ) -> (Result>, bool) { tracing::trace!( target: "executor", %method, @@ -363,7 +355,7 @@ where |module, mut instance, _onchain_version, mut ext| { with_externalities_safe(&mut **ext, move || { preregister_builtin_ext(module.clone()); - instance.call_export(method, data).map(NativeOrEncoded::Encoded) + instance.call_export(method, data) }) }, ); @@ -594,18 +586,14 @@ fn preregister_builtin_ext(module: Arc) { impl CodeExecutor for NativeElseWasmExecutor { type Error = Error; - fn call< - R: Decode + Encode + PartialEq, - NC: FnOnce() -> result::Result> + UnwindSafe, - >( + fn call( &self, ext: &mut dyn Externalities, runtime_code: &RuntimeCode, method: &str, data: &[u8], use_native: bool, - native_call: Option, - ) -> (Result>, bool) { + ) -> (Result>, bool) { tracing::trace!( target: "executor", function = %method, @@ -623,49 +611,31 @@ impl CodeExecutor for NativeElseWasmExecut let can_call_with = onchain_version.can_call_with(&self.native_version.runtime_version); - match (use_native, can_call_with, native_call) { - (_, false, _) | (false, _, _) => { - if !can_call_with { - tracing::trace!( - target: "executor", - native = %self.native_version.runtime_version, - chain = %onchain_version, - "Request for native execution failed", - ); - } - - with_externalities_safe(&mut **ext, move || { - preregister_builtin_ext(module.clone()); - instance.call_export(method, data).map(NativeOrEncoded::Encoded) - }) - }, - (true, true, Some(call)) => { - tracing::trace!( - target: "executor", - native = %self.native_version.runtime_version, - chain = %onchain_version, - "Request for native execution with native call succeeded" - ); - - used_native = true; - let res = with_externalities_safe(&mut **ext, move || (call)()) - .and_then(|r| r.map(NativeOrEncoded::Native).map_err(Error::ApiError)); - - Ok(res) - }, - _ => { + if use_native && can_call_with { + tracing::trace!( + target: "executor", + native = %self.native_version.runtime_version, + chain = %onchain_version, + "Request for native execution succeeded", + ); + + used_native = true; + Ok(with_externalities_safe(&mut **ext, move || D::dispatch(method, data))? + .ok_or_else(|| Error::MethodNotFound(method.to_owned()))) + } else { + if !can_call_with { tracing::trace!( target: "executor", native = %self.native_version.runtime_version, chain = %onchain_version, - "Request for native execution succeeded", + "Request for native execution failed", ); + } - used_native = true; - Ok(with_externalities_safe(&mut **ext, move || D::dispatch(method, data))? - .map(NativeOrEncoded::Encoded) - .ok_or_else(|| Error::MethodNotFound(method.to_owned()))) - }, + with_externalities_safe(&mut **ext, move || { + preregister_builtin_ext(module.clone()); + instance.call_export(method, data) + }) } }, ); diff --git a/client/executor/wasmi/Cargo.toml b/client/executor/wasmi/Cargo.toml index 46bacf54a42c6..879af677ca042 100644 --- a/client/executor/wasmi/Cargo.toml +++ b/client/executor/wasmi/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } log = "0.4.17" -wasmi = "0.9.1" +wasmi = "0.13" sc-allocator = { version = "4.1.0-dev", path = "../../allocator" } sc-executor-common = { version = "0.10.0-dev", path = "../common" } sp-runtime-interface = { version = "6.0.0", path = "../../../primitives/runtime-interface" } diff --git a/client/executor/wasmi/src/lib.rs b/client/executor/wasmi/src/lib.rs index e17707e158321..1284cc23e4c96 100644 --- a/client/executor/wasmi/src/lib.rs +++ b/client/executor/wasmi/src/lib.rs @@ -181,6 +181,7 @@ impl Sandbox for FunctionExecutor { let len = val_len as usize; + #[allow(deprecated)] let buffer = match self.memory.get(val_ptr.into(), len) { Err(_) => return Ok(sandbox_env::ERR_OUT_OF_BOUNDS), Ok(buffer) => buffer, @@ -568,6 +569,7 @@ fn call_in_wasm_module( match result { Ok(Some(I64(r))) => { let (ptr, length) = unpack_ptr_and_len(r as u64); + #[allow(deprecated)] memory.get(ptr, length as usize).map_err(|_| Error::Runtime) }, Err(e) => { diff --git a/client/executor/wasmtime/Cargo.toml b/client/executor/wasmtime/Cargo.toml index e75f2d9d043d0..fc6d5db14aa1d 100644 --- a/client/executor/wasmtime/Cargo.toml +++ b/client/executor/wasmtime/Cargo.toml @@ -17,11 +17,11 @@ cfg-if = "1.0" codec = { package = "parity-scale-codec", version = "3.0.0" } libc = "0.2.121" log = "0.4.17" -parity-wasm = "0.42.0" +parity-wasm = "0.45" # When bumping wasmtime do not forget to also bump rustix # to exactly the same version as used by wasmtime! -wasmtime = { version = "0.38.0", default-features = false, features = [ +wasmtime = { version = "1.0.0", default-features = false, features = [ "cache", "cranelift", "jitdump", @@ -35,16 +35,14 @@ sp-runtime-interface = { version = "6.0.0", path = "../../../primitives/runtime- sp-sandbox = { version = "0.10.0-dev", path = "../../../primitives/sandbox" } sp-wasm-interface = { version = "6.0.0", features = ["wasmtime"], path = "../../../primitives/wasm-interface" } -[target.'cfg(target_os = "linux")'.dependencies] -rustix = { version = "0.35.6", default-features = false, features = ["std", "mm", "fs", "param", "use-libc"] } -once_cell = "1.12.0" - -# Here we include the rustix crate used by wasmtime just to enable its 'use-libc' flag. +# Here we include the rustix crate in the exactly same semver-compatible version as used by +# wasmtime and enable its 'use-libc' flag. # # By default rustix directly calls the appropriate syscalls completely bypassing libc; # this doesn't have any actual benefits for us besides making it harder to debug memory # problems (since then `mmap` etc. cannot be easily hooked into). -rustix_wasmtime = { package = "rustix", version = "0.33.7", default-features = false, features = ["std", "use-libc"] } +rustix = { version = "0.35.9", default-features = false, features = ["std", "mm", "fs", "param", "use-libc"] } +once_cell = "1.12.0" [dev-dependencies] wat = "1.0" diff --git a/client/executor/wasmtime/src/runtime.rs b/client/executor/wasmtime/src/runtime.rs index 871de4e2300d2..e3509351022bc 100644 --- a/client/executor/wasmtime/src/runtime.rs +++ b/client/executor/wasmtime/src/runtime.rs @@ -320,9 +320,7 @@ fn common_config(semantics: &Semantics) -> std::result::Result native_stack_max, @@ -334,9 +332,7 @@ fn common_config(semantics: &Semantics) -> std::result::Result 1024 * 1024, }; - config - .max_wasm_stack(native_stack_max as usize) - .map_err(|e| WasmError::Other(format!("cannot set max wasm stack: {:#}", e)))?; + config.max_wasm_stack(native_stack_max as usize); config.parallel_compilation(semantics.parallel_compilation); @@ -548,6 +544,7 @@ pub struct Semantics { pub max_memory_size: Option, } +#[derive(Clone)] pub struct Config { /// The WebAssembly standard requires all imports of an instantiated module to be resolved, /// otherwise, the instantiation fails. If this option is set to `true`, then this behavior is diff --git a/client/finality-grandpa/Cargo.toml b/client/finality-grandpa/Cargo.toml index 5950b108ca4ab..83c6051946aff 100644 --- a/client/finality-grandpa/Cargo.toml +++ b/client/finality-grandpa/Cargo.toml @@ -15,12 +15,12 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] ahash = "0.7.6" +array-bytes = "4.1" async-trait = "0.1.57" dyn-clone = "1.0" finality-grandpa = { version = "0.16.0", features = ["derive-codec"] } futures = "0.3.21" futures-timer = "3.0.1" -hex = "0.4.2" log = "0.4.17" parity-scale-codec = { version = "3.0.0", features = ["derive"] } parking_lot = "0.12.1" diff --git a/client/finality-grandpa/src/aux_schema.rs b/client/finality-grandpa/src/aux_schema.rs index 25ed4a3f490e0..235453ea35df1 100644 --- a/client/finality-grandpa/src/aux_schema.rs +++ b/client/finality-grandpa/src/aux_schema.rs @@ -191,7 +191,7 @@ where "state is for completed round; completed rounds must have a prevote ghost; qed.", ); - let mut current_rounds = CurrentRounds::new(); + let mut current_rounds = CurrentRounds::::new(); current_rounds.insert(last_round_number + 1, HasVoted::No); let set_state = VoterSetState::Live { @@ -255,7 +255,7 @@ where let base = set_state.prevote_ghost .expect("state is for completed round; completed rounds must have a prevote ghost; qed."); - let mut current_rounds = CurrentRounds::new(); + let mut current_rounds = CurrentRounds::::new(); current_rounds.insert(last_round_number + 1, HasVoted::No); VoterSetState::Live { @@ -500,7 +500,7 @@ mod test { use super::*; use sp_core::{crypto::UncheckedFrom, H256}; use sp_finality_grandpa::AuthorityId; - use substrate_test_runtime_client; + use substrate_test_runtime_client::{self, runtime::Block}; fn dummy_id() -> AuthorityId { AuthorityId::unchecked_from([1; 32]) @@ -574,7 +574,7 @@ mod test { .unwrap(), ); - let mut current_rounds = CurrentRounds::new(); + let mut current_rounds = CurrentRounds::::new(); current_rounds.insert(round_number + 1, HasVoted::No); assert_eq!( @@ -667,7 +667,7 @@ mod test { .unwrap(), ); - let mut current_rounds = CurrentRounds::new(); + let mut current_rounds = CurrentRounds::::new(); current_rounds.insert(round_number + 1, HasVoted::No); assert_eq!( diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index 5f94a4d1b65be..ce85ca842aa52 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -35,7 +35,8 @@ //! impolite to send messages about r+1 or later. "future-round" messages can //! be dropped and ignored. //! -//! It is impolite to send a neighbor packet which moves backwards in protocol state. +//! It is impolite to send a neighbor packet which moves backwards or does not progress +//! protocol state. //! //! This is beneficial if it conveys some progress in the protocol state of the peer. //! @@ -90,14 +91,14 @@ use parity_scale_codec::{Decode, Encode}; use prometheus_endpoint::{register, CounterVec, Opts, PrometheusError, Registry, U64}; use rand::seq::SliceRandom; use sc_network::{PeerId, ReputationChange}; -use sc_network_common::protocol::event::ObservedRole; +use sc_network_common::protocol::role::ObservedRole; use sc_network_gossip::{MessageIntent, ValidatorContext}; use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG}; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; use sp_finality_grandpa::AuthorityId; use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; -use super::{benefit, cost, Round, SetId}; +use super::{benefit, cost, Round, SetId, NEIGHBOR_REBROADCAST_PERIOD}; use crate::{environment, CatchUp, CompactCommit, SignedMessage}; use std::{ @@ -148,14 +149,15 @@ enum Consider { /// A view of protocol state. #[derive(Debug)] struct View { - round: Round, // the current round we are at. - set_id: SetId, // the current voter set id. - last_commit: Option, // commit-finalized block height, if any. + round: Round, // the current round we are at. + set_id: SetId, // the current voter set id. + last_commit: Option, // commit-finalized block height, if any. + last_update: Option, // last time we heard from peer, used for spamming detection. } impl Default for View { fn default() -> Self { - View { round: Round(1), set_id: SetId(0), last_commit: None } + View { round: Round(1), set_id: SetId(0), last_commit: None, last_update: None } } } @@ -225,7 +227,12 @@ impl LocalView { /// Converts the local view to a `View` discarding round and set id /// information about the last commit. fn as_view(&self) -> View<&N> { - View { round: self.round, set_id: self.set_id, last_commit: self.last_commit_height() } + View { + round: self.round, + set_id: self.set_id, + last_commit: self.last_commit_height(), + last_update: None, + } } /// Update the set ID. implies a reset to round 1. @@ -350,7 +357,7 @@ pub(super) struct VoteMessage { /// The voter set ID this message is from. pub(super) set_id: SetId, /// The message itself. - pub(super) message: SignedMessage, + pub(super) message: SignedMessage, } /// Network level commit message with topic information. @@ -361,7 +368,7 @@ pub(super) struct FullCommitMessage { /// The voter set ID this message is from. pub(super) set_id: SetId, /// The compact commit message. - pub(super) message: CompactCommit, + pub(super) message: CompactCommit, } /// V1 neighbor packet. Neighbor packets are sent from nodes to their peers @@ -406,7 +413,7 @@ pub(super) struct FullCatchUpMessage { /// The voter set ID this message is from. pub(super) set_id: SetId, /// The compact commit message. - pub(super) message: CatchUp, + pub(super) message: CatchUp, } /// Misbehavior that peers can perform. @@ -417,6 +424,8 @@ pub(super) struct FullCatchUpMessage { pub(super) enum Misbehavior { // invalid neighbor message, considering the last one. InvalidViewChange, + // duplicate neighbor message. + DuplicateNeighborMessage, // could not decode neighbor message. bytes-length of the packet. UndecodablePacket(i32), // Bad catch up message (invalid signatures). @@ -438,6 +447,7 @@ impl Misbehavior { match *self { InvalidViewChange => cost::INVALID_VIEW_CHANGE, + DuplicateNeighborMessage => cost::DUPLICATE_NEIGHBOR_MESSAGE, UndecodablePacket(bytes) => ReputationChange::new( bytes.saturating_mul(cost::PER_UNDECODABLE_BYTE), "Grandpa: Bad packet", @@ -488,20 +498,22 @@ struct Peers { second_stage_peers: HashSet, /// The randomly picked set of `LUCKY_PEERS` light clients we'll gossip commit messages to. lucky_light_peers: HashSet, + /// Neighbor packet rebroadcast period --- we reduce the reputation of peers sending duplicate + /// packets too often. + neighbor_rebroadcast_period: Duration, } -impl Default for Peers { - fn default() -> Self { +impl Peers { + fn new(neighbor_rebroadcast_period: Duration) -> Self { Peers { inner: Default::default(), first_stage_peers: Default::default(), second_stage_peers: Default::default(), lucky_light_peers: Default::default(), + neighbor_rebroadcast_period, } } -} -impl Peers { fn new_peer(&mut self, who: PeerId, role: ObservedRole) { match role { ObservedRole::Authority if self.first_stage_peers.len() < LUCKY_PEERS => { @@ -547,10 +559,23 @@ impl Peers { return Err(Misbehavior::InvalidViewChange) } + let now = Instant::now(); + let duplicate_packet = (update.set_id, update.round, Some(&update.commit_finalized_height)) == + (peer.view.set_id, peer.view.round, peer.view.last_commit.as_ref()); + + if duplicate_packet { + if let Some(last_update) = peer.view.last_update { + if now < last_update + self.neighbor_rebroadcast_period / 2 { + return Err(Misbehavior::DuplicateNeighborMessage) + } + } + } + peer.view = View { round: update.round, set_id: update.set_id, last_commit: Some(update.commit_finalized_height), + last_update: Some(now), }; trace!(target: "afg", "Peer {} updated view. Now at {:?}, {:?}", @@ -748,7 +773,7 @@ impl Inner { Inner { local_view: None, - peers: Peers::default(), + peers: Peers::new(NEIGHBOR_REBROADCAST_PERIOD), live_topics: KeepTopics::new(), next_rebroadcast: Instant::now() + REBROADCAST_AFTER, authorities: Vec::new(), @@ -758,17 +783,21 @@ impl Inner { } } - /// Note a round in the current set has started. + /// Note a round in the current set has started. Does nothing if the last + /// call to the function was with the same `round`. fn note_round(&mut self, round: Round) -> MaybeMessage { { let local_view = match self.local_view { None => return None, - Some(ref mut v) => + Some(ref mut v) => { if v.round == round { + // Do not send neighbor packets out if `round` has not changed --- + // such behavior is punishable. return None } else { v - }, + } + }, }; let set_id = local_view.set_id; @@ -790,7 +819,7 @@ impl Inner { { let local_view = match self.local_view { ref mut x @ None => x.get_or_insert(LocalView::new(set_id, Round(1))), - Some(ref mut v) => + Some(ref mut v) => { if v.set_id == set_id { let diff_authorities = self.authorities.iter().collect::>() != authorities.iter().collect::>(); @@ -803,10 +832,13 @@ impl Inner { ); self.authorities = authorities; } + // Do not send neighbor packets out if the `set_id` has not changed --- + // such behavior is punishable. return None } else { v - }, + } + }, }; local_view.update_set(set_id); @@ -816,7 +848,9 @@ impl Inner { self.multicast_neighbor_packet() } - /// Note that we've imported a commit finalizing a given block. + /// Note that we've imported a commit finalizing a given block. Does nothing if the last + /// call to the function was with the same or higher `finalized` number. + /// `set_id` & `round` are the ones the commit message is from. fn note_commit_finalized( &mut self, round: Round, @@ -1071,7 +1105,7 @@ impl Inner { let (base_hash, base_number) = last_completed_round.base; - let catch_up = CatchUp:: { + let catch_up = CatchUp:: { round_number: last_completed_round.number, prevotes, precommits, @@ -1357,6 +1391,8 @@ impl GossipValidator { } /// Note that we've imported a commit finalizing a given block. + /// `set_id` & `round` are the ones the commit message is from and not necessarily + /// the latest set ID & round started. pub(super) fn note_commit_finalized( &self, round: Round, @@ -1647,12 +1683,13 @@ pub(super) struct PeerReport { #[cfg(test)] mod tests { - use super::{environment::SharedVoterSetState, *}; + use super::{super::NEIGHBOR_REBROADCAST_PERIOD, environment::SharedVoterSetState, *}; use crate::communication; use sc_network::config::Role; use sc_network_gossip::Validator as GossipValidatorT; - use sc_network_test::Block; use sp_core::{crypto::UncheckedFrom, H256}; + use std::time::Instant; + use substrate_test_runtime_client::runtime::{Block, Header}; // some random config (not really needed) fn config() -> crate::Config { @@ -1684,7 +1721,12 @@ mod tests { #[test] fn view_vote_rules() { - let view = View { round: Round(100), set_id: SetId(1), last_commit: Some(1000u64) }; + let view = View { + round: Round(100), + set_id: SetId(1), + last_commit: Some(1000u64), + last_update: None, + }; assert_eq!(view.consider_vote(Round(98), SetId(1)), Consider::RejectPast); assert_eq!(view.consider_vote(Round(1), SetId(0)), Consider::RejectPast); @@ -1701,7 +1743,12 @@ mod tests { #[test] fn view_global_message_rules() { - let view = View { round: Round(100), set_id: SetId(2), last_commit: Some(1000u64) }; + let view = View { + round: Round(100), + set_id: SetId(2), + last_commit: Some(1000u64), + last_update: None, + }; assert_eq!(view.consider_global(SetId(3), 1), Consider::RejectFuture); assert_eq!(view.consider_global(SetId(3), 1000), Consider::RejectFuture); @@ -1719,7 +1766,7 @@ mod tests { #[test] fn unknown_peer_cannot_be_updated() { - let mut peers = Peers::default(); + let mut peers = Peers::new(NEIGHBOR_REBROADCAST_PERIOD); let id = PeerId::random(); let update = @@ -1750,27 +1797,35 @@ mod tests { let update4 = NeighborPacket { round: Round(3), set_id: SetId(11), commit_finalized_height: 80 }; - let mut peers = Peers::default(); + // Use shorter rebroadcast period to safely roll the clock back in the last test + // and don't hit the system boot time on systems with unsigned time. + const SHORT_NEIGHBOR_REBROADCAST_PERIOD: Duration = Duration::from_secs(1); + let mut peers = Peers::new(SHORT_NEIGHBOR_REBROADCAST_PERIOD); let id = PeerId::random(); peers.new_peer(id, ObservedRole::Authority); - let mut check_update = move |update: NeighborPacket<_>| { + let check_update = |peers: &mut Peers<_>, update: NeighborPacket<_>| { let view = peers.update_peer_state(&id, update.clone()).unwrap().unwrap(); assert_eq!(view.round, update.round); assert_eq!(view.set_id, update.set_id); assert_eq!(view.last_commit, Some(update.commit_finalized_height)); }; - check_update(update1); - check_update(update2); - check_update(update3); - check_update(update4); + check_update(&mut peers, update1); + check_update(&mut peers, update2); + check_update(&mut peers, update3); + check_update(&mut peers, update4.clone()); + + // Allow duplicate neighbor packets if enough time has passed. + peers.inner.get_mut(&id).unwrap().view.last_update = + Some(Instant::now() - SHORT_NEIGHBOR_REBROADCAST_PERIOD); + check_update(&mut peers, update4); } #[test] fn invalid_view_change() { - let mut peers = Peers::default(); + let mut peers = Peers::new(NEIGHBOR_REBROADCAST_PERIOD); let id = PeerId::random(); peers.new_peer(id, ObservedRole::Authority); @@ -1783,29 +1838,41 @@ mod tests { .unwrap() .unwrap(); - let mut check_update = move |update: NeighborPacket<_>| { + let mut check_update = move |update: NeighborPacket<_>, misbehavior| { let err = peers.update_peer_state(&id, update.clone()).unwrap_err(); - assert_eq!(err, Misbehavior::InvalidViewChange); + assert_eq!(err, misbehavior); }; // round moves backwards. - check_update(NeighborPacket { - round: Round(9), - set_id: SetId(10), - commit_finalized_height: 10, - }); - // commit finalized height moves backwards. - check_update(NeighborPacket { - round: Round(10), - set_id: SetId(10), - commit_finalized_height: 9, - }); + check_update( + NeighborPacket { round: Round(9), set_id: SetId(10), commit_finalized_height: 10 }, + Misbehavior::InvalidViewChange, + ); // set ID moves backwards. - check_update(NeighborPacket { - round: Round(10), - set_id: SetId(9), - commit_finalized_height: 10, - }); + check_update( + NeighborPacket { round: Round(10), set_id: SetId(9), commit_finalized_height: 10 }, + Misbehavior::InvalidViewChange, + ); + // commit finalized height moves backwards. + check_update( + NeighborPacket { round: Round(10), set_id: SetId(10), commit_finalized_height: 9 }, + Misbehavior::InvalidViewChange, + ); + // duplicate packet without grace period. + check_update( + NeighborPacket { round: Round(10), set_id: SetId(10), commit_finalized_height: 10 }, + Misbehavior::DuplicateNeighborMessage, + ); + // commit finalized height moves backwards while round moves forward. + check_update( + NeighborPacket { round: Round(11), set_id: SetId(10), commit_finalized_height: 9 }, + Misbehavior::InvalidViewChange, + ); + // commit finalized height moves backwards while set ID moves forward. + check_update( + NeighborPacket { round: Round(10), set_id: SetId(11), commit_finalized_height: 9 }, + Misbehavior::InvalidViewChange, + ); } #[test] @@ -1856,7 +1923,7 @@ mod tests { &VoteMessage { round: Round(1), set_id: SetId(set_id), - message: SignedMessage:: { + message: SignedMessage::

{ message: finality_grandpa::Message::Prevote(finality_grandpa::Prevote { target_hash: Default::default(), target_number: 10, @@ -1872,7 +1939,7 @@ mod tests { &VoteMessage { round: Round(1), set_id: SetId(set_id), - message: SignedMessage:: { + message: SignedMessage::
{ message: finality_grandpa::Message::Prevote(finality_grandpa::Prevote { target_hash: Default::default(), target_number: 10, @@ -1943,7 +2010,7 @@ mod tests { votes: Default::default(), }); - let mut current_rounds = environment::CurrentRounds::new(); + let mut current_rounds = environment::CurrentRounds::::new(); current_rounds.insert(3, environment::HasVoted::No); let set_state = diff --git a/client/finality-grandpa/src/communication/mod.rs b/client/finality-grandpa/src/communication/mod.rs index 04d7ceaa05c8c..75a7697812c6c 100644 --- a/client/finality-grandpa/src/communication/mod.rs +++ b/client/finality-grandpa/src/communication/mod.rs @@ -37,6 +37,7 @@ use std::{ pin::Pin, sync::Arc, task::{Context, Poll}, + time::Duration, }; use finality_grandpa::{ @@ -68,6 +69,9 @@ mod periodic; #[cfg(test)] pub(crate) mod tests; +// How often to rebroadcast neighbor packets, in cases where no new packets are created. +pub(crate) const NEIGHBOR_REBROADCAST_PERIOD: Duration = Duration::from_secs(2 * 60); + pub mod grandpa_protocol_name { use sc_chain_spec::ChainSpec; use sc_network_common::protocol::ProtocolName; @@ -83,9 +87,10 @@ pub mod grandpa_protocol_name { genesis_hash: &Hash, chain_spec: &Box, ) -> ProtocolName { + let genesis_hash = genesis_hash.as_ref(); let chain_prefix = match chain_spec.fork_id() { - Some(fork_id) => format!("/{}/{}", hex::encode(genesis_hash), fork_id), - None => format!("/{}", hex::encode(genesis_hash)), + Some(fork_id) => format!("/{}/{}", array_bytes::bytes2hex("", genesis_hash), fork_id), + None => format!("/{}", array_bytes::bytes2hex("", genesis_hash)), }; format!("{}{}", chain_prefix, NAME).into() } @@ -102,6 +107,8 @@ mod cost { pub(super) const UNKNOWN_VOTER: Rep = Rep::new(-150, "Grandpa: Unknown voter"); pub(super) const INVALID_VIEW_CHANGE: Rep = Rep::new(-500, "Grandpa: Invalid view change"); + pub(super) const DUPLICATE_NEIGHBOR_MESSAGE: Rep = + Rep::new(-500, "Grandpa: Duplicate neighbor message without grace period"); pub(super) const PER_UNDECODABLE_BYTE: i32 = -5; pub(super) const PER_SIGNATURE_CHECKED: i32 = -25; pub(super) const PER_BLOCK_LOADED: i32 = -10; @@ -278,7 +285,7 @@ impl> NetworkBridge { } let (neighbor_packet_worker, neighbor_packet_sender) = - periodic::NeighborPacketWorker::new(); + periodic::NeighborPacketWorker::new(NEIGHBOR_REBROADCAST_PERIOD); NetworkBridge { service, @@ -312,8 +319,8 @@ impl> NetworkBridge { round: Round, set_id: SetId, voters: Arc>, - has_voted: HasVoted, - ) -> (impl Stream> + Unpin, OutgoingMessages) { + has_voted: HasVoted, + ) -> (impl Stream> + Unpin, OutgoingMessages) { self.note_round(round, set_id, &voters); let keystore = keystore.and_then(|ks| { @@ -675,15 +682,15 @@ pub(crate) struct OutgoingMessages { round: RoundNumber, set_id: SetIdNumber, keystore: Option, - sender: mpsc::Sender>, + sender: mpsc::Sender>, network: Arc>>, - has_voted: HasVoted, + has_voted: HasVoted, telemetry: Option, } impl Unpin for OutgoingMessages {} -impl Sink> for OutgoingMessages { +impl Sink> for OutgoingMessages { type Error = Error; fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { @@ -694,7 +701,10 @@ impl Sink> for OutgoingMessages { }) } - fn start_send(mut self: Pin<&mut Self>, mut msg: Message) -> Result<(), Self::Error> { + fn start_send( + mut self: Pin<&mut Self>, + mut msg: Message, + ) -> Result<(), Self::Error> { // if we've voted on this round previously under the same key, send that vote instead match &mut msg { finality_grandpa::Message::PrimaryPropose(ref mut vote) => { @@ -784,7 +794,7 @@ impl Sink> for OutgoingMessages { // checks a compact commit. returns the cost associated with processing it if // the commit was bad. fn check_compact_commit( - msg: &CompactCommit, + msg: &CompactCommit, voters: &VoterSet, round: Round, set_id: SetId, @@ -852,7 +862,7 @@ fn check_compact_commit( // checks a catch up. returns the cost associated with processing it if // the catch up was bad. fn check_catch_up( - msg: &CatchUp, + msg: &CatchUp, voters: &VoterSet, set_id: SetId, telemetry: Option, @@ -902,7 +912,7 @@ fn check_catch_up( ) -> Result where B: BlockT, - I: Iterator, &'a AuthorityId, &'a AuthoritySignature)>, + I: Iterator, &'a AuthorityId, &'a AuthoritySignature)>, { use crate::communication::gossip::Misbehavior; @@ -996,7 +1006,7 @@ impl CommitsOut { } } -impl Sink<(RoundNumber, Commit)> for CommitsOut { +impl Sink<(RoundNumber, Commit)> for CommitsOut { type Error = Error; fn poll_ready(self: Pin<&mut Self>, _: &mut Context) -> Poll> { @@ -1005,7 +1015,7 @@ impl Sink<(RoundNumber, Commit)> for CommitsOut { fn start_send( self: Pin<&mut Self>, - input: (RoundNumber, Commit), + input: (RoundNumber, Commit), ) -> Result<(), Self::Error> { if !self.is_voter { return Ok(()) @@ -1027,7 +1037,7 @@ impl Sink<(RoundNumber, Commit)> for CommitsOut { .map(|signed| (signed.precommit, (signed.signature, signed.id))) .unzip(); - let compact_commit = CompactCommit:: { + let compact_commit = CompactCommit:: { target_hash: commit.target_hash, target_number: commit.target_number, precommits, diff --git a/client/finality-grandpa/src/communication/periodic.rs b/client/finality-grandpa/src/communication/periodic.rs index e6d63beafc362..c001796b5ca5d 100644 --- a/client/finality-grandpa/src/communication/periodic.rs +++ b/client/finality-grandpa/src/communication/periodic.rs @@ -32,9 +32,6 @@ use super::gossip::{GossipMessage, NeighborPacket}; use sc_network::PeerId; use sp_runtime::traits::{Block as BlockT, NumberFor}; -// How often to rebroadcast, in cases where no new packets are created. -const REBROADCAST_AFTER: Duration = Duration::from_secs(2 * 60); - /// A sender used to send neighbor packets to a background job. #[derive(Clone)] pub(super) struct NeighborPacketSender( @@ -60,6 +57,7 @@ impl NeighborPacketSender { /// implementation). Periodically it sends out the last packet in cases where no new ones arrive. pub(super) struct NeighborPacketWorker { last: Option<(Vec, NeighborPacket>)>, + rebroadcast_period: Duration, delay: Delay, rx: TracingUnboundedReceiver<(Vec, NeighborPacket>)>, } @@ -67,13 +65,16 @@ pub(super) struct NeighborPacketWorker { impl Unpin for NeighborPacketWorker {} impl NeighborPacketWorker { - pub(super) fn new() -> (Self, NeighborPacketSender) { + pub(super) fn new(rebroadcast_period: Duration) -> (Self, NeighborPacketSender) { let (tx, rx) = tracing_unbounded::<(Vec, NeighborPacket>)>( "mpsc_grandpa_neighbor_packet_worker", ); - let delay = Delay::new(REBROADCAST_AFTER); + let delay = Delay::new(rebroadcast_period); - (NeighborPacketWorker { last: None, delay, rx }, NeighborPacketSender(tx)) + ( + NeighborPacketWorker { last: None, rebroadcast_period, delay, rx }, + NeighborPacketSender(tx), + ) } } @@ -85,7 +86,7 @@ impl Stream for NeighborPacketWorker { match this.rx.poll_next_unpin(cx) { Poll::Ready(None) => return Poll::Ready(None), Poll::Ready(Some((to, packet))) => { - this.delay.reset(REBROADCAST_AFTER); + this.delay.reset(this.rebroadcast_period); this.last = Some((to.clone(), packet.clone())); return Poll::Ready(Some((to, GossipMessage::::from(packet)))) @@ -98,7 +99,7 @@ impl Stream for NeighborPacketWorker { // Getting this far here implies that the timer fired. - this.delay.reset(REBROADCAST_AFTER); + this.delay.reset(this.rebroadcast_period); // Make sure the underlying task is scheduled for wake-up. // diff --git a/client/finality-grandpa/src/communication/tests.rs b/client/finality-grandpa/src/communication/tests.rs index 1f607e8d68c02..eab7bb2df50cf 100644 --- a/client/finality-grandpa/src/communication/tests.rs +++ b/client/finality-grandpa/src/communication/tests.rs @@ -28,10 +28,7 @@ use parity_scale_codec::Encode; use sc_network::{config::Role, Multiaddr, PeerId, ReputationChange}; use sc_network_common::{ config::MultiaddrWithPeerId, - protocol::{ - event::{Event as NetworkEvent, ObservedRole}, - ProtocolName, - }, + protocol::{event::Event as NetworkEvent, role::ObservedRole, ProtocolName}, service::{ NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, NetworkSyncForkRequest, NotificationSender, NotificationSenderError, @@ -646,7 +643,7 @@ fn grandpa_protocol_name() { // Create protocol name using random genesis hash. let genesis_hash = sp_core::H256::random(); - let expected = format!("/{}/grandpa/1", hex::encode(genesis_hash)); + let expected = format!("/{}/grandpa/1", array_bytes::bytes2hex("", genesis_hash.as_ref())); let proto_name = grandpa_protocol_name::standard_name(&genesis_hash, &chain_spec); assert_eq!(proto_name.to_string(), expected); diff --git a/client/finality-grandpa/src/environment.rs b/client/finality-grandpa/src/environment.rs index 63c8697053842..3d708a95f41cb 100644 --- a/client/finality-grandpa/src/environment.rs +++ b/client/finality-grandpa/src/environment.rs @@ -81,7 +81,7 @@ pub struct CompletedRound { /// The target block base used for voting in the round. pub base: (Block::Hash, NumberFor), /// All the votes observed in the round. - pub votes: Vec>, + pub votes: Vec>, } // Data about last completed rounds within a single voter set. Stores @@ -170,7 +170,7 @@ impl CompletedRounds { /// A map with voter status information for currently live rounds, /// which votes have we cast and what are they. -pub type CurrentRounds = BTreeMap>; +pub type CurrentRounds = BTreeMap::Header>>; /// The state of the current voter set, whether it is currently active or not /// and information related to the previously completed rounds. Current round @@ -214,7 +214,7 @@ impl VoterSetState { authority_set, ); - let mut current_rounds = CurrentRounds::new(); + let mut current_rounds = CurrentRounds::::new(); current_rounds.insert(1, HasVoted::No); VoterSetState::Live { completed_rounds, current_rounds } @@ -258,27 +258,27 @@ impl VoterSetState { /// Whether we've voted already during a prior run of the program. #[derive(Clone, Debug, Decode, Encode, PartialEq)] -pub enum HasVoted { +pub enum HasVoted { /// Has not voted already in this round. No, /// Has voted in this round. - Yes(AuthorityId, Vote), + Yes(AuthorityId, Vote
), } /// The votes cast by this voter already during a prior run of the program. #[derive(Debug, Clone, Decode, Encode, PartialEq)] -pub enum Vote { +pub enum Vote { /// Has cast a proposal. - Propose(PrimaryPropose), + Propose(PrimaryPropose
), /// Has cast a prevote. - Prevote(Option>, Prevote), + Prevote(Option>, Prevote
), /// Has cast a precommit (implies prevote.) - Precommit(Option>, Prevote, Precommit), + Precommit(Option>, Prevote
, Precommit
), } -impl HasVoted { +impl HasVoted
{ /// Returns the proposal we should vote with (if any.) - pub fn propose(&self) -> Option<&PrimaryPropose> { + pub fn propose(&self) -> Option<&PrimaryPropose
> { match self { HasVoted::Yes(_, Vote::Propose(propose)) => Some(propose), HasVoted::Yes(_, Vote::Prevote(propose, _)) | @@ -288,7 +288,7 @@ impl HasVoted { } /// Returns the prevote we should vote with (if any.) - pub fn prevote(&self) -> Option<&Prevote> { + pub fn prevote(&self) -> Option<&Prevote
> { match self { HasVoted::Yes(_, Vote::Prevote(_, prevote)) | HasVoted::Yes(_, Vote::Precommit(_, prevote, _)) => Some(prevote), @@ -297,7 +297,7 @@ impl HasVoted { } /// Returns the precommit we should vote with (if any.) - pub fn precommit(&self) -> Option<&Precommit> { + pub fn precommit(&self) -> Option<&Precommit
> { match self { HasVoted::Yes(_, Vote::Precommit(_, _, precommit)) => Some(precommit), _ => None, @@ -368,7 +368,7 @@ impl SharedVoterSetState { } /// Return vote status information for the current round. - pub(crate) fn has_voted(&self, round: RoundNumber) -> HasVoted { + pub(crate) fn has_voted(&self, round: RoundNumber) -> HasVoted { match &*self.inner.read() { VoterSetState::Live { current_rounds, .. } => current_rounds .get(&round) @@ -771,7 +771,7 @@ where fn proposed( &self, round: RoundNumber, - propose: PrimaryPropose, + propose: PrimaryPropose, ) -> Result<(), Self::Error> { let local_id = match self.voter_set_state.voting_on(round) { Some(id) => id, @@ -811,13 +811,17 @@ where Ok(()) } - fn prevoted(&self, round: RoundNumber, prevote: Prevote) -> Result<(), Self::Error> { + fn prevoted( + &self, + round: RoundNumber, + prevote: Prevote, + ) -> Result<(), Self::Error> { let local_id = match self.voter_set_state.voting_on(round) { Some(id) => id, None => return Ok(()), }; - let report_prevote_metrics = |prevote: &Prevote| { + let report_prevote_metrics = |prevote: &Prevote| { telemetry!( self.telemetry; CONSENSUS_DEBUG; @@ -873,14 +877,14 @@ where fn precommitted( &self, round: RoundNumber, - precommit: Precommit, + precommit: Precommit, ) -> Result<(), Self::Error> { let local_id = match self.voter_set_state.voting_on(round) { Some(id) => id, None => return Ok(()), }; - let report_precommit_metrics = |precommit: &Precommit| { + let report_precommit_metrics = |precommit: &Precommit| { telemetry!( self.telemetry; CONSENSUS_DEBUG; @@ -1065,7 +1069,7 @@ where hash: Block::Hash, number: NumberFor, round: RoundNumber, - commit: Commit, + commit: Commit, ) -> Result<(), Self::Error> { finalize_block( self.client.clone(), @@ -1092,7 +1096,11 @@ where fn prevote_equivocation( &self, _round: RoundNumber, - equivocation: finality_grandpa::Equivocation, Self::Signature>, + equivocation: finality_grandpa::Equivocation< + Self::Id, + Prevote, + Self::Signature, + >, ) { warn!(target: "afg", "Detected prevote equivocation in the finality worker: {:?}", equivocation); if let Err(err) = self.report_equivocation(equivocation.into()) { @@ -1103,7 +1111,11 @@ where fn precommit_equivocation( &self, _round: RoundNumber, - equivocation: finality_grandpa::Equivocation, Self::Signature>, + equivocation: finality_grandpa::Equivocation< + Self::Id, + Precommit, + Self::Signature, + >, ) { warn!(target: "afg", "Detected precommit equivocation in the finality worker: {:?}", equivocation); if let Err(err) = self.report_equivocation(equivocation.into()) { @@ -1114,11 +1126,11 @@ where pub(crate) enum JustificationOrCommit { Justification(GrandpaJustification), - Commit((RoundNumber, Commit)), + Commit((RoundNumber, Commit)), } -impl From<(RoundNumber, Commit)> for JustificationOrCommit { - fn from(commit: (RoundNumber, Commit)) -> JustificationOrCommit { +impl From<(RoundNumber, Commit)> for JustificationOrCommit { + fn from(commit: (RoundNumber, Commit)) -> JustificationOrCommit { JustificationOrCommit::Commit(commit) } } diff --git a/client/finality-grandpa/src/finality_proof.rs b/client/finality-grandpa/src/finality_proof.rs index ac243a1633ee1..e7578fa669463 100644 --- a/client/finality-grandpa/src/finality_proof.rs +++ b/client/finality-grandpa/src/finality_proof.rs @@ -380,8 +380,13 @@ mod tests { precommits: Vec::new(), }; - let grandpa_just = - GrandpaJustification:: { round: 8, votes_ancestries: Vec::new(), commit }; + let grandpa_just: GrandpaJustification = + sp_finality_grandpa::GrandpaJustification::
{ + round: 8, + votes_ancestries: Vec::new(), + commit, + } + .into(); let finality_proof = FinalityProof { block: header(2).hash(), diff --git a/client/finality-grandpa/src/import.rs b/client/finality-grandpa/src/import.rs index b5a0d7be70f19..d0a66888ec072 100644 --- a/client/finality-grandpa/src/import.rs +++ b/client/finality-grandpa/src/import.rs @@ -424,13 +424,15 @@ where } /// Read current set id form a given state. - fn current_set_id(&self, id: &BlockId) -> Result { + fn current_set_id(&self, hash: &Block::Hash) -> Result { + let id = &BlockId::hash(*hash); let runtime_version = self.inner.runtime_api().version(id).map_err(|e| { ConsensusError::ClientImport(format!( "Unable to retrieve current runtime version. {}", e )) })?; + if runtime_version .api_version(&>::ID) .map_or(false, |v| v < 3) @@ -439,7 +441,8 @@ where // This code may be removed once warp sync to an old runtime is no longer needed. for prefix in ["GrandpaFinality", "Grandpa"] { let k = [twox_128(prefix.as_bytes()), twox_128(b"CurrentSetId")].concat(); - if let Ok(Some(id)) = self.inner.storage(id, &sc_client_api::StorageKey(k.to_vec())) + if let Ok(Some(id)) = + self.inner.storage(hash, &sc_client_api::StorageKey(k.to_vec())) { if let Ok(id) = SetId::decode(&mut id.0.as_ref()) { return Ok(id) @@ -472,13 +475,12 @@ where // finality proofs and that the state is correct and final. // So we can read the authority list and set id from the state. self.authority_set_hard_forks.clear(); - let block_id = BlockId::hash(hash); let authorities = self .inner .runtime_api() - .grandpa_authorities(&block_id) + .grandpa_authorities(&BlockId::hash(hash)) .map_err(|e| ConsensusError::ClientImport(e.to_string()))?; - let set_id = self.current_set_id(&block_id)?; + let set_id = self.current_set_id(&hash)?; let authority_set = AuthoritySet::new( authorities.clone(), set_id, diff --git a/client/finality-grandpa/src/justification.rs b/client/finality-grandpa/src/justification.rs index 6c3b6aa826ded..56b26c964ce9b 100644 --- a/client/finality-grandpa/src/justification.rs +++ b/client/finality-grandpa/src/justification.rs @@ -18,6 +18,7 @@ use std::{ collections::{HashMap, HashSet}, + marker::PhantomData, sync::Arc, }; @@ -42,9 +43,25 @@ use crate::{AuthorityList, Commit, Error}; /// nodes, and are used by syncing nodes to prove authority set handoffs. #[derive(Clone, Encode, Decode, PartialEq, Eq, Debug)] pub struct GrandpaJustification { - pub(crate) round: u64, - pub(crate) commit: Commit, - pub(crate) votes_ancestries: Vec, + /// The GRANDPA justification for block finality. + pub justification: sp_finality_grandpa::GrandpaJustification, + _block: PhantomData, +} + +impl From> + for GrandpaJustification +{ + fn from(justification: sp_finality_grandpa::GrandpaJustification) -> Self { + Self { justification, _block: Default::default() } + } +} + +impl Into> + for GrandpaJustification +{ + fn into(self) -> sp_finality_grandpa::GrandpaJustification { + self.justification + } } impl GrandpaJustification { @@ -53,8 +70,8 @@ impl GrandpaJustification { pub fn from_commit( client: &Arc, round: u64, - commit: Commit, - ) -> Result, Error> + commit: Commit, + ) -> Result where C: HeaderBackend, { @@ -108,7 +125,7 @@ impl GrandpaJustification { } } - Ok(GrandpaJustification { round, commit, votes_ancestries }) + Ok(sp_finality_grandpa::GrandpaJustification { round, commit, votes_ancestries }.into()) } /// Decode a GRANDPA justification and validate the commit and the votes' @@ -118,15 +135,17 @@ impl GrandpaJustification { finalized_target: (Block::Hash, NumberFor), set_id: u64, voters: &VoterSet, - ) -> Result, ClientError> + ) -> Result where NumberFor: finality_grandpa::BlockNumberOps, { let justification = GrandpaJustification::::decode(&mut &*encoded) .map_err(|_| ClientError::JustificationDecode)?; - if (justification.commit.target_hash, justification.commit.target_number) != - finalized_target + if ( + justification.justification.commit.target_hash, + justification.justification.commit.target_number, + ) != finalized_target { let msg = "invalid commit target in grandpa justification".to_string(); Err(ClientError::BadJustification(msg)) @@ -157,9 +176,10 @@ impl GrandpaJustification { { use finality_grandpa::Chain; - let ancestry_chain = AncestryChain::::new(&self.votes_ancestries); + let ancestry_chain = AncestryChain::::new(&self.justification.votes_ancestries); - match finality_grandpa::validate_commit(&self.commit, voters, &ancestry_chain) { + match finality_grandpa::validate_commit(&self.justification.commit, voters, &ancestry_chain) + { Ok(ref result) if result.is_valid() => {}, _ => { let msg = "invalid commit in grandpa justification".to_string(); @@ -171,6 +191,7 @@ impl GrandpaJustification { // should serve as the root block for populating ancestry (i.e. // collect all headers from all precommit blocks to the base) let base_hash = self + .justification .commit .precommits .iter() @@ -186,12 +207,12 @@ impl GrandpaJustification { let mut buf = Vec::new(); let mut visited_hashes = HashSet::new(); - for signed in self.commit.precommits.iter() { + for signed in self.justification.commit.precommits.iter() { if !sp_finality_grandpa::check_message_signature_with_buffer( &finality_grandpa::Message::Precommit(signed.precommit.clone()), &signed.id, &signed.signature, - self.round, + self.justification.round, set_id, &mut buf, ) { @@ -220,8 +241,12 @@ impl GrandpaJustification { } } - let ancestry_hashes: HashSet<_> = - self.votes_ancestries.iter().map(|h: &Block::Header| h.hash()).collect(); + let ancestry_hashes: HashSet<_> = self + .justification + .votes_ancestries + .iter() + .map(|h: &Block::Header| h.hash()) + .collect(); if visited_hashes != ancestry_hashes { return Err(ClientError::BadJustification( @@ -235,7 +260,7 @@ impl GrandpaJustification { /// The target block number and hash that this justifications proves finality for. pub fn target(&self) -> (NumberFor, Block::Hash) { - (self.commit.target_number, self.commit.target_hash) + (self.justification.commit.target_number, self.justification.commit.target_hash) } } diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index 149cf1f89a222..a7326d57c2bf0 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -144,72 +144,35 @@ use sp_finality_grandpa::{AuthorityList, AuthoritySignature, SetId}; use until_imported::UntilGlobalMessageBlocksImported; // Re-export these two because it's just so damn convenient. -pub use sp_finality_grandpa::{AuthorityId, AuthorityPair, GrandpaApi, ScheduledChange}; +pub use sp_finality_grandpa::{ + AuthorityId, AuthorityPair, CatchUp, Commit, CompactCommit, GrandpaApi, Message, Precommit, + Prevote, PrimaryPropose, ScheduledChange, SignedMessage, +}; use std::marker::PhantomData; #[cfg(test)] mod tests; -/// A GRANDPA message for a substrate chain. -pub type Message = finality_grandpa::Message<::Hash, NumberFor>; - -/// A signed message. -pub type SignedMessage = finality_grandpa::SignedMessage< - ::Hash, - NumberFor, - AuthoritySignature, - AuthorityId, ->; - -/// A primary propose message for this chain's block type. -pub type PrimaryPropose = - finality_grandpa::PrimaryPropose<::Hash, NumberFor>; -/// A prevote message for this chain's block type. -pub type Prevote = finality_grandpa::Prevote<::Hash, NumberFor>; -/// A precommit message for this chain's block type. -pub type Precommit = finality_grandpa::Precommit<::Hash, NumberFor>; -/// A catch up message for this chain's block type. -pub type CatchUp = finality_grandpa::CatchUp< - ::Hash, - NumberFor, - AuthoritySignature, - AuthorityId, ->; -/// A commit message for this chain's block type. -pub type Commit = finality_grandpa::Commit< - ::Hash, - NumberFor, - AuthoritySignature, - AuthorityId, ->; -/// A compact commit message for this chain's block type. -pub type CompactCommit = finality_grandpa::CompactCommit< - ::Hash, - NumberFor, - AuthoritySignature, - AuthorityId, ->; /// A global communication input stream for commits and catch up messages. Not /// exposed publicly, used internally to simplify types in the communication /// layer. -type CommunicationIn = finality_grandpa::voter::CommunicationIn< +type CommunicationIn = voter::CommunicationIn< ::Hash, NumberFor, AuthoritySignature, AuthorityId, >; - /// Global communication input stream for commits and catch up messages, with /// the hash type not being derived from the block, useful for forcing the hash /// to some type (e.g. `H256`) when the compiler can't do the inference. type CommunicationInH = - finality_grandpa::voter::CommunicationIn, AuthoritySignature, AuthorityId>; + voter::CommunicationIn, AuthoritySignature, AuthorityId>; /// Global communication sink for commits with the hash type not being derived /// from the block, useful for forcing the hash to some type (e.g. `H256`) when /// the compiler can't do the inference. type CommunicationOutH = - finality_grandpa::voter::CommunicationOut, AuthoritySignature, AuthorityId>; + voter::CommunicationOut, AuthoritySignature, AuthorityId>; /// Shared voter state for querying. pub struct SharedVoterState { @@ -233,7 +196,7 @@ impl SharedVoterState { } /// Get the inner `VoterState` instance. - pub fn voter_state(&self) -> Option> { + pub fn voter_state(&self) -> Option> { self.inner.read().as_ref().map(|vs| vs.get()) } } @@ -725,18 +688,19 @@ pub struct GrandpaParams { /// For standard protocol name see [`crate::protocol_standard_name`]. pub fn grandpa_peers_set_config( protocol_name: ProtocolName, -) -> sc_network::config::NonDefaultSetConfig { +) -> sc_network_common::config::NonDefaultSetConfig { use communication::grandpa_protocol_name; - sc_network::config::NonDefaultSetConfig { + sc_network_common::config::NonDefaultSetConfig { notifications_protocol: protocol_name, fallback_names: grandpa_protocol_name::LEGACY_NAMES.iter().map(|&n| n.into()).collect(), // Notifications reach ~256kiB in size at the time of writing on Kusama and Polkadot. max_notification_size: 1024 * 1024, - set_config: sc_network::config::SetConfig { + handshake: None, + set_config: sc_network_common::config::SetConfig { in_peers: 0, out_peers: 0, reserved_nodes: Vec::new(), - non_reserved_mode: sc_network::config::NonReservedPeerMode::Deny, + non_reserved_mode: sc_network_common::config::NonReservedPeerMode::Deny, }, } } diff --git a/client/finality-grandpa/src/tests.rs b/client/finality-grandpa/src/tests.rs index 3dd21d51b6a2d..b1e46be5cabde 100644 --- a/client/finality-grandpa/src/tests.rs +++ b/client/finality-grandpa/src/tests.rs @@ -450,7 +450,7 @@ fn finalize_3_voters_1_full_observer() { let justification = crate::aux_schema::best_justification::<_, Block>(&*client).unwrap().unwrap(); - assert_eq!(justification.commit.target_number, 20); + assert_eq!(justification.justification.commit.target_number, 20); } } diff --git a/client/finality-grandpa/src/until_imported.rs b/client/finality-grandpa/src/until_imported.rs index fe7caf74422db..df0b63348e94b 100644 --- a/client/finality-grandpa/src/until_imported.rs +++ b/client/finality-grandpa/src/until_imported.rs @@ -354,7 +354,7 @@ fn warn_authority_wrong_target(hash: H, id: AuthorityId) ); } -impl BlockUntilImported for SignedMessage { +impl BlockUntilImported for SignedMessage { type Blocked = Self; fn needs_waiting>( @@ -389,8 +389,13 @@ impl BlockUntilImported for SignedMessage { /// Helper type definition for the stream which waits until vote targets for /// signed messages are imported. -pub(crate) type UntilVoteTargetImported = - UntilImported>; +pub(crate) type UntilVoteTargetImported = UntilImported< + Block, + BlockStatus, + BlockSyncRequester, + I, + SignedMessage<::Header>, +>; /// This blocks a global message import, i.e. a commit or catch up messages, /// until all blocks referenced in its votes are known. @@ -646,7 +651,7 @@ mod tests { // unwrap the commit from `CommunicationIn` returning its fields in a tuple, // panics if the given message isn't a commit - fn unapply_commit(msg: CommunicationIn) -> (u64, CompactCommit) { + fn unapply_commit(msg: CommunicationIn) -> (u64, CompactCommit
) { match msg { voter::CommunicationIn::Commit(round, commit, ..) => (round, commit), _ => panic!("expected commit"), @@ -655,7 +660,7 @@ mod tests { // unwrap the catch up from `CommunicationIn` returning its inner representation, // panics if the given message isn't a catch up - fn unapply_catch_up(msg: CommunicationIn) -> CatchUp { + fn unapply_catch_up(msg: CommunicationIn) -> CatchUp
{ match msg { voter::CommunicationIn::CatchUp(catch_up, ..) => catch_up, _ => panic!("expected catch up"), @@ -740,7 +745,7 @@ mod tests { let h2 = make_header(6); let h3 = make_header(7); - let unknown_commit = CompactCommit:: { + let unknown_commit = CompactCommit::
{ target_hash: h1.hash(), target_number: 5, precommits: vec![ @@ -768,7 +773,7 @@ mod tests { let h2 = make_header(6); let h3 = make_header(7); - let known_commit = CompactCommit:: { + let known_commit = CompactCommit::
{ target_hash: h1.hash(), target_number: 5, precommits: vec![ @@ -910,7 +915,7 @@ mod tests { // we create a commit message, with precommits for blocks 6 and 7 which // we haven't imported. - let unknown_commit = CompactCommit:: { + let unknown_commit = CompactCommit::
{ target_hash: h1.hash(), target_number: 5, precommits: vec![ diff --git a/client/informant/Cargo.toml b/client/informant/Cargo.toml index b3ac5d892fd58..073199d005fd1 100644 --- a/client/informant/Cargo.toml +++ b/client/informant/Cargo.toml @@ -17,7 +17,7 @@ ansi_term = "0.12.1" futures = "0.3.21" futures-timer = "3.0.1" log = "0.4.17" -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } diff --git a/client/keystore/Cargo.toml b/client/keystore/Cargo.toml index 9b7afba759c60..ff963f9d446f6 100644 --- a/client/keystore/Cargo.toml +++ b/client/keystore/Cargo.toml @@ -14,8 +14,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +array-bytes = "4.1" async-trait = "0.1.57" -hex = "0.4.0" parking_lot = "0.12.1" serde_json = "1.0.85" thiserror = "1.0" diff --git a/client/keystore/src/local.rs b/client/keystore/src/local.rs index 19be6715ffe3f..54ff6a5b164a8 100644 --- a/client/keystore/src/local.rs +++ b/client/keystore/src/local.rs @@ -512,8 +512,8 @@ impl KeystoreInner { /// Returns `None` if the keystore only exists in-memory and there isn't any path to provide. fn key_file_path(&self, public: &[u8], key_type: KeyTypeId) -> Option { let mut buf = self.path.as_ref()?.clone(); - let key_type = hex::encode(key_type.0); - let key = hex::encode(public); + let key_type = array_bytes::bytes2hex("", &key_type.0); + let key = array_bytes::bytes2hex("", public); buf.push(key_type + key.as_str()); Some(buf) } @@ -534,7 +534,7 @@ impl KeystoreInner { // skip directories and non-unicode file names (hex is unicode) if let Some(name) = path.file_name().and_then(|n| n.to_str()) { - match hex::decode(name) { + match array_bytes::hex2bytes(name) { Ok(ref hex) if hex.len() > 4 => { if hex[0..4] != id.0 { continue @@ -739,7 +739,7 @@ mod tests { let temp_dir = TempDir::new().unwrap(); let store = LocalKeystore::open(temp_dir.path(), None).unwrap(); - let file_name = temp_dir.path().join(hex::encode(&SR25519.0[..2])); + let file_name = temp_dir.path().join(array_bytes::bytes2hex("", &SR25519.0[..2])); fs::write(file_name, "test").expect("Invalid file is written"); assert!(SyncCryptoStore::sr25519_public_keys(&store, SR25519).is_empty()); diff --git a/client/network-gossip/Cargo.toml b/client/network-gossip/Cargo.toml index 8ecf2b9cec787..e84013fbfe436 100644 --- a/client/network-gossip/Cargo.toml +++ b/client/network-gossip/Cargo.toml @@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] ahash = "0.7.6" futures = "0.3.21" futures-timer = "3.0.1" -libp2p = { version = "0.46.1", default-features = false } +libp2p = { version = "0.49.0", default-features = false } log = "0.4.17" lru = "0.7.5" tracing = "0.1.29" diff --git a/client/network-gossip/src/bridge.rs b/client/network-gossip/src/bridge.rs index 121fa6dc9a50d..5563b3be35e8d 100644 --- a/client/network-gossip/src/bridge.rs +++ b/client/network-gossip/src/bridge.rs @@ -317,7 +317,7 @@ mod tests { use quickcheck::{Arbitrary, Gen, QuickCheck}; use sc_network_common::{ config::MultiaddrWithPeerId, - protocol::event::ObservedRole, + protocol::role::ObservedRole, service::{ NetworkBlock, NetworkEventStream, NetworkNotification, NetworkPeers, NotificationSender, NotificationSenderError, diff --git a/client/network-gossip/src/state_machine.rs b/client/network-gossip/src/state_machine.rs index 30a2e9d1494be..600383cf5f70d 100644 --- a/client/network-gossip/src/state_machine.rs +++ b/client/network-gossip/src/state_machine.rs @@ -22,7 +22,7 @@ use ahash::AHashSet; use libp2p::PeerId; use lru::LruCache; use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; -use sc_network_common::protocol::{event::ObservedRole, ProtocolName}; +use sc_network_common::protocol::{role::ObservedRole, ProtocolName}; use sp_runtime::traits::{Block as BlockT, Hash, HashFor}; use std::{collections::HashMap, iter, sync::Arc, time, time::Instant}; diff --git a/client/network-gossip/src/validator.rs b/client/network-gossip/src/validator.rs index 185c2cfeed2c7..77dcc3bdc8791 100644 --- a/client/network-gossip/src/validator.rs +++ b/client/network-gossip/src/validator.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use libp2p::PeerId; -use sc_network_common::protocol::event::ObservedRole; +use sc_network_common::protocol::role::ObservedRole; use sp_runtime::traits::Block as BlockT; /// Validates consensus messages. diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 82f77fa44450f..81b684af433d2 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -13,10 +13,8 @@ readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] -[build-dependencies] -prost-build = "0.10" - [dependencies] +array-bytes = "4.1" async-trait = "0.1" asynchronous-codec = "0.6" bitflags = "1.3.2" @@ -27,23 +25,21 @@ either = "1.5.3" fnv = "1.0.6" futures = "0.3.21" futures-timer = "3.0.2" -hex = "0.4.0" ip_network = "0.4.1" -libp2p = "0.46.1" +libp2p = { version = "0.49.0", features = ["async-std", "dns", "identify", "kad", "mdns-async-io", "mplex", "noise", "ping", "tcp", "yamux", "websocket"] } linked_hash_set = "0.1.3" linked-hash-map = "0.5.4" log = "0.4.17" lru = "0.7.5" parking_lot = "0.12.1" -pin-project = "1.0.10" -prost = "0.10" +pin-project = "1.0.12" +prost = "0.11" rand = "0.7.2" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.85" smallvec = "1.8.0" thiserror = "1.0" unsigned-varint = { version = "0.7.1", features = ["futures", "asynchronous_codec"] } -void = "1.0.2" zeroize = "1.4.3" fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" } prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../utils/prometheus" } @@ -61,7 +57,7 @@ sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } [dev-dependencies] assert_matches = "1.3" -async-std = "1.11.0" +async-std = { version = "1.11.0", features = ["attributes"] } rand = "0.7.2" tempfile = "3.1.0" sc-network-light = { version = "0.10.0-dev", path = "./light" } diff --git a/client/network/bitswap/Cargo.toml b/client/network/bitswap/Cargo.toml new file mode 100644 index 0000000000000..f60e21b4429fb --- /dev/null +++ b/client/network/bitswap/Cargo.toml @@ -0,0 +1,40 @@ +[package] +description = "Substrate bitswap protocol" +name = "sc-network-bitswap" +version = "0.10.0-dev" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +authors = ["Parity Technologies "] +edition = "2021" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +documentation = "https://docs.rs/sc-network-bitswap" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[build-dependencies] +prost-build = "0.11" + +[dependencies] +cid = "0.8.6" +futures = "0.3.21" +libp2p = "0.49.0" +log = "0.4.17" +prost = "0.11" +thiserror = "1.0" +unsigned-varint = { version = "0.7.1", features = ["futures", "asynchronous_codec"] } +void = "1.0.2" +sc-client-api = { version = "4.0.0-dev", path = "../../api" } +sc-network-common = { version = "0.10.0-dev", path = "../common" } +sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } + +[dev-dependencies] +tokio = { version = "1", features = ["full"] } +sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } +sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } +sp-core = { version = "6.0.0", path = "../../../primitives/core" } +sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } +substrate-test-runtime = { version = "2.0.0", path = "../../../test-utils/runtime" } +substrate-test-runtime-client = { version = "2.0.0", path = "../../../test-utils/runtime/client" } diff --git a/client/network/build.rs b/client/network/bitswap/build.rs similarity index 56% rename from client/network/build.rs rename to client/network/bitswap/build.rs index 671277230a774..bd6222d546851 100644 --- a/client/network/build.rs +++ b/client/network/bitswap/build.rs @@ -1,4 +1,4 @@ -const PROTOS: &[&str] = &["src/schema/bitswap.v1.2.0.proto"]; +const PROTOS: &[&str] = &["bitswap.v1.2.0.proto"]; fn main() { prost_build::compile_protos(PROTOS, &["src/schema"]).unwrap(); diff --git a/client/network/bitswap/src/lib.rs b/client/network/bitswap/src/lib.rs new file mode 100644 index 0000000000000..2c340202d113e --- /dev/null +++ b/client/network/bitswap/src/lib.rs @@ -0,0 +1,525 @@ +// Copyright 2022 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Bitswap server for Substrate. +//! +//! Allows querying transactions by hash over standard bitswap protocol +//! Only supports bitswap 1.2.0. +//! CID is expected to reference 256-bit Blake2b transaction hash. + +use cid::{self, Version}; +use futures::{channel::mpsc, StreamExt}; +use libp2p::core::PeerId; +use log::{debug, error, trace}; +use prost::Message; +use sc_client_api::BlockBackend; +use sc_network_common::{ + protocol::ProtocolName, + request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, +}; +use schema::bitswap::{ + message::{wantlist::WantType, Block as MessageBlock, BlockPresence, BlockPresenceType}, + Message as BitswapMessage, +}; +use sp_runtime::traits::Block as BlockT; +use std::{io, sync::Arc, time::Duration}; +use unsigned_varint::encode as varint_encode; + +mod schema; + +const LOG_TARGET: &str = "bitswap"; + +// Undocumented, but according to JS the bitswap messages have a max size of 512*1024 bytes +// https://github.com/ipfs/js-ipfs-bitswap/blob/ +// d8f80408aadab94c962f6b88f343eb9f39fa0fcc/src/decision-engine/index.js#L16 +// We set it to the same value as max substrate protocol message +const MAX_PACKET_SIZE: u64 = 16 * 1024 * 1024; + +/// Max number of queued responses before denying requests. +const MAX_REQUEST_QUEUE: usize = 20; + +/// Max number of blocks per wantlist +const MAX_WANTED_BLOCKS: usize = 16; + +/// Bitswap protocol name +const PROTOCOL_NAME: &'static str = "/ipfs/bitswap/1.2.0"; + +/// Prefix represents all metadata of a CID, without the actual content. +#[derive(PartialEq, Eq, Clone, Debug)] +struct Prefix { + /// The version of CID. + pub version: Version, + /// The codec of CID. + pub codec: u64, + /// The multihash type of CID. + pub mh_type: u64, + /// The multihash length of CID. + pub mh_len: u8, +} + +impl Prefix { + /// Convert the prefix to encoded bytes. + pub fn to_bytes(&self) -> Vec { + let mut res = Vec::with_capacity(4); + let mut buf = varint_encode::u64_buffer(); + let version = varint_encode::u64(self.version.into(), &mut buf); + res.extend_from_slice(version); + let mut buf = varint_encode::u64_buffer(); + let codec = varint_encode::u64(self.codec, &mut buf); + res.extend_from_slice(codec); + let mut buf = varint_encode::u64_buffer(); + let mh_type = varint_encode::u64(self.mh_type, &mut buf); + res.extend_from_slice(mh_type); + let mut buf = varint_encode::u64_buffer(); + let mh_len = varint_encode::u64(self.mh_len as u64, &mut buf); + res.extend_from_slice(mh_len); + res + } +} + +/// Bitswap request handler +pub struct BitswapRequestHandler { + client: Arc + Send + Sync>, + request_receiver: mpsc::Receiver, +} + +impl BitswapRequestHandler { + /// Create a new [`BitswapRequestHandler`]. + pub fn new(client: Arc + Send + Sync>) -> (Self, ProtocolConfig) { + let (tx, request_receiver) = mpsc::channel(MAX_REQUEST_QUEUE); + + let config = ProtocolConfig { + name: ProtocolName::from(PROTOCOL_NAME), + fallback_names: vec![], + max_request_size: MAX_PACKET_SIZE, + max_response_size: MAX_PACKET_SIZE, + request_timeout: Duration::from_secs(15), + inbound_queue: Some(tx), + }; + + (Self { client, request_receiver }, config) + } + + /// Run [`BitswapRequestHandler`]. + pub async fn run(mut self) { + while let Some(request) = self.request_receiver.next().await { + let IncomingRequest { peer, payload, pending_response } = request; + + match self.handle_message(&peer, &payload) { + Ok(response) => { + let response = OutgoingResponse { + result: Ok(response), + reputation_changes: Vec::new(), + sent_feedback: None, + }; + + match pending_response.send(response) { + Ok(()) => { + trace!(target: LOG_TARGET, "Handled bitswap request from {peer}.",) + }, + Err(_) => debug!( + target: LOG_TARGET, + "Failed to handle light client request from {peer}: {}", + BitswapError::SendResponse, + ), + } + }, + Err(err) => { + error!(target: LOG_TARGET, "Failed to process request from {peer}: {err}"); + + // TODO: adjust reputation? + + let response = OutgoingResponse { + result: Err(()), + reputation_changes: vec![], + sent_feedback: None, + }; + + if pending_response.send(response).is_err() { + debug!( + target: LOG_TARGET, + "Failed to handle bitswap request from {peer}: {}", + BitswapError::SendResponse, + ); + } + }, + } + } + } + + /// Handle received Bitswap request + fn handle_message( + &mut self, + peer: &PeerId, + payload: &Vec, + ) -> Result, BitswapError> { + let request = schema::bitswap::Message::decode(&payload[..])?; + + trace!(target: LOG_TARGET, "Received request: {:?} from {}", request, peer); + + let mut response = BitswapMessage::default(); + + let wantlist = match request.wantlist { + Some(wantlist) => wantlist, + None => { + debug!(target: LOG_TARGET, "Unexpected bitswap message from {}", peer); + return Err(BitswapError::InvalidWantList) + }, + }; + + if wantlist.entries.len() > MAX_WANTED_BLOCKS { + trace!(target: LOG_TARGET, "Ignored request: too many entries"); + return Err(BitswapError::TooManyEntries) + } + + for entry in wantlist.entries { + let cid = match cid::Cid::read_bytes(entry.block.as_slice()) { + Ok(cid) => cid, + Err(e) => { + trace!(target: LOG_TARGET, "Bad CID {:?}: {:?}", entry.block, e); + continue + }, + }; + + if cid.version() != cid::Version::V1 || + cid.hash().code() != u64::from(cid::multihash::Code::Blake2b256) || + cid.hash().size() != 32 + { + debug!(target: LOG_TARGET, "Ignoring unsupported CID {}: {}", peer, cid); + continue + } + + let mut hash = B::Hash::default(); + hash.as_mut().copy_from_slice(&cid.hash().digest()[0..32]); + let transaction = match self.client.indexed_transaction(&hash) { + Ok(ex) => ex, + Err(e) => { + error!(target: LOG_TARGET, "Error retrieving transaction {}: {}", hash, e); + None + }, + }; + + match transaction { + Some(transaction) => { + trace!(target: LOG_TARGET, "Found CID {:?}, hash {:?}", cid, hash); + + if entry.want_type == WantType::Block as i32 { + let prefix = Prefix { + version: cid.version(), + codec: cid.codec(), + mh_type: cid.hash().code(), + mh_len: cid.hash().size(), + }; + response + .payload + .push(MessageBlock { prefix: prefix.to_bytes(), data: transaction }); + } else { + response.block_presences.push(BlockPresence { + r#type: BlockPresenceType::Have as i32, + cid: cid.to_bytes(), + }); + } + }, + None => { + trace!(target: LOG_TARGET, "Missing CID {:?}, hash {:?}", cid, hash); + + if entry.send_dont_have { + response.block_presences.push(BlockPresence { + r#type: BlockPresenceType::DontHave as i32, + cid: cid.to_bytes(), + }); + } + }, + } + } + + Ok(response.encode_to_vec()) + } +} + +/// Bitswap protocol error. +#[derive(Debug, thiserror::Error)] +pub enum BitswapError { + /// Protobuf decoding error. + #[error("Failed to decode request: {0}.")] + DecodeProto(#[from] prost::DecodeError), + + /// Protobuf encoding error. + #[error("Failed to encode response: {0}.")] + EncodeProto(#[from] prost::EncodeError), + + /// Client backend error. + #[error(transparent)] + Client(#[from] sp_blockchain::Error), + + /// Error parsing CID + #[error(transparent)] + BadCid(#[from] cid::Error), + + /// Packet read error. + #[error(transparent)] + Read(#[from] io::Error), + + /// Error sending response. + #[error("Failed to send response.")] + SendResponse, + + /// Message doesn't have a WANT list. + #[error("Invalid WANT list.")] + InvalidWantList, + + /// Too many blocks requested. + #[error("Too many block entries in the request.")] + TooManyEntries, +} + +#[cfg(test)] +mod tests { + use super::*; + use futures::{channel::oneshot, SinkExt}; + use sc_block_builder::BlockBuilderProvider; + use schema::bitswap::{ + message::{wantlist::Entry, Wantlist}, + Message as BitswapMessage, + }; + use sp_consensus::BlockOrigin; + use sp_runtime::codec::Encode; + use substrate_test_runtime::Extrinsic; + use substrate_test_runtime_client::{self, prelude::*, TestClientBuilder}; + + #[tokio::test] + async fn undecodeable_message() { + let client = substrate_test_runtime_client::new(); + let (bitswap, config) = BitswapRequestHandler::new(Arc::new(client)); + + tokio::spawn(async move { bitswap.run().await }); + + let (tx, rx) = oneshot::channel(); + config + .inbound_queue + .unwrap() + .send(IncomingRequest { + peer: PeerId::random(), + payload: vec![0x13, 0x37, 0x13, 0x38], + pending_response: tx, + }) + .await + .unwrap(); + + if let Ok(OutgoingResponse { result, reputation_changes, sent_feedback }) = rx.await { + assert_eq!(result, Err(())); + assert_eq!(reputation_changes, Vec::new()); + assert!(sent_feedback.is_none()); + } else { + panic!("invalid event received"); + } + } + + #[tokio::test] + async fn empty_want_list() { + let client = substrate_test_runtime_client::new(); + let (bitswap, mut config) = BitswapRequestHandler::new(Arc::new(client)); + + tokio::spawn(async move { bitswap.run().await }); + + let (tx, rx) = oneshot::channel(); + config + .inbound_queue + .as_mut() + .unwrap() + .send(IncomingRequest { + peer: PeerId::random(), + payload: BitswapMessage { wantlist: None, ..Default::default() }.encode_to_vec(), + pending_response: tx, + }) + .await + .unwrap(); + + if let Ok(OutgoingResponse { result, reputation_changes, sent_feedback }) = rx.await { + assert_eq!(result, Err(())); + assert_eq!(reputation_changes, Vec::new()); + assert!(sent_feedback.is_none()); + } else { + panic!("invalid event received"); + } + + // Empty WANT list should not cause an error + let (tx, rx) = oneshot::channel(); + config + .inbound_queue + .unwrap() + .send(IncomingRequest { + peer: PeerId::random(), + payload: BitswapMessage { + wantlist: Some(Default::default()), + ..Default::default() + } + .encode_to_vec(), + pending_response: tx, + }) + .await + .unwrap(); + + if let Ok(OutgoingResponse { result, reputation_changes, sent_feedback }) = rx.await { + assert_eq!(result, Ok(BitswapMessage::default().encode_to_vec())); + assert_eq!(reputation_changes, Vec::new()); + assert!(sent_feedback.is_none()); + } else { + panic!("invalid event received"); + } + } + + #[tokio::test] + async fn too_long_want_list() { + let client = substrate_test_runtime_client::new(); + let (bitswap, config) = BitswapRequestHandler::new(Arc::new(client)); + + tokio::spawn(async move { bitswap.run().await }); + + let (tx, rx) = oneshot::channel(); + config + .inbound_queue + .unwrap() + .send(IncomingRequest { + peer: PeerId::random(), + payload: BitswapMessage { + wantlist: Some(Wantlist { + entries: (0..MAX_WANTED_BLOCKS + 1) + .map(|_| Entry::default()) + .collect::>(), + full: false, + }), + ..Default::default() + } + .encode_to_vec(), + pending_response: tx, + }) + .await + .unwrap(); + + if let Ok(OutgoingResponse { result, reputation_changes, sent_feedback }) = rx.await { + assert_eq!(result, Err(())); + assert_eq!(reputation_changes, Vec::new()); + assert!(sent_feedback.is_none()); + } else { + panic!("invalid event received"); + } + } + + #[tokio::test] + async fn transaction_not_found() { + let client = TestClientBuilder::with_tx_storage(u32::MAX).build(); + + let (bitswap, config) = BitswapRequestHandler::new(Arc::new(client)); + tokio::spawn(async move { bitswap.run().await }); + + let (tx, rx) = oneshot::channel(); + config + .inbound_queue + .unwrap() + .send(IncomingRequest { + peer: PeerId::random(), + payload: BitswapMessage { + wantlist: Some(Wantlist { + entries: vec![Entry { + block: cid::Cid::new_v1( + 0x70, + cid::multihash::Multihash::wrap( + u64::from(cid::multihash::Code::Blake2b256), + &[0u8; 32], + ) + .unwrap(), + ) + .to_bytes(), + ..Default::default() + }], + full: false, + }), + ..Default::default() + } + .encode_to_vec(), + pending_response: tx, + }) + .await + .unwrap(); + + if let Ok(OutgoingResponse { result, reputation_changes, sent_feedback }) = rx.await { + assert_eq!(result, Ok(vec![])); + assert_eq!(reputation_changes, Vec::new()); + assert!(sent_feedback.is_none()); + } else { + panic!("invalid event received"); + } + } + + #[tokio::test] + async fn transaction_found() { + let mut client = TestClientBuilder::with_tx_storage(u32::MAX).build(); + let mut block_builder = client.new_block(Default::default()).unwrap(); + + let ext = Extrinsic::Store(vec![0x13, 0x37, 0x13, 0x38]); + + block_builder.push(ext.clone()).unwrap(); + let block = block_builder.build().unwrap().block; + + client.import(BlockOrigin::File, block).await.unwrap(); + + let (bitswap, config) = BitswapRequestHandler::new(Arc::new(client)); + + tokio::spawn(async move { bitswap.run().await }); + + let (tx, rx) = oneshot::channel(); + config + .inbound_queue + .unwrap() + .send(IncomingRequest { + peer: PeerId::random(), + payload: BitswapMessage { + wantlist: Some(Wantlist { + entries: vec![Entry { + block: cid::Cid::new_v1( + 0x70, + cid::multihash::Multihash::wrap( + u64::from(cid::multihash::Code::Blake2b256), + &sp_core::hashing::blake2_256(&ext.encode()[2..]), + ) + .unwrap(), + ) + .to_bytes(), + ..Default::default() + }], + full: false, + }), + ..Default::default() + } + .encode_to_vec(), + pending_response: tx, + }) + .await + .unwrap(); + + if let Ok(OutgoingResponse { result, reputation_changes, sent_feedback }) = rx.await { + assert_eq!(reputation_changes, Vec::new()); + assert!(sent_feedback.is_none()); + + let response = + schema::bitswap::Message::decode(&result.expect("fetch to succeed")[..]).unwrap(); + assert_eq!(response.payload[0].data, vec![0x13, 0x37, 0x13, 0x38]); + } else { + panic!("invalid event received"); + } + } +} diff --git a/client/network/src/schema.rs b/client/network/bitswap/src/schema.rs similarity index 97% rename from client/network/src/schema.rs rename to client/network/bitswap/src/schema.rs index 4893bc28a7355..362e59aca68f9 100644 --- a/client/network/src/schema.rs +++ b/client/network/bitswap/src/schema.rs @@ -18,6 +18,6 @@ //! Include sources generated from protobuf definitions. -pub mod bitswap { +pub(crate) mod bitswap { include!(concat!(env!("OUT_DIR"), "/bitswap.message.rs")); } diff --git a/client/network/src/schema/bitswap.v1.2.0.proto b/client/network/bitswap/src/schema/bitswap.v1.2.0.proto similarity index 100% rename from client/network/src/schema/bitswap.v1.2.0.proto rename to client/network/bitswap/src/schema/bitswap.v1.2.0.proto diff --git a/client/network/common/Cargo.toml b/client/network/common/Cargo.toml index 47d43e8b4b03f..48d83a59c742b 100644 --- a/client/network/common/Cargo.toml +++ b/client/network/common/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" [dependencies] async-trait = "0.1.57" @@ -24,7 +24,10 @@ codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = "0.3.21" -libp2p = "0.46.1" +futures-timer = "3.0.2" +libp2p = { version = "0.49.0", features = [ "request-response", "kad" ] } +linked_hash_set = "0.1.3" +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } smallvec = "1.8.0" sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } diff --git a/client/network/common/src/config.rs b/client/network/common/src/config.rs index 8b7e045780d7d..96c7c11ec2696 100644 --- a/client/network/common/src/config.rs +++ b/client/network/common/src/config.rs @@ -18,6 +18,9 @@ //! Configuration of the networking layer. +use crate::protocol; + +use codec::Encode; use libp2p::{multiaddr, Multiaddr, PeerId}; use std::{fmt, str, str::FromStr}; @@ -171,3 +174,160 @@ impl From for ParseErr { Self::MultiaddrParse(err) } } + +/// Configuration for a set of nodes. +#[derive(Clone, Debug)] +pub struct SetConfig { + /// Maximum allowed number of incoming substreams related to this set. + pub in_peers: u32, + /// Number of outgoing substreams related to this set that we're trying to maintain. + pub out_peers: u32, + /// List of reserved node addresses. + pub reserved_nodes: Vec, + /// Whether nodes that aren't in [`SetConfig::reserved_nodes`] are accepted or automatically + /// refused. + pub non_reserved_mode: NonReservedPeerMode, +} + +impl Default for SetConfig { + fn default() -> Self { + Self { + in_peers: 25, + out_peers: 75, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Accept, + } + } +} + +/// Custom handshake for the notification protocol +#[derive(Debug, Clone)] +pub struct NotificationHandshake(Vec); + +impl NotificationHandshake { + /// Create new `NotificationHandshake` from an object that implements `Encode` + pub fn new(handshake: H) -> Self { + Self(handshake.encode()) + } + + /// Create new `NotificationHandshake` from raw bytes + pub fn from_bytes(bytes: Vec) -> Self { + Self(bytes) + } +} + +impl std::ops::Deref for NotificationHandshake { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +/// Extension to [`SetConfig`] for sets that aren't the default set. +/// +/// > **Note**: As new fields might be added in the future, please consider using the `new` method +/// > and modifiers instead of creating this struct manually. +#[derive(Clone, Debug)] +pub struct NonDefaultSetConfig { + /// Name of the notifications protocols of this set. A substream on this set will be + /// considered established once this protocol is open. + /// + /// > **Note**: This field isn't present for the default set, as this is handled internally + /// > by the networking code. + pub notifications_protocol: protocol::ProtocolName, + /// If the remote reports that it doesn't support the protocol indicated in the + /// `notifications_protocol` field, then each of these fallback names will be tried one by + /// one. + /// + /// If a fallback is used, it will be reported in + /// `sc_network::protocol::event::Event::NotificationStreamOpened::negotiated_fallback` + pub fallback_names: Vec, + /// Handshake of the protocol + /// + /// NOTE: Currently custom handshakes are not fully supported. See issue #5685 for more + /// details. This field is temporarily used to allow moving the hardcoded block announcement + /// protocol out of `protocol.rs`. + pub handshake: Option, + /// Maximum allowed size of single notifications. + pub max_notification_size: u64, + /// Base configuration. + pub set_config: SetConfig, +} + +impl NonDefaultSetConfig { + /// Creates a new [`NonDefaultSetConfig`]. Zero slots and accepts only reserved nodes. + pub fn new(notifications_protocol: protocol::ProtocolName, max_notification_size: u64) -> Self { + Self { + notifications_protocol, + max_notification_size, + fallback_names: Vec::new(), + handshake: None, + set_config: SetConfig { + in_peers: 0, + out_peers: 0, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Deny, + }, + } + } + + /// Modifies the configuration to allow non-reserved nodes. + pub fn allow_non_reserved(&mut self, in_peers: u32, out_peers: u32) { + self.set_config.in_peers = in_peers; + self.set_config.out_peers = out_peers; + self.set_config.non_reserved_mode = NonReservedPeerMode::Accept; + } + + /// Add a node to the list of reserved nodes. + pub fn add_reserved(&mut self, peer: MultiaddrWithPeerId) { + self.set_config.reserved_nodes.push(peer); + } + + /// Add a list of protocol names used for backward compatibility. + /// + /// See the explanations in [`NonDefaultSetConfig::fallback_names`]. + pub fn add_fallback_names(&mut self, fallback_names: Vec) { + self.fallback_names.extend(fallback_names); + } +} + +/// Configuration for the transport layer. +#[derive(Clone, Debug)] +pub enum TransportConfig { + /// Normal transport mode. + Normal { + /// If true, the network will use mDNS to discover other libp2p nodes on the local network + /// and connect to them if they support the same chain. + enable_mdns: bool, + + /// If true, allow connecting to private IPv4 addresses (as defined in + /// [RFC1918](https://tools.ietf.org/html/rfc1918)). Irrelevant for addresses that have + /// been passed in `::sc_network::config::NetworkConfiguration::boot_nodes`. + allow_private_ipv4: bool, + }, + + /// Only allow connections within the same process. + /// Only addresses of the form `/memory/...` will be supported. + MemoryOnly, +} + +/// The policy for connections to non-reserved peers. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum NonReservedPeerMode { + /// Accept them. This is the default. + Accept, + /// Deny them. + Deny, +} + +impl NonReservedPeerMode { + /// Attempt to parse the peer mode from a string. + pub fn parse(s: &str) -> Option { + match s { + "accept" => Some(Self::Accept), + "deny" => Some(Self::Deny), + _ => None, + } + } +} diff --git a/client/network/src/error.rs b/client/network/common/src/error.rs similarity index 96% rename from client/network/src/error.rs rename to client/network/common/src/error.rs index b4287ffbd55db..4326b1af52836 100644 --- a/client/network/src/error.rs +++ b/client/network/common/src/error.rs @@ -18,9 +18,8 @@ //! Substrate network possible errors. -use crate::config::TransportConfig; +use crate::{config::TransportConfig, protocol::ProtocolName}; use libp2p::{Multiaddr, PeerId}; -use sc_network_common::protocol::ProtocolName; use std::fmt; diff --git a/client/network/common/src/lib.rs b/client/network/common/src/lib.rs index 3a30d24900199..36e67f11e5cff 100644 --- a/client/network/common/src/lib.rs +++ b/client/network/common/src/lib.rs @@ -19,8 +19,16 @@ //! Common data structures of the networking layer. pub mod config; +pub mod error; pub mod message; pub mod protocol; pub mod request_responses; pub mod service; pub mod sync; +pub mod utils; + +/// Minimum Requirements for a Hash within Networking +pub trait ExHashT: std::hash::Hash + Eq + std::fmt::Debug + Clone + Send + Sync + 'static {} + +impl ExHashT for T where T: std::hash::Hash + Eq + std::fmt::Debug + Clone + Send + Sync + 'static +{} diff --git a/client/network/common/src/protocol.rs b/client/network/common/src/protocol.rs index 11edc373a2620..04bfaedbcac71 100644 --- a/client/network/common/src/protocol.rs +++ b/client/network/common/src/protocol.rs @@ -27,6 +27,7 @@ use std::{ use libp2p::core::upgrade; pub mod event; +pub mod role; /// The protocol name transmitted on the wire. #[derive(Debug, Clone)] diff --git a/client/network/common/src/protocol/event.rs b/client/network/common/src/protocol/event.rs index 3d8c183da495c..236913df1b120 100644 --- a/client/network/common/src/protocol/event.rs +++ b/client/network/common/src/protocol/event.rs @@ -20,6 +20,7 @@ //! events that happen on the network like DHT get/put results received. use super::ProtocolName; +use crate::protocol::role::ObservedRole; use bytes::Bytes; use libp2p::{core::PeerId, kad::record::Key}; @@ -97,26 +98,3 @@ pub enum Event { messages: Vec<(ProtocolName, Bytes)>, }, } - -/// Role that the peer sent to us during the handshake, with the addition of what our local node -/// knows about that peer. -/// -/// > **Note**: This enum is different from the `Role` enum. The `Role` enum indicates what a -/// > node says about itself, while `ObservedRole` is a `Role` merged with the -/// > information known locally about that node. -#[derive(Debug, Clone)] -pub enum ObservedRole { - /// Full node. - Full, - /// Light node. - Light, - /// Third-party authority. - Authority, -} - -impl ObservedRole { - /// Returns `true` for `ObservedRole::Light`. - pub fn is_light(&self) -> bool { - matches!(self, Self::Light) - } -} diff --git a/client/network/common/src/protocol/role.rs b/client/network/common/src/protocol/role.rs new file mode 100644 index 0000000000000..ed22830fd7170 --- /dev/null +++ b/client/network/common/src/protocol/role.rs @@ -0,0 +1,121 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use codec::{self, Encode, EncodeLike, Input, Output}; + +/// Role that the peer sent to us during the handshake, with the addition of what our local node +/// knows about that peer. +/// +/// > **Note**: This enum is different from the `Role` enum. The `Role` enum indicates what a +/// > node says about itself, while `ObservedRole` is a `Role` merged with the +/// > information known locally about that node. +#[derive(Debug, Clone)] +pub enum ObservedRole { + /// Full node. + Full, + /// Light node. + Light, + /// Third-party authority. + Authority, +} + +impl ObservedRole { + /// Returns `true` for `ObservedRole::Light`. + pub fn is_light(&self) -> bool { + matches!(self, Self::Light) + } +} + +/// Role of the local node. +#[derive(Debug, Clone)] +pub enum Role { + /// Regular full node. + Full, + /// Actual authority. + Authority, +} + +impl Role { + /// True for [`Role::Authority`]. + pub fn is_authority(&self) -> bool { + matches!(self, Self::Authority) + } +} + +impl std::fmt::Display for Role { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Full => write!(f, "FULL"), + Self::Authority => write!(f, "AUTHORITY"), + } + } +} + +bitflags::bitflags! { + /// Bitmask of the roles that a node fulfills. + pub struct Roles: u8 { + /// No network. + const NONE = 0b00000000; + /// Full node, does not participate in consensus. + const FULL = 0b00000001; + /// Light client node. + const LIGHT = 0b00000010; + /// Act as an authority + const AUTHORITY = 0b00000100; + } +} + +impl Roles { + /// Does this role represents a client that holds full chain data locally? + pub fn is_full(&self) -> bool { + self.intersects(Self::FULL | Self::AUTHORITY) + } + + /// Does this role represents a client that does not participates in the consensus? + pub fn is_authority(&self) -> bool { + *self == Self::AUTHORITY + } + + /// Does this role represents a client that does not hold full chain data locally? + pub fn is_light(&self) -> bool { + !self.is_full() + } +} + +impl<'a> From<&'a Role> for Roles { + fn from(roles: &'a Role) -> Self { + match roles { + Role::Full => Self::FULL, + Role::Authority => Self::AUTHORITY, + } + } +} + +impl Encode for Roles { + fn encode_to(&self, dest: &mut T) { + dest.push_byte(self.bits()) + } +} + +impl EncodeLike for Roles {} + +impl codec::Decode for Roles { + fn decode(input: &mut I) -> Result { + Self::from_bits(input.read_byte()?).ok_or_else(|| codec::Error::from("Invalid bytes")) + } +} diff --git a/client/network/common/src/service.rs b/client/network/common/src/service.rs index 88583832e4c38..aa4967ba51700 100644 --- a/client/network/common/src/service.rs +++ b/client/network/common/src/service.rs @@ -604,35 +604,6 @@ where } } -/// Provides ability to propagate transactions over the network. -pub trait NetworkTransaction { - /// You may call this when new transactions are imported by the transaction pool. - /// - /// All transactions will be fetched from the `TransactionPool` that was passed at - /// initialization as part of the configuration and propagated to peers. - fn trigger_repropagate(&self); - - /// You must call when new transaction is imported by the transaction pool. - /// - /// This transaction will be fetched from the `TransactionPool` that was passed at - /// initialization as part of the configuration and propagated to peers. - fn propagate_transaction(&self, hash: H); -} - -impl NetworkTransaction for Arc -where - T: ?Sized, - T: NetworkTransaction, -{ - fn trigger_repropagate(&self) { - T::trigger_repropagate(self) - } - - fn propagate_transaction(&self, hash: H) { - T::propagate_transaction(self, hash) - } -} - /// Provides ability to announce blocks to the network. pub trait NetworkBlock { /// Make sure an important block is propagated to peers. diff --git a/client/network/common/src/sync.rs b/client/network/common/src/sync.rs index 2ee8f8c51814b..aa761e66ebf68 100644 --- a/client/network/common/src/sync.rs +++ b/client/network/common/src/sync.rs @@ -96,6 +96,8 @@ pub enum OnBlockData { Import(BlockOrigin, Vec>), /// A new block request needs to be made to the given peer. Request(PeerId, BlockRequest), + /// Continue processing events. + Continue, } /// Result of [`ChainSync::on_block_justification`]. @@ -267,12 +269,14 @@ pub trait ChainSync: Send { ); /// Get an iterator over all scheduled justification requests. - fn justification_requests( - &mut self, - ) -> Box)> + '_>; + fn justification_requests<'a>( + &'a mut self, + ) -> Box)> + 'a>; /// Get an iterator over all block requests of all peers. - fn block_requests(&mut self) -> Box)> + '_>; + fn block_requests<'a>( + &'a mut self, + ) -> Box)> + 'a>; /// Get a state request, if any. fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)>; @@ -357,9 +361,9 @@ pub trait ChainSync: Send { /// /// If [`PollBlockAnnounceValidation::ImportHeader`] is returned, then the caller MUST try to /// import passed header (call `on_block_data`). The network request isn't sent in this case. - fn poll_block_announce_validation( + fn poll_block_announce_validation<'a>( &mut self, - cx: &mut std::task::Context, + cx: &mut std::task::Context<'a>, ) -> Poll>; /// Call when a peer has disconnected. @@ -391,4 +395,14 @@ pub trait ChainSync: Send { /// Decode implementation-specific state response. fn decode_state_response(&self, response: &[u8]) -> Result; + + /// Advance the state of `ChainSync` + /// + /// Internally calls [`ChainSync::poll_block_announce_validation()`] and + /// this function should be polled until it returns [`Poll::Pending`] to + /// consume all pending events. + fn poll( + &mut self, + cx: &mut std::task::Context, + ) -> Poll>; } diff --git a/client/network/common/src/sync/message.rs b/client/network/common/src/sync/message.rs index 27ab2704e6471..346f1dbce9bcc 100644 --- a/client/network/common/src/sync/message.rs +++ b/client/network/common/src/sync/message.rs @@ -19,10 +19,12 @@ //! Network packet message types. These get serialized and put into the lower level protocol //! payload. +use crate::protocol::role::Roles; + use bitflags::bitflags; use codec::{Decode, Encode, Error, Input, Output}; pub use generic::{BlockAnnounce, FromBlock}; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; /// Type alias for using the block request type using block type parameters. pub type BlockRequest = @@ -158,8 +160,6 @@ pub mod generic { pub fields: BlockAttributes, /// Start from this block. pub from: FromBlock, - /// End at this block. An implementation defined maximum is used when unspecified. - pub to: Option, /// Sequence direction. pub direction: Direction, /// Maximum number of blocks to return. An implementation defined maximum is used when @@ -220,3 +220,27 @@ pub mod generic { } } } + +/// Handshake sent when we open a block announces substream. +#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] +pub struct BlockAnnouncesHandshake { + /// Roles of the node. + pub roles: Roles, + /// Best block number. + pub best_number: NumberFor, + /// Best block hash. + pub best_hash: B::Hash, + /// Genesis block hash. + pub genesis_hash: B::Hash, +} + +impl BlockAnnouncesHandshake { + pub fn build( + roles: Roles, + best_number: NumberFor, + best_hash: B::Hash, + genesis_hash: B::Hash, + ) -> Self { + Self { genesis_hash, roles, best_number, best_hash } + } +} diff --git a/client/network/common/src/sync/warp.rs b/client/network/common/src/sync/warp.rs index 339a4c33a7eeb..c9b9037542388 100644 --- a/client/network/common/src/sync/warp.rs +++ b/client/network/common/src/sync/warp.rs @@ -64,6 +64,8 @@ pub enum WarpSyncPhase { AwaitingPeers, /// Downloading and verifying grandpa warp proofs. DownloadingWarpProofs, + /// Downloading target block. + DownloadingTargetBlock, /// Downloading state data. DownloadingState, /// Importing state. @@ -77,6 +79,7 @@ impl fmt::Display for WarpSyncPhase { match self { Self::AwaitingPeers => write!(f, "Waiting for peers"), Self::DownloadingWarpProofs => write!(f, "Downloading finality proofs"), + Self::DownloadingTargetBlock => write!(f, "Downloading target block"), Self::DownloadingState => write!(f, "Downloading state"), Self::ImportingState => write!(f, "Importing state"), Self::DownloadingBlocks(n) => write!(f, "Downloading block history (#{})", n), diff --git a/client/network/src/utils.rs b/client/network/common/src/utils.rs similarity index 100% rename from client/network/src/utils.rs rename to client/network/common/src/utils.rs diff --git a/client/network/light/Cargo.toml b/client/network/light/Cargo.toml index c1a0fb4759320..cd3be390d48c8 100644 --- a/client/network/light/Cargo.toml +++ b/client/network/light/Cargo.toml @@ -14,17 +14,17 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" [dependencies] +array-bytes = "4.1" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = "0.3.21" -hex = "0.4.0" -libp2p = "0.46.1" +libp2p = "0.49.0" log = "0.4.16" -prost = "0.10" +prost = "0.11" sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-network-common = { version = "0.10.0-dev", path = "../common" } diff --git a/client/network/light/src/light_client_requests.rs b/client/network/light/src/light_client_requests.rs index b58426cf15992..61b549d0f0984 100644 --- a/client/network/light/src/light_client_requests.rs +++ b/client/network/light/src/light_client_requests.rs @@ -27,10 +27,11 @@ use std::time::Duration; /// Generate the light client protocol name from the genesis hash and fork id. fn generate_protocol_name>(genesis_hash: Hash, fork_id: Option<&str>) -> String { + let genesis_hash = genesis_hash.as_ref(); if let Some(fork_id) = fork_id { - format!("/{}/{}/light/2", hex::encode(genesis_hash), fork_id) + format!("/{}/{}/light/2", array_bytes::bytes2hex("", genesis_hash), fork_id) } else { - format!("/{}/light/2", hex::encode(genesis_hash)) + format!("/{}/light/2", array_bytes::bytes2hex("", genesis_hash)) } } diff --git a/client/network/light/src/light_client_requests/handler.rs b/client/network/light/src/light_client_requests/handler.rs index 727a9b0d7e820..9dc02eb9ff291 100644 --- a/client/network/light/src/light_client_requests/handler.rs +++ b/client/network/light/src/light_client_requests/handler.rs @@ -28,7 +28,7 @@ use futures::{channel::mpsc, prelude::*}; use libp2p::PeerId; use log::{debug, trace}; use prost::Message; -use sc_client_api::{BlockBackend, ProofProvider, StorageProof}; +use sc_client_api::{BlockBackend, ProofProvider}; use sc_network_common::{ config::ProtocolId, request_responses::{IncomingRequest, OutgoingResponse, ProtocolConfig}, @@ -151,12 +151,8 @@ where self.on_remote_call_request(&peer, r)?, Some(schema::v1::light::request::Request::RemoteReadRequest(r)) => self.on_remote_read_request(&peer, r)?, - Some(schema::v1::light::request::Request::RemoteHeaderRequest(_r)) => - return Err(HandleRequestError::BadRequest("Not supported.")), Some(schema::v1::light::request::Request::RemoteReadChildRequest(r)) => self.on_remote_read_child_request(&peer, r)?, - Some(schema::v1::light::request::Request::RemoteChangesRequest(_r)) => - return Err(HandleRequestError::BadRequest("Not supported.")), None => return Err(HandleRequestError::BadRequest("Remote request without request data.")), }; @@ -176,12 +172,15 @@ where let block = Decode::decode(&mut request.block.as_ref())?; - let proof = + let response = match self .client .execution_proof(&BlockId::Hash(block), &request.method, &request.data) { - Ok((_, proof)) => proof, + Ok((_, proof)) => { + let r = schema::v1::light::RemoteCallResponse { proof: proof.encode() }; + Some(schema::v1::light::response::Response::RemoteCallResponse(r)) + }, Err(e) => { trace!( "remote call request from {} ({} at {:?}) failed with: {}", @@ -190,16 +189,11 @@ where request.block, e, ); - StorageProof::empty() + None }, }; - let response = { - let r = schema::v1::light::RemoteCallResponse { proof: proof.encode() }; - schema::v1::light::response::Response::RemoteCallResponse(r) - }; - - Ok(schema::v1::light::Response { response: Some(response) }) + Ok(schema::v1::light::Response { response }) } fn on_remote_read_request( @@ -221,11 +215,14 @@ where let block = Decode::decode(&mut request.block.as_ref())?; - let proof = match self + let response = match self .client .read_proof(&BlockId::Hash(block), &mut request.keys.iter().map(AsRef::as_ref)) { - Ok(proof) => proof, + Ok(proof) => { + let r = schema::v1::light::RemoteReadResponse { proof: proof.encode() }; + Some(schema::v1::light::response::Response::RemoteReadResponse(r)) + }, Err(error) => { trace!( "remote read request from {} ({} at {:?}) failed with: {}", @@ -234,16 +231,11 @@ where request.block, error, ); - StorageProof::empty() + None }, }; - let response = { - let r = schema::v1::light::RemoteReadResponse { proof: proof.encode() }; - schema::v1::light::response::Response::RemoteReadResponse(r) - }; - - Ok(schema::v1::light::Response { response: Some(response) }) + Ok(schema::v1::light::Response { response }) } fn on_remote_read_child_request( @@ -271,14 +263,17 @@ where Some((ChildType::ParentKeyId, storage_key)) => Ok(ChildInfo::new_default(storage_key)), None => Err(sp_blockchain::Error::InvalidChildStorageKey), }; - let proof = match child_info.and_then(|child_info| { + let response = match child_info.and_then(|child_info| { self.client.read_child_proof( &BlockId::Hash(block), &child_info, &mut request.keys.iter().map(AsRef::as_ref), ) }) { - Ok(proof) => proof, + Ok(proof) => { + let r = schema::v1::light::RemoteReadResponse { proof: proof.encode() }; + Some(schema::v1::light::response::Response::RemoteReadResponse(r)) + }, Err(error) => { trace!( "remote read child request from {} ({} {} at {:?}) failed with: {}", @@ -288,16 +283,11 @@ where request.block, error, ); - StorageProof::empty() + None }, }; - let response = { - let r = schema::v1::light::RemoteReadResponse { proof: proof.encode() }; - schema::v1::light::response::Response::RemoteReadResponse(r) - }; - - Ok(schema::v1::light::Response { response: Some(response) }) + Ok(schema::v1::light::Response { response }) } } diff --git a/client/network/light/src/schema/light.v1.proto b/client/network/light/src/schema/light.v1.proto index 9b5d47719dc28..1df5466e21988 100644 --- a/client/network/light/src/schema/light.v1.proto +++ b/client/network/light/src/schema/light.v1.proto @@ -17,9 +17,8 @@ message Request { oneof request { RemoteCallRequest remote_call_request = 1; RemoteReadRequest remote_read_request = 2; - RemoteHeaderRequest remote_header_request = 3; RemoteReadChildRequest remote_read_child_request = 4; - RemoteChangesRequest remote_changes_request = 5; + // Note: ids 3 and 5 were used in the past. It would be preferable to not re-use them. } } @@ -28,8 +27,7 @@ message Response { oneof response { RemoteCallResponse remote_call_response = 1; RemoteReadResponse remote_read_response = 2; - RemoteHeaderResponse remote_header_response = 3; - RemoteChangesResponse remote_changes_response = 4; + // Note: ids 3 and 4 were used in the past. It would be preferable to not re-use them. } } @@ -73,48 +71,3 @@ message RemoteReadChildRequest { // Storage keys. repeated bytes keys = 6; } - -// Remote header request. -message RemoteHeaderRequest { - // Block number to request header for. - bytes block = 2; -} - -// Remote header response. -message RemoteHeaderResponse { - // Header. None if proof generation has failed (e.g. header is unknown). - bytes header = 2; // optional - // Header proof. - bytes proof = 3; -} - -/// Remote changes request. -message RemoteChangesRequest { - // Hash of the first block of the range (including first) where changes are requested. - bytes first = 2; - // Hash of the last block of the range (including last) where changes are requested. - bytes last = 3; - // Hash of the first block for which the requester has the changes trie root. All other - // affected roots must be proved. - bytes min = 4; - // Hash of the last block that we can use when querying changes. - bytes max = 5; - // Storage child node key which changes are requested. - bytes storage_key = 6; // optional - // Storage key which changes are requested. - bytes key = 7; -} - -// Remote changes response. -message RemoteChangesResponse { - // Proof has been generated using block with this number as a max block. Should be - // less than or equal to the RemoteChangesRequest::max block number. - bytes max = 2; - // Changes proof. - repeated bytes proof = 3; - // Changes tries roots missing on the requester' node. - repeated Pair roots = 4; - // Missing changes tries roots proof. - bytes roots_proof = 5; -} - diff --git a/client/network/src/behaviour.rs b/client/network/src/behaviour.rs index 24df47db6803f..fa130fb4baacd 100644 --- a/client/network/src/behaviour.rs +++ b/client/network/src/behaviour.rs @@ -17,56 +17,46 @@ // along with this program. If not, see . use crate::{ - bitswap::Bitswap, discovery::{DiscoveryBehaviour, DiscoveryConfig, DiscoveryOut}, peer_info, - protocol::{message::Roles, CustomMessageOutcome, NotificationsSink, Protocol}, + protocol::{CustomMessageOutcome, NotificationsSink, Protocol}, request_responses, }; use bytes::Bytes; -use codec::Encode; use futures::channel::oneshot; use libp2p::{ core::{Multiaddr, PeerId, PublicKey}, - identify::IdentifyInfo, + identify::Info as IdentifyInfo, kad::record, - swarm::{ - behaviour::toggle::Toggle, NetworkBehaviour, NetworkBehaviourAction, - NetworkBehaviourEventProcess, PollParameters, - }, NetworkBehaviour, }; -use log::debug; -use sc_consensus::import_queue::{IncomingBlock, Origin}; +use sc_consensus::import_queue::{IncomingBlock, RuntimeOrigin}; use sc_network_common::{ config::ProtocolId, protocol::{ - event::{DhtEvent, ObservedRole}, + event::DhtEvent, + role::{ObservedRole, Roles}, ProtocolName, }, request_responses::{IfDisconnected, ProtocolConfig, RequestFailure}, + sync::{warp::WarpProofRequest, OpaqueBlockRequest, OpaqueStateRequest}, }; -use sc_peerset::PeersetHandle; +use sc_peerset::{PeersetHandle, ReputationChange}; use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; use sp_runtime::{ traits::{Block as BlockT, NumberFor}, Justifications, }; -use std::{ - collections::{HashSet, VecDeque}, - iter, - task::{Context, Poll}, - time::Duration, -}; +use std::{collections::HashSet, time::Duration}; pub use crate::request_responses::{InboundFailure, OutboundFailure, RequestId, ResponseFailure}; /// General behaviour of the network. Combines all protocols together. #[derive(NetworkBehaviour)] -#[behaviour(out_event = "BehaviourOut", poll_method = "poll", event_process = true)] +#[behaviour(out_event = "BehaviourOut")] pub struct Behaviour where B: BlockT, @@ -79,38 +69,17 @@ where peer_info: peer_info::PeerInfoBehaviour, /// Discovers nodes of the network. discovery: DiscoveryBehaviour, - /// Bitswap server for blockchain data. - bitswap: Toggle>, /// Generic request-response protocols. request_responses: request_responses::RequestResponsesBehaviour, - - /// Queue of events to produce for the outside. - #[behaviour(ignore)] - events: VecDeque>, - - /// Protocol name used to send out block requests via - /// [`request_responses::RequestResponsesBehaviour`]. - #[behaviour(ignore)] - block_request_protocol_name: String, - - /// Protocol name used to send out state requests via - /// [`request_responses::RequestResponsesBehaviour`]. - #[behaviour(ignore)] - state_request_protocol_name: String, - - /// Protocol name used to send out warp sync requests via - /// [`request_responses::RequestResponsesBehaviour`]. - #[behaviour(ignore)] - warp_sync_protocol_name: Option, } /// Event generated by `Behaviour`. pub enum BehaviourOut { BlockImport(BlockOrigin, Vec>), - JustificationImport(Origin, B::Hash, NumberFor, Justifications), + JustificationImport(RuntimeOrigin, B::Hash, NumberFor, Justifications), /// Started a random iterative Kademlia discovery query. - RandomKademliaStarted(ProtocolId), + RandomKademliaStarted(Vec), /// We have received a request from a peer and answered it. /// @@ -139,6 +108,12 @@ pub enum BehaviourOut { result: Result<(), RequestFailure>, }, + /// A request protocol handler issued reputation changes for the given peer. + ReputationChanges { + peer: PeerId, + changes: Vec, + }, + /// Opened a substream with the given node with the given notifications protocol. /// /// The protocol is always one of the notification protocols that have been registered. @@ -189,15 +164,60 @@ pub enum BehaviourOut { messages: Vec<(ProtocolName, Bytes)>, }, + /// A new block request must be emitted. + BlockRequest { + /// Node we send the request to. + target: PeerId, + /// Opaque implementation-specific block request. + request: OpaqueBlockRequest, + /// One-shot channel to receive the response. + pending_response: oneshot::Sender, RequestFailure>>, + }, + + /// A new state request must be emitted. + StateRequest { + /// Node we send the request to. + target: PeerId, + /// Opaque implementation-specific state request. + request: OpaqueStateRequest, + /// One-shot channel to receive the response. + pending_response: oneshot::Sender, RequestFailure>>, + }, + + /// A new warp sync request must be emitted. + WarpSyncRequest { + /// Node we send the request to. + target: PeerId, + /// Warp sync request. + request: WarpProofRequest, + /// One-shot channel to receive the response. + pending_response: oneshot::Sender, RequestFailure>>, + }, + /// Now connected to a new peer for syncing purposes. SyncConnected(PeerId), /// No longer connected to a peer for syncing purposes. SyncDisconnected(PeerId), + /// We have obtained identity information from a peer, including the addresses it is listening + /// on. + PeerIdentify { + /// Id of the peer that has been identified. + peer_id: PeerId, + /// Information about the peer. + info: IdentifyInfo, + }, + + /// We have learned about the existence of a node on the default set. + Discovered(PeerId), + /// Events generated by a DHT as a response to get_value or put_value requests as well as the /// request duration. Dht(DhtEvent, Duration), + + /// Ignored event generated by lower layers. + None, } impl Behaviour @@ -214,23 +234,14 @@ where block_request_protocol_config: ProtocolConfig, state_request_protocol_config: ProtocolConfig, warp_sync_protocol_config: Option, - bitswap: Option>, light_client_request_protocol_config: ProtocolConfig, // All remaining request protocol configs. mut request_response_protocols: Vec, peerset: PeersetHandle, ) -> Result { - // Extract protocol name and add to `request_response_protocols`. - let block_request_protocol_name = block_request_protocol_config.name.to_string(); - let state_request_protocol_name = state_request_protocol_config.name.to_string(); - let warp_sync_protocol_name = match warp_sync_protocol_config { - Some(config) => { - let name = config.name.to_string(); - request_response_protocols.push(config); - Some(name) - }, - None => None, - }; + if let Some(config) = warp_sync_protocol_config { + request_response_protocols.push(config); + } request_response_protocols.push(block_request_protocol_config); request_response_protocols.push(state_request_protocol_config); request_response_protocols.push(light_client_request_protocol_config); @@ -239,15 +250,10 @@ where substrate, peer_info: peer_info::PeerInfoBehaviour::new(user_agent, local_public_key), discovery: disco_config.finish(), - bitswap: bitswap.into(), request_responses: request_responses::RequestResponsesBehaviour::new( request_response_protocols.into_iter(), peerset, )?, - events: VecDeque::new(), - block_request_protocol_name, - state_request_protocol_name, - warp_sync_protocol_name, }) } @@ -315,6 +321,17 @@ where &mut self.substrate } + /// Add a self-reported address of a remote peer to the k-buckets of the supported + /// DHTs (`supported_protocols`). + pub fn add_self_reported_address_to_dht( + &mut self, + peer_id: &PeerId, + supported_protocols: &[impl AsRef<[u8]>], + addr: Multiaddr, + ) { + self.discovery.add_self_reported_address(peer_id, supported_protocols, addr); + } + /// Start querying a record from the DHT. Will later produce either a `ValueFound` or a /// `ValueNotFound` event. pub fn get_value(&mut self, key: record::Key) { @@ -338,231 +355,91 @@ fn reported_roles_to_observed_role(roles: Roles) -> ObservedRole { } } -impl NetworkBehaviourEventProcess for Behaviour -where - B: BlockT, - Client: HeaderBackend + 'static, -{ - fn inject_event(&mut self, event: void::Void) { - void::unreachable(event) - } -} - -impl NetworkBehaviourEventProcess> for Behaviour -where - B: BlockT, - Client: HeaderBackend + 'static, -{ - fn inject_event(&mut self, event: CustomMessageOutcome) { +impl From> for BehaviourOut { + fn from(event: CustomMessageOutcome) -> Self { match event { CustomMessageOutcome::BlockImport(origin, blocks) => - self.events.push_back(BehaviourOut::BlockImport(origin, blocks)), - CustomMessageOutcome::JustificationImport(origin, hash, nb, justification) => self - .events - .push_back(BehaviourOut::JustificationImport(origin, hash, nb, justification)), - CustomMessageOutcome::BlockRequest { target, request, pending_response } => { - match self.substrate.encode_block_request(&request) { - Ok(data) => { - self.request_responses.send_request( - &target, - &self.block_request_protocol_name, - data, - pending_response, - IfDisconnected::ImmediateError, - ); - }, - Err(err) => { - log::warn!( - target: "sync", - "Failed to encode block request {:?}: {:?}", - request, err - ); - }, - } - }, - CustomMessageOutcome::StateRequest { target, request, pending_response } => { - match self.substrate.encode_state_request(&request) { - Ok(data) => { - self.request_responses.send_request( - &target, - &self.state_request_protocol_name, - data, - pending_response, - IfDisconnected::ImmediateError, - ); - }, - Err(err) => { - log::warn!( - target: "sync", - "Failed to encode state request {:?}: {:?}", - request, err - ); - }, - } - }, + BehaviourOut::BlockImport(origin, blocks), + CustomMessageOutcome::JustificationImport(origin, hash, nb, justification) => + BehaviourOut::JustificationImport(origin, hash, nb, justification), + CustomMessageOutcome::BlockRequest { target, request, pending_response } => + BehaviourOut::BlockRequest { target, request, pending_response }, + CustomMessageOutcome::StateRequest { target, request, pending_response } => + BehaviourOut::StateRequest { target, request, pending_response }, CustomMessageOutcome::WarpSyncRequest { target, request, pending_response } => - match &self.warp_sync_protocol_name { - Some(name) => self.request_responses.send_request( - &target, - name, - request.encode(), - pending_response, - IfDisconnected::ImmediateError, - ), - None => { - log::warn!( - target: "sync", - "Trying to send warp sync request when no protocol is configured {:?}", - request, - ); - }, - }, + BehaviourOut::WarpSyncRequest { target, request, pending_response }, CustomMessageOutcome::NotificationStreamOpened { remote, protocol, negotiated_fallback, roles, notifications_sink, - } => { - self.events.push_back(BehaviourOut::NotificationStreamOpened { - remote, - protocol, - negotiated_fallback, - role: reported_roles_to_observed_role(roles), - notifications_sink, - }); - }, - CustomMessageOutcome::NotificationStreamReplaced { + } => BehaviourOut::NotificationStreamOpened { remote, protocol, + negotiated_fallback, + role: reported_roles_to_observed_role(roles), notifications_sink, - } => self.events.push_back(BehaviourOut::NotificationStreamReplaced { + }, + CustomMessageOutcome::NotificationStreamReplaced { remote, protocol, notifications_sink, - }), - CustomMessageOutcome::NotificationStreamClosed { remote, protocol } => self - .events - .push_back(BehaviourOut::NotificationStreamClosed { remote, protocol }), - CustomMessageOutcome::NotificationsReceived { remote, messages } => { - self.events.push_back(BehaviourOut::NotificationsReceived { remote, messages }); - }, - CustomMessageOutcome::PeerNewBest(_peer_id, _number) => {}, - CustomMessageOutcome::SyncConnected(peer_id) => - self.events.push_back(BehaviourOut::SyncConnected(peer_id)), + } => BehaviourOut::NotificationStreamReplaced { remote, protocol, notifications_sink }, + CustomMessageOutcome::NotificationStreamClosed { remote, protocol } => + BehaviourOut::NotificationStreamClosed { remote, protocol }, + CustomMessageOutcome::NotificationsReceived { remote, messages } => + BehaviourOut::NotificationsReceived { remote, messages }, + CustomMessageOutcome::PeerNewBest(_peer_id, _number) => BehaviourOut::None, + CustomMessageOutcome::SyncConnected(peer_id) => BehaviourOut::SyncConnected(peer_id), CustomMessageOutcome::SyncDisconnected(peer_id) => - self.events.push_back(BehaviourOut::SyncDisconnected(peer_id)), - CustomMessageOutcome::None => {}, + BehaviourOut::SyncDisconnected(peer_id), + CustomMessageOutcome::None => BehaviourOut::None, } } } -impl NetworkBehaviourEventProcess for Behaviour -where - B: BlockT, - Client: HeaderBackend + 'static, -{ - fn inject_event(&mut self, event: request_responses::Event) { +impl From for BehaviourOut { + fn from(event: request_responses::Event) -> Self { match event { - request_responses::Event::InboundRequest { peer, protocol, result } => { - self.events.push_back(BehaviourOut::InboundRequest { peer, protocol, result }); - }, - request_responses::Event::RequestFinished { peer, protocol, duration, result } => { - self.events.push_back(BehaviourOut::RequestFinished { - peer, - protocol, - duration, - result, - }); - }, + request_responses::Event::InboundRequest { peer, protocol, result } => + BehaviourOut::InboundRequest { peer, protocol, result }, + request_responses::Event::RequestFinished { peer, protocol, duration, result } => + BehaviourOut::RequestFinished { peer, protocol, duration, result }, request_responses::Event::ReputationChanges { peer, changes } => - for change in changes { - self.substrate.report_peer(peer, change); - }, + BehaviourOut::ReputationChanges { peer, changes }, } } } -impl NetworkBehaviourEventProcess for Behaviour -where - B: BlockT, - Client: HeaderBackend + 'static, -{ - fn inject_event(&mut self, event: peer_info::PeerInfoEvent) { - let peer_info::PeerInfoEvent::Identified { - peer_id, - info: IdentifyInfo { protocol_version, agent_version, mut listen_addrs, protocols, .. }, - } = event; - - if listen_addrs.len() > 30 { - debug!( - target: "sub-libp2p", - "Node {:?} has reported more than 30 addresses; it is identified by {:?} and {:?}", - peer_id, protocol_version, agent_version - ); - listen_addrs.truncate(30); - } - - for addr in listen_addrs { - self.discovery.add_self_reported_address(&peer_id, protocols.iter(), addr); - } - self.substrate.add_default_set_discovered_nodes(iter::once(peer_id)); +impl From for BehaviourOut { + fn from(event: peer_info::PeerInfoEvent) -> Self { + let peer_info::PeerInfoEvent::Identified { peer_id, info } = event; + BehaviourOut::PeerIdentify { peer_id, info } } } -impl NetworkBehaviourEventProcess for Behaviour -where - B: BlockT, - Client: HeaderBackend + 'static, -{ - fn inject_event(&mut self, out: DiscoveryOut) { - match out { +impl From for BehaviourOut { + fn from(event: DiscoveryOut) -> Self { + match event { DiscoveryOut::UnroutablePeer(_peer_id) => { // Obtaining and reporting listen addresses for unroutable peers back // to Kademlia is handled by the `Identify` protocol, part of the - // `PeerInfoBehaviour`. See the `NetworkBehaviourEventProcess` - // implementation for `PeerInfoEvent`. - }, - DiscoveryOut::Discovered(peer_id) => { - self.substrate.add_default_set_discovered_nodes(iter::once(peer_id)); - }, - DiscoveryOut::ValueFound(results, duration) => { - self.events - .push_back(BehaviourOut::Dht(DhtEvent::ValueFound(results), duration)); - }, - DiscoveryOut::ValueNotFound(key, duration) => { - self.events.push_back(BehaviourOut::Dht(DhtEvent::ValueNotFound(key), duration)); - }, - DiscoveryOut::ValuePut(key, duration) => { - self.events.push_back(BehaviourOut::Dht(DhtEvent::ValuePut(key), duration)); - }, - DiscoveryOut::ValuePutFailed(key, duration) => { - self.events - .push_back(BehaviourOut::Dht(DhtEvent::ValuePutFailed(key), duration)); + // `PeerInfoBehaviour`. See the `From` + // implementation. + BehaviourOut::None }, + DiscoveryOut::Discovered(peer_id) => BehaviourOut::Discovered(peer_id), + DiscoveryOut::ValueFound(results, duration) => + BehaviourOut::Dht(DhtEvent::ValueFound(results), duration), + DiscoveryOut::ValueNotFound(key, duration) => + BehaviourOut::Dht(DhtEvent::ValueNotFound(key), duration), + DiscoveryOut::ValuePut(key, duration) => + BehaviourOut::Dht(DhtEvent::ValuePut(key), duration), + DiscoveryOut::ValuePutFailed(key, duration) => + BehaviourOut::Dht(DhtEvent::ValuePutFailed(key), duration), DiscoveryOut::RandomKademliaStarted(protocols) => - for protocol in protocols { - self.events.push_back(BehaviourOut::RandomKademliaStarted(protocol)); - }, - } - } -} - -impl Behaviour -where - B: BlockT, - Client: HeaderBackend + 'static, -{ - fn poll( - &mut self, - _cx: &mut Context, - _: &mut impl PollParameters, - ) -> Poll, ::ConnectionHandler>> - { - if let Some(event) = self.events.pop_front() { - return Poll::Ready(NetworkBehaviourAction::GenerateEvent(event)) + BehaviourOut::RandomKademliaStarted(protocols), } - - Poll::Pending } } diff --git a/client/network/src/bitswap.rs b/client/network/src/bitswap.rs deleted file mode 100644 index 52fa0c36caedf..0000000000000 --- a/client/network/src/bitswap.rs +++ /dev/null @@ -1,416 +0,0 @@ -// Copyright 2022 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Substrate is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Substrate. If not, see . - -//! Bitswap server for substrate. -//! -//! Allows querying transactions by hash over standard bitswap protocol -//! Only supports bitswap 1.2.0. -//! CID is expected to reference 256-bit Blake2b transaction hash. - -use crate::schema::bitswap::{ - message::{wantlist::WantType, Block as MessageBlock, BlockPresence, BlockPresenceType}, - Message as BitswapMessage, -}; -use cid::Version; -use core::pin::Pin; -use futures::{ - io::{AsyncRead, AsyncWrite}, - Future, -}; -use libp2p::{ - core::{ - connection::ConnectionId, upgrade, InboundUpgrade, Multiaddr, OutboundUpgrade, PeerId, - UpgradeInfo, - }, - swarm::{ - NetworkBehaviour, NetworkBehaviourAction, NotifyHandler, OneShotHandler, PollParameters, - }, -}; -use log::{debug, error, trace}; -use prost::Message; -use sc_client_api::BlockBackend; -use sp_runtime::traits::Block as BlockT; -use std::{ - collections::VecDeque, - io, - marker::PhantomData, - sync::Arc, - task::{Context, Poll}, -}; -use unsigned_varint::encode as varint_encode; - -const LOG_TARGET: &str = "bitswap"; - -// Undocumented, but according to JS the bitswap messages have a max size of 512*1024 bytes -// https://github.com/ipfs/js-ipfs-bitswap/blob/ -// d8f80408aadab94c962f6b88f343eb9f39fa0fcc/src/decision-engine/index.js#L16 -// We set it to the same value as max substrate protocol message -const MAX_PACKET_SIZE: usize = 16 * 1024 * 1024; - -// Max number of queued responses before denying requests. -const MAX_RESPONSE_QUEUE: usize = 20; -// Max number of blocks per wantlist -const MAX_WANTED_BLOCKS: usize = 16; - -const PROTOCOL_NAME: &[u8] = b"/ipfs/bitswap/1.2.0"; - -type FutureResult = Pin> + Send>>; - -/// Bitswap protocol config -#[derive(Clone, Copy, Debug, Default)] -pub struct BitswapConfig; - -impl UpgradeInfo for BitswapConfig { - type Info = &'static [u8]; - type InfoIter = std::iter::Once; - - fn protocol_info(&self) -> Self::InfoIter { - std::iter::once(PROTOCOL_NAME) - } -} - -impl InboundUpgrade for BitswapConfig -where - TSocket: AsyncRead + AsyncWrite + Send + Unpin + 'static, -{ - type Output = BitswapMessage; - type Error = BitswapError; - type Future = FutureResult; - - fn upgrade_inbound(self, mut socket: TSocket, _info: Self::Info) -> Self::Future { - Box::pin(async move { - let packet = upgrade::read_length_prefixed(&mut socket, MAX_PACKET_SIZE).await?; - let message: BitswapMessage = Message::decode(packet.as_slice())?; - Ok(message) - }) - } -} - -impl UpgradeInfo for BitswapMessage { - type Info = &'static [u8]; - type InfoIter = std::iter::Once; - - fn protocol_info(&self) -> Self::InfoIter { - std::iter::once(PROTOCOL_NAME) - } -} - -impl OutboundUpgrade for BitswapMessage -where - TSocket: AsyncRead + AsyncWrite + Send + Unpin + 'static, -{ - type Output = (); - type Error = io::Error; - type Future = FutureResult; - - fn upgrade_outbound(self, mut socket: TSocket, _info: Self::Info) -> Self::Future { - Box::pin(async move { - let data = self.encode_to_vec(); - upgrade::write_length_prefixed(&mut socket, data).await - }) - } -} - -/// Internal protocol handler event. -#[derive(Debug)] -pub enum HandlerEvent { - /// We received a `BitswapMessage` from a remote. - Request(BitswapMessage), - /// We successfully sent a `BitswapMessage`. - ResponseSent, -} - -impl From for HandlerEvent { - fn from(message: BitswapMessage) -> Self { - Self::Request(message) - } -} - -impl From<()> for HandlerEvent { - fn from(_: ()) -> Self { - Self::ResponseSent - } -} - -/// Prefix represents all metadata of a CID, without the actual content. -#[derive(PartialEq, Eq, Clone, Debug)] -struct Prefix { - /// The version of CID. - pub version: Version, - /// The codec of CID. - pub codec: u64, - /// The multihash type of CID. - pub mh_type: u64, - /// The multihash length of CID. - pub mh_len: u8, -} - -impl Prefix { - /// Convert the prefix to encoded bytes. - pub fn to_bytes(&self) -> Vec { - let mut res = Vec::with_capacity(4); - let mut buf = varint_encode::u64_buffer(); - let version = varint_encode::u64(self.version.into(), &mut buf); - res.extend_from_slice(version); - let mut buf = varint_encode::u64_buffer(); - let codec = varint_encode::u64(self.codec, &mut buf); - res.extend_from_slice(codec); - let mut buf = varint_encode::u64_buffer(); - let mh_type = varint_encode::u64(self.mh_type, &mut buf); - res.extend_from_slice(mh_type); - let mut buf = varint_encode::u64_buffer(); - let mh_len = varint_encode::u64(self.mh_len as u64, &mut buf); - res.extend_from_slice(mh_len); - res - } -} - -/// Bitswap trait -pub trait BitswapT { - /// Get single indexed transaction by content hash. - /// - /// Note that this will only fetch transactions - /// that are indexed by the runtime with `storage_index_transaction`. - fn indexed_transaction( - &self, - hash: ::Hash, - ) -> sp_blockchain::Result>>; - - /// Queue of blocks ready to be sent out on `poll()` - fn ready_blocks(&mut self) -> &mut VecDeque<(PeerId, BitswapMessage)>; -} - -/// Network behaviour that handles sending and receiving IPFS blocks. -struct BitswapInternal { - client: Arc, - ready_blocks: VecDeque<(PeerId, BitswapMessage)>, - _block: PhantomData, -} - -impl BitswapInternal { - /// Create a new instance of the bitswap protocol handler. - pub fn new(client: Arc) -> Self { - Self { client, ready_blocks: Default::default(), _block: PhantomData::default() } - } -} - -impl BitswapT for BitswapInternal -where - Block: BlockT, - Client: BlockBackend, -{ - fn indexed_transaction( - &self, - hash: ::Hash, - ) -> sp_blockchain::Result>> { - self.client.indexed_transaction(&hash) - } - - fn ready_blocks(&mut self) -> &mut VecDeque<(PeerId, BitswapMessage)> { - &mut self.ready_blocks - } -} - -/// Wrapper for bitswap trait object implement NetworkBehaviour -pub struct Bitswap { - inner: Box + Sync + Send>, -} - -impl Bitswap { - /// Create new Bitswap wrapper - pub fn from_client + Send + Sync + 'static>( - client: Arc, - ) -> Self { - let inner = Box::new(BitswapInternal::new(client)) as Box<_>; - Self { inner } - } -} - -impl BitswapT for Bitswap { - fn indexed_transaction( - &self, - hash: ::Hash, - ) -> sp_blockchain::Result>> { - self.inner.indexed_transaction(hash) - } - - fn ready_blocks(&mut self) -> &mut VecDeque<(PeerId, BitswapMessage)> { - self.inner.ready_blocks() - } -} - -impl BitswapT for Box -where - T: BitswapT, -{ - fn indexed_transaction( - &self, - hash: ::Hash, - ) -> sp_blockchain::Result>> { - T::indexed_transaction(self, hash) - } - - fn ready_blocks(&mut self) -> &mut VecDeque<(PeerId, BitswapMessage)> { - T::ready_blocks(self) - } -} - -impl NetworkBehaviour for Bitswap -where - B: BlockT, -{ - type ConnectionHandler = OneShotHandler; - type OutEvent = void::Void; - - fn new_handler(&mut self) -> Self::ConnectionHandler { - Default::default() - } - - fn addresses_of_peer(&mut self, _peer: &PeerId) -> Vec { - Vec::new() - } - - fn inject_event(&mut self, peer: PeerId, _connection: ConnectionId, message: HandlerEvent) { - let request = match message { - HandlerEvent::ResponseSent => return, - HandlerEvent::Request(msg) => msg, - }; - trace!(target: LOG_TARGET, "Received request: {:?} from {}", request, peer); - if self.ready_blocks().len() > MAX_RESPONSE_QUEUE { - debug!(target: LOG_TARGET, "Ignored request: queue is full"); - return - } - - let mut response = BitswapMessage { - wantlist: None, - blocks: Default::default(), - payload: Default::default(), - block_presences: Default::default(), - pending_bytes: 0, - }; - let wantlist = match request.wantlist { - Some(wantlist) => wantlist, - None => { - debug!(target: LOG_TARGET, "Unexpected bitswap message from {}", peer); - return - }, - }; - if wantlist.entries.len() > MAX_WANTED_BLOCKS { - trace!(target: LOG_TARGET, "Ignored request: too many entries"); - return - } - for entry in wantlist.entries { - let cid = match cid::Cid::read_bytes(entry.block.as_slice()) { - Ok(cid) => cid, - Err(e) => { - trace!(target: LOG_TARGET, "Bad CID {:?}: {:?}", entry.block, e); - continue - }, - }; - if cid.version() != cid::Version::V1 || - cid.hash().code() != u64::from(cid::multihash::Code::Blake2b256) || - cid.hash().size() != 32 - { - debug!(target: LOG_TARGET, "Ignoring unsupported CID {}: {}", peer, cid); - continue - } - let mut hash = B::Hash::default(); - hash.as_mut().copy_from_slice(&cid.hash().digest()[0..32]); - let transaction = match self.indexed_transaction(hash) { - Ok(ex) => ex, - Err(e) => { - error!(target: LOG_TARGET, "Error retrieving transaction {}: {}", hash, e); - None - }, - }; - match transaction { - Some(transaction) => { - trace!(target: LOG_TARGET, "Found CID {:?}, hash {:?}", cid, hash); - if entry.want_type == WantType::Block as i32 { - let prefix = Prefix { - version: cid.version(), - codec: cid.codec(), - mh_type: cid.hash().code(), - mh_len: cid.hash().size(), - }; - response - .payload - .push(MessageBlock { prefix: prefix.to_bytes(), data: transaction }); - } else { - response.block_presences.push(BlockPresence { - r#type: BlockPresenceType::Have as i32, - cid: cid.to_bytes(), - }); - } - }, - None => { - trace!(target: LOG_TARGET, "Missing CID {:?}, hash {:?}", cid, hash); - if entry.send_dont_have { - response.block_presences.push(BlockPresence { - r#type: BlockPresenceType::DontHave as i32, - cid: cid.to_bytes(), - }); - } - }, - } - } - trace!(target: LOG_TARGET, "Response: {:?}", response); - self.ready_blocks().push_back((peer, response)); - } - - fn poll( - &mut self, - _ctx: &mut Context, - _: &mut impl PollParameters, - ) -> Poll> { - if let Some((peer_id, message)) = self.ready_blocks().pop_front() { - return Poll::Ready(NetworkBehaviourAction::NotifyHandler { - peer_id, - handler: NotifyHandler::Any, - event: message, - }) - } - Poll::Pending - } -} - -/// Bitswap protocol error. -#[derive(Debug, thiserror::Error)] -pub enum BitswapError { - /// Protobuf decoding error. - #[error("Failed to decode request: {0}.")] - DecodeProto(#[from] prost::DecodeError), - - /// Protobuf encoding error. - #[error("Failed to encode response: {0}.")] - EncodeProto(#[from] prost::EncodeError), - - /// Client backend error. - #[error(transparent)] - Client(#[from] sp_blockchain::Error), - - /// Error parsing CID - #[error(transparent)] - BadCid(#[from] cid::Error), - - /// Packet read error. - #[error(transparent)] - Read(#[from] io::Error), - - /// Error sending response. - #[error("Failed to send response.")] - SendResponse, -} diff --git a/client/network/src/config.rs b/client/network/src/config.rs index 3fe95deb0c1ed..14f7e8ffbf76a 100644 --- a/client/network/src/config.rs +++ b/client/network/src/config.rs @@ -23,28 +23,30 @@ pub use sc_network_common::{ config::ProtocolId, + protocol::role::Role, request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, sync::warp::WarpSyncProvider, + ExHashT, }; pub use libp2p::{build_multiaddr, core::PublicKey, identity}; -use crate::{bitswap::Bitswap, ExHashT}; - +use crate::ChainSyncInterface; use core::{fmt, iter}; -use futures::future; use libp2p::{ identity::{ed25519, Keypair}, multiaddr, Multiaddr, }; use prometheus_endpoint::Registry; use sc_consensus::ImportQueue; -use sc_network_common::{config::MultiaddrWithPeerId, protocol::ProtocolName, sync::ChainSync}; +use sc_network_common::{ + config::{MultiaddrWithPeerId, NonDefaultSetConfig, SetConfig, TransportConfig}, + sync::ChainSync, +}; use sp_runtime::traits::Block as BlockT; use std::{ - collections::HashMap, error::Error, fs, future::Future, @@ -52,16 +54,14 @@ use std::{ net::Ipv4Addr, path::{Path, PathBuf}, pin::Pin, - str, sync::Arc, }; use zeroize::Zeroize; /// Network initialization parameters. -pub struct Params +pub struct Params where B: BlockT + 'static, - H: ExHashT, { /// Assigned role for our node (full, light, ...). pub role: Role, @@ -70,24 +70,12 @@ where /// default. pub executor: Option + Send>>) + Send>>, - /// How to spawn the background task dedicated to the transactions handler. - pub transactions_handler_executor: Box + Send>>) + Send>, - /// Network layer configuration. pub network_config: NetworkConfiguration, /// Client that contains the blockchain. pub chain: Arc, - /// Bitswap block request protocol implementation. - pub bitswap: Option>, - - /// Pool of transactions. - /// - /// The network worker will fetch transactions from this object in order to propagate them on - /// the network. - pub transaction_pool: Arc>, - /// Legacy name of the protocol to use on the wire. Should be different for each chain. pub protocol_id: ProtocolId, @@ -104,9 +92,15 @@ where /// Instance of chain sync implementation. pub chain_sync: Box>, + /// Interface that can be used to delegate syncing-related function calls to `ChainSync` + pub chain_sync_service: Box>, + /// Registry for recording prometheus metrics to. pub metrics_registry: Option, + /// Block announce protocol configuration + pub block_announce_config: NonDefaultSetConfig, + /// Request response configuration for the block request protocol. /// /// [`RequestResponseConfig::name`] is used to tag outgoing block requests with the correct @@ -139,91 +133,9 @@ where /// Optional warp sync protocol config. pub warp_sync_protocol_config: Option, -} - -/// Role of the local node. -#[derive(Debug, Clone)] -pub enum Role { - /// Regular full node. - Full, - /// Actual authority. - Authority, -} - -impl Role { - /// True for [`Role::Authority`]. - pub fn is_authority(&self) -> bool { - matches!(self, Self::Authority { .. }) - } -} - -impl fmt::Display for Role { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Full => write!(f, "FULL"), - Self::Authority { .. } => write!(f, "AUTHORITY"), - } - } -} - -/// Result of the transaction import. -#[derive(Clone, Copy, Debug)] -pub enum TransactionImport { - /// Transaction is good but already known by the transaction pool. - KnownGood, - /// Transaction is good and not yet known. - NewGood, - /// Transaction is invalid. - Bad, - /// Transaction import was not performed. - None, -} - -/// Future resolving to transaction import result. -pub type TransactionImportFuture = Pin + Send>>; - -/// Transaction pool interface -pub trait TransactionPool: Send + Sync { - /// Get transactions from the pool that are ready to be propagated. - fn transactions(&self) -> Vec<(H, B::Extrinsic)>; - /// Get hash of transaction. - fn hash_of(&self, transaction: &B::Extrinsic) -> H; - /// Import a transaction into the pool. - /// - /// This will return future. - fn import(&self, transaction: B::Extrinsic) -> TransactionImportFuture; - /// Notify the pool about transactions broadcast. - fn on_broadcasted(&self, propagations: HashMap>); - /// Get transaction by hash. - fn transaction(&self, hash: &H) -> Option; -} - -/// Dummy implementation of the [`TransactionPool`] trait for a transaction pool that is always -/// empty and discards all incoming transactions. -/// -/// Requires the "hash" type to implement the `Default` trait. -/// -/// Useful for testing purposes. -pub struct EmptyTransactionPool; - -impl TransactionPool for EmptyTransactionPool { - fn transactions(&self) -> Vec<(H, B::Extrinsic)> { - Vec::new() - } - - fn hash_of(&self, _transaction: &B::Extrinsic) -> H { - Default::default() - } - - fn import(&self, _transaction: B::Extrinsic) -> TransactionImportFuture { - Box::pin(future::ready(TransactionImport::KnownGood)) - } - fn on_broadcasted(&self, _: HashMap>) {} - - fn transaction(&self, _h: &H) -> Option { - None - } + /// Request response protocol configurations + pub request_response_protocol_configs: Vec, } /// Sync operation mode. @@ -394,132 +306,6 @@ impl NetworkConfiguration { } } -/// Configuration for a set of nodes. -#[derive(Clone, Debug)] -pub struct SetConfig { - /// Maximum allowed number of incoming substreams related to this set. - pub in_peers: u32, - /// Number of outgoing substreams related to this set that we're trying to maintain. - pub out_peers: u32, - /// List of reserved node addresses. - pub reserved_nodes: Vec, - /// Whether nodes that aren't in [`SetConfig::reserved_nodes`] are accepted or automatically - /// refused. - pub non_reserved_mode: NonReservedPeerMode, -} - -impl Default for SetConfig { - fn default() -> Self { - Self { - in_peers: 25, - out_peers: 75, - reserved_nodes: Vec::new(), - non_reserved_mode: NonReservedPeerMode::Accept, - } - } -} - -/// Extension to [`SetConfig`] for sets that aren't the default set. -/// -/// > **Note**: As new fields might be added in the future, please consider using the `new` method -/// > and modifiers instead of creating this struct manually. -#[derive(Clone, Debug)] -pub struct NonDefaultSetConfig { - /// Name of the notifications protocols of this set. A substream on this set will be - /// considered established once this protocol is open. - /// - /// > **Note**: This field isn't present for the default set, as this is handled internally - /// > by the networking code. - pub notifications_protocol: ProtocolName, - /// If the remote reports that it doesn't support the protocol indicated in the - /// `notifications_protocol` field, then each of these fallback names will be tried one by - /// one. - /// - /// If a fallback is used, it will be reported in - /// [`crate::Event::NotificationStreamOpened::negotiated_fallback`]. - pub fallback_names: Vec, - /// Maximum allowed size of single notifications. - pub max_notification_size: u64, - /// Base configuration. - pub set_config: SetConfig, -} - -impl NonDefaultSetConfig { - /// Creates a new [`NonDefaultSetConfig`]. Zero slots and accepts only reserved nodes. - pub fn new(notifications_protocol: ProtocolName, max_notification_size: u64) -> Self { - Self { - notifications_protocol, - max_notification_size, - fallback_names: Vec::new(), - set_config: SetConfig { - in_peers: 0, - out_peers: 0, - reserved_nodes: Vec::new(), - non_reserved_mode: NonReservedPeerMode::Deny, - }, - } - } - - /// Modifies the configuration to allow non-reserved nodes. - pub fn allow_non_reserved(&mut self, in_peers: u32, out_peers: u32) { - self.set_config.in_peers = in_peers; - self.set_config.out_peers = out_peers; - self.set_config.non_reserved_mode = NonReservedPeerMode::Accept; - } - - /// Add a node to the list of reserved nodes. - pub fn add_reserved(&mut self, peer: MultiaddrWithPeerId) { - self.set_config.reserved_nodes.push(peer); - } - - /// Add a list of protocol names used for backward compatibility. - /// - /// See the explanations in [`NonDefaultSetConfig::fallback_names`]. - pub fn add_fallback_names(&mut self, fallback_names: Vec) { - self.fallback_names.extend(fallback_names); - } -} - -/// Configuration for the transport layer. -#[derive(Clone, Debug)] -pub enum TransportConfig { - /// Normal transport mode. - Normal { - /// If true, the network will use mDNS to discover other libp2p nodes on the local network - /// and connect to them if they support the same chain. - enable_mdns: bool, - - /// If true, allow connecting to private IPv4 addresses (as defined in - /// [RFC1918](https://tools.ietf.org/html/rfc1918)). Irrelevant for addresses that have - /// been passed in [`NetworkConfiguration::boot_nodes`]. - allow_private_ipv4: bool, - }, - - /// Only allow connections within the same process. - /// Only addresses of the form `/memory/...` will be supported. - MemoryOnly, -} - -/// The policy for connections to non-reserved peers. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum NonReservedPeerMode { - /// Accept them. This is the default. - Accept, - /// Deny them. - Deny, -} - -impl NonReservedPeerMode { - /// Attempt to parse the peer mode from a string. - pub fn parse(s: &str) -> Option { - match s { - "accept" => Some(Self::Accept), - "deny" => Some(Self::Deny), - _ => None, - } - } -} - /// The configuration of a node's secret key, describing the type of key /// and how it is obtained. A node's identity keypair is the result of /// the evaluation of the node key configuration. @@ -585,7 +371,7 @@ impl NodeKeyConfig { f, |mut b| match String::from_utf8(b.to_vec()).ok().and_then(|s| { if s.len() == 64 { - hex::decode(&s).ok() + array_bytes::hex2bytes(&s).ok() } else { None } @@ -669,11 +455,8 @@ mod tests { } fn secret_bytes(kp: &Keypair) -> Vec { - match kp { - Keypair::Ed25519(p) => p.secret().as_ref().iter().cloned().collect(), - Keypair::Secp256k1(p) => p.secret().to_bytes().to_vec(), - _ => panic!("Unexpected keypair."), - } + let Keypair::Ed25519(p) = kp; + p.secret().as_ref().iter().cloned().collect() } #[test] diff --git a/client/network/src/discovery.rs b/client/network/src/discovery.rs index ab93662968dc2..da4dec70b29ab 100644 --- a/client/network/src/discovery.rs +++ b/client/network/src/discovery.rs @@ -46,7 +46,6 @@ //! active mechanism that asks nodes for the addresses they are listening on. Whenever we learn //! of a node's address, you must call `add_self_reported_address`. -use crate::utils::LruHashSet; use futures::prelude::*; use futures_timer::Delay; use ip_network::IpNetwork; @@ -72,7 +71,7 @@ use libp2p::{ }, }; use log::{debug, error, info, trace, warn}; -use sc_network_common::config::ProtocolId; +use sc_network_common::{config::ProtocolId, utils::LruHashSet}; use sp_core::hexdisplay::HexDisplay; use std::{ cmp, @@ -199,7 +198,7 @@ impl DiscoveryConfig { let proto_name = protocol_name_from_protocol_id(&protocol_id); let mut config = KademliaConfig::default(); - config.set_protocol_name(proto_name); + config.set_protocol_names(std::iter::once(proto_name.into()).collect()); // By default Kademlia attempts to insert all peers into its routing table once a // dialing attempt succeeds. In order to control which peer is added, disable the // auto-insertion and instead add peers manually. @@ -233,9 +232,15 @@ impl DiscoveryConfig { allow_private_ipv4, discovery_only_if_under_num, mdns: if enable_mdns { - MdnsWrapper::Instantiating(Mdns::new(MdnsConfig::default()).boxed()) + match Mdns::new(MdnsConfig::default()) { + Ok(mdns) => Some(mdns), + Err(err) => { + warn!(target: "sub-libp2p", "Failed to initialize mDNS: {:?}", err); + None + }, + } } else { - MdnsWrapper::Disabled + None }, allow_non_globals_in_dht, known_external_addresses: LruHashSet::new( @@ -257,7 +262,7 @@ pub struct DiscoveryBehaviour { /// Kademlia requests and answers. kademlias: HashMap>, /// Discovers nodes on the local network. - mdns: MdnsWrapper, + mdns: Option, /// Stream that fires when we need to perform the next random Kademlia query. `None` if /// random walking is disabled. next_kad_random_query: Option, @@ -321,7 +326,7 @@ impl DiscoveryBehaviour { pub fn add_self_reported_address( &mut self, peer_id: &PeerId, - supported_protocols: impl Iterator>, + supported_protocols: &[impl AsRef<[u8]>], addr: Multiaddr, ) { if !self.allow_non_globals_in_dht && !self.can_add_to_dht(&addr) { @@ -330,17 +335,18 @@ impl DiscoveryBehaviour { } let mut added = false; - for protocol in supported_protocols { - for kademlia in self.kademlias.values_mut() { - if protocol.as_ref() == kademlia.protocol_name() { - trace!( - target: "sub-libp2p", - "Adding self-reported address {} from {} to Kademlia DHT {}.", - addr, peer_id, String::from_utf8_lossy(kademlia.protocol_name()), - ); - kademlia.add_address(peer_id, addr.clone()); - added = true; - } + for kademlia in self.kademlias.values_mut() { + if let Some(matching_protocol) = supported_protocols + .iter() + .find(|p| kademlia.protocol_names().iter().any(|k| k.as_ref() == p.as_ref())) + { + trace!( + target: "sub-libp2p", + "Adding self-reported address {} from {} to Kademlia DHT {}.", + addr, peer_id, String::from_utf8_lossy(matching_protocol.as_ref()), + ); + kademlia.add_address(peer_id, addr.clone()); + added = true; } } @@ -533,7 +539,9 @@ impl NetworkBehaviour for DiscoveryBehaviour { list_to_filter.extend(k.addresses_of_peer(peer_id)) } - list_to_filter.extend(self.mdns.addresses_of_peer(peer_id)); + if let Some(ref mut mdns) = self.mdns { + list_to_filter.extend(mdns.addresses_of_peer(peer_id)); + } if !self.allow_private_ipv4 { list_to_filter.retain(|addr| match addr.iter().next() { @@ -914,36 +922,38 @@ impl NetworkBehaviour for DiscoveryBehaviour { } // Poll mDNS. - while let Poll::Ready(ev) = self.mdns.poll(cx, params) { - match ev { - NetworkBehaviourAction::GenerateEvent(event) => match event { - MdnsEvent::Discovered(list) => { - if self.num_connections >= self.discovery_only_if_under_num { - continue - } - - self.pending_events - .extend(list.map(|(peer_id, _)| DiscoveryOut::Discovered(peer_id))); - if let Some(ev) = self.pending_events.pop_front() { - return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) - } + if let Some(ref mut mdns) = self.mdns { + while let Poll::Ready(ev) = mdns.poll(cx, params) { + match ev { + NetworkBehaviourAction::GenerateEvent(event) => match event { + MdnsEvent::Discovered(list) => { + if self.num_connections >= self.discovery_only_if_under_num { + continue + } + + self.pending_events + .extend(list.map(|(peer_id, _)| DiscoveryOut::Discovered(peer_id))); + if let Some(ev) = self.pending_events.pop_front() { + return Poll::Ready(NetworkBehaviourAction::GenerateEvent(ev)) + } + }, + MdnsEvent::Expired(_) => {}, + }, + NetworkBehaviourAction::Dial { .. } => { + unreachable!("mDNS never dials!"); }, - MdnsEvent::Expired(_) => {}, - }, - NetworkBehaviourAction::Dial { .. } => { - unreachable!("mDNS never dials!"); - }, - NetworkBehaviourAction::NotifyHandler { event, .. } => match event {}, /* `event` is an enum with no variant */ - NetworkBehaviourAction::ReportObservedAddr { address, score } => - return Poll::Ready(NetworkBehaviourAction::ReportObservedAddr { - address, - score, - }), - NetworkBehaviourAction::CloseConnection { peer_id, connection } => - return Poll::Ready(NetworkBehaviourAction::CloseConnection { - peer_id, - connection, - }), + NetworkBehaviourAction::NotifyHandler { event, .. } => match event {}, /* `event` is an enum with no variant */ + NetworkBehaviourAction::ReportObservedAddr { address, score } => + return Poll::Ready(NetworkBehaviourAction::ReportObservedAddr { + address, + score, + }), + NetworkBehaviourAction::CloseConnection { peer_id, connection } => + return Poll::Ready(NetworkBehaviourAction::CloseConnection { + peer_id, + connection, + }), + } } } @@ -960,45 +970,6 @@ fn protocol_name_from_protocol_id(id: &ProtocolId) -> Vec { v } -/// [`Mdns::new`] returns a future. Instead of forcing [`DiscoveryConfig::finish`] and all its -/// callers to be async, lazily instantiate [`Mdns`]. -enum MdnsWrapper { - Instantiating(futures::future::BoxFuture<'static, std::io::Result>), - Ready(Mdns), - Disabled, -} - -impl MdnsWrapper { - fn addresses_of_peer(&mut self, peer_id: &PeerId) -> Vec { - match self { - Self::Instantiating(_) => Vec::new(), - Self::Ready(mdns) => mdns.addresses_of_peer(peer_id), - Self::Disabled => Vec::new(), - } - } - - fn poll( - &mut self, - cx: &mut Context<'_>, - params: &mut impl PollParameters, - ) -> Poll::ConnectionHandler>> { - loop { - match self { - Self::Instantiating(fut) => - *self = match futures::ready!(fut.as_mut().poll(cx)) { - Ok(mdns) => Self::Ready(mdns), - Err(err) => { - warn!(target: "sub-libp2p", "Failed to initialize mDNS: {:?}", err); - Self::Disabled - }, - }, - Self::Ready(mdns) => return mdns.poll(cx, params), - Self::Disabled => return Poll::Pending, - } - } - } -} - #[cfg(test)] mod tests { use super::{protocol_name_from_protocol_id, DiscoveryConfig, DiscoveryOut}; @@ -1101,8 +1072,7 @@ mod tests { .behaviour_mut() .add_self_reported_address( &other, - [protocol_name_from_protocol_id(&protocol_id)] - .iter(), + &[protocol_name_from_protocol_id(&protocol_id)], addr, ); @@ -1157,7 +1127,7 @@ mod tests { // Add remote peer with unsupported protocol. discovery.add_self_reported_address( &remote_peer_id, - [protocol_name_from_protocol_id(&unsupported_protocol_id)].iter(), + &[protocol_name_from_protocol_id(&unsupported_protocol_id)], remote_addr.clone(), ); @@ -1174,7 +1144,7 @@ mod tests { // Add remote peer with supported protocol. discovery.add_self_reported_address( &remote_peer_id, - [protocol_name_from_protocol_id(&supported_protocol_id)].iter(), + &[protocol_name_from_protocol_id(&supported_protocol_id)], remote_addr.clone(), ); @@ -1213,7 +1183,7 @@ mod tests { // Add remote peer with `protocol_a` only. discovery.add_self_reported_address( &remote_peer_id, - [protocol_name_from_protocol_id(&protocol_a)].iter(), + &[protocol_name_from_protocol_id(&protocol_a)], remote_addr.clone(), ); diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 35a91e77da524..f3faa44ee6dbd 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -249,30 +249,26 @@ mod discovery; mod peer_info; mod protocol; mod request_responses; -mod schema; mod service; mod transport; -mod utils; -pub mod bitswap; pub mod config; -pub mod error; pub mod network_state; -pub mod transactions; #[doc(inline)] pub use libp2p::{multiaddr, Multiaddr, PeerId}; pub use protocol::PeerInfo; pub use sc_network_common::{ protocol::{ - event::{DhtEvent, Event, ObservedRole}, + event::{DhtEvent, Event}, + role::ObservedRole, ProtocolName, }, request_responses::{IfDisconnected, RequestFailure}, service::{ KademliaKey, NetworkBlock, NetworkDHTProvider, NetworkRequest, NetworkSigner, - NetworkStateInfo, NetworkStatus, NetworkStatusProvider, NetworkSyncForkRequest, - NetworkTransaction, Signature, SigningError, + NetworkStateInfo, NetworkStatus, NetworkStatusProvider, NetworkSyncForkRequest, Signature, + SigningError, }, sync::{ warp::{WarpSyncPhase, WarpSyncProgress}, @@ -283,6 +279,7 @@ pub use service::{ DecodingError, Keypair, NetworkService, NetworkWorker, NotificationSender, NotificationSenderReady, OutboundFailure, PublicKey, }; +use sp_runtime::traits::{Block as BlockT, NumberFor}; pub use sc_peerset::ReputationChange; @@ -298,8 +295,13 @@ const MAX_CONNECTIONS_PER_PEER: usize = 2; /// The maximum number of concurrent established connections that were incoming. const MAX_CONNECTIONS_ESTABLISHED_INCOMING: u32 = 10_000; -/// Minimum Requirements for a Hash within Networking -pub trait ExHashT: std::hash::Hash + Eq + std::fmt::Debug + Clone + Send + Sync + 'static {} +/// Abstraction over syncing-related services +pub trait ChainSyncInterface: + NetworkSyncForkRequest> + Send + Sync +{ +} -impl ExHashT for T where T: std::hash::Hash + Eq + std::fmt::Debug + Clone + Send + Sync + 'static -{} +impl ChainSyncInterface for T where + T: NetworkSyncForkRequest> + Send + Sync +{ +} diff --git a/client/network/src/peer_info.rs b/client/network/src/peer_info.rs index d668cb25ea455..e04d006f50501 100644 --- a/client/network/src/peer_info.rs +++ b/client/network/src/peer_info.rs @@ -16,7 +16,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::utils::interval; use fnv::FnvHashMap; use futures::prelude::*; use libp2p::{ @@ -24,8 +23,11 @@ use libp2p::{ connection::ConnectionId, either::EitherOutput, transport::ListenerId, ConnectedPoint, PeerId, PublicKey, }, - identify::{Identify, IdentifyConfig, IdentifyEvent, IdentifyInfo}, - ping::{Ping, PingConfig, PingEvent, PingSuccess}, + identify::{ + Behaviour as Identify, Config as IdentifyConfig, Event as IdentifyEvent, + Info as IdentifyInfo, + }, + ping::{Behaviour as Ping, Config as PingConfig, Event as PingEvent, Success as PingSuccess}, swarm::{ ConnectionHandler, IntoConnectionHandler, IntoConnectionHandlerSelect, NetworkBehaviour, NetworkBehaviourAction, PollParameters, @@ -33,6 +35,7 @@ use libp2p::{ Multiaddr, }; use log::{debug, error, trace}; +use sc_network_common::utils::interval; use smallvec::SmallVec; use std::{ collections::hash_map::Entry, diff --git a/client/network/src/protocol.rs b/client/network/src/protocol.rs index 9bcf363cd0692..a04dba79f7fd2 100644 --- a/client/network/src/protocol.rs +++ b/client/network/src/protocol.rs @@ -16,10 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{ - config, error, - utils::{interval, LruHashSet}, -}; +use crate::config; use bytes::Bytes; use codec::{Decode, DecodeAll, Encode}; @@ -34,27 +31,29 @@ use libp2p::{ Multiaddr, PeerId, }; use log::{debug, error, info, log, trace, warn, Level}; -use message::{ - generic::{Message as GenericMessage, Roles}, - Message, -}; +use message::{generic::Message as GenericMessage, Message}; use notifications::{Notifications, NotificationsOut}; use prometheus_endpoint::{register, Gauge, GaugeVec, Opts, PrometheusError, Registry, U64}; use sc_client_api::HeaderBackend; -use sc_consensus::import_queue::{BlockImportError, BlockImportStatus, IncomingBlock, Origin}; +use sc_consensus::import_queue::{ + BlockImportError, BlockImportStatus, IncomingBlock, RuntimeOrigin, +}; use sc_network_common::{ - config::ProtocolId, - protocol::ProtocolName, + config::NonReservedPeerMode, + error, + protocol::{role::Roles, ProtocolName}, request_responses::RequestFailure, sync::{ message::{ - BlockAnnounce, BlockAttributes, BlockData, BlockRequest, BlockResponse, BlockState, + BlockAnnounce, BlockAnnouncesHandshake, BlockAttributes, BlockData, BlockRequest, + BlockResponse, BlockState, }, warp::{EncodedProof, WarpProofRequest}, BadPeer, ChainSync, OnBlockData, OnBlockJustification, OnStateData, OpaqueBlockRequest, OpaqueBlockResponse, OpaqueStateRequest, OpaqueStateResponse, PollBlockAnnounceValidation, SyncStatus, }, + utils::{interval, LruHashSet}, }; use sp_arithmetic::traits::SaturatedConversion; use sp_consensus::BlockOrigin; @@ -84,8 +83,6 @@ const TICK_TIMEOUT: time::Duration = time::Duration::from_millis(1100); /// Maximum number of known block hashes to keep for a peer. const MAX_KNOWN_BLOCKS: usize = 1024; // ~32kb per peer + LruHashSet overhead -/// Maximum allowed size for a block announce. -const MAX_BLOCK_ANNOUNCE_SIZE: u64 = 1024 * 1024; /// Maximum size used for notifications in the block announce and transaction protocols. // Must be equal to `max(MAX_BLOCK_ANNOUNCE_SIZE, MAX_TRANSACTIONS_SIZE)`. @@ -234,30 +231,6 @@ pub struct PeerInfo { pub best_number: ::Number, } -/// Handshake sent when we open a block announces substream. -#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] -struct BlockAnnouncesHandshake { - /// Roles of the node. - roles: Roles, - /// Best block number. - best_number: NumberFor, - /// Best block hash. - best_hash: B::Hash, - /// Genesis block hash. - genesis_hash: B::Hash, -} - -impl BlockAnnouncesHandshake { - fn build( - roles: Roles, - best_number: NumberFor, - best_hash: B::Hash, - genesis_hash: B::Hash, - ) -> Self { - Self { genesis_hash, roles, best_number, best_hash } - } -} - impl Protocol where B: BlockT, @@ -267,12 +240,10 @@ where pub fn new( roles: Roles, chain: Arc, - protocol_id: ProtocolId, - fork_id: &Option, network_config: &config::NetworkConfiguration, - notifications_protocols_handshakes: Vec>, metrics_registry: Option<&Registry>, chain_sync: Box>, + block_announces_protocol: sc_network_common::config::NonDefaultSetConfig, ) -> error::Result<(Self, sc_peerset::PeersetHandle, Vec<(PeerId, Multiaddr)>)> { let info = chain.info(); @@ -339,7 +310,7 @@ where bootnodes, reserved_nodes: default_sets_reserved.clone(), reserved_only: network_config.default_peers_set.non_reserved_mode == - config::NonReservedPeerMode::Deny, + NonReservedPeerMode::Deny, }); for set_cfg in &network_config.extra_sets { @@ -350,7 +321,7 @@ where } let reserved_only = - set_cfg.set_config.non_reserved_mode == config::NonReservedPeerMode::Deny; + set_cfg.set_config.non_reserved_mode == NonReservedPeerMode::Deny; sets.push(sc_peerset::SetConfig { in_peers: set_cfg.set_config.in_peers, @@ -364,46 +335,24 @@ where sc_peerset::Peerset::from_config(sc_peerset::PeersetConfig { sets }) }; - let block_announces_protocol = { - let genesis_hash = - chain.hash(0u32.into()).ok().flatten().expect("Genesis block exists; qed"); - if let Some(fork_id) = fork_id { - format!("/{}/{}/block-announces/1", hex::encode(genesis_hash), fork_id) - } else { - format!("/{}/block-announces/1", hex::encode(genesis_hash)) - } - }; - - let legacy_ba_protocol_name = format!("/{}/block-announces/1", protocol_id.as_ref()); - let behaviour = { - let best_number = info.best_number; - let best_hash = info.best_hash; - let genesis_hash = info.genesis_hash; - - let block_announces_handshake = - BlockAnnouncesHandshake::::build(roles, best_number, best_hash, genesis_hash) - .encode(); - - let sync_protocol_config = notifications::ProtocolConfig { - name: block_announces_protocol.into(), - fallback_names: iter::once(legacy_ba_protocol_name.into()).collect(), - handshake: block_announces_handshake, - max_notification_size: MAX_BLOCK_ANNOUNCE_SIZE, - }; - Notifications::new( peerset, - iter::once(sync_protocol_config).chain( - network_config.extra_sets.iter().zip(notifications_protocols_handshakes).map( - |(s, hs)| notifications::ProtocolConfig { - name: s.notifications_protocol.clone(), - fallback_names: s.fallback_names.clone(), - handshake: hs, - max_notification_size: s.max_notification_size, - }, - ), - ), + // NOTE: Block announcement protocol is still very much hardcoded into `Protocol`. + // This protocol must be the first notification protocol given to + // `Notifications` + iter::once(notifications::ProtocolConfig { + name: block_announces_protocol.notifications_protocol.clone(), + fallback_names: block_announces_protocol.fallback_names.clone(), + handshake: block_announces_protocol.handshake.as_ref().unwrap().to_vec(), + max_notification_size: block_announces_protocol.max_notification_size, + }) + .chain(network_config.extra_sets.iter().map(|s| notifications::ProtocolConfig { + name: s.notifications_protocol.clone(), + fallback_names: s.fallback_names.clone(), + handshake: s.handshake.as_ref().map_or(roles.encode(), |h| (*h).to_vec()), + max_notification_size: s.max_notification_size, + })), ) }; @@ -431,10 +380,8 @@ where }, peerset_handle: peerset_handle.clone(), behaviour, - notification_protocols: network_config - .extra_sets - .iter() - .map(|s| s.notifications_protocol.clone()) + notification_protocols: iter::once(block_announces_protocol.notifications_protocol) + .chain(network_config.extra_sets.iter().map(|s| s.notifications_protocol.clone())) .collect(), bad_handshake_substreams: Default::default(), metrics: if let Some(r) = metrics_registry { @@ -463,10 +410,7 @@ where pub fn disconnect_peer(&mut self, peer_id: &PeerId, protocol_name: ProtocolName) { if let Some(position) = self.notification_protocols.iter().position(|p| *p == protocol_name) { - self.behaviour.disconnect_peer( - peer_id, - sc_peerset::SetId::from(position + NUM_HARDCODED_PEERSETS), - ); + self.behaviour.disconnect_peer(peer_id, sc_peerset::SetId::from(position)); } else { warn!(target: "sub-libp2p", "disconnect_peer() with invalid protocol name") } @@ -627,6 +571,7 @@ where CustomMessageOutcome::BlockImport(origin, blocks), Ok(OnBlockData::Request(peer, req)) => prepare_block_request(self.chain_sync.as_ref(), &mut self.peers, peer, req), + Ok(OnBlockData::Continue) => CustomMessageOutcome::None, Err(BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); self.peerset_handle.report_peer(id, repu); @@ -974,6 +919,7 @@ where CustomMessageOutcome::BlockImport(origin, blocks), Ok(OnBlockData::Request(peer, req)) => prepare_block_request(self.chain_sync.as_ref(), &mut self.peers, peer, req), + Ok(OnBlockData::Continue) => CustomMessageOutcome::None, Err(BadPeer(id, repu)) => { self.behaviour.disconnect_peer(&id, HARDCODED_PEERSETS_SYNC); self.peerset_handle.report_peer(id, repu); @@ -1001,18 +947,6 @@ where self.chain_sync.clear_justification_requests(); } - /// Request syncing for the given block from given set of peers. - /// Uses `protocol` to queue a new block download request and tries to dispatch all pending - /// requests. - pub fn set_sync_fork_request( - &mut self, - peers: Vec, - hash: &B::Hash, - number: NumberFor, - ) { - self.chain_sync.set_sync_fork_request(peers, hash, number) - } - /// A batch of blocks have been processed, with or without errors. /// Call this when a batch of blocks have been processed by the importqueue, with or without /// errors. @@ -1087,8 +1021,7 @@ where /// Sets the list of reserved peers for the given protocol/peerset. pub fn set_reserved_peerset_peers(&self, protocol: ProtocolName, peers: HashSet) { if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { - self.peerset_handle - .set_reserved_peers(sc_peerset::SetId::from(index + NUM_HARDCODED_PEERSETS), peers); + self.peerset_handle.set_reserved_peers(sc_peerset::SetId::from(index), peers); } else { error!( target: "sub-libp2p", @@ -1101,10 +1034,7 @@ where /// Removes a `PeerId` from the list of reserved peers. pub fn remove_set_reserved_peer(&self, protocol: ProtocolName, peer: PeerId) { if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { - self.peerset_handle.remove_reserved_peer( - sc_peerset::SetId::from(index + NUM_HARDCODED_PEERSETS), - peer, - ); + self.peerset_handle.remove_reserved_peer(sc_peerset::SetId::from(index), peer); } else { error!( target: "sub-libp2p", @@ -1117,8 +1047,7 @@ where /// Adds a `PeerId` to the list of reserved peers. pub fn add_set_reserved_peer(&self, protocol: ProtocolName, peer: PeerId) { if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { - self.peerset_handle - .add_reserved_peer(sc_peerset::SetId::from(index + NUM_HARDCODED_PEERSETS), peer); + self.peerset_handle.add_reserved_peer(sc_peerset::SetId::from(index), peer); } else { error!( target: "sub-libp2p", @@ -1140,8 +1069,7 @@ where /// Add a peer to a peers set. pub fn add_to_peers_set(&self, protocol: ProtocolName, peer: PeerId) { if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { - self.peerset_handle - .add_to_peers_set(sc_peerset::SetId::from(index + NUM_HARDCODED_PEERSETS), peer); + self.peerset_handle.add_to_peers_set(sc_peerset::SetId::from(index), peer); } else { error!( target: "sub-libp2p", @@ -1154,10 +1082,7 @@ where /// Remove a peer from a peers set. pub fn remove_from_peers_set(&self, protocol: ProtocolName, peer: PeerId) { if let Some(index) = self.notification_protocols.iter().position(|p| *p == protocol) { - self.peerset_handle.remove_from_peers_set( - sc_peerset::SetId::from(index + NUM_HARDCODED_PEERSETS), - peer, - ); + self.peerset_handle.remove_from_peers_set(sc_peerset::SetId::from(index), peer); } else { error!( target: "sub-libp2p", @@ -1255,7 +1180,7 @@ fn prepare_warp_sync_request( #[must_use] pub enum CustomMessageOutcome { BlockImport(BlockOrigin, Vec>), - JustificationImport(Origin, B::Hash, NumberFor, Justifications), + JustificationImport(RuntimeOrigin, B::Hash, NumberFor, Justifications), /// Notification protocols have been opened with a remote. NotificationStreamOpened { remote: PeerId, @@ -1503,7 +1428,7 @@ where for (id, request) in self .chain_sync .block_requests() - .map(|(peer_id, request)| (*peer_id, request)) + .map(|(peer_id, request)| (peer_id, request)) .collect::>() { let event = @@ -1524,8 +1449,11 @@ where self.pending_messages.push_back(event); } - // Check if there is any block announcement validation finished. - while let Poll::Ready(result) = self.chain_sync.poll_block_announce_validation(cx) { + // Advance the state of `ChainSync` + // + // Process any received requests received from `NetworkService` and + // check if there is any block announcement validation finished. + while let Poll::Ready(result) = self.chain_sync.poll(cx) { match self.process_block_announce_validation_result(result) { CustomMessageOutcome::None => {}, outcome => self.pending_messages.push_back(outcome), @@ -1619,14 +1547,12 @@ where } } else { match ( - message::Roles::decode_all(&mut &received_handshake[..]), + Roles::decode_all(&mut &received_handshake[..]), self.peers.get(&peer_id), ) { (Ok(roles), _) => CustomMessageOutcome::NotificationStreamOpened { remote: peer_id, - protocol: self.notification_protocols - [usize::from(set_id) - NUM_HARDCODED_PEERSETS] - .clone(), + protocol: self.notification_protocols[usize::from(set_id)].clone(), negotiated_fallback, roles, notifications_sink, @@ -1638,9 +1564,7 @@ where // TODO: remove this after https://github.com/paritytech/substrate/issues/5685 CustomMessageOutcome::NotificationStreamOpened { remote: peer_id, - protocol: self.notification_protocols - [usize::from(set_id) - NUM_HARDCODED_PEERSETS] - .clone(), + protocol: self.notification_protocols[usize::from(set_id)].clone(), negotiated_fallback, roles: peer.info.roles, notifications_sink, @@ -1664,9 +1588,7 @@ where } else { CustomMessageOutcome::NotificationStreamReplaced { remote: peer_id, - protocol: self.notification_protocols - [usize::from(set_id) - NUM_HARDCODED_PEERSETS] - .clone(), + protocol: self.notification_protocols[usize::from(set_id)].clone(), notifications_sink, } }, @@ -1691,9 +1613,7 @@ where } else { CustomMessageOutcome::NotificationStreamClosed { remote: peer_id, - protocol: self.notification_protocols - [usize::from(set_id) - NUM_HARDCODED_PEERSETS] - .clone(), + protocol: self.notification_protocols[usize::from(set_id)].clone(), } } }, @@ -1726,9 +1646,7 @@ where _ if self.bad_handshake_substreams.contains(&(peer_id, set_id)) => CustomMessageOutcome::None, _ => { - let protocol_name = self.notification_protocols - [usize::from(set_id) - NUM_HARDCODED_PEERSETS] - .clone(); + let protocol_name = self.notification_protocols[usize::from(set_id)].clone(); CustomMessageOutcome::NotificationsReceived { remote: peer_id, messages: vec![(protocol_name, message.freeze())], diff --git a/client/network/src/protocol/message.rs b/client/network/src/protocol/message.rs index 50c4a264a5f95..ef652387d2c7d 100644 --- a/client/network/src/protocol/message.rs +++ b/client/network/src/protocol/message.rs @@ -21,7 +21,7 @@ pub use self::generic::{ RemoteCallRequest, RemoteChangesRequest, RemoteChangesResponse, RemoteHeaderRequest, - RemoteHeaderResponse, RemoteReadChildRequest, RemoteReadRequest, Roles, + RemoteHeaderResponse, RemoteReadChildRequest, RemoteReadRequest, }; use codec::{Decode, Encode}; use sc_client_api::StorageProof; @@ -36,9 +36,6 @@ pub type Message = generic::Message< ::Extrinsic, >; -/// A set of transactions. -pub type Transactions = Vec; - /// Remote call response. #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub struct RemoteCallResponse { @@ -59,12 +56,12 @@ pub struct RemoteReadResponse { /// Generic types. pub mod generic { - use super::{RemoteCallResponse, RemoteReadResponse, Transactions}; - use bitflags::bitflags; - use codec::{Decode, Encode, Input, Output}; + use super::{RemoteCallResponse, RemoteReadResponse}; + use codec::{Decode, Encode, Input}; use sc_client_api::StorageProof; use sc_network_common::{ message::RequestId, + protocol::role::Roles, sync::message::{ generic::{BlockRequest, BlockResponse}, BlockAnnounce, @@ -72,60 +69,6 @@ pub mod generic { }; use sp_runtime::ConsensusEngineId; - bitflags! { - /// Bitmask of the roles that a node fulfills. - pub struct Roles: u8 { - /// No network. - const NONE = 0b00000000; - /// Full node, does not participate in consensus. - const FULL = 0b00000001; - /// Light client node. - const LIGHT = 0b00000010; - /// Act as an authority - const AUTHORITY = 0b00000100; - } - } - - impl Roles { - /// Does this role represents a client that holds full chain data locally? - pub fn is_full(&self) -> bool { - self.intersects(Self::FULL | Self::AUTHORITY) - } - - /// Does this role represents a client that does not participates in the consensus? - pub fn is_authority(&self) -> bool { - *self == Self::AUTHORITY - } - - /// Does this role represents a client that does not hold full chain data locally? - pub fn is_light(&self) -> bool { - !self.is_full() - } - } - - impl<'a> From<&'a crate::config::Role> for Roles { - fn from(roles: &'a crate::config::Role) -> Self { - match roles { - crate::config::Role::Full => Self::FULL, - crate::config::Role::Authority { .. } => Self::AUTHORITY, - } - } - } - - impl codec::Encode for Roles { - fn encode_to(&self, dest: &mut T) { - dest.push_byte(self.bits()) - } - } - - impl codec::EncodeLike for Roles {} - - impl codec::Decode for Roles { - fn decode(input: &mut I) -> Result { - Self::from_bits(input.read_byte()?).ok_or_else(|| codec::Error::from("Invalid bytes")) - } - } - /// Consensus is mostly opaque to us #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] pub struct ConsensusMessage { @@ -146,9 +89,10 @@ pub mod generic { BlockResponse(BlockResponse), /// Block announce. BlockAnnounce(BlockAnnounce
), - /// Transactions. - Transactions(Transactions), /// Consensus protocol message. + // NOTE: index is incremented by 1 due to transaction-related + // message that was removed + #[codec(index = 6)] Consensus(ConsensusMessage), /// Remote method call request. RemoteCallRequest(RemoteCallRequest), diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 4610b025dde0d..f95e67df142b0 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -29,23 +29,20 @@ use crate::{ behaviour::{self, Behaviour, BehaviourOut}, - config::{Params, TransportConfig}, + config::Params, discovery::DiscoveryConfig, - error::Error, network_state::{ NetworkState, NotConnectedPeer as NetworkStateNotConnectedPeer, Peer as NetworkStatePeer, }, - protocol::{ - self, message::generic::Roles, NotificationsSink, NotifsHandlerError, PeerInfo, Protocol, - Ready, - }, - transactions, transport, ExHashT, ReputationChange, + protocol::{self, NotificationsSink, NotifsHandlerError, PeerInfo, Protocol, Ready}, + transport, ChainSyncInterface, ReputationChange, }; -use codec::Encode as _; +use codec::Encode; use futures::{channel::oneshot, prelude::*}; use libp2p::{ core::{either::EitherError, upgrade, ConnectedPoint, Executor}, + identify::Info as IdentifyInfo, kad::record::Key as KademliaKey, multiaddr, ping::Failure as PingFailure, @@ -60,7 +57,8 @@ use metrics::{Histogram, HistogramVec, MetricSources, Metrics}; use parking_lot::Mutex; use sc_consensus::{BlockImportError, BlockImportStatus, ImportQueue, Link}; use sc_network_common::{ - config::MultiaddrWithPeerId, + config::{MultiaddrWithPeerId, TransportConfig}, + error::Error, protocol::{ event::{DhtEvent, Event}, ProtocolName, @@ -73,6 +71,7 @@ use sc_network_common::{ NotificationSenderReady as NotificationSenderReadyT, Signature, SigningError, }, sync::{SyncState, SyncStatus}, + ExHashT, }; use sc_peerset::PeersetHandle; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}; @@ -95,13 +94,15 @@ use std::{ pub use behaviour::{InboundFailure, OutboundFailure, ResponseFailure}; +#[cfg(test)] +mod chainsync_tests; mod metrics; mod out_events; #[cfg(test)] mod tests; pub use libp2p::identity::{error::DecodingError, Keypair, PublicKey}; -use sc_network_common::service::{NetworkBlock, NetworkRequest, NetworkTransaction}; +use sc_network_common::service::{NetworkBlock, NetworkRequest}; /// Substrate network service. Handles network IO and manages connectivity. pub struct NetworkService { @@ -121,7 +122,9 @@ pub struct NetworkService { /// nodes it should be connected to or not. peerset: PeersetHandle, /// Channel that sends messages to the actual worker. - to_worker: TracingUnboundedSender>, + to_worker: TracingUnboundedSender>, + /// Interface that can be used to delegate calls to `ChainSync` + chain_sync_service: Box>, /// For each peer and protocol combination, an object that allows sending notifications to /// that peer. Updated by the [`NetworkWorker`]. peers_notifications_sinks: Arc>>, @@ -137,19 +140,24 @@ impl NetworkWorker where B: BlockT + 'static, H: ExHashT, - Client: sp_blockchain::HeaderBackend + 'static, + Client: HeaderBackend + 'static, { /// Creates the network service. /// /// Returns a `NetworkWorker` that implements `Future` and must be regularly polled in order /// for the network processing to advance. From it, you can extract a `NetworkService` using /// `worker.service()`. The `NetworkService` can be shared through the codebase. - pub fn new(mut params: Params) -> Result { + pub fn new(mut params: Params) -> Result { // Private and public keys configuration. let local_identity = params.network_config.node_key.clone().into_keypair()?; let local_public = local_identity.public(); let local_peer_id = local_public.to_peer_id(); + params + .network_config + .request_response_protocols + .extend(params.request_response_protocol_configs); + params.network_config.boot_nodes = params .network_config .boot_nodes @@ -210,43 +218,19 @@ where fs::create_dir_all(path)?; } - let transactions_handler_proto = transactions::TransactionsHandlerPrototype::new( - params.protocol_id.clone(), - params - .chain - .hash(0u32.into()) - .ok() - .flatten() - .expect("Genesis block exists; qed"), - params.fork_id.clone(), - ); - params - .network_config - .extra_sets - .insert(0, transactions_handler_proto.set_config()); - info!( target: "sub-libp2p", "🏷 Local node identity is: {}", local_peer_id.to_base58(), ); - let default_notif_handshake_message = Roles::from(¶ms.role).encode(); - let (protocol, peerset_handle, mut known_addresses) = Protocol::new( From::from(¶ms.role), params.chain.clone(), - params.protocol_id.clone(), - ¶ms.fork_id, ¶ms.network_config, - iter::once(Vec::new()) - .chain( - (0..params.network_config.extra_sets.len() - 1) - .map(|_| default_notif_handshake_message.clone()), - ) - .collect(), params.metrics_registry.as_ref(), params.chain_sync, + params.block_announce_config, )?; // List of multiaddresses that we know in the network. @@ -282,6 +266,11 @@ where let num_connected = Arc::new(AtomicUsize::new(0)); let is_major_syncing = Arc::new(AtomicBool::new(false)); + let block_request_protocol_name = params.block_request_protocol_config.name.clone(); + let state_request_protocol_name = params.state_request_protocol_config.name.clone(); + let warp_sync_protocol_name = + params.warp_sync_protocol_config.as_ref().map(|c| c.name.clone()); + // Build the swarm. let (mut swarm, bandwidth): (Swarm>, _) = { let user_agent = format!( @@ -376,7 +365,6 @@ where params.block_request_protocol_config, params.state_request_protocol_config, params.warp_sync_protocol_config, - params.bitswap, params.light_client_request_protocol_config, params.network_config.request_response_protocols, peerset_handle.clone(), @@ -454,6 +442,7 @@ where local_peer_id, local_identity, to_worker, + chain_sync_service: params.chain_sync_service, peers_notifications_sinks: peers_notifications_sinks.clone(), notifications_sizes_metric: metrics .as_ref() @@ -461,13 +450,6 @@ where _marker: PhantomData, }); - let (tx_handler, tx_handler_controller) = transactions_handler_proto.build( - service.clone(), - params.transaction_pool, - params.metrics_registry.as_ref(), - )?; - (params.transactions_handler_executor)(tx_handler.run().boxed()); - Ok(NetworkWorker { external_addresses, num_connected, @@ -478,9 +460,12 @@ where from_service, event_streams: out_events::OutChannels::new(params.metrics_registry.as_ref())?, peers_notifications_sinks, - tx_handler_controller, metrics, boot_node_ids, + block_request_protocol_name, + state_request_protocol_name, + warp_sync_protocol_name, + _marker: Default::default(), }) } @@ -842,7 +827,7 @@ where /// a stale fork missing. /// Passing empty `peers` set effectively removes the sync request. fn set_sync_fork_request(&self, peers: Vec, hash: B::Hash, number: NumberFor) { - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::SyncFork(peers, hash, number)); + self.chain_sync_service.set_sync_fork_request(peers, hash, number); } } @@ -1145,20 +1130,6 @@ where } } -impl NetworkTransaction for NetworkService -where - B: BlockT + 'static, - H: ExHashT, -{ - fn trigger_repropagate(&self) { - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::PropagateTransactions); - } - - fn propagate_transaction(&self, hash: H) { - let _ = self.to_worker.unbounded_send(ServiceToWorkerMsg::PropagateTransaction(hash)); - } -} - impl NetworkBlock> for NetworkService where B: BlockT + 'static, @@ -1245,9 +1216,7 @@ impl<'a> NotificationSenderReadyT for NotificationSenderReady<'a> { /// Messages sent from the `NetworkService` to the `NetworkWorker`. /// /// Each entry corresponds to a method of `NetworkService`. -enum ServiceToWorkerMsg { - PropagateTransaction(H), - PropagateTransactions, +enum ServiceToWorkerMsg { RequestJustification(B::Hash, NumberFor), ClearJustificationRequests, AnnounceBlock(B::Hash, Option>), @@ -1263,7 +1232,6 @@ enum ServiceToWorkerMsg { RemoveSetReserved(ProtocolName, PeerId), AddToPeersSet(ProtocolName, PeerId), RemoveFromPeersSet(ProtocolName, PeerId), - SyncFork(Vec, B::Hash, NumberFor), EventStream(out_events::Sender), Request { target: PeerId, @@ -1305,7 +1273,7 @@ where /// The import queue that was passed at initialization. import_queue: Box>, /// Messages from the [`NetworkService`] that must be processed. - from_service: TracingUnboundedReceiver>, + from_service: TracingUnboundedReceiver>, /// Senders for events that happen on the network. event_streams: out_events::OutChannels, /// Prometheus network metrics. @@ -1315,8 +1283,18 @@ where /// For each peer and protocol combination, an object that allows sending notifications to /// that peer. Shared with the [`NetworkService`]. peers_notifications_sinks: Arc>>, - /// Controller for the handler of incoming and outgoing transactions. - tx_handler_controller: transactions::TransactionsHandlerController, + /// Protocol name used to send out block requests via + /// [`crate::request_responses::RequestResponsesBehaviour`]. + block_request_protocol_name: ProtocolName, + /// Protocol name used to send out state requests via + /// [`crate::request_responses::RequestResponsesBehaviour`]. + state_request_protocol_name: ProtocolName, + /// Protocol name used to send out warp sync requests via + /// [`crate::request_responses::RequestResponsesBehaviour`]. + warp_sync_protocol_name: Option, + /// Marker to pin the `H` generic. Serves no purpose except to not break backwards + /// compatibility. + _marker: PhantomData, } impl Future for NetworkWorker @@ -1372,10 +1350,6 @@ where .behaviour_mut() .user_protocol_mut() .clear_justification_requests(), - ServiceToWorkerMsg::PropagateTransaction(hash) => - this.tx_handler_controller.propagate_transaction(hash), - ServiceToWorkerMsg::PropagateTransactions => - this.tx_handler_controller.propagate_transactions(), ServiceToWorkerMsg::GetValue(key) => this.network_service.behaviour_mut().get_value(key), ServiceToWorkerMsg::PutValue(key, value) => @@ -1427,11 +1401,6 @@ where .behaviour_mut() .user_protocol_mut() .remove_from_peers_set(protocol, peer_id), - ServiceToWorkerMsg::SyncFork(peer_ids, hash, number) => this - .network_service - .behaviour_mut() - .user_protocol_mut() - .set_sync_fork_request(peer_ids, &hash, number), ServiceToWorkerMsg::EventStream(sender) => this.event_streams.push(sender), ServiceToWorkerMsg::Request { target, @@ -1501,6 +1470,84 @@ where } this.import_queue.import_justifications(origin, hash, nb, justifications); }, + Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::BlockRequest { + target, + request, + pending_response, + })) => { + match this + .network_service + .behaviour() + .user_protocol() + .encode_block_request(&request) + { + Ok(data) => { + this.network_service.behaviour_mut().send_request( + &target, + &this.block_request_protocol_name, + data, + pending_response, + IfDisconnected::ImmediateError, + ); + }, + Err(err) => { + log::warn!( + target: "sync", + "Failed to encode block request {:?}: {:?}", + request, err + ); + }, + } + }, + Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::StateRequest { + target, + request, + pending_response, + })) => { + match this + .network_service + .behaviour() + .user_protocol() + .encode_state_request(&request) + { + Ok(data) => { + this.network_service.behaviour_mut().send_request( + &target, + &this.state_request_protocol_name, + data, + pending_response, + IfDisconnected::ImmediateError, + ); + }, + Err(err) => { + log::warn!( + target: "sync", + "Failed to encode state request {:?}: {:?}", + request, err + ); + }, + } + }, + Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::WarpSyncRequest { + target, + request, + pending_response, + })) => match &this.warp_sync_protocol_name { + Some(name) => this.network_service.behaviour_mut().send_request( + &target, + &name, + request.encode(), + pending_response, + IfDisconnected::ImmediateError, + ), + None => { + log::warn!( + target: "sync", + "Trying to send warp sync request when no protocol is configured {:?}", + request, + ); + }, + }, Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::InboundRequest { protocol, result, @@ -1576,14 +1623,58 @@ where }, } }, + Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::ReputationChanges { + peer, + changes, + })) => + for change in changes { + this.network_service.behaviour().user_protocol().report_peer(peer, change); + }, + Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::PeerIdentify { + peer_id, + info: + IdentifyInfo { + protocol_version, + agent_version, + mut listen_addrs, + protocols, + .. + }, + })) => { + if listen_addrs.len() > 30 { + debug!( + target: "sub-libp2p", + "Node {:?} has reported more than 30 addresses; it is identified by {:?} and {:?}", + peer_id, protocol_version, agent_version + ); + listen_addrs.truncate(30); + } + for addr in listen_addrs { + this.network_service + .behaviour_mut() + .add_self_reported_address_to_dht(&peer_id, &protocols, addr); + } + this.network_service + .behaviour_mut() + .user_protocol_mut() + .add_default_set_discovered_nodes(iter::once(peer_id)); + }, + Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::Discovered(peer_id))) => { + this.network_service + .behaviour_mut() + .user_protocol_mut() + .add_default_set_discovered_nodes(iter::once(peer_id)); + }, Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::RandomKademliaStarted( - protocol, + protocols, ))) => if let Some(metrics) = this.metrics.as_ref() { - metrics - .kademlia_random_queries_total - .with_label_values(&[protocol.as_ref()]) - .inc(); + for protocol in protocols { + metrics + .kademlia_random_queries_total + .with_label_values(&[protocol.as_ref()]) + .inc(); + } }, Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::NotificationStreamOpened { remote, @@ -1704,6 +1795,9 @@ where this.event_streams.send(Event::Dht(event)); }, + Poll::Ready(SwarmEvent::Behaviour(BehaviourOut::None)) => { + // Ignored event from lower layers. + }, Poll::Ready(SwarmEvent::ConnectionEstablished { peer_id, endpoint, @@ -1743,14 +1837,10 @@ where let reason = match cause { Some(ConnectionError::IO(_)) => "transport-error", Some(ConnectionError::Handler(EitherError::A(EitherError::A( - EitherError::A(EitherError::B(EitherError::A( - PingFailure::Timeout, - ))), + EitherError::B(EitherError::A(PingFailure::Timeout)), )))) => "ping-timeout", Some(ConnectionError::Handler(EitherError::A(EitherError::A( - EitherError::A(EitherError::A( - NotifsHandlerError::SyncNotificationsClogged, - )), + EitherError::A(NotifsHandlerError::SyncNotificationsClogged), )))) => "sync-notifications-clogged", Some(ConnectionError::Handler(_)) => "protocol-error", Some(ConnectionError::KeepAliveTimeout) => "keep-alive-timeout", @@ -1922,8 +2012,6 @@ where SyncState::Downloading => true, }; - this.tx_handler_controller.set_gossip_enabled(!is_major_syncing); - this.is_major_syncing.store(is_major_syncing, Ordering::Relaxed); if let Some(metrics) = this.metrics.as_ref() { diff --git a/client/network/src/service/chainsync_tests.rs b/client/network/src/service/chainsync_tests.rs new file mode 100644 index 0000000000000..27c0588a67200 --- /dev/null +++ b/client/network/src/service/chainsync_tests.rs @@ -0,0 +1,375 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate::{config, ChainSyncInterface, NetworkWorker}; + +use futures::prelude::*; +use libp2p::PeerId; +use sc_block_builder::BlockBuilderProvider; +use sc_client_api::{BlockBackend, HeaderBackend}; +use sc_consensus::JustificationSyncLink; +use sc_network_common::{ + config::{ + NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, ProtocolId, SetConfig, + TransportConfig, + }, + protocol::role::Roles, + service::NetworkSyncForkRequest, + sync::{message::BlockAnnouncesHandshake, ChainSync as ChainSyncT, SyncState, SyncStatus}, +}; +use sc_network_light::light_client_requests::handler::LightClientRequestHandler; +use sc_network_sync::{ + block_request_handler::BlockRequestHandler, mock::MockChainSync, + service::mock::MockChainSyncInterface, state_request_handler::StateRequestHandler, +}; +use sp_core::H256; +use sp_runtime::{ + generic::BlockId, + traits::{Block as BlockT, Header as _, Zero}, +}; +use std::{iter, sync::Arc, task::Poll}; +use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _}; + +type TestNetworkWorker = NetworkWorker< + substrate_test_runtime_client::runtime::Block, + substrate_test_runtime_client::runtime::Hash, + substrate_test_runtime_client::TestClient, +>; + +const BLOCK_ANNOUNCE_PROTO_NAME: &str = "/block-announces"; +const PROTOCOL_NAME: &str = "/foo"; + +fn make_network( + chain_sync: Box>, + chain_sync_service: Box>, + client: Arc, +) -> (TestNetworkWorker, Arc) { + let network_config = config::NetworkConfiguration { + extra_sets: vec![NonDefaultSetConfig { + notifications_protocol: PROTOCOL_NAME.into(), + fallback_names: Vec::new(), + max_notification_size: 1024 * 1024, + handshake: None, + set_config: Default::default(), + }], + listen_addresses: vec![config::build_multiaddr![Memory(rand::random::())]], + transport: TransportConfig::MemoryOnly, + ..config::NetworkConfiguration::new_local() + }; + + #[derive(Clone)] + struct PassThroughVerifier(bool); + + #[async_trait::async_trait] + impl sc_consensus::Verifier for PassThroughVerifier { + async fn verify( + &mut self, + mut block: sc_consensus::BlockImportParams, + ) -> Result< + ( + sc_consensus::BlockImportParams, + Option)>>, + ), + String, + > { + let maybe_keys = block + .header + .digest() + .log(|l| { + l.try_as_raw(sp_runtime::generic::OpaqueDigestItemId::Consensus(b"aura")) + .or_else(|| { + l.try_as_raw(sp_runtime::generic::OpaqueDigestItemId::Consensus( + b"babe", + )) + }) + }) + .map(|blob| { + vec![(sp_blockchain::well_known_cache_keys::AUTHORITIES, blob.to_vec())] + }); + + block.finalized = self.0; + block.fork_choice = Some(sc_consensus::ForkChoiceStrategy::LongestChain); + Ok((block, maybe_keys)) + } + } + + let import_queue = Box::new(sc_consensus::BasicQueue::new( + PassThroughVerifier(false), + Box::new(client.clone()), + None, + &sp_core::testing::TaskExecutor::new(), + None, + )); + + let protocol_id = ProtocolId::from("/test-protocol-name"); + + let fork_id = Some(String::from("test-fork-id")); + + let block_request_protocol_config = { + let (handler, protocol_config) = + BlockRequestHandler::new(&protocol_id, None, client.clone(), 50); + async_std::task::spawn(handler.run().boxed()); + protocol_config + }; + + let state_request_protocol_config = { + let (handler, protocol_config) = + StateRequestHandler::new(&protocol_id, None, client.clone(), 50); + async_std::task::spawn(handler.run().boxed()); + protocol_config + }; + + let light_client_request_protocol_config = { + let (handler, protocol_config) = + LightClientRequestHandler::new(&protocol_id, None, client.clone()); + async_std::task::spawn(handler.run().boxed()); + protocol_config + }; + + let block_announce_config = NonDefaultSetConfig { + notifications_protocol: BLOCK_ANNOUNCE_PROTO_NAME.into(), + fallback_names: vec![], + max_notification_size: 1024 * 1024, + handshake: Some(NotificationHandshake::new(BlockAnnouncesHandshake::< + substrate_test_runtime_client::runtime::Block, + >::build( + Roles::from(&config::Role::Full), + client.info().best_number, + client.info().best_hash, + client + .block_hash(Zero::zero()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + ))), + set_config: SetConfig { + in_peers: 0, + out_peers: 0, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Deny, + }, + }; + + let worker = NetworkWorker::new(config::Params { + block_announce_config, + role: config::Role::Full, + executor: None, + network_config, + chain: client.clone(), + protocol_id, + fork_id, + import_queue, + chain_sync, + chain_sync_service, + metrics_registry: None, + block_request_protocol_config, + state_request_protocol_config, + light_client_request_protocol_config, + warp_sync_protocol_config: None, + request_response_protocol_configs: Vec::new(), + }) + .unwrap(); + + (worker, client) +} + +fn set_default_expecations_no_peers( + chain_sync: &mut MockChainSync, +) { + chain_sync.expect_block_requests().returning(|| Box::new(iter::empty())); + chain_sync.expect_state_request().returning(|| None); + chain_sync.expect_justification_requests().returning(|| Box::new(iter::empty())); + chain_sync.expect_warp_sync_request().returning(|| None); + chain_sync.expect_poll().returning(|_| Poll::Pending); + chain_sync.expect_status().returning(|| SyncStatus { + state: SyncState::Idle, + best_seen_block: None, + num_peers: 0u32, + queued_blocks: 0u32, + state_sync: None, + warp_sync: None, + }); +} + +#[async_std::test] +async fn normal_network_poll_no_peers() { + let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); + + // build `ChainSync` and set default expectations for it + let mut chain_sync = + Box::new(MockChainSync::::new()); + set_default_expecations_no_peers(&mut chain_sync); + + // build `ChainSyncInterface` provider and set no expecations for it (i.e., it cannot be + // called) + let chain_sync_service = + Box::new(MockChainSyncInterface::::new()); + + let (mut network, _) = make_network(chain_sync, chain_sync_service, client); + + // poll the network once + futures::future::poll_fn(|cx| { + let _ = network.poll_unpin(cx); + Poll::Ready(()) + }) + .await; +} + +#[async_std::test] +async fn request_justification() { + let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); + + // build `ChainSyncInterface` provider and set no expecations for it (i.e., it cannot be + // called) + let chain_sync_service = + Box::new(MockChainSyncInterface::::new()); + + // build `ChainSync` and verify that call to `request_justification()` is made + let mut chain_sync = + Box::new(MockChainSync::::new()); + + let hash = H256::random(); + let number = 1337u64; + + chain_sync + .expect_request_justification() + .withf(move |in_hash, in_number| &hash == in_hash && &number == in_number) + .once() + .returning(|_, _| ()); + + set_default_expecations_no_peers(&mut chain_sync); + let (mut network, _) = make_network(chain_sync, chain_sync_service, client); + + // send "request justifiction" message and poll the network + network.service().request_justification(&hash, number); + + futures::future::poll_fn(|cx| { + let _ = network.poll_unpin(cx); + Poll::Ready(()) + }) + .await; +} + +#[async_std::test] +async fn clear_justification_requests(&mut self) { + let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); + + // build `ChainSyncInterface` provider and set no expecations for it (i.e., it cannot be + // called) + let chain_sync_service = + Box::new(MockChainSyncInterface::::new()); + + // build `ChainSync` and verify that call to `clear_justification_requests()` is made + let mut chain_sync = + Box::new(MockChainSync::::new()); + + chain_sync.expect_clear_justification_requests().once().returning(|| ()); + + set_default_expecations_no_peers(&mut chain_sync); + let (mut network, _) = make_network(chain_sync, chain_sync_service, client); + + // send "request justifiction" message and poll the network + network.service().clear_justification_requests(); + + futures::future::poll_fn(|cx| { + let _ = network.poll_unpin(cx); + Poll::Ready(()) + }) + .await; +} + +#[async_std::test] +async fn set_sync_fork_request() { + let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); + + // build `ChainSync` and set default expectations for it + let mut chain_sync = + Box::new(MockChainSync::::new()); + set_default_expecations_no_peers(&mut chain_sync); + + // build `ChainSyncInterface` provider and verify that the `set_sync_fork_request()` + // call is delegated to `ChainSyncInterface` (which eventually forwards it to `ChainSync`) + let mut chain_sync_service = + MockChainSyncInterface::::new(); + + let hash = H256::random(); + let number = 1337u64; + let peers = (0..3).map(|_| PeerId::random()).collect::>(); + let copy_peers = peers.clone(); + + chain_sync_service + .expect_set_sync_fork_request() + .withf(move |in_peers, in_hash, in_number| { + &peers == in_peers && &hash == in_hash && &number == in_number + }) + .once() + .returning(|_, _, _| ()); + + let (mut network, _) = make_network(chain_sync, Box::new(chain_sync_service), client); + + // send "set sync fork request" message and poll the network + network.service().set_sync_fork_request(copy_peers, hash, number); + + futures::future::poll_fn(|cx| { + let _ = network.poll_unpin(cx); + Poll::Ready(()) + }) + .await; +} + +#[async_std::test] +async fn on_block_finalized() { + let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); + // build `ChainSyncInterface` provider and set no expecations for it (i.e., it cannot be + // called) + let chain_sync_service = + Box::new(MockChainSyncInterface::::new()); + + // build `ChainSync` and verify that call to `on_block_finalized()` is made + let mut chain_sync = + Box::new(MockChainSync::::new()); + + let at = client.header(&BlockId::Hash(client.info().best_hash)).unwrap().unwrap().hash(); + let block = client + .new_block_at(&BlockId::Hash(at), Default::default(), false) + .unwrap() + .build() + .unwrap() + .block; + let header = block.header.clone(); + let block_number = *header.number(); + let hash = block.hash(); + + chain_sync + .expect_on_block_finalized() + .withf(move |in_hash, in_number| &hash == in_hash && &block_number == in_number) + .once() + .returning(|_, _| ()); + + set_default_expecations_no_peers(&mut chain_sync); + let (mut network, _) = make_network(chain_sync, chain_sync_service, client); + + // send "set sync fork request" message and poll the network + network.on_block_finalized(hash, header); + + futures::future::poll_fn(|cx| { + let _ = network.poll_unpin(cx); + Poll::Ready(()) + }) + .await; +} diff --git a/client/network/src/service/tests.rs b/client/network/src/service/tests.rs index 8770e14bf5338..4a0ef4611da6e 100644 --- a/client/network/src/service/tests.rs +++ b/client/network/src/service/tests.rs @@ -20,10 +20,15 @@ use crate::{config, NetworkService, NetworkWorker}; use futures::prelude::*; use libp2p::PeerId; +use sc_client_api::{BlockBackend, HeaderBackend}; use sc_network_common::{ - config::{MultiaddrWithPeerId, ProtocolId}, - protocol::event::Event, + config::{ + MultiaddrWithPeerId, NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, + ProtocolId, SetConfig, TransportConfig, + }, + protocol::{event::Event, role::Roles}, service::{NetworkEventStream, NetworkNotification, NetworkPeers, NetworkStateInfo}, + sync::message::BlockAnnouncesHandshake, }; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; use sc_network_sync::{ @@ -31,7 +36,7 @@ use sc_network_sync::{ ChainSync, }; use sp_consensus::block_validation::DefaultBlockAnnounceValidator; -use sp_runtime::traits::{Block as BlockT, Header as _}; +use sp_runtime::traits::{Block as BlockT, Header as _, Zero}; use std::{sync::Arc, time::Duration}; use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _}; @@ -119,7 +124,7 @@ fn build_test_full_node( protocol_config }; - let chain_sync = ChainSync::new( + let (chain_sync, chain_sync_service) = ChainSync::new( match network_config.sync_mode { config::SyncMode::Full => sc_network_common::sync::SyncMode::Full, config::SyncMode::Fast { skip_proofs, storage_chain_mode } => @@ -132,25 +137,48 @@ fn build_test_full_node( None, ) .unwrap(); + + let block_announce_config = NonDefaultSetConfig { + notifications_protocol: BLOCK_ANNOUNCE_PROTO_NAME.into(), + fallback_names: vec![], + max_notification_size: 1024 * 1024, + handshake: Some(NotificationHandshake::new(BlockAnnouncesHandshake::< + substrate_test_runtime_client::runtime::Block, + >::build( + Roles::from(&config::Role::Full), + client.info().best_number, + client.info().best_hash, + client + .block_hash(Zero::zero()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + ))), + set_config: SetConfig { + in_peers: 0, + out_peers: 0, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Deny, + }, + }; + let worker = NetworkWorker::new(config::Params { + block_announce_config, role: config::Role::Full, executor: None, - transactions_handler_executor: Box::new(|task| { - async_std::task::spawn(task); - }), network_config, chain: client.clone(), - transaction_pool: Arc::new(config::EmptyTransactionPool), protocol_id, fork_id, import_queue, chain_sync: Box::new(chain_sync), + chain_sync_service, metrics_registry: None, - bitswap: None, block_request_protocol_config, state_request_protocol_config, light_client_request_protocol_config, warp_sync_protocol_config: None, + request_response_protocol_configs: Vec::new(), }) .unwrap(); @@ -165,6 +193,7 @@ fn build_test_full_node( (service, event_stream) } +const BLOCK_ANNOUNCE_PROTO_NAME: &str = "/block-announces"; const PROTOCOL_NAME: &str = "/foo"; /// Builds two nodes and their associated events stream. @@ -178,23 +207,25 @@ fn build_nodes_one_proto() -> ( let listen_addr = config::build_multiaddr![Memory(rand::random::())]; let (node1, events_stream1) = build_test_full_node(config::NetworkConfiguration { - extra_sets: vec![config::NonDefaultSetConfig { + extra_sets: vec![NonDefaultSetConfig { notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, + handshake: None, set_config: Default::default(), }], listen_addresses: vec![listen_addr.clone()], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, ..config::NetworkConfiguration::new_local() }); let (node2, events_stream2) = build_test_full_node(config::NetworkConfiguration { - extra_sets: vec![config::NonDefaultSetConfig { + extra_sets: vec![NonDefaultSetConfig { notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, - set_config: config::SetConfig { + handshake: None, + set_config: SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, peer_id: node1.local_peer_id(), @@ -203,7 +234,7 @@ fn build_nodes_one_proto() -> ( }, }], listen_addresses: vec![], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, ..config::NetworkConfiguration::new_local() }); @@ -368,13 +399,14 @@ fn lots_of_incoming_peers_works() { let (main_node, _) = build_test_full_node(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], - extra_sets: vec![config::NonDefaultSetConfig { + extra_sets: vec![NonDefaultSetConfig { notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, - set_config: config::SetConfig { in_peers: u32::MAX, ..Default::default() }, + handshake: None, + set_config: SetConfig { in_peers: u32::MAX, ..Default::default() }, }], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, ..config::NetworkConfiguration::new_local() }); @@ -387,11 +419,12 @@ fn lots_of_incoming_peers_works() { for _ in 0..32 { let (_dialing_node, event_stream) = build_test_full_node(config::NetworkConfiguration { listen_addresses: vec![], - extra_sets: vec![config::NonDefaultSetConfig { + extra_sets: vec![NonDefaultSetConfig { notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, - set_config: config::SetConfig { + handshake: None, + set_config: SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr.clone(), peer_id: main_node_peer_id, @@ -399,7 +432,7 @@ fn lots_of_incoming_peers_works() { ..Default::default() }, }], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, ..config::NetworkConfiguration::new_local() }); @@ -504,23 +537,25 @@ fn fallback_name_working() { let listen_addr = config::build_multiaddr![Memory(rand::random::())]; let (node1, mut events_stream1) = build_test_full_node(config::NetworkConfiguration { - extra_sets: vec![config::NonDefaultSetConfig { + extra_sets: vec![NonDefaultSetConfig { notifications_protocol: NEW_PROTOCOL_NAME.into(), fallback_names: vec![PROTOCOL_NAME.into()], max_notification_size: 1024 * 1024, + handshake: None, set_config: Default::default(), }], listen_addresses: vec![listen_addr.clone()], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, ..config::NetworkConfiguration::new_local() }); let (_, mut events_stream2) = build_test_full_node(config::NetworkConfiguration { - extra_sets: vec![config::NonDefaultSetConfig { + extra_sets: vec![NonDefaultSetConfig { notifications_protocol: PROTOCOL_NAME.into(), fallback_names: Vec::new(), max_notification_size: 1024 * 1024, - set_config: config::SetConfig { + handshake: None, + set_config: SetConfig { reserved_nodes: vec![MultiaddrWithPeerId { multiaddr: listen_addr, peer_id: node1.local_peer_id(), @@ -529,7 +564,7 @@ fn fallback_name_working() { }, }], listen_addresses: vec![], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, ..config::NetworkConfiguration::new_local() }); @@ -565,6 +600,74 @@ fn fallback_name_working() { }); } +// Disconnect peer by calling `Protocol::disconnect_peer()` with the supplied block announcement +// protocol name and verify that `SyncDisconnected` event is emitted +#[async_std::test] +async fn disconnect_sync_peer_using_block_announcement_protocol_name() { + let listen_addr = config::build_multiaddr![Memory(rand::random::())]; + + let (node1, mut events_stream1) = build_test_full_node(config::NetworkConfiguration { + extra_sets: vec![NonDefaultSetConfig { + notifications_protocol: PROTOCOL_NAME.into(), + fallback_names: vec![], + max_notification_size: 1024 * 1024, + handshake: None, + set_config: Default::default(), + }], + listen_addresses: vec![listen_addr.clone()], + transport: TransportConfig::MemoryOnly, + ..config::NetworkConfiguration::new_local() + }); + + let (node2, mut events_stream2) = build_test_full_node(config::NetworkConfiguration { + extra_sets: vec![NonDefaultSetConfig { + notifications_protocol: PROTOCOL_NAME.into(), + fallback_names: Vec::new(), + max_notification_size: 1024 * 1024, + handshake: None, + set_config: SetConfig { + reserved_nodes: vec![MultiaddrWithPeerId { + multiaddr: listen_addr, + peer_id: node1.local_peer_id(), + }], + ..Default::default() + }, + }], + listen_addresses: vec![], + transport: TransportConfig::MemoryOnly, + ..config::NetworkConfiguration::new_local() + }); + + async fn wait_for_events(stream: &mut (impl Stream + std::marker::Unpin)) { + let mut notif_received = false; + let mut sync_received = false; + + while !notif_received || !sync_received { + match stream.next().await.unwrap() { + Event::NotificationStreamOpened { .. } => notif_received = true, + Event::SyncConnected { .. } => sync_received = true, + _ => {}, + }; + } + } + + wait_for_events(&mut events_stream1).await; + wait_for_events(&mut events_stream2).await; + + // disconnect peer using `PROTOCOL_NAME`, verify `NotificationStreamClosed` event is emitted + node2.disconnect_peer(node1.local_peer_id(), PROTOCOL_NAME.into()); + assert!(std::matches!( + events_stream2.next().await, + Some(Event::NotificationStreamClosed { .. }) + )); + let _ = events_stream2.next().await; // ignore the reopen event + + // now disconnect using `BLOCK_ANNOUNCE_PROTO_NAME`, verify that `SyncDisconnected` is + // emitted + node2.disconnect_peer(node1.local_peer_id(), BLOCK_ANNOUNCE_PROTO_NAME.into()); + assert!(std::matches!(events_stream2.next().await, Some(Event::SyncDisconnected { .. }))); +} + #[test] #[should_panic(expected = "don't match the transport")] fn ensure_listen_addresses_consistent_with_transport_memory() { @@ -572,7 +675,7 @@ fn ensure_listen_addresses_consistent_with_transport_memory() { let _ = build_test_full_node(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) }); } @@ -599,7 +702,7 @@ fn ensure_boot_node_addresses_consistent_with_transport_memory() { let _ = build_test_full_node(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, boot_nodes: vec![boot_node], ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) }); @@ -632,11 +735,8 @@ fn ensure_reserved_node_addresses_consistent_with_transport_memory() { let _ = build_test_full_node(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], - transport: config::TransportConfig::MemoryOnly, - default_peers_set: config::SetConfig { - reserved_nodes: vec![reserved_node], - ..Default::default() - }, + transport: TransportConfig::MemoryOnly, + default_peers_set: SetConfig { reserved_nodes: vec![reserved_node], ..Default::default() }, ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) }); } @@ -652,10 +752,7 @@ fn ensure_reserved_node_addresses_consistent_with_transport_not_memory() { let _ = build_test_full_node(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], - default_peers_set: config::SetConfig { - reserved_nodes: vec![reserved_node], - ..Default::default() - }, + default_peers_set: SetConfig { reserved_nodes: vec![reserved_node], ..Default::default() }, ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) }); } @@ -668,7 +765,7 @@ fn ensure_public_addresses_consistent_with_transport_memory() { let _ = build_test_full_node(config::NetworkConfiguration { listen_addresses: vec![listen_addr.clone()], - transport: config::TransportConfig::MemoryOnly, + transport: TransportConfig::MemoryOnly, public_addresses: vec![public_address], ..config::NetworkConfiguration::new("test-node", "test-client", Default::default(), None) }); diff --git a/client/network/sync/Cargo.toml b/client/network/sync/Cargo.toml index 7c8f8adafd214..441b02fb22b8a 100644 --- a/client/network/sync/Cargo.toml +++ b/client/network/sync/Cargo.toml @@ -14,18 +14,19 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -prost-build = "0.10" +prost-build = "0.11" [dependencies] +array-bytes = "4.1" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive", ] } futures = "0.3.21" -hex = "0.4.0" -libp2p = "0.46.1" +libp2p = "0.49.0" log = "0.4.17" lru = "0.7.5" -prost = "0.10" +mockall = "0.11.2" +prost = "0.11" smallvec = "1.8.0" thiserror = "1.0" fork-tree = { version = "3.0.0", path = "../../../utils/fork-tree" } @@ -33,6 +34,7 @@ sc-client-api = { version = "4.0.0-dev", path = "../../api" } sc-consensus = { version = "0.10.0-dev", path = "../../consensus/common" } sc-network-common = { version = "0.10.0-dev", path = "../common" } sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } +sc-utils = { version = "4.0.0-dev", path = "../../utils" } sp-arithmetic = { version = "5.0.0", path = "../../../primitives/arithmetic" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } @@ -41,6 +43,7 @@ sp-finality-grandpa = { version = "4.0.0-dev", path = "../../../primitives/final sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } [dev-dependencies] +async-std = { version = "1.11.0", features = ["attributes"] } quickcheck = { version = "1.0.3", default-features = false } sc-block-builder = { version = "0.10.0-dev", path = "../../block-builder" } sp-test-primitives = { version = "2.0.0", path = "../../../primitives/test-primitives" } diff --git a/client/network/sync/src/block_request_handler.rs b/client/network/sync/src/block_request_handler.rs index cc61be2b57256..a6b39591e7945 100644 --- a/client/network/sync/src/block_request_handler.rs +++ b/client/network/sync/src/block_request_handler.rs @@ -80,10 +80,11 @@ pub fn generate_protocol_config>( /// Generate the block protocol name from the genesis hash and fork id. fn generate_protocol_name>(genesis_hash: Hash, fork_id: Option<&str>) -> String { + let genesis_hash = genesis_hash.as_ref(); if let Some(fork_id) = fork_id { - format!("/{}/{}/sync/2", hex::encode(genesis_hash), fork_id) + format!("/{}/{}/sync/2", array_bytes::bytes2hex("", genesis_hash), fork_id) } else { - format!("/{}/sync/2", hex::encode(genesis_hash)) + format!("/{}/sync/2", array_bytes::bytes2hex("", genesis_hash)) } } diff --git a/client/network/sync/src/lib.rs b/client/network/sync/src/lib.rs index aae5f4de353fe..e9c2b24b2ba95 100644 --- a/client/network/sync/src/lib.rs +++ b/client/network/sync/src/lib.rs @@ -30,15 +30,20 @@ pub mod block_request_handler; pub mod blocks; +pub mod mock; mod schema; +pub mod service; pub mod state; pub mod state_request_handler; +#[cfg(test)] +mod tests; pub mod warp; pub mod warp_request_handler; use crate::{ blocks::BlockCollection, schema::v1::{StateRequest, StateResponse}, + service::chain_sync::{ChainSyncInterfaceHandle, ToServiceCommand}, state::StateSync, warp::{WarpProofImportResult, WarpSync}, }; @@ -50,16 +55,23 @@ use log::{debug, error, info, trace, warn}; use prost::Message; use sc_client_api::{BlockBackend, ProofProvider}; use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock}; -use sc_network_common::sync::{ - message::{ - BlockAnnounce, BlockAttributes, BlockData, BlockRequest, BlockResponse, Direction, - FromBlock, +use sc_network_common::{ + config::{ + NonDefaultSetConfig, NonReservedPeerMode, NotificationHandshake, ProtocolId, SetConfig, + }, + protocol::role::Roles, + sync::{ + message::{ + BlockAnnounce, BlockAnnouncesHandshake, BlockAttributes, BlockData, BlockRequest, + BlockResponse, Direction, FromBlock, + }, + warp::{EncodedProof, WarpProofRequest, WarpSyncPhase, WarpSyncProgress, WarpSyncProvider}, + BadPeer, ChainSync as ChainSyncT, Metrics, OnBlockData, OnBlockJustification, OnStateData, + OpaqueBlockRequest, OpaqueBlockResponse, OpaqueStateRequest, OpaqueStateResponse, PeerInfo, + PollBlockAnnounceValidation, SyncMode, SyncState, SyncStatus, }, - warp::{EncodedProof, WarpProofRequest, WarpSyncPhase, WarpSyncProgress, WarpSyncProvider}, - BadPeer, ChainSync as ChainSyncT, Metrics, OnBlockData, OnBlockJustification, OnStateData, - OpaqueBlockRequest, OpaqueBlockResponse, OpaqueStateRequest, OpaqueStateResponse, PeerInfo, - PollBlockAnnounceValidation, SyncMode, SyncState, SyncStatus, }; +use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedReceiver}; use sp_arithmetic::traits::Saturating; use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata}; use sp_consensus::{ @@ -76,10 +88,12 @@ use sp_runtime::{ }; use std::{ collections::{hash_map::Entry, HashMap, HashSet}, + iter, ops::Range, pin::Pin, sync::Arc, }; +use warp::TargetBlockImportResult; mod extra_requests; @@ -120,6 +134,9 @@ const MAJOR_SYNC_BLOCKS: u8 = 5; /// Number of peers that need to be connected before warp sync is started. const MIN_PEERS_TO_START_WARP_SYNC: usize = 3; +/// Maximum allowed size for a block announce. +const MAX_BLOCK_ANNOUNCE_SIZE: u64 = 1024 * 1024; + mod rep { use sc_peerset::ReputationChange as Rep; /// Reputation change when a peer sent us a message that led to a @@ -252,6 +269,8 @@ pub struct ChainSync { import_existing: bool, /// Gap download process. gap_sync: Option>, + /// Channel for receiving service commands + service_rx: TracingUnboundedReceiver>, } /// All the data we have about a Peer that we are trying to sync with @@ -315,6 +334,8 @@ pub enum PeerSyncState { DownloadingState, /// Downloading warp proof. DownloadingWarpProof, + /// Downloading warp sync target block. + DownloadingWarpTargetBlock, /// Actively downloading block history after warp sync. DownloadingGap(NumberFor), } @@ -630,9 +651,9 @@ where .extend(peers); } - fn justification_requests( - &mut self, - ) -> Box)> + '_> { + fn justification_requests<'a>( + &'a mut self, + ) -> Box)> + 'a> { let peers = &mut self.peers; let mut matcher = self.extra_justifications.matcher(); Box::new(std::iter::from_fn(move || { @@ -647,7 +668,6 @@ where id: 0, fields: BlockAttributes::JUSTIFICATION, from: FromBlock::Hash(request.0), - to: None, direction: Direction::Ascending, max: Some(1), }; @@ -658,11 +678,14 @@ where })) } - fn block_requests(&mut self) -> Box)> + '_> { - if self.allowed_requests.is_empty() || - self.state_sync.is_some() || - self.mode == SyncMode::Warp - { + fn block_requests<'a>( + &'a mut self, + ) -> Box)> + 'a> { + if self.mode == SyncMode::Warp { + return Box::new(std::iter::once(self.warp_target_block_request()).flatten()) + } + + if self.allowed_requests.is_empty() || self.state_sync.is_some() { return Box::new(std::iter::empty()) } @@ -682,8 +705,8 @@ where let allowed_requests = self.allowed_requests.take(); let max_parallel = if major_sync { 1 } else { self.max_parallel_downloads }; let gap_sync = &mut self.gap_sync; - let iter = self.peers.iter_mut().filter_map(move |(id, peer)| { - if !peer.state.is_available() || !allowed_requests.contains(id) { + let iter = self.peers.iter_mut().filter_map(move |(&id, peer)| { + if !peer.state.is_available() || !allowed_requests.contains(&id) { return None } @@ -712,7 +735,7 @@ where }; Some((id, ancestry_request::(current))) } else if let Some((range, req)) = peer_block_request( - id, + &id, peer, blocks, attrs, @@ -731,7 +754,7 @@ where ); Some((id, req)) } else if let Some((hash, req)) = - fork_sync_request(id, fork_targets, best_queued, last_finalized, attrs, |hash| { + fork_sync_request(&id, fork_targets, best_queued, last_finalized, attrs, |hash| { if queue.contains(hash) { BlockStatus::Queued } else { @@ -743,7 +766,7 @@ where Some((id, req)) } else if let Some((range, req)) = gap_sync.as_mut().and_then(|sync| { peer_gap_block_request( - id, + &id, peer, &mut sync.blocks, attrs, @@ -824,7 +847,7 @@ where // Only one pending state request is allowed. return None } - if let Some(request) = sync.next_warp_poof_request() { + if let Some(request) = sync.next_warp_proof_request() { let mut targets: Vec<_> = self.peers.values().map(|p| p.best_number).collect(); if !targets.is_empty() { targets.sort(); @@ -1031,6 +1054,40 @@ where Vec::new() } }, + PeerSyncState::DownloadingWarpTargetBlock => { + peer.state = PeerSyncState::Available; + if let Some(warp_sync) = &mut self.warp_sync { + if blocks.len() == 1 { + validate_blocks::(&blocks, who, Some(request))?; + match warp_sync.import_target_block( + blocks.pop().expect("`blocks` len checked above."), + ) { + TargetBlockImportResult::Success => + return Ok(OnBlockData::Continue), + TargetBlockImportResult::BadResponse => + return Err(BadPeer(*who, rep::VERIFICATION_FAIL)), + } + } else if blocks.is_empty() { + debug!(target: "sync", "Empty block response from {}", who); + return Err(BadPeer(*who, rep::NO_BLOCK)) + } else { + debug!( + target: "sync", + "Too many blocks ({}) in warp target block response from {}", + blocks.len(), + who, + ); + return Err(BadPeer(*who, rep::NOT_REQUESTED)) + } + } else { + debug!( + target: "sync", + "Logic error: we think we are downloading warp target block from {}, but no warp sync is happening.", + who, + ); + return Ok(OnBlockData::Continue) + } + }, PeerSyncState::Available | PeerSyncState::DownloadingJustification(..) | PeerSyncState::DownloadingState | @@ -1112,14 +1169,14 @@ where }; match import_result { - state::ImportResult::Import(hash, header, state) => { + state::ImportResult::Import(hash, header, state, body, justifications) => { let origin = BlockOrigin::NetworkInitialSync; let block = IncomingBlock { hash, header: Some(header), - body: None, + body, indexed_body: None, - justifications: None, + justifications, origin: None, allow_missing_state: true, import_existing: true, @@ -1387,8 +1444,7 @@ where if let SyncMode::LightState { skip_proofs, .. } = &self.mode { if self.state_sync.is_none() && !self.peers.is_empty() && self.queue_blocks.is_empty() { // Finalized a recent block. - let mut heads: Vec<_> = - self.peers.iter().map(|(_, peer)| peer.best_number).collect(); + let mut heads: Vec<_> = self.peers.values().map(|peer| peer.best_number).collect(); heads.sort(); let median = heads[heads.len() / 2]; if number + STATE_SYNC_FINALITY_THRESHOLD.saturated_into() >= median { @@ -1399,8 +1455,13 @@ where number, hash, ); - self.state_sync = - Some(StateSync::new(self.client.clone(), header, *skip_proofs)); + self.state_sync = Some(StateSync::new( + self.client.clone(), + header, + None, + None, + *skip_proofs, + )); self.allowed_requests.set_all(); } } @@ -1565,7 +1626,6 @@ where FromBlock::Number(n) => Some(schema::v1::block_request::FromBlock::Number(n.encode())), }, - to_block: request.to.map(|h| h.encode()).unwrap_or_default(), direction: request.direction as i32, max_blocks: request.max.unwrap_or(0), support_multiple_justifications: true, @@ -1671,6 +1731,21 @@ where Ok(OpaqueStateResponse(Box::new(response))) } + + fn poll( + &mut self, + cx: &mut std::task::Context, + ) -> Poll> { + while let Poll::Ready(Some(event)) = self.service_rx.poll_next_unpin(cx) { + match event { + ToServiceCommand::SetSyncForkRequest(peers, hash, number) => { + self.set_sync_fork_request(peers, &hash, number); + }, + } + } + + self.poll_block_announce_validation(cx) + } } impl ChainSync @@ -1692,7 +1767,9 @@ where block_announce_validator: Box + Send>, max_parallel_downloads: u32, warp_sync_provider: Option>>, - ) -> Result { + ) -> Result<(Self, Box>), ClientError> { + let (tx, service_rx) = tracing_unbounded("mpsc_chain_sync"); + let mut sync = Self { client, peers: HashMap::new(), @@ -1714,9 +1791,10 @@ where warp_sync_provider, import_existing: false, gap_sync: None, + service_rx, }; sync.reset_sync_start_point()?; - Ok(sync) + Ok((sync, Box::new(ChainSyncInterfaceHandle::new(tx)))) } /// Returns the best seen block number if we don't have that block yet, `None` otherwise. @@ -2163,6 +2241,80 @@ where }) .collect() } + + /// Generate block request for downloading of the target block body during warp sync. + fn warp_target_block_request(&mut self) -> Option<(PeerId, BlockRequest)> { + if let Some(sync) = &self.warp_sync { + if self.allowed_requests.is_empty() || + sync.is_complete() || + self.peers + .iter() + .any(|(_, peer)| peer.state == PeerSyncState::DownloadingWarpTargetBlock) + { + // Only one pending warp target block request is allowed. + return None + } + if let Some((target_number, request)) = sync.next_target_block_request() { + // Find a random peer that has a block with the target number. + for (id, peer) in self.peers.iter_mut() { + if peer.state.is_available() && peer.best_number >= target_number { + trace!(target: "sync", "New warp target block request for {}", id); + peer.state = PeerSyncState::DownloadingWarpTargetBlock; + self.allowed_requests.clear(); + return Some((*id, request)) + } + } + } + } + None + } + + /// Get config for the block announcement protocol + pub fn get_block_announce_proto_config( + &self, + protocol_id: ProtocolId, + fork_id: &Option, + roles: Roles, + best_number: NumberFor, + best_hash: B::Hash, + genesis_hash: B::Hash, + ) -> NonDefaultSetConfig { + let block_announces_protocol = { + let genesis_hash = genesis_hash.as_ref(); + if let Some(ref fork_id) = fork_id { + format!( + "/{}/{}/block-announces/1", + array_bytes::bytes2hex("", genesis_hash), + fork_id + ) + } else { + format!("/{}/block-announces/1", array_bytes::bytes2hex("", genesis_hash)) + } + }; + + NonDefaultSetConfig { + notifications_protocol: block_announces_protocol.into(), + fallback_names: iter::once( + format!("/{}/block-announces/1", protocol_id.as_ref()).into(), + ) + .collect(), + max_notification_size: MAX_BLOCK_ANNOUNCE_SIZE, + handshake: Some(NotificationHandshake::new(BlockAnnouncesHandshake::::build( + roles, + best_number, + best_hash, + genesis_hash, + ))), + // NOTE: `set_config` will be ignored by `protocol.rs` as the block announcement + // protocol is still hardcoded into the peerset. + set_config: SetConfig { + in_peers: 0, + out_peers: 0, + reserved_nodes: Vec::new(), + non_reserved_mode: NonReservedPeerMode::Deny, + }, + } + } } // This is purely during a backwards compatible transitionary period and should be removed @@ -2182,7 +2334,6 @@ fn ancestry_request(block: NumberFor) -> BlockRequest { id: 0, fields: BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION, from: FromBlock::Number(block), - to: None, direction: Direction::Ascending, max: Some(1), } @@ -2298,7 +2449,6 @@ fn peer_block_request( id: 0, fields: attrs, from, - to: None, direction: Direction::Descending, max: Some((range.end - range.start).saturated_into::()), }; @@ -2332,7 +2482,6 @@ fn peer_gap_block_request( id: 0, fields: attrs, from, - to: None, direction: Direction::Descending, max: Some((range.end - range.start).saturated_into::()), }; @@ -2360,7 +2509,7 @@ fn fork_sync_request( true }); for (hash, r) in targets { - if !r.peers.contains(id) { + if !r.peers.contains(&id) { continue } // Download the fork only if it is behind or not too far ahead our tip of the chain @@ -2382,7 +2531,6 @@ fn fork_sync_request( id: 0, fields: attributes, from: FromBlock::Hash(*hash), - to: None, direction: Direction::Descending, max: Some(count), }, @@ -2540,7 +2688,7 @@ mod test { let block_announce_validator = Box::new(DefaultBlockAnnounceValidator); let peer_id = PeerId::random(); - let mut sync = + let (mut sync, _) = ChainSync::new(SyncMode::Full, client.clone(), block_announce_validator, 1, None) .unwrap(); @@ -2588,7 +2736,7 @@ mod test { #[test] fn restart_doesnt_affect_peers_downloading_finality_data() { let mut client = Arc::new(TestClientBuilder::new().build()); - let mut sync = ChainSync::new( + let (mut sync, _) = ChainSync::new( SyncMode::Full, client.clone(), Box::new(DefaultBlockAnnounceValidator), @@ -2619,7 +2767,7 @@ mod test { // we wil send block requests to these peers // for these blocks we don't know about - assert!(sync.block_requests().all(|(p, _)| { *p == peer_id1 || *p == peer_id2 })); + assert!(sync.block_requests().all(|(p, _)| { p == peer_id1 || p == peer_id2 })); // add a new peer at a known block sync.new_peer(peer_id3, b1_hash, b1_number).unwrap(); @@ -2632,8 +2780,7 @@ mod test { assert!(sync.justification_requests().any(|(p, r)| { p == peer_id3 && r.fields == BlockAttributes::JUSTIFICATION && - r.from == FromBlock::Hash(b1_hash) && - r.to == None + r.from == FromBlock::Hash(b1_hash) })); assert_eq!( @@ -2715,7 +2862,7 @@ mod test { log::trace!(target: "sync", "Requests: {:?}", requests); assert_eq!(1, requests.len()); - assert_eq!(peer, requests[0].0); + assert_eq!(*peer, requests[0].0); let request = requests[0].1.clone(); @@ -2756,7 +2903,7 @@ mod test { let mut client = Arc::new(TestClientBuilder::new().build()); - let mut sync = ChainSync::new( + let (mut sync, _) = ChainSync::new( SyncMode::Full, client.clone(), Box::new(DefaultBlockAnnounceValidator), @@ -2871,7 +3018,7 @@ mod test { let mut client = Arc::new(TestClientBuilder::new().build()); let info = client.info(); - let mut sync = ChainSync::new( + let (mut sync, _) = ChainSync::new( SyncMode::Full, client.clone(), Box::new(DefaultBlockAnnounceValidator), @@ -2945,9 +3092,9 @@ mod test { send_block_announce(best_block.header().clone(), &peer_id2, &mut sync); let (peer1_req, peer2_req) = sync.block_requests().fold((None, None), |res, req| { - if req.0 == &peer_id1 { + if req.0 == peer_id1 { (Some(req.1), res.1) - } else if req.0 == &peer_id2 { + } else if req.0 == peer_id2 { (res.0, Some(req.1)) } else { panic!("Unexpected req: {:?}", req) @@ -3014,7 +3161,7 @@ mod test { let info = client.info(); - let mut sync = ChainSync::new( + let (mut sync, _) = ChainSync::new( SyncMode::Full, client.clone(), Box::new(DefaultBlockAnnounceValidator), @@ -3145,7 +3292,7 @@ mod test { let info = client.info(); - let mut sync = ChainSync::new( + let (mut sync, _) = ChainSync::new( SyncMode::Full, client.clone(), Box::new(DefaultBlockAnnounceValidator), @@ -3276,7 +3423,7 @@ mod test { let mut client = Arc::new(TestClientBuilder::new().build()); let blocks = (0..3).map(|_| build_block(&mut client, None, false)).collect::>(); - let mut sync = ChainSync::new( + let (mut sync, _) = ChainSync::new( SyncMode::Full, client.clone(), Box::new(DefaultBlockAnnounceValidator), @@ -3309,7 +3456,7 @@ mod test { let empty_client = Arc::new(TestClientBuilder::new().build()); - let mut sync = ChainSync::new( + let (mut sync, _) = ChainSync::new( SyncMode::Full, empty_client.clone(), Box::new(DefaultBlockAnnounceValidator), diff --git a/client/network/sync/src/mock.rs b/client/network/sync/src/mock.rs new file mode 100644 index 0000000000000..fbb54bd5e998d --- /dev/null +++ b/client/network/sync/src/mock.rs @@ -0,0 +1,122 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Contains a mock implementation of `ChainSync` that can be used +//! for testing calls made to `ChainSync`. + +use futures::task::Poll; +use libp2p::PeerId; +use sc_consensus::{BlockImportError, BlockImportStatus}; +use sc_network_common::sync::{ + message::{BlockAnnounce, BlockData, BlockRequest, BlockResponse}, + warp::{EncodedProof, WarpProofRequest}, + BadPeer, ChainSync as ChainSyncT, Metrics, OnBlockData, OnBlockJustification, OnStateData, + OpaqueBlockRequest, OpaqueBlockResponse, OpaqueStateRequest, OpaqueStateResponse, PeerInfo, + PollBlockAnnounceValidation, SyncStatus, +}; +use sp_runtime::traits::{Block as BlockT, NumberFor}; + +mockall::mock! { + pub ChainSync {} + + impl ChainSyncT for ChainSync { + fn peer_info(&self, who: &PeerId) -> Option>; + fn status(&self) -> SyncStatus; + fn num_sync_requests(&self) -> usize; + fn num_downloaded_blocks(&self) -> usize; + fn num_peers(&self) -> usize; + fn new_peer( + &mut self, + who: PeerId, + best_hash: Block::Hash, + best_number: NumberFor, + ) -> Result>, BadPeer>; + fn update_chain_info(&mut self, best_hash: &Block::Hash, best_number: NumberFor); + fn request_justification(&mut self, hash: &Block::Hash, number: NumberFor); + fn clear_justification_requests(&mut self); + fn set_sync_fork_request( + &mut self, + peers: Vec, + hash: &Block::Hash, + number: NumberFor, + ); + fn justification_requests<'a>( + &'a mut self, + ) -> Box)> + 'a>; + fn block_requests<'a>(&'a mut self) -> Box)> + 'a>; + fn state_request(&mut self) -> Option<(PeerId, OpaqueStateRequest)>; + fn warp_sync_request(&mut self) -> Option<(PeerId, WarpProofRequest)>; + fn on_block_data( + &mut self, + who: &PeerId, + request: Option>, + response: BlockResponse, + ) -> Result, BadPeer>; + fn on_state_data( + &mut self, + who: &PeerId, + response: OpaqueStateResponse, + ) -> Result, BadPeer>; + fn on_warp_sync_data(&mut self, who: &PeerId, response: EncodedProof) -> Result<(), BadPeer>; + fn on_block_justification( + &mut self, + who: PeerId, + response: BlockResponse, + ) -> Result, BadPeer>; + fn on_blocks_processed( + &mut self, + imported: usize, + count: usize, + results: Vec<(Result>, BlockImportError>, Block::Hash)>, + ) -> Box), BadPeer>>>; + fn on_justification_import( + &mut self, + hash: Block::Hash, + number: NumberFor, + success: bool, + ); + fn on_block_finalized(&mut self, hash: &Block::Hash, number: NumberFor); + fn push_block_announce_validation( + &mut self, + who: PeerId, + hash: Block::Hash, + announce: BlockAnnounce, + is_best: bool, + ); + fn poll_block_announce_validation<'a>( + &mut self, + cx: &mut std::task::Context<'a>, + ) -> Poll>; + fn peer_disconnected(&mut self, who: &PeerId) -> Option>; + fn metrics(&self) -> Metrics; + fn create_opaque_block_request(&self, request: &BlockRequest) -> OpaqueBlockRequest; + fn encode_block_request(&self, request: &OpaqueBlockRequest) -> Result, String>; + fn decode_block_response(&self, response: &[u8]) -> Result; + fn block_response_into_blocks( + &self, + request: &BlockRequest, + response: OpaqueBlockResponse, + ) -> Result>, String>; + fn encode_state_request(&self, request: &OpaqueStateRequest) -> Result, String>; + fn decode_state_response(&self, response: &[u8]) -> Result; + fn poll<'a>( + &mut self, + cx: &mut std::task::Context<'a>, + ) -> Poll>; + } +} diff --git a/client/network/sync/src/schema/api.v1.proto b/client/network/sync/src/schema/api.v1.proto index b51137d1d51d4..1490f61a41ddd 100644 --- a/client/network/sync/src/schema/api.v1.proto +++ b/client/network/sync/src/schema/api.v1.proto @@ -23,9 +23,8 @@ message BlockRequest { // Start with given block number. bytes number = 3; } - // End at this block. An implementation defined maximum is used when unspecified. - bytes to_block = 4; // optional // Sequence direction. + // If missing, should be interpreted as "Ascending". Direction direction = 5; // Maximum number of blocks to return. An implementation defined maximum is used when unspecified. uint32 max_blocks = 6; // optional diff --git a/client/network/sync/src/service/chain_sync.rs b/client/network/sync/src/service/chain_sync.rs new file mode 100644 index 0000000000000..cf07c65ee3109 --- /dev/null +++ b/client/network/sync/src/service/chain_sync.rs @@ -0,0 +1,58 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use libp2p::PeerId; +use sc_network_common::service::NetworkSyncForkRequest; +use sc_utils::mpsc::TracingUnboundedSender; +use sp_runtime::traits::{Block as BlockT, NumberFor}; + +/// Commands send to `ChainSync` +#[derive(Debug)] +pub enum ToServiceCommand { + SetSyncForkRequest(Vec, B::Hash, NumberFor), +} + +/// Handle for communicating with `ChainSync` asynchronously +pub struct ChainSyncInterfaceHandle { + tx: TracingUnboundedSender>, +} + +impl ChainSyncInterfaceHandle { + /// Create new handle + pub fn new(tx: TracingUnboundedSender>) -> Self { + Self { tx } + } +} + +impl NetworkSyncForkRequest> + for ChainSyncInterfaceHandle +{ + /// Configure an explicit fork sync request. + /// + /// Note that this function should not be used for recent blocks. + /// Sync should be able to download all the recent forks normally. + /// `set_sync_fork_request` should only be used if external code detects that there's + /// a stale fork missing. + /// + /// Passing empty `peers` set effectively removes the sync request. + fn set_sync_fork_request(&self, peers: Vec, hash: B::Hash, number: NumberFor) { + let _ = self + .tx + .unbounded_send(ToServiceCommand::SetSyncForkRequest(peers, hash, number)); + } +} diff --git a/client/network/sync/src/service/mock.rs b/client/network/sync/src/service/mock.rs new file mode 100644 index 0000000000000..e283907b392d1 --- /dev/null +++ b/client/network/sync/src/service/mock.rs @@ -0,0 +1,31 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use libp2p::PeerId; +use sc_network_common::service::NetworkSyncForkRequest; +use sp_runtime::traits::{Block as BlockT, NumberFor}; + +mockall::mock! { + pub ChainSyncInterface {} + + impl NetworkSyncForkRequest> + for ChainSyncInterface + { + fn set_sync_fork_request(&self, peers: Vec, hash: B::Hash, number: NumberFor); + } +} diff --git a/client/network/sync/src/service/mod.rs b/client/network/sync/src/service/mod.rs new file mode 100644 index 0000000000000..d64d9bbd1b01f --- /dev/null +++ b/client/network/sync/src/service/mod.rs @@ -0,0 +1,22 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! `ChainSync`-related service code + +pub mod chain_sync; +pub mod mock; diff --git a/client/network/sync/src/state.rs b/client/network/sync/src/state.rs index e70d3b6b33a28..9f64b52334c8a 100644 --- a/client/network/sync/src/state.rs +++ b/client/network/sync/src/state.rs @@ -26,7 +26,10 @@ use sc_consensus::ImportedState; use sc_network_common::sync::StateDownloadProgress; use smallvec::SmallVec; use sp_core::storage::well_known_keys; -use sp_runtime::traits::{Block as BlockT, Header, NumberFor}; +use sp_runtime::{ + traits::{Block as BlockT, Header, NumberFor}, + Justifications, +}; use std::{collections::HashMap, sync::Arc}; /// State sync state machine. Accumulates partial state data until it @@ -35,6 +38,8 @@ pub struct StateSync { target_block: B::Hash, target_header: B::Header, target_root: B::Hash, + target_body: Option>, + target_justifications: Option, last_key: SmallVec<[Vec; 2]>, state: HashMap, (Vec<(Vec, Vec)>, Vec>)>, complete: bool, @@ -46,7 +51,7 @@ pub struct StateSync { /// Import state chunk result. pub enum ImportResult { /// State is complete and ready for import. - Import(B::Hash, B::Header, ImportedState), + Import(B::Hash, B::Header, ImportedState, Option>, Option), /// Continue downloading. Continue, /// Bad state chunk. @@ -59,12 +64,20 @@ where Client: ProofProvider + Send + Sync + 'static, { /// Create a new instance. - pub fn new(client: Arc, target: B::Header, skip_proof: bool) -> Self { + pub fn new( + client: Arc, + target_header: B::Header, + target_body: Option>, + target_justifications: Option, + skip_proof: bool, + ) -> Self { Self { client, - target_block: target.hash(), - target_root: *target.state_root(), - target_header: target, + target_block: target_header.hash(), + target_root: *target_header.state_root(), + target_header, + target_body, + target_justifications, last_key: SmallVec::default(), state: HashMap::default(), complete: false, @@ -213,6 +226,8 @@ where block: self.target_block, state: std::mem::take(&mut self.state).into(), }, + self.target_body.clone(), + self.target_justifications.clone(), ) } else { ImportResult::Continue diff --git a/client/network/sync/src/state_request_handler.rs b/client/network/sync/src/state_request_handler.rs index 6cf6482a44f8b..abbbcad2e378f 100644 --- a/client/network/sync/src/state_request_handler.rs +++ b/client/network/sync/src/state_request_handler.rs @@ -69,10 +69,11 @@ pub fn generate_protocol_config>( /// Generate the state protocol name from the genesis hash and fork id. fn generate_protocol_name>(genesis_hash: Hash, fork_id: Option<&str>) -> String { + let genesis_hash = genesis_hash.as_ref(); if let Some(fork_id) = fork_id { - format!("/{}/{}/state/2", hex::encode(genesis_hash), fork_id) + format!("/{}/{}/state/2", array_bytes::bytes2hex("", genesis_hash), fork_id) } else { - format!("/{}/state/2", hex::encode(genesis_hash)) + format!("/{}/state/2", array_bytes::bytes2hex("", genesis_hash)) } } diff --git a/client/network/sync/src/tests.rs b/client/network/sync/src/tests.rs new file mode 100644 index 0000000000000..47483c4ac440d --- /dev/null +++ b/client/network/sync/src/tests.rs @@ -0,0 +1,59 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate::{ChainSync, ForkTarget}; + +use libp2p::PeerId; +use sc_network_common::{service::NetworkSyncForkRequest, sync::ChainSync as ChainSyncT}; +use sp_consensus::block_validation::DefaultBlockAnnounceValidator; +use sp_core::H256; +use std::{sync::Arc, task::Poll}; +use substrate_test_runtime_client::{TestClientBuilder, TestClientBuilderExt as _}; + +// verify that the fork target map is empty, then submit a new sync fork request, +// poll `ChainSync` and verify that a new sync fork request has been registered +#[async_std::test] +async fn delegate_to_chainsync() { + let (mut chain_sync, chain_sync_service) = ChainSync::new( + sc_network_common::sync::SyncMode::Full, + Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0), + Box::new(DefaultBlockAnnounceValidator), + 1u32, + None, + ) + .unwrap(); + + let hash = H256::random(); + let in_number = 1337u64; + let peers = (0..3).map(|_| PeerId::random()).collect::>(); + + assert!(chain_sync.fork_targets.is_empty()); + chain_sync_service.set_sync_fork_request(peers, hash, in_number); + + futures::future::poll_fn(|cx| { + let _ = chain_sync.poll(cx); + Poll::Ready(()) + }) + .await; + + if let Some(ForkTarget { number, .. }) = chain_sync.fork_targets.get(&hash) { + assert_eq!(number, &in_number); + } else { + panic!("expected to contain `ForkTarget`"); + } +} diff --git a/client/network/sync/src/warp.rs b/client/network/sync/src/warp.rs index f3fad6c1b7fdb..ab8a7c66b9856 100644 --- a/client/network/sync/src/warp.rs +++ b/client/network/sync/src/warp.rs @@ -23,17 +23,21 @@ use crate::{ state::{ImportResult, StateSync}, }; use sc_client_api::ProofProvider; -use sc_network_common::sync::warp::{ - EncodedProof, VerificationResult, WarpProofRequest, WarpSyncPhase, WarpSyncProgress, - WarpSyncProvider, +use sc_network_common::sync::{ + message::{BlockAttributes, BlockData, BlockRequest, Direction, FromBlock}, + warp::{ + EncodedProof, VerificationResult, WarpProofRequest, WarpSyncPhase, WarpSyncProgress, + WarpSyncProvider, + }, }; use sp_blockchain::HeaderBackend; use sp_finality_grandpa::{AuthorityList, SetId}; -use sp_runtime::traits::{Block as BlockT, NumberFor, Zero}; +use sp_runtime::traits::{Block as BlockT, Header, NumberFor, Zero}; use std::sync::Arc; enum Phase { WarpProof { set_id: SetId, authorities: AuthorityList, last_hash: B::Hash }, + TargetBlock(B::Header), State(StateSync), } @@ -45,6 +49,14 @@ pub enum WarpProofImportResult { BadResponse, } +/// Import target block result. +pub enum TargetBlockImportResult { + /// Import was successful. + Success, + /// Invalid block. + BadResponse, +} + /// Warp sync state machine. Accumulates warp proofs and state. pub struct WarpSync { phase: Phase, @@ -72,7 +84,7 @@ where /// Validate and import a state response. pub fn import_state(&mut self, response: StateResponse) -> ImportResult { match &mut self.phase { - Phase::WarpProof { .. } => { + Phase::WarpProof { .. } | Phase::TargetBlock(_) => { log::debug!(target: "sync", "Unexpected state response"); ImportResult::BadResponse }, @@ -83,7 +95,7 @@ where /// Validate and import a warp proof response. pub fn import_warp_proof(&mut self, response: EncodedProof) -> WarpProofImportResult { match &mut self.phase { - Phase::State(_) => { + Phase::State(_) | Phase::TargetBlock(_) => { log::debug!(target: "sync", "Unexpected warp proof response"); WarpProofImportResult::BadResponse }, @@ -104,8 +116,7 @@ where Ok(VerificationResult::Complete(new_set_id, _, header)) => { log::debug!(target: "sync", "Verified complete proof, set_id={:?}", new_set_id); self.total_proof_bytes += response.0.len() as u64; - let state_sync = StateSync::new(self.client.clone(), header, false); - self.phase = Phase::State(state_sync); + self.phase = Phase::TargetBlock(header); WarpProofImportResult::Success }, } @@ -113,35 +124,99 @@ where } } + /// Import the target block body. + pub fn import_target_block(&mut self, block: BlockData) -> TargetBlockImportResult { + match &mut self.phase { + Phase::WarpProof { .. } | Phase::State(_) => { + log::debug!(target: "sync", "Unexpected target block response"); + TargetBlockImportResult::BadResponse + }, + Phase::TargetBlock(header) => + if let Some(block_header) = &block.header { + if block_header == header { + if block.body.is_some() { + let state_sync = StateSync::new( + self.client.clone(), + header.clone(), + block.body, + block.justifications, + false, + ); + self.phase = Phase::State(state_sync); + TargetBlockImportResult::Success + } else { + log::debug!( + target: "sync", + "Importing target block failed: missing body.", + ); + TargetBlockImportResult::BadResponse + } + } else { + log::debug!( + target: "sync", + "Importing target block failed: different header.", + ); + TargetBlockImportResult::BadResponse + } + } else { + log::debug!(target: "sync", "Importing target block failed: missing header."); + TargetBlockImportResult::BadResponse + }, + } + } + /// Produce next state request. pub fn next_state_request(&self) -> Option { match &self.phase { Phase::WarpProof { .. } => None, + Phase::TargetBlock(_) => None, Phase::State(sync) => Some(sync.next_request()), } } /// Produce next warp proof request. - pub fn next_warp_poof_request(&self) -> Option> { + pub fn next_warp_proof_request(&self) -> Option> { match &self.phase { - Phase::State(_) => None, Phase::WarpProof { last_hash, .. } => Some(WarpProofRequest { begin: *last_hash }), + Phase::TargetBlock(_) => None, + Phase::State(_) => None, + } + } + + /// Produce next target block request. + pub fn next_target_block_request(&self) -> Option<(NumberFor, BlockRequest)> { + match &self.phase { + Phase::WarpProof { .. } => None, + Phase::TargetBlock(header) => { + let request = BlockRequest:: { + id: 0, + fields: BlockAttributes::HEADER | + BlockAttributes::BODY | BlockAttributes::JUSTIFICATION, + from: FromBlock::Hash(header.hash()), + direction: Direction::Ascending, + max: Some(1), + }; + Some((*header.number(), request)) + }, + Phase::State(_) => None, } } /// Return target block hash if it is known. pub fn target_block_hash(&self) -> Option { match &self.phase { - Phase::State(s) => Some(s.target()), Phase::WarpProof { .. } => None, + Phase::TargetBlock(_) => None, + Phase::State(s) => Some(s.target()), } } /// Return target block number if it is known. pub fn target_block_number(&self) -> Option> { match &self.phase { - Phase::State(s) => Some(s.target_block_num()), Phase::WarpProof { .. } => None, + Phase::TargetBlock(header) => Some(*header.number()), + Phase::State(s) => Some(s.target_block_num()), } } @@ -149,6 +224,7 @@ where pub fn is_complete(&self) -> bool { match &self.phase { Phase::WarpProof { .. } => false, + Phase::TargetBlock(_) => false, Phase::State(sync) => sync.is_complete(), } } @@ -160,6 +236,10 @@ where phase: WarpSyncPhase::DownloadingWarpProofs, total_bytes: self.total_proof_bytes, }, + Phase::TargetBlock(_) => WarpSyncProgress { + phase: WarpSyncPhase::DownloadingTargetBlock, + total_bytes: self.total_proof_bytes, + }, Phase::State(sync) => WarpSyncProgress { phase: if self.is_complete() { WarpSyncPhase::ImportingState diff --git a/client/network/sync/src/warp_request_handler.rs b/client/network/sync/src/warp_request_handler.rs index 394bc68449099..e675bf45cad91 100644 --- a/client/network/sync/src/warp_request_handler.rs +++ b/client/network/sync/src/warp_request_handler.rs @@ -54,10 +54,11 @@ pub fn generate_request_response_config>( /// Generate the grandpa warp sync protocol name from the genesi hash and fork id. fn generate_protocol_name>(genesis_hash: Hash, fork_id: Option<&str>) -> String { + let genesis_hash = genesis_hash.as_ref(); if let Some(fork_id) = fork_id { - format!("/{}/{}/sync/warp", hex::encode(genesis_hash), fork_id) + format!("/{}/{}/sync/warp", array_bytes::bytes2hex("", genesis_hash), fork_id) } else { - format!("/{}/sync/warp", hex::encode(genesis_hash)) + format!("/{}/sync/warp", array_bytes::bytes2hex("", genesis_hash)) } } diff --git a/client/network/test/Cargo.toml b/client/network/test/Cargo.toml index 990129229a40f..30a57bc1b5171 100644 --- a/client/network/test/Cargo.toml +++ b/client/network/test/Cargo.toml @@ -17,7 +17,7 @@ async-std = "1.11.0" async-trait = "0.1.57" futures = "0.3.21" futures-timer = "3.0.1" -libp2p = { version = "0.46.1", default-features = false } +libp2p = { version = "0.49.0", default-features = false } log = "0.4.17" parking_lot = "0.12.1" rand = "0.7.2" diff --git a/client/network/test/src/lib.rs b/client/network/test/src/lib.rs index 837cdeed0f3d1..d4bee77b54aff 100644 --- a/client/network/test/src/lib.rs +++ b/client/network/test/src/lib.rs @@ -47,17 +47,15 @@ use sc_consensus::{ ForkChoiceStrategy, ImportResult, JustificationImport, JustificationSyncLink, LongestChain, Verifier, }; -pub use sc_network::config::EmptyTransactionPool; use sc_network::{ - config::{ - NetworkConfiguration, NonDefaultSetConfig, NonReservedPeerMode, Role, SyncMode, - TransportConfig, - }, + config::{NetworkConfiguration, RequestResponseConfig, Role, SyncMode}, Multiaddr, NetworkService, NetworkWorker, }; use sc_network_common::{ - config::{MultiaddrWithPeerId, ProtocolId}, - protocol::ProtocolName, + config::{ + MultiaddrWithPeerId, NonDefaultSetConfig, NonReservedPeerMode, ProtocolId, TransportConfig, + }, + protocol::{role::Roles, ProtocolName}, service::{NetworkBlock, NetworkStateInfo, NetworkSyncForkRequest}, sync::warp::{AuthorityList, EncodedProof, SetId, VerificationResult, WarpSyncProvider}, }; @@ -69,7 +67,7 @@ use sc_network_sync::{ use sc_service::client::Client; use sp_blockchain::{ well_known_cache_keys::{self, Id as CacheKeyId}, - HeaderBackend, Info as BlockchainInfo, Result as ClientResult, + Backend as BlockchainBackend, HeaderBackend, Info as BlockchainInfo, Result as ClientResult, }; use sp_consensus::{ block_validation::{BlockAnnounceValidator, DefaultBlockAnnounceValidator}, @@ -79,7 +77,7 @@ use sp_core::H256; use sp_runtime::{ codec::{Decode, Encode}, generic::{BlockId, OpaqueDigestItemId}, - traits::{Block as BlockT, Header as HeaderT, NumberFor}, + traits::{Block as BlockT, Header as HeaderT, NumberFor, Zero}, Justification, Justifications, }; use substrate_test_runtime_client::AccountKeyring; @@ -540,6 +538,13 @@ where .map(|backend| backend.blockchain().header(BlockId::hash(*hash)).unwrap().is_some()) .unwrap_or(false) } + + pub fn has_body(&self, hash: &H256) -> bool { + self.backend + .as_ref() + .map(|backend| backend.blockchain().body(BlockId::hash(*hash)).unwrap().is_some()) + .unwrap_or(false) + } } pub trait BlockImportAdapterFull: @@ -683,6 +688,8 @@ pub struct FullPeerConfig { pub block_announce_validator: Option + Send + Sync>>, /// List of notification protocols that the network must support. pub notifications_protocols: Vec, + /// List of request-response protocols that the network must support. + pub request_response_protocols: Vec, /// The indices of the peers the peer should be connected to. /// /// If `None`, it will be connected to all other peers. @@ -785,6 +792,9 @@ where network_config.transport = TransportConfig::MemoryOnly; network_config.listen_addresses = vec![listen_addr.clone()]; network_config.allow_non_globals_in_dht = true; + network_config + .request_response_protocols + .extend(config.request_response_protocols); network_config.extra_sets = config .notifications_protocols .into_iter() @@ -792,6 +802,7 @@ where notifications_protocol: p, fallback_names: Vec::new(), max_notification_size: 1024 * 1024, + handshake: None, set_config: Default::default(), }) .collect(); @@ -853,7 +864,7 @@ where let block_announce_validator = config .block_announce_validator .unwrap_or_else(|| Box::new(DefaultBlockAnnounceValidator)); - let chain_sync = ChainSync::new( + let (chain_sync, chain_sync_service) = ChainSync::new( match network_config.sync_mode { SyncMode::Full => sc_network_common::sync::SyncMode::Full, SyncMode::Fast { skip_proofs, storage_chain_mode } => @@ -869,25 +880,36 @@ where Some(warp_sync), ) .unwrap(); + let block_announce_config = chain_sync.get_block_announce_proto_config( + protocol_id.clone(), + &fork_id, + Roles::from(if config.is_authority { &Role::Authority } else { &Role::Full }), + client.info().best_number, + client.info().best_hash, + client + .block_hash(Zero::zero()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + ); + let network = NetworkWorker::new(sc_network::config::Params { role: if config.is_authority { Role::Authority } else { Role::Full }, executor: None, - transactions_handler_executor: Box::new(|task| { - async_std::task::spawn(task); - }), network_config, chain: client.clone(), - transaction_pool: Arc::new(EmptyTransactionPool), protocol_id, fork_id, import_queue, chain_sync: Box::new(chain_sync), + chain_sync_service, metrics_registry: None, - bitswap: None, + block_announce_config, block_request_protocol_config, state_request_protocol_config, light_client_request_protocol_config, warp_sync_protocol_config: Some(warp_protocol_config), + request_response_protocol_configs: Vec::new(), }) .unwrap(); diff --git a/client/network/test/src/sync.rs b/client/network/test/src/sync.rs index c0778767b75af..6115e0e3b2c86 100644 --- a/client/network/test/src/sync.rs +++ b/client/network/test/src/sync.rs @@ -1192,7 +1192,7 @@ fn warp_sync() { ..Default::default() }); let gap_end = net.peer(0).push_blocks(63, false); - net.peer(0).push_blocks(1, false); + let target = net.peer(0).push_blocks(1, false); net.peer(1).push_blocks(64, false); net.peer(2).push_blocks(64, false); // Wait for peer 1 to sync state. @@ -1203,7 +1203,7 @@ fn warp_sync() { // Wait for peer 1 download block history block_on(futures::future::poll_fn::<(), _>(|cx| { net.poll(cx); - if net.peer(3).has_block(&gap_end) { + if net.peer(3).has_body(&gap_end) && net.peer(3).has_body(&target) { Poll::Ready(()) } else { Poll::Pending diff --git a/client/network/transactions/Cargo.toml b/client/network/transactions/Cargo.toml new file mode 100644 index 0000000000000..d92c07cd461a8 --- /dev/null +++ b/client/network/transactions/Cargo.toml @@ -0,0 +1,28 @@ +[package] +description = "Substrate transaction protocol" +name = "sc-network-transactions" +version = "0.10.0-dev" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +authors = ["Parity Technologies "] +edition = "2021" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +documentation = "https://docs.rs/sc-network-transactions" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +array-bytes = "4.1" +codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } +futures = "0.3.21" +hex = "0.4.0" +libp2p = "0.49.0" +log = "0.4.17" +pin-project = "1.0.12" +prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", path = "../../../utils/prometheus" } +sc-network-common = { version = "0.10.0-dev", path = "../common" } +sc-peerset = { version = "4.0.0-dev", path = "../../peerset" } +sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } +sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } diff --git a/client/network/transactions/src/config.rs b/client/network/transactions/src/config.rs new file mode 100644 index 0000000000000..abb8cccd301ac --- /dev/null +++ b/client/network/transactions/src/config.rs @@ -0,0 +1,98 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Configuration of the transaction protocol + +use futures::prelude::*; +use sc_network_common::ExHashT; +use sp_runtime::traits::Block as BlockT; +use std::{collections::HashMap, future::Future, pin::Pin, time}; + +/// Interval at which we propagate transactions; +pub(crate) const PROPAGATE_TIMEOUT: time::Duration = time::Duration::from_millis(2900); + +/// Maximum number of known transaction hashes to keep for a peer. +/// +/// This should be approx. 2 blocks full of transactions for the network to function properly. +pub(crate) const MAX_KNOWN_TRANSACTIONS: usize = 10240; // ~300kb per peer + overhead. + +/// Maximum allowed size for a transactions notification. +pub(crate) const MAX_TRANSACTIONS_SIZE: u64 = 16 * 1024 * 1024; + +/// Maximum number of transaction validation request we keep at any moment. +pub(crate) const MAX_PENDING_TRANSACTIONS: usize = 8192; + +/// Result of the transaction import. +#[derive(Clone, Copy, Debug)] +pub enum TransactionImport { + /// Transaction is good but already known by the transaction pool. + KnownGood, + /// Transaction is good and not yet known. + NewGood, + /// Transaction is invalid. + Bad, + /// Transaction import was not performed. + None, +} + +/// Future resolving to transaction import result. +pub type TransactionImportFuture = Pin + Send>>; + +/// Transaction pool interface +pub trait TransactionPool: Send + Sync { + /// Get transactions from the pool that are ready to be propagated. + fn transactions(&self) -> Vec<(H, B::Extrinsic)>; + /// Get hash of transaction. + fn hash_of(&self, transaction: &B::Extrinsic) -> H; + /// Import a transaction into the pool. + /// + /// This will return future. + fn import(&self, transaction: B::Extrinsic) -> TransactionImportFuture; + /// Notify the pool about transactions broadcast. + fn on_broadcasted(&self, propagations: HashMap>); + /// Get transaction by hash. + fn transaction(&self, hash: &H) -> Option; +} + +/// Dummy implementation of the [`TransactionPool`] trait for a transaction pool that is always +/// empty and discards all incoming transactions. +/// +/// Requires the "hash" type to implement the `Default` trait. +/// +/// Useful for testing purposes. +pub struct EmptyTransactionPool; + +impl TransactionPool for EmptyTransactionPool { + fn transactions(&self) -> Vec<(H, B::Extrinsic)> { + Vec::new() + } + + fn hash_of(&self, _transaction: &B::Extrinsic) -> H { + Default::default() + } + + fn import(&self, _transaction: B::Extrinsic) -> TransactionImportFuture { + Box::pin(future::ready(TransactionImport::KnownGood)) + } + + fn on_broadcasted(&self, _: HashMap>) {} + + fn transaction(&self, _h: &H) -> Option { + None + } +} diff --git a/client/network/src/transactions.rs b/client/network/transactions/src/lib.rs similarity index 83% rename from client/network/src/transactions.rs rename to client/network/transactions/src/lib.rs index 1cf532f33ddc6..5239a94ef23f3 100644 --- a/client/network/src/transactions.rs +++ b/client/network/transactions/src/lib.rs @@ -26,27 +26,19 @@ //! - Use [`TransactionsHandlerPrototype::build`] then [`TransactionsHandler::run`] to obtain a //! `Future` that processes transactions. -use crate::{ - config::{self, TransactionImport, TransactionImportFuture, TransactionPool}, - error, - protocol::message, - service::NetworkService, - utils::{interval, LruHashSet}, - ExHashT, -}; - +use crate::config::*; use codec::{Decode, Encode}; use futures::{channel::mpsc, prelude::*, stream::FuturesUnordered}; use libp2p::{multiaddr, PeerId}; use log::{debug, trace, warn}; use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64}; use sc_network_common::{ - config::ProtocolId, - protocol::{ - event::{Event, ObservedRole}, - ProtocolName, - }, + config::{NonDefaultSetConfig, NonReservedPeerMode, ProtocolId, SetConfig}, + error, + protocol::{event::Event, role::ObservedRole, ProtocolName}, service::{NetworkEventStream, NetworkNotification, NetworkPeers}, + utils::{interval, LruHashSet}, + ExHashT, }; use sp_runtime::traits::Block as BlockT; use std::{ @@ -54,27 +46,14 @@ use std::{ iter, num::NonZeroUsize, pin::Pin, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, - }, + sync::Arc, task::Poll, - time, }; -/// Interval at which we propagate transactions; -const PROPAGATE_TIMEOUT: time::Duration = time::Duration::from_millis(2900); - -/// Maximum number of known transaction hashes to keep for a peer. -/// -/// This should be approx. 2 blocks full of transactions for the network to function properly. -const MAX_KNOWN_TRANSACTIONS: usize = 10240; // ~300kb per peer + overhead. +pub mod config; -/// Maximum allowed size for a transactions notification. -const MAX_TRANSACTIONS_SIZE: u64 = 16 * 1024 * 1024; - -/// Maximum number of transaction validation request we keep at any moment. -const MAX_PENDING_TRANSACTIONS: usize = 8192; +/// A set of transactions. +pub type Transactions = Vec; mod rep { use sc_peerset::ReputationChange as Rep; @@ -141,12 +120,13 @@ impl TransactionsHandlerPrototype { pub fn new>( protocol_id: ProtocolId, genesis_hash: Hash, - fork_id: Option, + fork_id: Option<&str>, ) -> Self { + let genesis_hash = genesis_hash.as_ref(); let protocol_name = if let Some(fork_id) = fork_id { - format!("/{}/{}/transactions/1", hex::encode(genesis_hash), fork_id) + format!("/{}/{}/transactions/1", array_bytes::bytes2hex("", genesis_hash), fork_id) } else { - format!("/{}/transactions/1", hex::encode(genesis_hash)) + format!("/{}/transactions/1", array_bytes::bytes2hex("", genesis_hash)) }; let legacy_protocol_name = format!("/{}/transactions/1", protocol_id.as_ref()); @@ -157,16 +137,17 @@ impl TransactionsHandlerPrototype { } /// Returns the configuration of the set to put in the network configuration. - pub fn set_config(&self) -> config::NonDefaultSetConfig { - config::NonDefaultSetConfig { + pub fn set_config(&self) -> NonDefaultSetConfig { + NonDefaultSetConfig { notifications_protocol: self.protocol_name.clone(), fallback_names: self.fallback_protocol_names.clone(), max_notification_size: MAX_TRANSACTIONS_SIZE, - set_config: config::SetConfig { + handshake: None, + set_config: SetConfig { in_peers: 0, out_peers: 0, reserved_nodes: Vec::new(), - non_reserved_mode: config::NonReservedPeerMode::Deny, + non_reserved_mode: NonReservedPeerMode::Deny, }, } } @@ -175,23 +156,25 @@ impl TransactionsHandlerPrototype { /// the behaviour of the handler while it's running. /// /// Important: the transactions handler is initially disabled and doesn't gossip transactions. - /// You must call [`TransactionsHandlerController::set_gossip_enabled`] to enable it. - pub fn build( + /// Gossiping is enabled when major syncing is done. + pub fn build< + B: BlockT + 'static, + H: ExHashT, + S: NetworkPeers + NetworkEventStream + NetworkNotification + sp_consensus::SyncOracle, + >( self, - service: Arc>, + service: S, transaction_pool: Arc>, metrics_registry: Option<&Registry>, - ) -> error::Result<(TransactionsHandler, TransactionsHandlerController)> { + ) -> error::Result<(TransactionsHandler, TransactionsHandlerController)> { let event_stream = service.event_stream("transactions-handler"); let (to_handler, from_controller) = mpsc::unbounded(); - let gossip_enabled = Arc::new(AtomicBool::new(false)); let handler = TransactionsHandler { protocol_name: self.protocol_name, propagate_timeout: Box::pin(interval(PROPAGATE_TIMEOUT)), pending_transactions: FuturesUnordered::new(), pending_transactions_peers: HashMap::new(), - gossip_enabled: gossip_enabled.clone(), service, event_stream, peers: HashMap::new(), @@ -204,7 +187,7 @@ impl TransactionsHandlerPrototype { }, }; - let controller = TransactionsHandlerController { to_handler, gossip_enabled }; + let controller = TransactionsHandlerController { to_handler }; Ok((handler, controller)) } @@ -213,15 +196,9 @@ impl TransactionsHandlerPrototype { /// Controls the behaviour of a [`TransactionsHandler`] it is connected to. pub struct TransactionsHandlerController { to_handler: mpsc::UnboundedSender>, - gossip_enabled: Arc, } impl TransactionsHandlerController { - /// Controls whether transactions are being gossiped on the network. - pub fn set_gossip_enabled(&mut self, enabled: bool) { - self.gossip_enabled.store(enabled, Ordering::Relaxed); - } - /// You may call this when new transactions are imported by the transaction pool. /// /// All transactions will be fetched from the `TransactionPool` that was passed at @@ -245,7 +222,11 @@ enum ToHandler { } /// Handler for transactions. Call [`TransactionsHandler::run`] to start the processing. -pub struct TransactionsHandler { +pub struct TransactionsHandler< + B: BlockT + 'static, + H: ExHashT, + S: NetworkPeers + NetworkEventStream + NetworkNotification + sp_consensus::SyncOracle, +> { protocol_name: ProtocolName, /// Interval at which we call `propagate_transactions`. propagate_timeout: Pin + Send>>, @@ -257,13 +238,12 @@ pub struct TransactionsHandler { /// multiple times concurrently. pending_transactions_peers: HashMap>, /// Network service to use to send messages and manage peers. - service: Arc>, + service: S, /// Stream of networking events. event_stream: Pin + Send>>, // All connected peers peers: HashMap>, transaction_pool: Arc>, - gossip_enabled: Arc, from_controller: mpsc::UnboundedReceiver>, /// Prometheus metrics. metrics: Option, @@ -277,7 +257,12 @@ struct Peer { role: ObservedRole, } -impl TransactionsHandler { +impl TransactionsHandler +where + B: BlockT + 'static, + H: ExHashT, + S: NetworkPeers + NetworkEventStream + NetworkNotification + sp_consensus::SyncOracle, +{ /// Turns the [`TransactionsHandler`] into a future that should run forever and not be /// interrupted. pub async fn run(mut self) { @@ -359,9 +344,9 @@ impl TransactionsHandler { continue } - if let Ok(m) = as Decode>::decode( - &mut message.as_ref(), - ) { + if let Ok(m) = + as Decode>::decode(&mut message.as_ref()) + { self.on_transactions(remote, m); } else { warn!(target: "sub-libp2p", "Failed to decode transactions list"); @@ -375,10 +360,10 @@ impl TransactionsHandler { } /// Called when peer sends us new transactions - fn on_transactions(&mut self, who: PeerId, transactions: message::Transactions) { - // Accept transactions only when enabled - if !self.gossip_enabled.load(Ordering::Relaxed) { - trace!(target: "sync", "{} Ignoring transactions while disabled", who); + fn on_transactions(&mut self, who: PeerId, transactions: Transactions) { + // Accept transactions only when node is not major syncing + if self.service.is_major_syncing() { + trace!(target: "sync", "{} Ignoring transactions while major syncing", who); return } @@ -427,10 +412,11 @@ impl TransactionsHandler { /// Propagate one transaction. pub fn propagate_transaction(&mut self, hash: &H) { - // Accept transactions only when enabled - if !self.gossip_enabled.load(Ordering::Relaxed) { + // Accept transactions only when node is not major syncing + if self.service.is_major_syncing() { return } + debug!(target: "sync", "Propagating transaction [{:?}]", hash); if let Some(transaction) = self.transaction_pool.transaction(hash) { let propagated_to = self.do_propagate_transactions(&[(hash.clone(), transaction)]); @@ -478,10 +464,11 @@ impl TransactionsHandler { /// Call when we must propagate ready transactions to peers. fn propagate_transactions(&mut self) { - // Accept transactions only when enabled - if !self.gossip_enabled.load(Ordering::Relaxed) { + // Accept transactions only when node is not major syncing + if self.service.is_major_syncing() { return } + debug!(target: "sync", "Propagating transactions"); let transactions = self.transaction_pool.transactions(); let propagated_to = self.do_propagate_transactions(&transactions); diff --git a/client/offchain/Cargo.toml b/client/offchain/Cargo.toml index ff97f29961155..1e8c802496453 100644 --- a/client/offchain/Cargo.toml +++ b/client/offchain/Cargo.toml @@ -13,15 +13,15 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +array-bytes = "4.1" bytes = "1.1" codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } fnv = "1.0.6" futures = "0.3.21" futures-timer = "3.0.2" -hex = "0.4" hyper = { version = "0.14.16", features = ["stream", "http2"] } hyper-rustls = { version = "0.23.0", features = ["http2"] } -libp2p = { version = "0.46.1", default-features = false } +libp2p = { version = "0.49.0", default-features = false } num_cpus = "1.13" once_cell = "1.8" parking_lot = "0.12.1" diff --git a/client/offchain/src/api.rs b/client/offchain/src/api.rs index 6d6c52c989c34..7d3dd8302f343 100644 --- a/client/offchain/src/api.rs +++ b/client/offchain/src/api.rs @@ -79,8 +79,8 @@ impl offchain::DbExternalities for Db { tracing::debug!( target: "offchain-worker::storage", ?kind, - key = ?hex::encode(key), - value = ?hex::encode(value), + key = ?array_bytes::bytes2hex("", key), + value = ?array_bytes::bytes2hex("", value), "Write", ); match kind { @@ -93,7 +93,7 @@ impl offchain::DbExternalities for Db { tracing::debug!( target: "offchain-worker::storage", ?kind, - key = ?hex::encode(key), + key = ?array_bytes::bytes2hex("", key), "Clear", ); match kind { @@ -112,9 +112,9 @@ impl offchain::DbExternalities for Db { tracing::debug!( target: "offchain-worker::storage", ?kind, - key = ?hex::encode(key), - new_value = ?hex::encode(new_value), - old_value = ?old_value.as_ref().map(hex::encode), + key = ?array_bytes::bytes2hex("", key), + new_value = ?array_bytes::bytes2hex("", new_value), + old_value = ?old_value.as_ref().map(|s| array_bytes::bytes2hex("", s)), "CAS", ); match kind { @@ -132,8 +132,8 @@ impl offchain::DbExternalities for Db { tracing::debug!( target: "offchain-worker::storage", ?kind, - key = ?hex::encode(key), - result = ?result.as_ref().map(hex::encode), + key = ?array_bytes::bytes2hex("", key), + result = ?result.as_ref().map(|s| array_bytes::bytes2hex("", s)), "Read", ); result diff --git a/client/peerset/Cargo.toml b/client/peerset/Cargo.toml index d3d6e267f1768..ade2bc3d78d03 100644 --- a/client/peerset/Cargo.toml +++ b/client/peerset/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] futures = "0.3.21" -libp2p = { version = "0.46.1", default-features = false } +libp2p = { version = "0.49.0", default-features = false } log = "0.4.17" serde_json = "1.0.85" wasm-timer = "0.2" diff --git a/client/rpc-servers/src/lib.rs b/client/rpc-servers/src/lib.rs index 68b4aa6767348..7eb825e169bfa 100644 --- a/client/rpc-servers/src/lib.rs +++ b/client/rpc-servers/src/lib.rs @@ -198,12 +198,11 @@ fn format_allowed_hosts(addrs: &[SocketAddr]) -> Vec { fn build_rpc_api(mut rpc_api: RpcModule) -> RpcModule { let mut available_methods = rpc_api.method_names().collect::>(); - available_methods.sort_unstable(); + available_methods.sort(); rpc_api .register_method("rpc_methods", move |_, _| { Ok(serde_json::json!({ - "version": 1, "methods": available_methods, })) }) diff --git a/client/rpc-spec-v2/Cargo.toml b/client/rpc-spec-v2/Cargo.toml new file mode 100644 index 0000000000000..885d415eb50d2 --- /dev/null +++ b/client/rpc-spec-v2/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "sc-rpc-spec-v2" +version = "0.10.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "Substrate RPC interface v2." +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } +# Internal chain structures for "chain_spec". +sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } +# Pool for submitting extrinsics required by "transaction" +sc-transaction-pool-api = { version = "4.0.0-dev", path = "../transaction-pool/api" } +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } +sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" } +codec = { package = "parity-scale-codec", version = "3.0.0" } +thiserror = "1.0" +serde = "1.0" +hex = "0.4" +futures = "0.3.21" + +[dev-dependencies] +serde_json = "1.0" +tokio = { version = "1.17.0", features = ["macros"] } diff --git a/client/rpc-spec-v2/README.md b/client/rpc-spec-v2/README.md new file mode 100644 index 0000000000000..e860e0c2334da --- /dev/null +++ b/client/rpc-spec-v2/README.md @@ -0,0 +1,5 @@ +Substrate RPC interfaces. + +A collection of RPC methods and subscriptions supported by all substrate clients. + +License: GPL-3.0-or-later WITH Classpath-exception-2.0 \ No newline at end of file diff --git a/client/rpc-spec-v2/src/chain_spec/api.rs b/client/rpc-spec-v2/src/chain_spec/api.rs new file mode 100644 index 0000000000000..dfe2d76de6501 --- /dev/null +++ b/client/rpc-spec-v2/src/chain_spec/api.rs @@ -0,0 +1,53 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! API trait of the chain spec. + +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use sc_chain_spec::Properties; + +#[rpc(client, server)] +pub trait ChainSpecApi { + /// Get the chain name, as present in the chain specification. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[method(name = "chainSpec_unstable_chainName")] + fn chain_spec_unstable_chain_name(&self) -> RpcResult; + + /// Get the chain's genesis hash. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[method(name = "chainSpec_unstable_genesisHash")] + fn chain_spec_unstable_genesis_hash(&self) -> RpcResult; + + /// Get the properties of the chain, as present in the chain specification. + /// + /// # Note + /// + /// The json whitespaces are not guaranteed to persist. + /// + /// # Unstable + /// + /// This method is unstable and subject to change in the future. + #[method(name = "chainSpec_unstable_properties")] + fn chain_spec_unstable_properties(&self) -> RpcResult; +} diff --git a/client/rpc-spec-v2/src/chain_spec/chain_spec.rs b/client/rpc-spec-v2/src/chain_spec/chain_spec.rs new file mode 100644 index 0000000000000..90d05f1d9d41d --- /dev/null +++ b/client/rpc-spec-v2/src/chain_spec/chain_spec.rs @@ -0,0 +1,60 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! API implementation for the specification of a chain. + +use crate::chain_spec::api::ChainSpecApiServer; +use jsonrpsee::core::RpcResult; +use sc_chain_spec::Properties; + +/// An API for chain spec RPC calls. +pub struct ChainSpec { + /// The name of the chain. + name: String, + /// The hexadecimal encoded hash of the genesis block. + genesis_hash: String, + /// Chain properties. + properties: Properties, +} + +impl ChainSpec { + /// Creates a new [`ChainSpec`]. + pub fn new>( + name: String, + genesis_hash: Hash, + properties: Properties, + ) -> Self { + let genesis_hash = format!("0x{}", hex::encode(genesis_hash)); + + Self { name, properties, genesis_hash } + } +} + +impl ChainSpecApiServer for ChainSpec { + fn chain_spec_unstable_chain_name(&self) -> RpcResult { + Ok(self.name.clone()) + } + + fn chain_spec_unstable_genesis_hash(&self) -> RpcResult { + Ok(self.genesis_hash.clone()) + } + + fn chain_spec_unstable_properties(&self) -> RpcResult { + Ok(self.properties.clone()) + } +} diff --git a/client/rpc-spec-v2/src/chain_spec/mod.rs b/client/rpc-spec-v2/src/chain_spec/mod.rs new file mode 100644 index 0000000000000..cd4fcf246f603 --- /dev/null +++ b/client/rpc-spec-v2/src/chain_spec/mod.rs @@ -0,0 +1,38 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Substrate chain specification API. +//! +//! The *chain spec* (short for *chain specification*) allows inspecting the content of +//! the specification of the chain that a JSON-RPC server is targeting. +//! +//! The values returned by the API are guaranteed to never change during the lifetime of the +//! JSON-RPC server. +//! +//! # Note +//! +//! Methods are prefixed by `chainSpec`. + +#[cfg(test)] +mod tests; + +pub mod api; +pub mod chain_spec; + +pub use api::ChainSpecApiServer; +pub use chain_spec::ChainSpec; diff --git a/client/rpc-spec-v2/src/chain_spec/tests.rs b/client/rpc-spec-v2/src/chain_spec/tests.rs new file mode 100644 index 0000000000000..6c078b2974e98 --- /dev/null +++ b/client/rpc-spec-v2/src/chain_spec/tests.rs @@ -0,0 +1,61 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::*; +use jsonrpsee::{types::EmptyParams, RpcModule}; +use sc_chain_spec::Properties; + +const CHAIN_NAME: &'static str = "TEST_CHAIN_NAME"; +const CHAIN_GENESIS: [u8; 32] = [0; 32]; +const CHAIN_PROPERTIES: &'static str = r#"{"three": "123", "one": 1, "two": 12}"#; + +fn api() -> RpcModule { + ChainSpec::new( + CHAIN_NAME.to_string(), + CHAIN_GENESIS, + serde_json::from_str(CHAIN_PROPERTIES).unwrap(), + ) + .into_rpc() +} + +#[tokio::test] +async fn chain_spec_chain_name_works() { + let name = api() + .call::<_, String>("chainSpec_unstable_chainName", EmptyParams::new()) + .await + .unwrap(); + assert_eq!(name, CHAIN_NAME); +} + +#[tokio::test] +async fn chain_spec_genesis_hash_works() { + let genesis = api() + .call::<_, String>("chainSpec_unstable_genesisHash", EmptyParams::new()) + .await + .unwrap(); + assert_eq!(genesis, format!("0x{}", hex::encode(CHAIN_GENESIS))); +} + +#[tokio::test] +async fn chain_spec_properties_works() { + let properties = api() + .call::<_, Properties>("chainSpec_unstable_properties", EmptyParams::new()) + .await + .unwrap(); + assert_eq!(properties, serde_json::from_str(CHAIN_PROPERTIES).unwrap()); +} diff --git a/client/rpc-spec-v2/src/lib.rs b/client/rpc-spec-v2/src/lib.rs new file mode 100644 index 0000000000000..f4b9d2f95bf97 --- /dev/null +++ b/client/rpc-spec-v2/src/lib.rs @@ -0,0 +1,30 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Substrate JSON-RPC interface v2. +//! +//! Specification [document](https://paritytech.github.io/json-rpc-interface-spec/). + +#![warn(missing_docs)] +#![deny(unused_crate_dependencies)] + +pub mod chain_spec; +pub mod transaction; + +/// Task executor that is being used by RPC subscriptions. +pub type SubscriptionTaskExecutor = std::sync::Arc; diff --git a/client/rpc-spec-v2/src/transaction/api.rs b/client/rpc-spec-v2/src/transaction/api.rs new file mode 100644 index 0000000000000..2f0c799f1cc19 --- /dev/null +++ b/client/rpc-spec-v2/src/transaction/api.rs @@ -0,0 +1,37 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! API trait for transactions. + +use crate::transaction::event::TransactionEvent; +use jsonrpsee::proc_macros::rpc; +use sp_core::Bytes; + +#[rpc(client, server)] +pub trait TransactionApi { + /// Submit an extrinsic to watch. + /// + /// See [`TransactionEvent`](crate::transaction::event::TransactionEvent) for details on + /// transaction life cycle. + #[subscription( + name = "transaction_unstable_submitAndWatch" => "transaction_unstable_submitExtrinsic", + unsubscribe = "transaction_unstable_unwatch", + item = TransactionEvent, + )] + fn submit_and_watch(&self, bytes: Bytes); +} diff --git a/client/rpc-spec-v2/src/transaction/error.rs b/client/rpc-spec-v2/src/transaction/error.rs new file mode 100644 index 0000000000000..72a5959992f9e --- /dev/null +++ b/client/rpc-spec-v2/src/transaction/error.rs @@ -0,0 +1,100 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Transaction RPC errors. +//! +//! Errors are interpreted as transaction events for subscriptions. + +use crate::transaction::event::{TransactionError, TransactionEvent}; +use sc_transaction_pool_api::error::Error as PoolError; +use sp_runtime::transaction_validity::InvalidTransaction; + +/// Transaction RPC errors. +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// Transaction pool error. + #[error("Transaction pool error: {}", .0)] + Pool(#[from] PoolError), + /// Verification error. + #[error("Extrinsic verification error: {}", .0)] + Verification(Box), +} + +impl From for TransactionEvent { + fn from(e: Error) -> Self { + match e { + Error::Verification(e) => TransactionEvent::Invalid(TransactionError { + error: format!("Verification error: {}", e), + }), + Error::Pool(PoolError::InvalidTransaction(InvalidTransaction::Custom(e))) => + TransactionEvent::Invalid(TransactionError { + error: format!("Invalid transaction with custom error: {}", e), + }), + Error::Pool(PoolError::InvalidTransaction(e)) => { + let msg: &str = e.into(); + TransactionEvent::Invalid(TransactionError { + error: format!("Invalid transaction: {}", msg), + }) + }, + Error::Pool(PoolError::UnknownTransaction(e)) => { + let msg: &str = e.into(); + TransactionEvent::Invalid(TransactionError { + error: format!("Unknown transaction validity: {}", msg), + }) + }, + Error::Pool(PoolError::TemporarilyBanned) => + TransactionEvent::Invalid(TransactionError { + error: "Transaction is temporarily banned".into(), + }), + Error::Pool(PoolError::AlreadyImported(_)) => + TransactionEvent::Invalid(TransactionError { + error: "Transaction is already imported".into(), + }), + Error::Pool(PoolError::TooLowPriority { old, new }) => + TransactionEvent::Invalid(TransactionError { + error: format!( + "The priority of the transactin is too low (pool {} > current {})", + old, new + ), + }), + Error::Pool(PoolError::CycleDetected) => TransactionEvent::Invalid(TransactionError { + error: "The transaction contains a cyclic dependency".into(), + }), + Error::Pool(PoolError::ImmediatelyDropped) => + TransactionEvent::Invalid(TransactionError { + error: "The transaction could not enter the pool because of the limit".into(), + }), + Error::Pool(PoolError::Unactionable) => TransactionEvent::Invalid(TransactionError { + error: "Transaction cannot be propagated and the local node does not author blocks" + .into(), + }), + Error::Pool(PoolError::NoTagsProvided) => TransactionEvent::Invalid(TransactionError { + error: "Transaction does not provide any tags, so the pool cannot identify it" + .into(), + }), + Error::Pool(PoolError::InvalidBlockId(_)) => + TransactionEvent::Invalid(TransactionError { + error: "The provided block ID is not valid".into(), + }), + Error::Pool(PoolError::RejectedFutureTransaction) => + TransactionEvent::Invalid(TransactionError { + error: "The pool is not accepting future transactions".into(), + }), + } + } +} diff --git a/client/rpc-spec-v2/src/transaction/event.rs b/client/rpc-spec-v2/src/transaction/event.rs new file mode 100644 index 0000000000000..3c75eaff10fd4 --- /dev/null +++ b/client/rpc-spec-v2/src/transaction/event.rs @@ -0,0 +1,353 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! The transaction's event returned as json compatible object. + +use serde::{Deserialize, Serialize}; + +/// The transaction was broadcasted to a number of peers. +/// +/// # Note +/// +/// The RPC does not guarantee that the peers have received the +/// transaction. +/// +/// When the number of peers is zero, the event guarantees that +/// shutting down the local node will lead to the transaction +/// not being included in the chain. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TransactionBroadcasted { + /// The number of peers the transaction was broadcasted to. + #[serde(with = "as_string")] + pub num_peers: usize, +} + +/// The transaction was included in a block of the chain. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TransactionBlock { + /// The hash of the block the transaction was included into. + pub hash: Hash, + /// The index (zero-based) of the transaction within the body of the block. + #[serde(with = "as_string")] + pub index: usize, +} + +/// The transaction could not be processed due to an error. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TransactionError { + /// Reason of the error. + pub error: String, +} + +/// The transaction was dropped because of exceeding limits. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TransactionDropped { + /// True if the transaction was broadcasted to other peers and + /// may still be included in the block. + pub broadcasted: bool, + /// Reason of the event. + pub error: String, +} + +/// Possible transaction status events. +/// +/// The status events can be grouped based on their kinds as: +/// +/// 1. Runtime validated the transaction: +/// - `Validated` +/// +/// 2. Inside the `Ready` queue: +/// - `Broadcast` +/// +/// 3. Leaving the pool: +/// - `BestChainBlockIncluded` +/// - `Invalid` +/// +/// 4. Block finalized: +/// - `Finalized` +/// +/// 5. At any time: +/// - `Dropped` +/// - `Error` +/// +/// The subscription's stream is considered finished whenever the following events are +/// received: `Finalized`, `Error`, `Invalid` or `Dropped`. However, the user is allowed +/// to unsubscribe at any moment. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +// We need to manually specify the trait bounds for the `Hash` trait to ensure `into` and +// `from` still work. +#[serde(bound( + serialize = "Hash: Serialize + Clone", + deserialize = "Hash: Deserialize<'de> + Clone" +))] +#[serde(into = "TransactionEventIR", from = "TransactionEventIR")] +pub enum TransactionEvent { + /// The transaction was validated by the runtime. + Validated, + /// The transaction was broadcasted to a number of peers. + Broadcasted(TransactionBroadcasted), + /// The transaction was included in a best block of the chain. + /// + /// # Note + /// + /// This may contain `None` if the block is no longer a best + /// block of the chain. + BestChainBlockIncluded(Option>), + /// The transaction was included in a finalized block. + Finalized(TransactionBlock), + /// The transaction could not be processed due to an error. + Error(TransactionError), + /// The transaction is marked as invalid. + Invalid(TransactionError), + /// The client was not capable of keeping track of this transaction. + Dropped(TransactionDropped), +} + +/// Intermediate representation (IR) for the transaction events +/// that handles block events only. +/// +/// The block events require a JSON compatible interpretation similar to: +/// +/// ```json +/// { event: "EVENT", block: { hash: "0xFF", index: 0 } } +/// ``` +/// +/// This IR is introduced to circumvent that the block events need to +/// be serialized/deserialized with "tag" and "content", while other +/// events only require "tag". +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(tag = "event", content = "block")] +enum TransactionEventBlockIR { + /// The transaction was included in the best block of the chain. + BestChainBlockIncluded(Option>), + /// The transaction was included in a finalized block of the chain. + Finalized(TransactionBlock), +} + +/// Intermediate representation (IR) for the transaction events +/// that handles non-block events only. +/// +/// The non-block events require a JSON compatible interpretation similar to: +/// +/// ```json +/// { event: "EVENT", num_peers: 0 } +/// ``` +/// +/// This IR is introduced to circumvent that the block events need to +/// be serialized/deserialized with "tag" and "content", while other +/// events only require "tag". +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(tag = "event")] +enum TransactionEventNonBlockIR { + Validated, + Broadcasted(TransactionBroadcasted), + Error(TransactionError), + Invalid(TransactionError), + Dropped(TransactionDropped), +} + +/// Intermediate representation (IR) used for serialization/deserialization of the +/// [`TransactionEvent`] in a JSON compatible format. +/// +/// Serde cannot mix `#[serde(tag = "event")]` with `#[serde(tag = "event", content = "block")]` +/// for specific enum variants. Therefore, this IR is introduced to circumvent this +/// restriction, while exposing a simplified [`TransactionEvent`] for users of the +/// rust ecosystem. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(bound(serialize = "Hash: Serialize", deserialize = "Hash: Deserialize<'de>"))] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +enum TransactionEventIR { + Block(TransactionEventBlockIR), + NonBlock(TransactionEventNonBlockIR), +} + +impl From> for TransactionEventIR { + fn from(value: TransactionEvent) -> Self { + match value { + TransactionEvent::Validated => + TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Validated), + TransactionEvent::Broadcasted(event) => + TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Broadcasted(event)), + TransactionEvent::BestChainBlockIncluded(event) => + TransactionEventIR::Block(TransactionEventBlockIR::BestChainBlockIncluded(event)), + TransactionEvent::Finalized(event) => + TransactionEventIR::Block(TransactionEventBlockIR::Finalized(event)), + TransactionEvent::Error(event) => + TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Error(event)), + TransactionEvent::Invalid(event) => + TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Invalid(event)), + TransactionEvent::Dropped(event) => + TransactionEventIR::NonBlock(TransactionEventNonBlockIR::Dropped(event)), + } + } +} + +impl From> for TransactionEvent { + fn from(value: TransactionEventIR) -> Self { + match value { + TransactionEventIR::NonBlock(status) => match status { + TransactionEventNonBlockIR::Validated => TransactionEvent::Validated, + TransactionEventNonBlockIR::Broadcasted(event) => + TransactionEvent::Broadcasted(event), + TransactionEventNonBlockIR::Error(event) => TransactionEvent::Error(event), + TransactionEventNonBlockIR::Invalid(event) => TransactionEvent::Invalid(event), + TransactionEventNonBlockIR::Dropped(event) => TransactionEvent::Dropped(event), + }, + TransactionEventIR::Block(block) => match block { + TransactionEventBlockIR::Finalized(event) => TransactionEvent::Finalized(event), + TransactionEventBlockIR::BestChainBlockIncluded(event) => + TransactionEvent::BestChainBlockIncluded(event), + }, + } + } +} + +/// Serialize and deserialize helper as string. +mod as_string { + use super::*; + use serde::{Deserializer, Serializer}; + + pub fn serialize(data: &usize, serializer: S) -> Result { + data.to_string().serialize(serializer) + } + + pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result { + String::deserialize(deserializer)? + .parse() + .map_err(|e| serde::de::Error::custom(format!("Parsing failed: {}", e))) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sp_core::H256; + + #[test] + fn validated_event() { + let event: TransactionEvent<()> = TransactionEvent::Validated; + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"event":"validated"}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn broadcasted_event() { + let event: TransactionEvent<()> = + TransactionEvent::Broadcasted(TransactionBroadcasted { num_peers: 2 }); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"event":"broadcasted","numPeers":"2"}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn best_chain_event() { + let event: TransactionEvent<()> = TransactionEvent::BestChainBlockIncluded(None); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"event":"bestChainBlockIncluded","block":null}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + + let event: TransactionEvent = + TransactionEvent::BestChainBlockIncluded(Some(TransactionBlock { + hash: H256::from_low_u64_be(1), + index: 2, + })); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"event":"bestChainBlockIncluded","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":"2"}}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionEvent = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn finalized_event() { + let event: TransactionEvent = TransactionEvent::Finalized(TransactionBlock { + hash: H256::from_low_u64_be(1), + index: 10, + }); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"event":"finalized","block":{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","index":"10"}}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionEvent = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn error_event() { + let event: TransactionEvent<()> = + TransactionEvent::Error(TransactionError { error: "abc".to_string() }); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"event":"error","error":"abc"}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn invalid_event() { + let event: TransactionEvent<()> = + TransactionEvent::Invalid(TransactionError { error: "abc".to_string() }); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"event":"invalid","error":"abc"}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } + + #[test] + fn dropped_event() { + let event: TransactionEvent<()> = TransactionEvent::Dropped(TransactionDropped { + broadcasted: true, + error: "abc".to_string(), + }); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"event":"dropped","broadcasted":true,"error":"abc"}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionEvent<()> = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, event); + } +} diff --git a/client/rpc-spec-v2/src/transaction/mod.rs b/client/rpc-spec-v2/src/transaction/mod.rs new file mode 100644 index 0000000000000..bb983894a428c --- /dev/null +++ b/client/rpc-spec-v2/src/transaction/mod.rs @@ -0,0 +1,38 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Substrate transaction API. +//! +//! The transaction methods allow submitting a transaction and subscribing to +//! its status updates generated by the chain. +//! +//! # Note +//! +//! Methods are prefixed by `transaction`. + +pub mod api; +pub mod error; +pub mod event; +pub mod transaction; + +pub use api::TransactionApiServer; +pub use event::{ + TransactionBlock, TransactionBroadcasted, TransactionDropped, TransactionError, + TransactionEvent, +}; +pub use transaction::Transaction; diff --git a/client/rpc-spec-v2/src/transaction/transaction.rs b/client/rpc-spec-v2/src/transaction/transaction.rs new file mode 100644 index 0000000000000..e2cf736dff17a --- /dev/null +++ b/client/rpc-spec-v2/src/transaction/transaction.rs @@ -0,0 +1,208 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! API implementation for submitting transactions. + +use crate::{ + transaction::{ + api::TransactionApiServer, + error::Error, + event::{ + TransactionBlock, TransactionBroadcasted, TransactionDropped, TransactionError, + TransactionEvent, + }, + }, + SubscriptionTaskExecutor, +}; +use jsonrpsee::{ + core::async_trait, + types::{ + error::{CallError, ErrorObject}, + SubscriptionResult, + }, + SubscriptionSink, +}; +use sc_transaction_pool_api::{ + error::IntoPoolError, BlockHash, TransactionFor, TransactionPool, TransactionSource, + TransactionStatus, +}; +use std::sync::Arc; + +use sp_api::ProvideRuntimeApi; +use sp_blockchain::HeaderBackend; +use sp_core::Bytes; +use sp_runtime::{generic, traits::Block as BlockT}; + +use codec::Decode; +use futures::{FutureExt, StreamExt, TryFutureExt}; + +/// An API for transaction RPC calls. +pub struct Transaction { + /// Substrate client. + client: Arc, + /// Transactions pool. + pool: Arc, + /// Executor to spawn subscriptions. + executor: SubscriptionTaskExecutor, +} + +impl Transaction { + /// Creates a new [`Transaction`]. + pub fn new(client: Arc, pool: Arc, executor: SubscriptionTaskExecutor) -> Self { + Transaction { client, pool, executor } + } +} + +/// Currently we treat all RPC transactions as externals. +/// +/// Possibly in the future we could allow opt-in for special treatment +/// of such transactions, so that the block authors can inject +/// some unique transactions via RPC and have them included in the pool. +const TX_SOURCE: TransactionSource = TransactionSource::External; + +/// Extrinsic has an invalid format. +/// +/// # Note +/// +/// This is similar to the old `author` API error code. +const BAD_FORMAT: i32 = 1001; + +#[async_trait] +impl TransactionApiServer> for Transaction +where + Pool: TransactionPool + Sync + Send + 'static, + Pool::Hash: Unpin, + ::Hash: Unpin, + Client: HeaderBackend + ProvideRuntimeApi + Send + Sync + 'static, +{ + fn submit_and_watch(&self, mut sink: SubscriptionSink, xt: Bytes) -> SubscriptionResult { + // This is the only place where the RPC server can return an error for this + // subscription. Other defects must be signaled as events to the sink. + let decoded_extrinsic = match TransactionFor::::decode(&mut &xt[..]) { + Ok(decoded_extrinsic) => decoded_extrinsic, + Err(e) => { + let err = CallError::Custom(ErrorObject::owned( + BAD_FORMAT, + format!("Extrinsic has invalid format: {}", e), + None::<()>, + )); + let _ = sink.reject(err); + return Ok(()) + }, + }; + + let best_block_hash = self.client.info().best_hash; + + let submit = self + .pool + .submit_and_watch( + &generic::BlockId::hash(best_block_hash), + TX_SOURCE, + decoded_extrinsic, + ) + .map_err(|e| { + e.into_pool_error() + .map(Error::from) + .unwrap_or_else(|e| Error::Verification(Box::new(e))) + }); + + let fut = async move { + match submit.await { + Ok(stream) => { + let mut state = TransactionState::new(); + let stream = + stream.filter_map(|event| async move { state.handle_event(event) }); + sink.pipe_from_stream(stream.boxed()).await; + }, + Err(err) => { + // We have not created an `Watcher` for the tx. Make sure the + // error is still propagated as an event. + let event: TransactionEvent<::Hash> = err.into(); + sink.pipe_from_stream(futures::stream::once(async { event }).boxed()).await; + }, + }; + }; + + self.executor.spawn("substrate-rpc-subscription", Some("rpc"), fut.boxed()); + Ok(()) + } +} + +/// The transaction's state that needs to be preserved between +/// multiple events generated by the transaction-pool. +/// +/// # Note +/// +/// In the future, the RPC server can submit only the last event when multiple +/// identical events happen in a row. +#[derive(Clone, Copy)] +struct TransactionState { + /// True if the transaction was previously broadcasted. + broadcasted: bool, +} + +impl TransactionState { + /// Construct a new [`TransactionState`]. + pub fn new() -> Self { + TransactionState { broadcasted: false } + } + + /// Handle events generated by the transaction-pool and convert them + /// to the new API expected state. + #[inline] + pub fn handle_event( + &mut self, + event: TransactionStatus, + ) -> Option> { + match event { + TransactionStatus::Ready | TransactionStatus::Future => + Some(TransactionEvent::::Validated), + TransactionStatus::Broadcast(peers) => { + // Set the broadcasted flag once if we submitted the transaction to + // at least one peer. + self.broadcasted = self.broadcasted || !peers.is_empty(); + + Some(TransactionEvent::Broadcasted(TransactionBroadcasted { + num_peers: peers.len(), + })) + }, + TransactionStatus::InBlock((hash, index)) => + Some(TransactionEvent::BestChainBlockIncluded(Some(TransactionBlock { + hash, + index, + }))), + TransactionStatus::Retracted(_) => Some(TransactionEvent::BestChainBlockIncluded(None)), + TransactionStatus::FinalityTimeout(_) => + Some(TransactionEvent::Dropped(TransactionDropped { + broadcasted: self.broadcasted, + error: "Maximum number of finality watchers has been reached".into(), + })), + TransactionStatus::Finalized((hash, index)) => + Some(TransactionEvent::Finalized(TransactionBlock { hash, index })), + TransactionStatus::Usurped(_) => Some(TransactionEvent::Invalid(TransactionError { + error: "Extrinsic was rendered invalid by another extrinsic".into(), + })), + TransactionStatus::Dropped => Some(TransactionEvent::Invalid(TransactionError { + error: "Extrinsic dropped from the pool due to exceeding limits".into(), + })), + TransactionStatus::Invalid => Some(TransactionEvent::Invalid(TransactionError { + error: "Extrinsic marked as invalid".into(), + })), + } + } +} diff --git a/client/rpc/src/dev/tests.rs b/client/rpc/src/dev/tests.rs index f3b18690d0972..816f3cdfe6025 100644 --- a/client/rpc/src/dev/tests.rs +++ b/client/rpc/src/dev/tests.rs @@ -43,8 +43,8 @@ async fn block_stats_work() { .await .unwrap(), Some(BlockStats { - witness_len: 597, - witness_compact_len: 500, + witness_len: 630, + witness_compact_len: 534, block_len: 99, num_extrinsics: 0, }), diff --git a/client/rpc/src/state/state_full.rs b/client/rpc/src/state/state_full.rs index 42ba70b0af7e7..d6ab93f7680b0 100644 --- a/client/rpc/src/state/state_full.rs +++ b/client/rpc/src/state/state_full.rs @@ -145,10 +145,9 @@ where ) -> Result<()> { for block_hash in &range.hashes { let mut block_changes = StorageChangeSet { block: *block_hash, changes: Vec::new() }; - let id = BlockId::hash(*block_hash); for key in keys { let (has_changed, data) = { - let curr_data = self.client.storage(&id, key).map_err(client_err)?; + let curr_data = self.client.storage(block_hash, key).map_err(client_err)?; match last_values.get(key) { Some(prev_data) => (curr_data != *prev_data, curr_data), None => (true, curr_data), @@ -214,7 +213,7 @@ where prefix: StorageKey, ) -> std::result::Result, Error> { self.block_or_best(block) - .and_then(|block| self.client.storage_keys(&BlockId::Hash(block), &prefix)) + .and_then(|block| self.client.storage_keys(&block, &prefix)) .map_err(client_err) } @@ -224,7 +223,7 @@ where prefix: StorageKey, ) -> std::result::Result, Error> { self.block_or_best(block) - .and_then(|block| self.client.storage_pairs(&BlockId::Hash(block), &prefix)) + .and_then(|block| self.client.storage_pairs(&block, &prefix)) .map_err(client_err) } @@ -237,11 +236,7 @@ where ) -> std::result::Result, Error> { self.block_or_best(block) .and_then(|block| { - self.client.storage_keys_iter( - &BlockId::Hash(block), - prefix.as_ref(), - start_key.as_ref(), - ) + self.client.storage_keys_iter(&block, prefix.as_ref(), start_key.as_ref()) }) .map(|iter| iter.take(count as usize).collect()) .map_err(client_err) @@ -253,7 +248,7 @@ where key: StorageKey, ) -> std::result::Result, Error> { self.block_or_best(block) - .and_then(|block| self.client.storage(&BlockId::Hash(block), &key)) + .and_then(|block| self.client.storage(&block, &key)) .map_err(client_err) } @@ -267,14 +262,14 @@ where Err(e) => return Err(client_err(e)), }; - match self.client.storage(&BlockId::Hash(block), &key) { + match self.client.storage(&block, &key) { Ok(Some(d)) => return Ok(Some(d.0.len() as u64)), Err(e) => return Err(client_err(e)), Ok(None) => {}, } self.client - .storage_pairs(&BlockId::Hash(block), &key) + .storage_pairs(&block, &key) .map(|kv| { let item_sum = kv.iter().map(|(_, v)| v.0.len() as u64).sum::(); if item_sum > 0 { @@ -292,7 +287,7 @@ where key: StorageKey, ) -> std::result::Result, Error> { self.block_or_best(block) - .and_then(|block| self.client.storage_hash(&BlockId::Hash(block), &key)) + .and_then(|block| self.client.storage_hash(&block, &key)) .map_err(client_err) } @@ -418,7 +413,7 @@ where let changes = keys .into_iter() .map(|key| { - let v = self.client.storage(&BlockId::Hash(block), &key).ok().flatten(); + let v = self.client.storage(&block, &key).ok().flatten(); (key, v) }) .collect(); @@ -522,7 +517,7 @@ where ChildInfo::new_default(storage_key), None => return Err(sp_blockchain::Error::InvalidChildStorageKey), }; - self.client.child_storage_keys(&BlockId::Hash(block), &child_info, &prefix) + self.client.child_storage_keys(&block, &child_info, &prefix) }) .map_err(client_err) } @@ -543,7 +538,7 @@ where None => return Err(sp_blockchain::Error::InvalidChildStorageKey), }; self.client.child_storage_keys_iter( - &BlockId::Hash(block), + &block, child_info, prefix.as_ref(), start_key.as_ref(), @@ -566,7 +561,7 @@ where ChildInfo::new_default(storage_key), None => return Err(sp_blockchain::Error::InvalidChildStorageKey), }; - self.client.child_storage(&BlockId::Hash(block), &child_info, &key) + self.client.child_storage(&block, &child_info, &key) }) .map_err(client_err) } @@ -589,10 +584,7 @@ where keys.into_iter() .map(move |key| { - client - .clone() - .child_storage(&BlockId::Hash(block), &child_info, &key) - .map_err(client_err) + client.clone().child_storage(&block, &child_info, &key).map_err(client_err) }) .collect() } @@ -610,7 +602,7 @@ where ChildInfo::new_default(storage_key), None => return Err(sp_blockchain::Error::InvalidChildStorageKey), }; - self.client.child_storage_hash(&BlockId::Hash(block), &child_info, &key) + self.client.child_storage_hash(&block, &child_info, &key) }) .map_err(client_err) } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 12e30c631eec2..d76e32b42843b 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -20,6 +20,7 @@ rocksdb = ["sc-client-db/rocksdb"] wasmtime = ["sc-executor/wasmtime"] # exposes the client type test-helpers = [] +runtime-benchmarks = ["sc-client-db/runtime-benchmarks"] [dependencies] jsonrpsee = { version = "0.15.1", features = ["server"] } @@ -30,7 +31,7 @@ parking_lot = "0.12.1" log = "0.4.17" futures-timer = "3.0.1" exit-future = "0.2.0" -pin-project = "1.0.10" +pin-project = "1.0.12" hash-db = "0.15.2" serde = "1.0.136" serde_json = "1.0.85" @@ -51,9 +52,11 @@ sc-consensus = { version = "0.10.0-dev", path = "../../client/consensus/common" sp-inherents = { version = "4.0.0-dev", path = "../../primitives/inherents" } sp-storage = { version = "6.0.0", path = "../../primitives/storage" } sc-network = { version = "0.10.0-dev", path = "../network" } +sc-network-bitswap = { version = "0.10.0-dev", path = "../network/bitswap" } sc-network-common = { version = "0.10.0-dev", path = "../network/common" } sc-network-light = { version = "0.10.0-dev", path = "../network/light" } sc-network-sync = { version = "0.10.0-dev", path = "../network/sync" } +sc-network-transactions = { version = "0.10.0-dev", path = "../network/transactions" } sc-chain-spec = { version = "4.0.0-dev", path = "../chain-spec" } sc-client-api = { version = "4.0.0-dev", path = "../api" } sp-api = { version = "4.0.0-dev", path = "../../primitives/api" } @@ -67,6 +70,7 @@ sp-transaction-storage-proof = { version = "4.0.0-dev", path = "../../primitives ver-api = { version = "4.0.0-dev", path = "../../primitives/ver-api" } sc-rpc-server = { version = "4.0.0-dev", path = "../rpc-servers" } sc-rpc = { version = "4.0.0-dev", path = "../rpc" } +sc-rpc-spec-v2 = { version = "0.10.0-dev", path = "../rpc-spec-v2" } sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sc-block-builder-ver = { version = "0.10.0-dev", path = "../block-builder-ver" } sp-block-builder = { version = "4.0.0-dev", path = "../../primitives/block-builder" } @@ -79,13 +83,14 @@ sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } sc-sysinfo = { version = "6.0.0-dev", path = "../sysinfo" } tracing = "0.1.29" tracing-futures = { version = "0.2.4" } -parity-util-mem = { version = "0.11.0", default-features = false, features = [ +parity-util-mem = { version = "0.12.0", default-features = false, features = [ "primitive-types", ] } async-trait = "0.1.57" tokio = { version = "1.17.0", features = ["time", "rt-multi-thread", "parking_lot"] } tempfile = "3.1.0" directories = "4.0.1" +static_init = "1.0.3" [dev-dependencies] substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index f03ba6de2866d..1a16268839054 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -37,9 +37,11 @@ use sc_client_db::{Backend, DatabaseSettings}; use sc_consensus::import_queue::ImportQueue; use sc_executor::RuntimeVersionOf; use sc_keystore::LocalKeystore; -use sc_network::{bitswap::Bitswap, config::SyncMode, NetworkService}; +use sc_network::{config::SyncMode, NetworkService}; +use sc_network_bitswap::BitswapRequestHandler; use sc_network_common::{ - service::{NetworkStateInfo, NetworkStatusProvider, NetworkTransaction}, + protocol::role::Roles, + service::{NetworkStateInfo, NetworkStatusProvider}, sync::warp::WarpSyncProvider, }; use sc_network_light::light_client_requests::handler::LightClientRequestHandler; @@ -55,6 +57,7 @@ use sc_rpc::{ system::SystemApiServer, DenyUnsafe, SubscriptionTaskExecutor, }; +use sc_rpc_spec_v2::transaction::TransactionApiServer; use sc_telemetry::{telemetry, ConnectionMessage, Telemetry, TelemetryHandle, SUBSTRATE_INFO}; use sc_transaction_pool_api::MaintainedTransactionPool; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; @@ -325,7 +328,6 @@ where pub trait SpawnTaskNetwork: sc_offchain::NetworkProvider + NetworkStateInfo - + NetworkTransaction + NetworkStatusProvider + Send + Sync @@ -338,7 +340,6 @@ where Block: BlockT, T: sc_offchain::NetworkProvider + NetworkStateInfo - + NetworkTransaction + NetworkStatusProvider + Send + Sync @@ -367,6 +368,9 @@ pub struct SpawnTasksParams<'a, TBl: BlockT, TCl, TExPool, TRpc, Backend> { pub network: Arc>, /// A Sender for RPC requests. pub system_rpc_tx: TracingUnboundedSender>, + /// Controller for transactions handlers + pub tx_handler_controller: + sc_network_transactions::TransactionsHandlerController<::Hash>, /// Telemetry instance for this node. pub telemetry: Option<&'a mut Telemetry>, } @@ -445,6 +449,7 @@ where rpc_builder, network, system_rpc_tx, + tx_handler_controller, telemetry, } = params; @@ -480,7 +485,11 @@ where spawn_handle.spawn( "on-transaction-imported", Some("transaction-pool"), - transaction_notifications(transaction_pool.clone(), network.clone(), telemetry.clone()), + transaction_notifications( + transaction_pool.clone(), + tx_handler_controller, + telemetry.clone(), + ), ); // Prometheus metrics. @@ -543,20 +552,21 @@ where Ok(rpc_handlers) } -async fn transaction_notifications( +async fn transaction_notifications( transaction_pool: Arc, - network: Network, + tx_handler_controller: sc_network_transactions::TransactionsHandlerController< + ::Hash, + >, telemetry: Option, ) where Block: BlockT, ExPool: MaintainedTransactionPool::Hash>, - Network: NetworkTransaction<::Hash> + Send + Sync, { // transaction notifications transaction_pool .import_notification_stream() .for_each(move |hash| { - network.propagate_transaction(hash); + tx_handler_controller.propagate_transaction(hash); let status = transaction_pool.status(); telemetry!( telemetry; @@ -664,6 +674,13 @@ where (chain, state, child_state) }; + let transaction_v2 = sc_rpc_spec_v2::transaction::Transaction::new( + client.clone(), + transaction_pool.clone(), + task_executor.clone(), + ) + .into_rpc(); + let author = sc_rpc::author::Author::new( client.clone(), transaction_pool, @@ -681,6 +698,10 @@ where rpc_api.merge(offchain).map_err(|e| Error::Application(e.into()))?; } + // Part of the RPC v2 spec. + rpc_api.merge(transaction_v2).map_err(|e| Error::Application(e.into()))?; + + // Part of the old RPC spec. rpc_api.merge(chain).map_err(|e| Error::Application(e.into()))?; rpc_api.merge(author).map_err(|e| Error::Application(e.into()))?; rpc_api.merge(system).map_err(|e| Error::Application(e.into()))?; @@ -718,6 +739,7 @@ pub fn build_network( ( Arc::Hash>>, TracingUnboundedSender>, + sc_network_transactions::TransactionsHandlerController<::Hash>, NetworkStarter, ), Error, @@ -746,6 +768,8 @@ where warp_sync, } = params; + let mut request_response_protocol_configs = Vec::new(); + if warp_sync.is_none() && config.network.sync_mode.is_warp() { return Err("Warp sync enabled, but no warp sync provider configured.".into()) } @@ -758,9 +782,6 @@ where } } - let transaction_pool_adapter = - Arc::new(TransactionPoolAdapter { pool: transaction_pool, client: client.clone() }); - let protocol_id = config.protocol_id(); let block_announce_validator = if let Some(f) = block_announce_validator_builder { @@ -823,7 +844,7 @@ where protocol_config }; - let chain_sync = ChainSync::new( + let (chain_sync, chain_sync_service) = ChainSync::new( match config.network.sync_mode { SyncMode::Full => sc_network_common::sync::SyncMode::Full, SyncMode::Fast { skip_proofs, storage_chain_mode } => @@ -835,7 +856,26 @@ where config.network.max_parallel_downloads, warp_sync_provider, )?; - let network_params = sc_network::config::Params { + let block_announce_config = chain_sync.get_block_announce_proto_config( + protocol_id.clone(), + &config.chain_spec.fork_id().map(ToOwned::to_owned), + Roles::from(&config.role.clone()), + client.info().best_number, + client.info().best_hash, + client + .block_hash(Zero::zero()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + ); + + request_response_protocol_configs.push(config.network.ipfs_server.then(|| { + let (handler, protocol_config) = BitswapRequestHandler::new(client.clone()); + spawn_handle.spawn("bitswap-request-handler", Some("networking"), handler.run()); + protocol_config + })); + + let mut network_params = sc_network::config::Params { role: config.role.clone(), executor: { let spawn_handle = Clone::clone(&spawn_handle); @@ -843,31 +883,51 @@ where spawn_handle.spawn("libp2p-node", Some("networking"), fut); })) }, - transactions_handler_executor: { - let spawn_handle = Clone::clone(&spawn_handle); - Box::new(move |fut| { - spawn_handle.spawn("network-transactions-handler", Some("networking"), fut); - }) - }, network_config: config.network.clone(), chain: client.clone(), - transaction_pool: transaction_pool_adapter as _, - protocol_id, + protocol_id: protocol_id.clone(), fork_id: config.chain_spec.fork_id().map(ToOwned::to_owned), import_queue: Box::new(import_queue), chain_sync: Box::new(chain_sync), - bitswap: config.network.ipfs_server.then(|| Bitswap::from_client(client.clone())), + chain_sync_service, metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), + block_announce_config, block_request_protocol_config, state_request_protocol_config, warp_sync_protocol_config, light_client_request_protocol_config, + request_response_protocol_configs: request_response_protocol_configs + .into_iter() + .flatten() + .collect::>(), }; + // crate transactions protocol and add it to the list of supported protocols of `network_params` + let transactions_handler_proto = sc_network_transactions::TransactionsHandlerPrototype::new( + protocol_id.clone(), + client + .block_hash(0u32.into()) + .ok() + .flatten() + .expect("Genesis block exists; qed"), + config.chain_spec.fork_id(), + ); + network_params + .network_config + .extra_sets + .insert(0, transactions_handler_proto.set_config()); + let has_bootnodes = !network_params.network_config.boot_nodes.is_empty(); let network_mut = sc_network::NetworkWorker::new(network_params)?; let network = network_mut.service().clone(); + let (tx_handler, tx_handler_controller) = transactions_handler_proto.build( + network.clone(), + Arc::new(TransactionPoolAdapter { pool: transaction_pool, client: client.clone() }), + config.prometheus_config.as_ref().map(|config| &config.registry), + )?; + spawn_handle.spawn("network-transactions-handler", Some("networking"), tx_handler.run()); + let (system_rpc_tx, system_rpc_rx) = tracing_unbounded("mpsc_system_rpc"); let future = build_network_future( @@ -915,7 +975,7 @@ where future.await }); - Ok((network, system_rpc_tx, NetworkStarter(network_start_tx))) + Ok((network, system_rpc_tx, tx_handler_controller, NetworkStarter(network_start_tx))) } /// Object used to start the network. diff --git a/client/service/src/chain_ops/export_raw_state.rs b/client/service/src/chain_ops/export_raw_state.rs index ffe91d0d7355e..04dba387de908 100644 --- a/client/service/src/chain_ops/export_raw_state.rs +++ b/client/service/src/chain_ops/export_raw_state.rs @@ -19,25 +19,20 @@ use crate::error::Error; use sc_client_api::{StorageProvider, UsageProvider}; use sp_core::storage::{well_known_keys, ChildInfo, Storage, StorageChild, StorageKey, StorageMap}; -use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use sp_runtime::traits::Block as BlockT; use std::{collections::HashMap, sync::Arc}; /// Export the raw state at the given `block`. If `block` is `None`, the /// best block will be used. -pub fn export_raw_state( - client: Arc, - block: Option>, -) -> Result +pub fn export_raw_state(client: Arc, hash: &B::Hash) -> Result where C: UsageProvider + StorageProvider, B: BlockT, BA: sc_client_api::backend::Backend, { - let block = block.unwrap_or_else(|| BlockId::Hash(client.usage_info().chain.best_hash)); - let empty_key = StorageKey(Vec::new()); - let mut top_storage = client.storage_pairs(&block, &empty_key)?; + let mut top_storage = client.storage_pairs(hash, &empty_key)?; let mut children_default = HashMap::new(); // Remove all default child storage roots from the top storage and collect the child storage @@ -52,10 +47,10 @@ where StorageKey(key.0[well_known_keys::DEFAULT_CHILD_STORAGE_KEY_PREFIX.len()..].to_vec()); let child_info = ChildInfo::new_default(&key.0); - let keys = client.child_storage_keys(&block, &child_info, &empty_key)?; + let keys = client.child_storage_keys(hash, &child_info, &empty_key)?; let mut pairs = StorageMap::new(); keys.into_iter().try_for_each(|k| { - if let Some(value) = client.child_storage(&block, &child_info, &k)? { + if let Some(value) = client.child_storage(hash, &child_info, &k)? { pairs.insert(k.0, value.0); } diff --git a/client/service/src/client/call_executor.rs b/client/service/src/client/call_executor.rs index de851ac848919..8ab332a24be78 100644 --- a/client/service/src/client/call_executor.rs +++ b/client/service/src/client/call_executor.rs @@ -17,21 +17,17 @@ // along with this program. If not, see . use super::{client::ClientConfig, wasm_override::WasmOverride, wasm_substitutes::WasmSubstitutes}; -use codec::{Decode, Encode}; use sc_client_api::{backend, call_executor::CallExecutor, HeaderBackend}; use sc_executor::{RuntimeVersion, RuntimeVersionOf}; use sp_api::{ProofRecorder, StorageTransactionCache}; -use sp_core::{ - traits::{CodeExecutor, RuntimeCode, SpawnNamed}, - NativeOrEncoded, NeverNativeValue, -}; +use sp_core::traits::{CodeExecutor, RuntimeCode, SpawnNamed}; use sp_externalities::Extensions; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; use sp_state_machine::{ backend::AsTrieBackend, ExecutionManager, ExecutionStrategy, Ext, OverlayedChanges, StateMachine, StorageProof, }; -use std::{cell::RefCell, panic::UnwindSafe, result, sync::Arc}; +use std::{cell::RefCell, sync::Arc}; /// Call executor that executes methods locally, querying all required /// data from local backend. @@ -151,18 +147,15 @@ where extensions: Option, ) -> sp_blockchain::Result> { let mut changes = OverlayedChanges::default(); - let state = self.backend.state_at(*at)?; + let at_hash = self.backend.blockchain().expect_block_hash_from_id(at)?; + let state = self.backend.state_at(&at_hash)?; let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state); let runtime_code = state_runtime_code.runtime_code().map_err(sp_blockchain::Error::RuntimeCode)?; let runtime_code = self.check_override(runtime_code, at)?; - let at_hash = self.backend.blockchain().block_hash_from_id(at)?.ok_or_else(|| { - sp_blockchain::Error::UnknownBlock(format!("Could not find block hash for {:?}", at)) - })?; - - let return_data = StateMachine::new( + let mut sm = StateMachine::new( &state, &mut changes, &self.executor, @@ -172,22 +165,17 @@ where &runtime_code, self.spawn_handle.clone(), ) - .set_parent_hash(at_hash) - .execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( - strategy.get_manager(), - None, - )?; + .set_parent_hash(at_hash); - Ok(return_data.into_encoded()) + sm.execute_using_consensus_failure_handler(strategy.get_manager()) + .map_err(Into::into) } fn contextual_call< EM: Fn( - Result, Self::Error>, - Result, Self::Error>, - ) -> Result, Self::Error>, - R: Encode + Decode + PartialEq, - NC: FnOnce() -> result::Result + UnwindSafe, + Result, Self::Error>, + Result, Self::Error>, + ) -> Result, Self::Error>, >( &self, at: &BlockId, @@ -196,23 +184,19 @@ where changes: &RefCell, storage_transaction_cache: Option<&RefCell>>, execution_manager: ExecutionManager, - native_call: Option, recorder: &Option>, extensions: Option, - ) -> Result, sp_blockchain::Error> + ) -> Result, sp_blockchain::Error> where ExecutionManager: Clone, { let mut storage_transaction_cache = storage_transaction_cache.map(|c| c.borrow_mut()); - let state = self.backend.state_at(*at)?; + let at_hash = self.backend.blockchain().expect_block_hash_from_id(at)?; + let state = self.backend.state_at(&at_hash)?; let changes = &mut *changes.borrow_mut(); - let at_hash = self.backend.blockchain().block_hash_from_id(at)?.ok_or_else(|| { - sp_blockchain::Error::UnknownBlock(format!("Could not find block hash for {:?}", at)) - })?; - // It is important to extract the runtime code here before we create the proof // recorder to not record it. We also need to fetch the runtime code from `state` to // make sure we use the caching layers. @@ -242,10 +226,7 @@ where ) .with_storage_transaction_cache(storage_transaction_cache.as_deref_mut()) .set_parent_hash(at_hash); - state_machine.execute_using_consensus_failure_handler( - execution_manager, - native_call.map(|n| || (n)().map_err(|e| Box::new(e) as Box<_>)), - ) + state_machine.execute_using_consensus_failure_handler(execution_manager) }, None => { let mut state_machine = StateMachine::new( @@ -260,10 +241,7 @@ where ) .with_storage_transaction_cache(storage_transaction_cache.as_deref_mut()) .set_parent_hash(at_hash); - state_machine.execute_using_consensus_failure_handler( - execution_manager, - native_call.map(|n| || (n)().map_err(|e| Box::new(e) as Box<_>)), - ) + state_machine.execute_using_consensus_failure_handler(execution_manager) }, } .map_err(Into::into) @@ -271,7 +249,9 @@ where fn runtime_version(&self, id: &BlockId) -> sp_blockchain::Result { let mut overlay = OverlayedChanges::default(); - let state = self.backend.state_at(*id)?; + + let at_hash = self.backend.blockchain().expect_block_hash_from_id(id)?; + let state = self.backend.state_at(&at_hash)?; let mut cache = StorageTransactionCache::::default(); let mut ext = Ext::new(&mut overlay, &mut cache, &state, None); let state_runtime_code = sp_state_machine::backend::BackendRuntimeCode::new(&state); @@ -288,7 +268,8 @@ where method: &str, call_data: &[u8], ) -> sp_blockchain::Result<(Vec, StorageProof)> { - let state = self.backend.state_at(*at)?; + let at_hash = self.backend.blockchain().expect_block_hash_from_id(at)?; + let state = self.backend.state_at(&at_hash)?; let trie_backend = state.as_trie_backend(); diff --git a/client/service/src/client/client.rs b/client/service/src/client/client.rs index d05268d50a84e..5a389498908d2 100644 --- a/client/service/src/client/client.rs +++ b/client/service/src/client/client.rs @@ -22,7 +22,6 @@ use super::{ block_rules::{BlockRules, LookupResult as BlockLookupResult}, genesis, }; -use codec::{Decode, Encode}; use log::{info, trace, warn}; use parking_lot::{Mutex, RwLock}; use prometheus_endpoint::Registry; @@ -64,12 +63,9 @@ use sp_consensus::{BlockOrigin, BlockStatus, Error as ConsensusError}; use ver_api::VerApi; use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; -use sp_core::{ - storage::{ - well_known_keys, ChildInfo, ChildType, PrefixedStorageKey, Storage, StorageChild, - StorageData, StorageKey, - }, - NativeOrEncoded, +use sp_core::storage::{ + well_known_keys, ChildInfo, ChildType, PrefixedStorageKey, Storage, StorageChild, StorageData, + StorageKey, }; #[cfg(feature = "test-helpers")] use sp_keystore::SyncCryptoStorePtr; @@ -90,9 +86,7 @@ use sp_trie::{CompactProof, StorageProof}; use std::{ collections::{hash_map::DefaultHasher, HashMap, HashSet}, marker::PhantomData, - panic::UnwindSafe, path::PathBuf, - result, sync::Arc, }; @@ -425,13 +419,14 @@ where } /// Get a reference to the state at a given block. - pub fn state_at(&self, block: &BlockId) -> sp_blockchain::Result { - self.backend.state_at(*block) + pub fn state_at(&self, hash: &Block::Hash) -> sp_blockchain::Result { + self.backend.state_at(hash) } /// Get the code at a given block. pub fn code_at(&self, id: &BlockId) -> sp_blockchain::Result> { - Ok(StorageProvider::storage(self, id, &StorageKey(well_known_keys::CODE.to_vec()))? + let hash = self.backend.blockchain().expect_block_hash_from_id(id)?; + Ok(StorageProvider::storage(self, &hash, &StorageKey(well_known_keys::CODE.to_vec()))? .expect( "None is returned if there's no value stored for the given key;\ ':code' key is always defined; qed", @@ -824,7 +819,7 @@ where Block::new(import_block.header.clone(), body.clone()), )?; - let state = self.backend.state_at(at)?; + let state = self.backend.state_at(parent_hash)?; let gen_storage_changes = runtime_api .into_storage_changes(&state, *parent_hash) .map_err(sp_blockchain::Error::Storage)?; @@ -1165,7 +1160,9 @@ where id: &BlockId, keys: &mut dyn Iterator, ) -> sp_blockchain::Result { - self.state_at(id).and_then(|state| prove_read(state, keys).map_err(Into::into)) + let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; + self.state_at(&hash) + .and_then(|state| prove_read(state, keys).map_err(Into::into)) } fn read_child_proof( @@ -1174,7 +1171,8 @@ where child_info: &ChildInfo, keys: &mut dyn Iterator, ) -> sp_blockchain::Result { - self.state_at(id) + let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; + self.state_at(&hash) .and_then(|state| prove_child_read(state, child_info, keys).map_err(Into::into)) } @@ -1193,7 +1191,8 @@ where start_key: &[Vec], size_limit: usize, ) -> sp_blockchain::Result<(CompactProof, u32)> { - let state = self.state_at(id)?; + let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; + let state = self.state_at(&hash)?; // this is a read proof, using version V0 or V1 is equivalent. let root = state.storage_root(std::iter::empty(), StateVersion::V0).0; @@ -1215,7 +1214,8 @@ where if start_key.len() > MAX_NESTED_TRIE_DEPTH { return Err(Error::Backend("Invalid start key.".to_string())) } - let state = self.state_at(id)?; + let hash = self.backend.blockchain().expect_block_hash_from_id(&id)?; + let state = self.state_at(&hash)?; let child_info = |storage_key: &Vec| -> sp_blockchain::Result { let storage_key = PrefixedStorageKey::new_ref(storage_key); match ChildType::from_prefixed_key(storage_key) { @@ -1450,19 +1450,19 @@ where { fn storage_keys( &self, - id: &BlockId, + hash: &Block::Hash, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { - let keys = self.state_at(id)?.keys(&key_prefix.0).into_iter().map(StorageKey).collect(); + let keys = self.state_at(hash)?.keys(&key_prefix.0).into_iter().map(StorageKey).collect(); Ok(keys) } fn storage_pairs( &self, - id: &BlockId, + hash: &::Hash, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { - let state = self.state_at(id)?; + let state = self.state_at(hash)?; let keys = state .keys(&key_prefix.0) .into_iter() @@ -1476,34 +1476,34 @@ where fn storage_keys_iter<'a>( &self, - id: &BlockId, + hash: &::Hash, prefix: Option<&'a StorageKey>, start_key: Option<&StorageKey>, ) -> sp_blockchain::Result> { - let state = self.state_at(id)?; + let state = self.state_at(hash)?; let start_key = start_key.or(prefix).map(|key| key.0.clone()).unwrap_or_else(Vec::new); Ok(KeyIterator::new(state, prefix, start_key)) } fn child_storage_keys_iter<'a>( &self, - id: &BlockId, + hash: &::Hash, child_info: ChildInfo, prefix: Option<&'a StorageKey>, start_key: Option<&StorageKey>, ) -> sp_blockchain::Result> { - let state = self.state_at(id)?; + let state = self.state_at(hash)?; let start_key = start_key.or(prefix).map(|key| key.0.clone()).unwrap_or_else(Vec::new); Ok(KeyIterator::new_child(state, child_info, prefix, start_key)) } fn storage( &self, - id: &BlockId, + hash: &Block::Hash, key: &StorageKey, ) -> sp_blockchain::Result> { Ok(self - .state_at(id)? + .state_at(hash)? .storage(&key.0) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? .map(StorageData)) @@ -1511,22 +1511,22 @@ where fn storage_hash( &self, - id: &BlockId, + hash: &::Hash, key: &StorageKey, ) -> sp_blockchain::Result> { - self.state_at(id)? + self.state_at(hash)? .storage_hash(&key.0) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e))) } fn child_storage_keys( &self, - id: &BlockId, + hash: &::Hash, child_info: &ChildInfo, key_prefix: &StorageKey, ) -> sp_blockchain::Result> { let keys = self - .state_at(id)? + .state_at(hash)? .child_keys(child_info, &key_prefix.0) .into_iter() .map(StorageKey) @@ -1536,12 +1536,12 @@ where fn child_storage( &self, - id: &BlockId, + hash: &::Hash, child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result> { Ok(self - .state_at(id)? + .state_at(hash)? .child_storage(child_info, &key.0) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))? .map(StorageData)) @@ -1549,11 +1549,11 @@ where fn child_storage_hash( &self, - id: &BlockId, + hash: &::Hash, child_info: &ChildInfo, key: &StorageKey, ) -> sp_blockchain::Result> { - self.state_at(id)? + self.state_at(hash)? .child_storage_hash(child_info, &key.0) .map_err(|e| sp_blockchain::Error::from_state(Box::new(e))) } @@ -1706,27 +1706,23 @@ where { type StateBackend = B::State; - fn call_api_at< - R: Encode + Decode + PartialEq, - NC: FnOnce() -> result::Result + UnwindSafe, - >( + fn call_api_at( &self, - params: CallApiAtParams, - ) -> Result, sp_api::ApiError> { + params: CallApiAtParams, + ) -> Result, sp_api::ApiError> { let at = params.at; let (manager, extensions) = self.execution_extensions.manager_and_extensions(at, params.context); self.executor - .contextual_call:: _, _, _>( + .contextual_call( at, params.function, ¶ms.arguments, params.overlayed_changes, Some(params.storage_transaction_cache), manager, - params.native_call, params.recorder, Some(extensions), ) @@ -1738,7 +1734,8 @@ where } fn state_at(&self, at: &BlockId) -> Result { - self.state_at(at).map_err(Into::into) + let hash = self.backend.blockchain().expect_block_hash_from_id(at)?; + self.state_at(&hash).map_err(Into::into) } } diff --git a/client/service/src/config.rs b/client/service/src/config.rs index 2fb3f820ebf15..bca0697bcbd08 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -24,13 +24,11 @@ pub use sc_executor::WasmExecutionMethod; #[cfg(feature = "wasmtime")] pub use sc_executor::WasmtimeInstantiationStrategy; pub use sc_network::{ - config::{ - NetworkConfiguration, NodeKeyConfig, NonDefaultSetConfig, Role, SetConfig, TransportConfig, - }, + config::{NetworkConfiguration, NodeKeyConfig, Role}, Multiaddr, }; pub use sc_network_common::{ - config::{MultiaddrWithPeerId, ProtocolId}, + config::{MultiaddrWithPeerId, NonDefaultSetConfig, ProtocolId, SetConfig, TransportConfig}, request_responses::{ IncomingRequest, OutgoingResponse, ProtocolConfig as RequestResponseConfig, }, @@ -262,31 +260,43 @@ impl Default for RpcMethods { } } -/// The base path that is used for everything that needs to be write on disk to run a node. +#[static_init::dynamic(drop, lazy)] +static mut BASE_PATH_TEMP: Option = None; + +/// The base path that is used for everything that needs to be written on disk to run a node. #[derive(Debug)] -pub enum BasePath { - /// A temporary directory is used as base path and will be deleted when dropped. - Temporary(TempDir), - /// A path on the disk. - Permanenent(PathBuf), +pub struct BasePath { + path: PathBuf, } impl BasePath { /// Create a `BasePath` instance using a temporary directory prefixed with "substrate" and use /// it as base path. /// - /// Note: the temporary directory will be created automatically and deleted when the `BasePath` - /// instance is dropped. + /// Note: The temporary directory will be created automatically and deleted when the program + /// exits. Every call to this function will return the same path for the lifetime of the + /// program. pub fn new_temp_dir() -> io::Result { - Ok(BasePath::Temporary(tempfile::Builder::new().prefix("substrate").tempdir()?)) + let mut temp = BASE_PATH_TEMP.write(); + + match &*temp { + Some(p) => Ok(Self::new(p.path())), + None => { + let temp_dir = tempfile::Builder::new().prefix("substrate").tempdir()?; + let path = PathBuf::from(temp_dir.path()); + + *temp = Some(temp_dir); + Ok(Self::new(path)) + }, + } } /// Create a `BasePath` instance based on an existing path on disk. /// /// Note: this function will not ensure that the directory exist nor create the directory. It /// will also not delete the directory when the instance is dropped. - pub fn new>(path: P) -> BasePath { - BasePath::Permanenent(path.as_ref().to_path_buf()) + pub fn new>(path: P) -> BasePath { + Self { path: path.into() } } /// Create a base path from values describing the project. @@ -300,10 +310,7 @@ impl BasePath { /// Retrieve the base path. pub fn path(&self) -> &Path { - match self { - BasePath::Temporary(temp_dir) => temp_dir.path(), - BasePath::Permanenent(path) => path.as_path(), - } + &self.path } /// Returns the configuration directory inside this base path. diff --git a/client/service/src/error.rs b/client/service/src/error.rs index 0d702c7f37b98..001a83922d776 100644 --- a/client/service/src/error.rs +++ b/client/service/src/error.rs @@ -19,7 +19,6 @@ //! Errors that can occur during the service operation. use sc_keystore; -use sc_network; use sp_blockchain; use sp_consensus; @@ -41,7 +40,7 @@ pub enum Error { Consensus(#[from] sp_consensus::Error), #[error(transparent)] - Network(#[from] sc_network::error::Error), + Network(#[from] sc_network_common::error::Error), #[error(transparent)] Keystore(#[from] sc_keystore::Error), diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 19358c1e5bc4c..091b4bbe9fe5f 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -72,7 +72,7 @@ pub use sc_chain_spec::{ pub use sc_consensus::ImportQueue; pub use sc_executor::NativeExecutionDispatch; #[doc(hidden)] -pub use sc_network::config::{TransactionImport, TransactionImportFuture}; +pub use sc_network_transactions::config::{TransactionImport, TransactionImportFuture}; pub use sc_rpc::{ RandomIntegerSubscriptionId, RandomStringSubscriptionId, RpcSubscriptionIdProvider, }; @@ -148,7 +148,7 @@ async fn build_network_future< + Send + Sync + 'static, - H: sc_network::ExHashT, + H: sc_network_common::ExHashT, >( role: Role, mut network: sc_network::NetworkWorker, @@ -415,7 +415,8 @@ where .collect() } -impl sc_network::config::TransactionPool for TransactionPoolAdapter +impl sc_network_transactions::config::TransactionPool + for TransactionPoolAdapter where C: HeaderBackend + BlockBackend diff --git a/client/service/test/Cargo.toml b/client/service/test/Cargo.toml index 92df5381c202b..1f934a6e5355f 100644 --- a/client/service/test/Cargo.toml +++ b/client/service/test/Cargo.toml @@ -12,10 +12,9 @@ repository = "https://github.com/paritytech/substrate/" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +array-bytes = "4.1" fdlimit = "0.2.1" futures = "0.3.21" -hex = "0.4" -hex-literal = "0.3.4" log = "0.4.17" parity-scale-codec = "3.0.0" parking_lot = "0.12.1" diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 54bbf9b35d866..04a790a56774a 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -17,11 +17,10 @@ // along with this program. If not, see . use futures::executor::block_on; -use hex_literal::hex; use parity_scale_codec::{Decode, Encode, Joiner}; use sc_block_builder::BlockBuilderProvider; use sc_client_api::{ - in_mem, BlockBackend, BlockchainEvents, FinalityNotifications, StorageProvider, + in_mem, BlockBackend, BlockchainEvents, FinalityNotifications, HeaderBackend, StorageProvider, }; use sc_client_db::{Backend, BlocksPruning, DatabaseSettings, DatabaseSource, PruningMode}; use sc_consensus::{ @@ -157,7 +156,9 @@ fn block1(genesis_hash: Hash, backend: &InMemoryBackend) -> (Vec = client - .storage_keys_iter(&BlockId::Number(0), Some(&prefix), None) + .storage_keys_iter(&block_hash, Some(&prefix), None) .unwrap() .map(|x| x.0) .collect(); assert_eq!( res, - [child_root.clone(), hex!("3a636f6465").to_vec(), hex!("3a686561707061676573").to_vec(),] + [ + child_root.clone(), + array_bytes::hex2bytes_unchecked("3a636f6465"), + array_bytes::hex2bytes_unchecked("3a686561707061676573"), + ] ); let res: Vec<_> = client .storage_keys_iter( - &BlockId::Number(0), + &block_hash, Some(&prefix), - Some(&StorageKey(hex!("3a636f6465").to_vec())), + Some(&StorageKey(array_bytes::hex2bytes_unchecked("3a636f6465"))), ) .unwrap() .map(|x| x.0) .collect(); - assert_eq!(res, [hex!("3a686561707061676573").to_vec()]); + assert_eq!(res, [array_bytes::hex2bytes_unchecked("3a686561707061676573")]); let res: Vec<_> = client .storage_keys_iter( - &BlockId::Number(0), + &block_hash, Some(&prefix), - Some(&StorageKey(hex!("3a686561707061676573").to_vec())), + Some(&StorageKey(array_bytes::hex2bytes_unchecked("3a686561707061676573"))), ) .unwrap() .map(|x| x.0) @@ -1632,7 +1647,7 @@ fn storage_keys_iter_prefix_and_start_key_works() { assert_eq!(res, Vec::>::new()); let res: Vec<_> = client - .child_storage_keys_iter(&BlockId::Number(0), child_info.clone(), Some(&child_prefix), None) + .child_storage_keys_iter(&block_hash, child_info.clone(), Some(&child_prefix), None) .unwrap() .map(|x| x.0) .collect(); @@ -1640,7 +1655,7 @@ fn storage_keys_iter_prefix_and_start_key_works() { let res: Vec<_> = client .child_storage_keys_iter( - &BlockId::Number(0), + &block_hash, child_info, None, Some(&StorageKey(b"second".to_vec())), @@ -1655,13 +1670,15 @@ fn storage_keys_iter_prefix_and_start_key_works() { fn storage_keys_iter_works() { let client = substrate_test_runtime_client::new(); - let prefix = StorageKey(hex!("").to_vec()); + let block_hash = client.info().best_hash; + + let prefix = StorageKey(array_bytes::hex2bytes_unchecked("")); let res: Vec<_> = client - .storage_keys_iter(&BlockId::Number(0), Some(&prefix), None) + .storage_keys_iter(&block_hash, Some(&prefix), None) .unwrap() - .take(8) - .map(|x| hex::encode(&x.0)) + .take(9) + .map(|x| array_bytes::bytes2hex("", &x.0)) .collect(); assert_eq!( res, @@ -1672,6 +1689,7 @@ fn storage_keys_iter_works() { "1a560ecfd2a62c2b8521ef149d0804eb621050e3988ed97dca55f0d7c3e6aa34", "1d66850d32002979d67dd29dc583af5b2ae2a1f71c1f35ad90fff122be7a3824", "237498b98d8803334286e9f0483ef513098dd3c1c22ca21c4dc155b4ef6cc204", + "26aa394eea5630e07c48ae0c9558cef75e0621c4869aa60c02be9adcc98a0d1d", "29b9db10ec5bf7907d8f74b5e60aa8140c4fbdd8127a1ee5600cb98e5ec01729", "3a636f6465", ] @@ -1679,13 +1697,13 @@ fn storage_keys_iter_works() { let res: Vec<_> = client .storage_keys_iter( - &BlockId::Number(0), + &block_hash, Some(&prefix), - Some(&StorageKey(hex!("3a636f6465").to_vec())), + Some(&StorageKey(array_bytes::hex2bytes_unchecked("3a636f6465"))), ) .unwrap() .take(7) - .map(|x| hex::encode(&x.0)) + .map(|x| array_bytes::bytes2hex("", &x.0)) .collect(); assert_eq!( res, @@ -1696,30 +1714,30 @@ fn storage_keys_iter_works() { "5c2d5fda66373dabf970e4fb13d277ce91c5233473321129d32b5a8085fa8133", "6644b9b8bc315888ac8e41a7968dc2b4141a5403c58acdf70b7e8f7e07bf5081", "66484000ed3f75c95fc7b03f39c20ca1e1011e5999278247d3b2f5e3c3273808", - "79c07e2b1d2e2abfd4855b936617eeff5e0621c4869aa60c02be9adcc98a0d1d", + "7d5007603a7f5dd729d51d93cf695d6465789443bb967c0d1fe270e388c96eaa", ] ); let res: Vec<_> = client .storage_keys_iter( - &BlockId::Number(0), + &block_hash, Some(&prefix), - Some(&StorageKey( - hex!("79c07e2b1d2e2abfd4855b936617eeff5e0621c4869aa60c02be9adcc98a0d1d").to_vec(), - )), + Some(&StorageKey(array_bytes::hex2bytes_unchecked( + "7d5007603a7f5dd729d51d93cf695d6465789443bb967c0d1fe270e388c96eaa", + ))), ) .unwrap() .take(5) - .map(|x| hex::encode(x.0)) + .map(|x| array_bytes::bytes2hex("", &x.0)) .collect(); assert_eq!( res, [ - "7d5007603a7f5dd729d51d93cf695d6465789443bb967c0d1fe270e388c96eaa", "811ecfaadcf5f2ee1d67393247e2f71a1662d433e8ce7ff89fb0d4aa9561820b", "a93d74caa7ec34ea1b04ce1e5c090245f867d333f0f88278a451e45299654dc5", "a9ee1403384afbfc13f13be91ff70bfac057436212e53b9733914382ac942892", "cf722c0832b5231d35e29f319ff27389f5032bfc7bfc3ba5ed7839f2042fb99f", + "e3b47b6c84c0493481f97c5197d2554f", ] ); } diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index 11c1cbaf7afb1..5d29d34a3cbf2 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -22,12 +22,9 @@ use futures::{task::Poll, Future, TryFutureExt as _}; use log::{debug, info}; use parking_lot::Mutex; use sc_client_api::{Backend, CallExecutor}; -use sc_network::{ - config::{NetworkConfiguration, TransportConfig}, - multiaddr, -}; +use sc_network::{config::NetworkConfiguration, multiaddr}; use sc_network_common::{ - config::MultiaddrWithPeerId, + config::{MultiaddrWithPeerId, TransportConfig}, service::{NetworkBlock, NetworkPeers, NetworkStateInfo}, }; use sc_service::{ @@ -237,7 +234,7 @@ fn node_config< database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, trie_cache_maximum_size: Some(16 * 1024 * 1024), state_pruning: Default::default(), - blocks_pruning: BlocksPruning::All, + blocks_pruning: BlocksPruning::KeepFinalized, chain_spec: Box::new((*spec).clone()), wasm_method: sc_service::config::WasmExecutionMethod::Interpreted, wasm_runtime_overrides: Default::default(), diff --git a/client/state-db/Cargo.toml b/client/state-db/Cargo.toml index 4243968ec79b4..7f9a502aef8e9 100644 --- a/client/state-db/Cargo.toml +++ b/client/state-db/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"] } log = "0.4.17" -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } parity-util-mem-derive = "0.1.0" parking_lot = "0.12.1" sc-client-api = { version = "4.0.0-dev", path = "../api" } diff --git a/client/state-db/src/lib.rs b/client/state-db/src/lib.rs index f21b707a489f0..8730b4fb60c2f 100644 --- a/client/state-db/src/lib.rs +++ b/client/state-db/src/lib.rs @@ -189,8 +189,9 @@ impl fmt::Debug for StateDbError { Self::TooManySiblingBlocks => write!(f, "Too many sibling blocks inserted"), Self::BlockAlreadyExists => write!(f, "Block already exists"), Self::Metadata(message) => write!(f, "Invalid metadata: {}", message), - Self::BlockUnavailable => - write!(f, "Trying to get a block record from db while it is not commit to db yet"), + Self::BlockUnavailable => { + write!(f, "Trying to get a block record from db while it is not commit to db yet") + }, Self::BlockMissing => write!(f, "Block record is missing from the pruning window"), } } diff --git a/client/state-db/src/pruning.rs b/client/state-db/src/pruning.rs index 2c23110910495..50a46def59541 100644 --- a/client/state-db/src/pruning.rs +++ b/client/state-db/src/pruning.rs @@ -117,7 +117,7 @@ impl DeathRowQueue { window_size: u32, ) -> Result, Error> { // limit the cache capacity from 1 to `DEFAULT_MAX_BLOCK_CONSTRAINT` - let cache_capacity = window_size.max(1).min(DEFAULT_MAX_BLOCK_CONSTRAINT) as usize; + let cache_capacity = window_size.clamp(1, DEFAULT_MAX_BLOCK_CONSTRAINT) as usize; let mut cache = VecDeque::with_capacity(cache_capacity); trace!(target: "state-db", "Reading pruning journal for the database-backed queue. Pending #{}", base); // Load block from db diff --git a/client/telemetry/Cargo.toml b/client/telemetry/Cargo.toml index 4be7c186720fc..f8c6f281546db 100644 --- a/client/telemetry/Cargo.toml +++ b/client/telemetry/Cargo.toml @@ -16,10 +16,10 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] chrono = "0.4.19" futures = "0.3.21" -libp2p = { version = "0.46.1", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } +libp2p = { version = "0.49.0", default-features = false, features = ["dns-async-std", "tcp-async-io", "wasm-ext", "websocket"] } log = "0.4.17" parking_lot = "0.12.1" -pin-project = "1.0.10" +pin-project = "1.0.12" rand = "0.7.2" serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.85" diff --git a/client/tracing/src/logging/mod.rs b/client/tracing/src/logging/mod.rs index 58941617bfb6a..978e24df68d78 100644 --- a/client/tracing/src/logging/mod.rs +++ b/client/tracing/src/logging/mod.rs @@ -133,7 +133,14 @@ where .add_directive( parse_default_directive("cranelift_wasm=warn").expect("provided directive is valid"), ) - .add_directive(parse_default_directive("hyper=warn").expect("provided directive is valid")); + .add_directive(parse_default_directive("hyper=warn").expect("provided directive is valid")) + .add_directive( + parse_default_directive("trust_dns_proto=off").expect("provided directive is valid"), + ) + .add_directive( + parse_default_directive("libp2p_mdns::behaviour::iface=off") + .expect("provided directive is valid"), + ); if let Ok(lvl) = std::env::var("RUST_LOG") { if lvl != "" { diff --git a/client/transaction-pool/Cargo.toml b/client/transaction-pool/Cargo.toml index 9aa05694b6619..0bdfb623e6c14 100644 --- a/client/transaction-pool/Cargo.toml +++ b/client/transaction-pool/Cargo.toml @@ -13,12 +13,13 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" futures-timer = "3.0.2" linked-hash-map = "0.5.4" log = "0.4.17" -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } parking_lot = "0.12.1" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0.30" @@ -34,9 +35,9 @@ sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } sp-transaction-pool = { version = "4.0.0-dev", path = "../../primitives/transaction-pool" } [dev-dependencies] +array-bytes = "4.1" assert_matches = "1.3.0" criterion = "0.3" -hex = "0.4" sc-block-builder = { version = "0.10.0-dev", path = "../block-builder" } sp-consensus = { version = "0.10.0-dev", path = "../../primitives/consensus/common" } substrate-test-runtime = { version = "2.0.0", path = "../../test-utils/runtime" } diff --git a/client/transaction-pool/api/Cargo.toml b/client/transaction-pool/api/Cargo.toml index d34ffe512b023..366d0eb99b945 100644 --- a/client/transaction-pool/api/Cargo.toml +++ b/client/transaction-pool/api/Cargo.toml @@ -9,9 +9,13 @@ repository = "https://github.com/paritytech/substrate/" description = "Transaction pool client facing API." [dependencies] +async-trait = "0.1.57" futures = "0.3.21" log = "0.4.17" serde = { version = "1.0.136", features = ["derive"] } thiserror = "1.0.30" sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } + +[dev-dependencies] +serde_json = "1.0" diff --git a/client/transaction-pool/api/src/lib.rs b/client/transaction-pool/api/src/lib.rs index 0ebb8f9d4cd9c..c1e49ad07d7b1 100644 --- a/client/transaction-pool/api/src/lib.rs +++ b/client/transaction-pool/api/src/lib.rs @@ -21,6 +21,7 @@ pub mod error; +use async_trait::async_trait; use futures::{Future, Stream}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use sp_runtime::{ @@ -108,15 +109,18 @@ pub enum TransactionStatus { Ready, /// The transaction has been broadcast to the given peers. Broadcast(Vec), - /// Transaction has been included in block with given hash. - InBlock(BlockHash), + /// Transaction has been included in block with given hash + /// at the given position. + #[serde(with = "v1_compatible")] + InBlock((BlockHash, TxIndex)), /// The block this transaction was included in has been retracted. Retracted(BlockHash), /// Maximum number of finality watchers has been reached, /// old watchers are being removed. FinalityTimeout(BlockHash), - /// Transaction has been finalized by a finality-gadget, e.g GRANDPA - Finalized(BlockHash), + /// Transaction has been finalized by a finality-gadget, e.g GRANDPA. + #[serde(with = "v1_compatible")] + Finalized((BlockHash, TxIndex)), /// Transaction has been replaced in the pool, by another transaction /// that provides the same tags. (e.g. same (sender, nonce)). Usurped(Hash), @@ -143,6 +147,8 @@ pub type TransactionFor

= <

::Block as BlockT>::Extrinsi pub type TransactionStatusStreamFor

= TransactionStatusStream, BlockHash

>; /// Transaction type for a local pool. pub type LocalTransactionFor

= <

::Block as BlockT>::Extrinsic; +/// Transaction's index within the block in which it was included. +pub type TxIndex = usize; /// Typical future type used in transaction pool api. pub type PoolFuture = std::pin::Pin> + Send>>; @@ -298,9 +304,10 @@ pub enum ChainEvent { } /// Trait for transaction pool maintenance. +#[async_trait] pub trait MaintainedTransactionPool: TransactionPool { /// Perform maintenance - fn maintain(&self, event: ChainEvent) -> Pin + Send>>; + async fn maintain(&self, event: ChainEvent); } /// Transaction pool interface for submitting local transactions that exposes a @@ -362,3 +369,52 @@ impl OffchainSubmitTransaction for TP }) } } + +/// Wrapper functions to keep the API backwards compatible over the wire for the old RPC spec. +mod v1_compatible { + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + + pub fn serialize(data: &(H, usize), serializer: S) -> Result + where + S: Serializer, + H: Serialize, + { + let (hash, _) = data; + serde::Serialize::serialize(&hash, serializer) + } + + pub fn deserialize<'de, D, H>(deserializer: D) -> Result<(H, usize), D::Error> + where + D: Deserializer<'de>, + H: Deserialize<'de>, + { + let hash: H = serde::Deserialize::deserialize(deserializer)?; + Ok((hash, 0)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn tx_status_compatibility() { + let event: TransactionStatus = TransactionStatus::InBlock((1, 2)); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"inBlock":1}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionStatus = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, TransactionStatus::InBlock((1, 0))); + + let event: TransactionStatus = TransactionStatus::Finalized((1, 2)); + let ser = serde_json::to_string(&event).unwrap(); + + let exp = r#"{"finalized":1}"#; + assert_eq!(ser, exp); + + let event_dec: TransactionStatus = serde_json::from_str(exp).unwrap(); + assert_eq!(event_dec, TransactionStatus::Finalized((1, 0))); + } +} diff --git a/client/transaction-pool/benches/basics.rs b/client/transaction-pool/benches/basics.rs index a7991269439ce..2632f8fb6aab5 100644 --- a/client/transaction-pool/benches/basics.rs +++ b/client/transaction-pool/benches/basics.rs @@ -121,6 +121,14 @@ impl ChainApi for TestApi { ) -> Result::Header>, Self::Error> { Ok(None) } + + fn tree_route( + &self, + _from: ::Hash, + _to: ::Hash, + ) -> Result, Self::Error> { + unimplemented!() + } } fn uxt(transfer: Transfer) -> Extrinsic { diff --git a/client/transaction-pool/src/api.rs b/client/transaction-pool/src/api.rs index 4710c96b003cd..110647b8cb3b0 100644 --- a/client/transaction-pool/src/api.rs +++ b/client/transaction-pool/src/api.rs @@ -30,6 +30,7 @@ use std::{marker::PhantomData, pin::Pin, sync::Arc}; use prometheus_endpoint::Registry as PrometheusRegistry; use sc_client_api::{blockchain::HeaderBackend, BlockBackend}; use sp_api::{ApiExt, ProvideRuntimeApi}; +use sp_blockchain::{HeaderMetadata, TreeRoute}; use sp_core::traits::SpawnEssentialNamed; use sp_runtime::{ generic::BlockId, @@ -111,8 +112,11 @@ impl FullChainApi { impl graph::ChainApi for FullChainApi where Block: BlockT, - Client: - ProvideRuntimeApi + BlockBackend + BlockIdTo + HeaderBackend, + Client: ProvideRuntimeApi + + BlockBackend + + BlockIdTo + + HeaderBackend + + HeaderMetadata, Client: Send + Sync + 'static, Client::Api: TaggedTransactionQueue, { @@ -190,6 +194,14 @@ where ) -> Result::Header>, Self::Error> { self.client.header(*at).map_err(Into::into) } + + fn tree_route( + &self, + from: ::Hash, + to: ::Hash, + ) -> Result, Self::Error> { + sp_blockchain::tree_route::(&*self.client, from, to).map_err(Into::into) + } } /// Helper function to validate a transaction using a full chain API. @@ -202,8 +214,11 @@ fn validate_transaction_blocking( ) -> error::Result where Block: BlockT, - Client: - ProvideRuntimeApi + BlockBackend + BlockIdTo + HeaderBackend, + Client: ProvideRuntimeApi + + BlockBackend + + BlockIdTo + + HeaderBackend + + HeaderMetadata, Client: Send + Sync + 'static, Client::Api: TaggedTransactionQueue, { @@ -264,8 +279,11 @@ where impl FullChainApi where Block: BlockT, - Client: - ProvideRuntimeApi + BlockBackend + BlockIdTo + HeaderBackend, + Client: ProvideRuntimeApi + + BlockBackend + + BlockIdTo + + HeaderBackend + + HeaderMetadata, Client: Send + Sync + 'static, Client::Api: TaggedTransactionQueue, { diff --git a/client/transaction-pool/src/enactment_state.rs b/client/transaction-pool/src/enactment_state.rs new file mode 100644 index 0000000000000..242b557dfbbbd --- /dev/null +++ b/client/transaction-pool/src/enactment_state.rs @@ -0,0 +1,579 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Substrate transaction pool implementation. + +use sc_transaction_pool_api::ChainEvent; +use sp_blockchain::TreeRoute; +use sp_runtime::traits::Block as BlockT; + +/// Helper struct for keeping track of the current state of processed new best +/// block and finalized events. The main purpose of keeping track of this state +/// is to figure out if a transaction pool enactment is needed or not. +/// +/// Given the following chain: +/// +/// B1-C1-D1-E1 +/// / +/// A +/// \ +/// B2-C2-D2-E2 +/// +/// Some scenarios and expected behavior for sequence of `NewBestBlock` (`nbb`) and `Finalized` +/// (`f`) events: +/// +/// - `nbb(C1)`, `f(C1)` -> false (enactment was already performed in `nbb(C1))` +/// - `f(C1)`, `nbb(C1)` -> false (enactment was already performed in `f(C1))` +/// - `f(C1)`, `nbb(D2)` -> false (enactment was already performed in `f(C1)`, +/// we should not retract finalized block) +/// - `f(C1)`, `f(C2)`, `nbb(C1)` -> false +/// - `nbb(C1)`, `nbb(C2)` -> true (switching fork is OK) +/// - `nbb(B1)`, `nbb(B2)` -> true +/// - `nbb(B1)`, `nbb(C1)`, `f(C1)` -> false (enactment was already performed in `nbb(B1)`) +/// - `nbb(C1)`, `f(B1)` -> false (enactment was already performed in `nbb(B2)`) +pub struct EnactmentState +where + Block: BlockT, +{ + recent_best_block: Block::Hash, + recent_finalized_block: Block::Hash, +} + +impl EnactmentState +where + Block: BlockT, +{ + /// Returns a new `EnactmentState` initialized with the given parameters. + pub fn new(recent_best_block: Block::Hash, recent_finalized_block: Block::Hash) -> Self { + EnactmentState { recent_best_block, recent_finalized_block } + } + + /// Returns the recently finalized block. + pub fn recent_finalized_block(&self) -> Block::Hash { + self.recent_finalized_block + } + + /// Updates the state according to the given `ChainEvent`, returning + /// `Some(tree_route)` with a tree route including the blocks that need to + /// be enacted/retracted. If no enactment is needed then `None` is returned. + pub fn update( + &mut self, + event: &ChainEvent, + tree_route: &F, + ) -> Result>, String> + where + F: Fn(Block::Hash, Block::Hash) -> Result, String>, + { + let (new_hash, finalized) = match event { + ChainEvent::NewBestBlock { hash, .. } => (*hash, false), + ChainEvent::Finalized { hash, .. } => (*hash, true), + }; + + // block was already finalized + if self.recent_finalized_block == new_hash { + log::debug!(target: "txpool", "handle_enactment: block already finalized"); + return Ok(None) + } + + // compute actual tree route from best_block to notified block, and use + // it instead of tree_route provided with event + let tree_route = tree_route(self.recent_best_block, new_hash)?; + + log::debug!( + target: "txpool", + "resolve hash:{:?} finalized:{:?} tree_route:{:?} best_block:{:?} finalized_block:{:?}", + new_hash, finalized, tree_route, self.recent_best_block, self.recent_finalized_block + ); + + // check if recently finalized block is on retracted path. this could be + // happening if we first received a finalization event and then a new + // best event for some old stale best head. + if tree_route.retracted().iter().any(|x| x.hash == self.recent_finalized_block) { + log::debug!( + target: "txpool", + "Recently finalized block {} would be retracted by ChainEvent {}, skipping", + self.recent_finalized_block, new_hash + ); + return Ok(None) + } + + if finalized { + self.recent_finalized_block = new_hash; + + // if there are no enacted blocks in best_block -> hash tree_route, + // it means that block being finalized was already enacted (this + // case also covers best_block == new_hash), recent_best_block + // remains valid. + if tree_route.enacted().is_empty() { + log::trace!( + target: "txpool", + "handle_enactment: no newly enacted blocks since recent best block" + ); + return Ok(None) + } + + // otherwise enacted finalized block becomes best block... + } + + self.recent_best_block = new_hash; + + Ok(Some(tree_route)) + } +} + +#[cfg(test)] +mod enactment_state_tests { + use super::EnactmentState; + use sc_transaction_pool_api::ChainEvent; + use sp_blockchain::{HashAndNumber, TreeRoute}; + use std::sync::Arc; + use substrate_test_runtime_client::runtime::{Block, Hash}; + + // some helpers for convenient blocks' hash naming + fn a() -> HashAndNumber { + HashAndNumber { number: 1, hash: Hash::from([0xAA; 32]) } + } + fn b1() -> HashAndNumber { + HashAndNumber { number: 2, hash: Hash::from([0xB1; 32]) } + } + fn c1() -> HashAndNumber { + HashAndNumber { number: 3, hash: Hash::from([0xC1; 32]) } + } + fn d1() -> HashAndNumber { + HashAndNumber { number: 4, hash: Hash::from([0xD1; 32]) } + } + fn e1() -> HashAndNumber { + HashAndNumber { number: 5, hash: Hash::from([0xE1; 32]) } + } + fn b2() -> HashAndNumber { + HashAndNumber { number: 2, hash: Hash::from([0xB2; 32]) } + } + fn c2() -> HashAndNumber { + HashAndNumber { number: 3, hash: Hash::from([0xC2; 32]) } + } + fn d2() -> HashAndNumber { + HashAndNumber { number: 4, hash: Hash::from([0xD2; 32]) } + } + fn e2() -> HashAndNumber { + HashAndNumber { number: 5, hash: Hash::from([0xE2; 32]) } + } + + /// mock tree_route computing function for simple two-forks chain + fn tree_route(from: Hash, to: Hash) -> Result, String> { + let chain = vec![e1(), d1(), c1(), b1(), a(), b2(), c2(), d2(), e2()]; + let pivot = 4_usize; + + let from = chain + .iter() + .position(|bn| bn.hash == from) + .ok_or("existing block should be given")?; + let to = chain + .iter() + .position(|bn| bn.hash == to) + .ok_or("existing block should be given")?; + + // B1-C1-D1-E1 + // / + // A + // \ + // B2-C2-D2-E2 + // + // [E1 D1 C1 B1 A B2 C2 D2 E2] + + let vec: Vec> = if from < to { + chain.into_iter().skip(from).take(to - from + 1).collect() + } else { + chain.into_iter().skip(to).take(from - to + 1).rev().collect() + }; + + let pivot = if from <= pivot && to <= pivot { + if from < to { + to - from + } else { + 0 + } + } else if from >= pivot && to >= pivot { + if from < to { + 0 + } else { + from - to + } + } else { + if from < to { + pivot - from + } else { + from - pivot + } + }; + + Ok(TreeRoute::new(vec, pivot)) + } + + mod mock_tree_route_tests { + use super::*; + + /// asserts that tree routes are equal + fn assert_treeroute_eq(expected: TreeRoute, result: TreeRoute) { + assert_eq!(result.common_block().hash, expected.common_block().hash); + assert_eq!(result.enacted().len(), expected.enacted().len()); + assert_eq!(result.retracted().len(), expected.retracted().len()); + assert!(result + .enacted() + .iter() + .zip(expected.enacted().iter()) + .all(|(a, b)| a.hash == b.hash)); + assert!(result + .retracted() + .iter() + .zip(expected.retracted().iter()) + .all(|(a, b)| a.hash == b.hash)); + } + + // some tests for mock tree_route function + #[test] + fn tree_route_mock_test_01() { + let result = tree_route(b1().hash, a().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![b1(), a()], 1); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_02() { + let result = tree_route(a().hash, b1().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![a(), b1()], 0); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_03() { + let result = tree_route(a().hash, c2().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![a(), b2(), c2()], 0); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_04() { + let result = tree_route(e2().hash, a().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![e2(), d2(), c2(), b2(), a()], 4); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_05() { + let result = tree_route(d1().hash, b1().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![d1(), c1(), b1()], 2); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_06() { + let result = tree_route(d2().hash, b2().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![d2(), c2(), b2()], 2); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_07() { + let result = tree_route(b1().hash, d1().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![b1(), c1(), d1()], 0); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_08() { + let result = tree_route(b2().hash, d2().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![b2(), c2(), d2()], 0); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_09() { + let result = tree_route(e2().hash, e1().hash).expect("tree route exists"); + let expected = + TreeRoute::new(vec![e2(), d2(), c2(), b2(), a(), b1(), c1(), d1(), e1()], 4); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_10() { + let result = tree_route(e1().hash, e2().hash).expect("tree route exists"); + let expected = + TreeRoute::new(vec![e1(), d1(), c1(), b1(), a(), b2(), c2(), d2(), e2()], 4); + assert_treeroute_eq(result, expected); + } + #[test] + fn tree_route_mock_test_11() { + let result = tree_route(b1().hash, c2().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![b1(), a(), b2(), c2()], 1); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_12() { + let result = tree_route(d2().hash, b1().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![d2(), c2(), b2(), a(), b1()], 3); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_13() { + let result = tree_route(c2().hash, e1().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![c2(), b2(), a(), b1(), c1(), d1(), e1()], 2); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_14() { + let result = tree_route(b1().hash, b1().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![b1()], 0); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_15() { + let result = tree_route(b2().hash, b2().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![b2()], 0); + assert_treeroute_eq(result, expected); + } + + #[test] + fn tree_route_mock_test_16() { + let result = tree_route(a().hash, a().hash).expect("tree route exists"); + let expected = TreeRoute::new(vec![a()], 0); + assert_treeroute_eq(result, expected); + } + } + + fn trigger_new_best_block( + state: &mut EnactmentState, + from: HashAndNumber, + acted_on: HashAndNumber, + ) -> bool { + let (from, acted_on) = (from.hash, acted_on.hash); + + let event_tree_route = tree_route(from, acted_on).expect("Tree route exists"); + + state + .update( + &ChainEvent::NewBestBlock { + hash: acted_on, + tree_route: Some(Arc::new(event_tree_route)), + }, + &tree_route, + ) + .unwrap() + .is_some() + } + + fn trigger_finalized( + state: &mut EnactmentState, + from: HashAndNumber, + acted_on: HashAndNumber, + ) -> bool { + let (from, acted_on) = (from.hash, acted_on.hash); + + let v = tree_route(from, acted_on) + .expect("Tree route exists") + .enacted() + .iter() + .map(|h| h.hash) + .collect::>(); + + state + .update(&ChainEvent::Finalized { hash: acted_on, tree_route: v.into() }, &tree_route) + .unwrap() + .is_some() + } + + fn assert_es_eq( + es: &EnactmentState, + expected_best_block: HashAndNumber, + expected_finalized_block: HashAndNumber, + ) { + assert_eq!(es.recent_best_block, expected_best_block.hash); + assert_eq!(es.recent_finalized_block, expected_finalized_block.hash); + } + + #[test] + fn test_enactment_helper() { + sp_tracing::try_init_simple(); + let mut es = EnactmentState::new(a().hash, a().hash); + + // B1-C1-D1-E1 + // / + // A + // \ + // B2-C2-D2-E2 + + let result = trigger_new_best_block(&mut es, a(), d1()); + assert!(result); + assert_es_eq(&es, d1(), a()); + + let result = trigger_new_best_block(&mut es, d1(), e1()); + assert!(result); + assert_es_eq(&es, e1(), a()); + + let result = trigger_finalized(&mut es, a(), d2()); + assert!(result); + assert_es_eq(&es, d2(), d2()); + + let result = trigger_new_best_block(&mut es, d2(), e1()); + assert_eq!(result, false); + assert_es_eq(&es, d2(), d2()); + + let result = trigger_finalized(&mut es, a(), b2()); + assert_eq!(result, false); + assert_es_eq(&es, d2(), d2()); + + let result = trigger_finalized(&mut es, a(), b1()); + assert_eq!(result, false); + assert_es_eq(&es, d2(), d2()); + + let result = trigger_new_best_block(&mut es, a(), d2()); + assert_eq!(result, false); + assert_es_eq(&es, d2(), d2()); + + let result = trigger_finalized(&mut es, a(), d2()); + assert_eq!(result, false); + assert_es_eq(&es, d2(), d2()); + + let result = trigger_new_best_block(&mut es, a(), c2()); + assert_eq!(result, false); + assert_es_eq(&es, d2(), d2()); + + let result = trigger_new_best_block(&mut es, a(), c1()); + assert_eq!(result, false); + assert_es_eq(&es, d2(), d2()); + + let result = trigger_new_best_block(&mut es, d2(), e2()); + assert!(result); + assert_es_eq(&es, e2(), d2()); + + let result = trigger_finalized(&mut es, d2(), e2()); + assert_eq!(result, false); + assert_es_eq(&es, e2(), e2()); + } + + #[test] + fn test_enactment_helper_2() { + sp_tracing::try_init_simple(); + let mut es = EnactmentState::new(a().hash, a().hash); + + // A-B1-C1-D1-E1 + + let result = trigger_new_best_block(&mut es, a(), b1()); + assert!(result); + assert_es_eq(&es, b1(), a()); + + let result = trigger_new_best_block(&mut es, b1(), c1()); + assert!(result); + assert_es_eq(&es, c1(), a()); + + let result = trigger_new_best_block(&mut es, c1(), d1()); + assert!(result); + assert_es_eq(&es, d1(), a()); + + let result = trigger_new_best_block(&mut es, d1(), e1()); + assert!(result); + assert_es_eq(&es, e1(), a()); + + let result = trigger_finalized(&mut es, a(), c1()); + assert_eq!(result, false); + assert_es_eq(&es, e1(), c1()); + + let result = trigger_finalized(&mut es, c1(), e1()); + assert_eq!(result, false); + assert_es_eq(&es, e1(), e1()); + } + + #[test] + fn test_enactment_helper_3() { + sp_tracing::try_init_simple(); + let mut es = EnactmentState::new(a().hash, a().hash); + + // A-B1-C1-D1-E1 + + let result = trigger_new_best_block(&mut es, a(), e1()); + assert!(result); + assert_es_eq(&es, e1(), a()); + + let result = trigger_finalized(&mut es, a(), b1()); + assert_eq!(result, false); + assert_es_eq(&es, e1(), b1()); + } + + #[test] + fn test_enactment_helper_4() { + sp_tracing::try_init_simple(); + let mut es = EnactmentState::new(a().hash, a().hash); + + // A-B1-C1-D1-E1 + + let result = trigger_finalized(&mut es, a(), e1()); + assert!(result); + assert_es_eq(&es, e1(), e1()); + + let result = trigger_finalized(&mut es, e1(), b1()); + assert_eq!(result, false); + assert_es_eq(&es, e1(), e1()); + } + + #[test] + fn test_enactment_helper_5() { + sp_tracing::try_init_simple(); + let mut es = EnactmentState::new(a().hash, a().hash); + + // B1-C1-D1-E1 + // / + // A + // \ + // B2-C2-D2-E2 + + let result = trigger_finalized(&mut es, a(), e1()); + assert!(result); + assert_es_eq(&es, e1(), e1()); + + let result = trigger_finalized(&mut es, e1(), e2()); + assert_eq!(result, false); + assert_es_eq(&es, e1(), e1()); + } + + #[test] + fn test_enactment_helper_6() { + sp_tracing::try_init_simple(); + let mut es = EnactmentState::new(a().hash, a().hash); + + // A-B1-C1-D1-E1 + + let result = trigger_new_best_block(&mut es, a(), b1()); + assert!(result); + assert_es_eq(&es, b1(), a()); + + let result = trigger_finalized(&mut es, a(), d1()); + assert!(result); + assert_es_eq(&es, d1(), d1()); + + let result = trigger_new_best_block(&mut es, a(), e1()); + assert!(result); + assert_es_eq(&es, e1(), d1()); + + let result = trigger_new_best_block(&mut es, a(), c1()); + assert_eq!(result, false); + assert_es_eq(&es, e1(), d1()); + } +} diff --git a/client/transaction-pool/src/graph/listener.rs b/client/transaction-pool/src/graph/listener.rs index d4f42b32fdbb8..776749abf2d5d 100644 --- a/client/transaction-pool/src/graph/listener.rs +++ b/client/transaction-pool/src/graph/listener.rs @@ -104,13 +104,18 @@ impl Listener { /// Transaction was pruned from the pool. pub fn pruned(&mut self, block_hash: BlockHash, tx: &H) { debug!(target: "txpool", "[{:?}] Pruned at {:?}", tx, block_hash); - self.fire(tx, |s| s.in_block(block_hash)); - self.finality_watchers.entry(block_hash).or_insert(vec![]).push(tx.clone()); + // Get the transactions included in the given block hash. + let txs = self.finality_watchers.entry(block_hash).or_insert(vec![]); + txs.push(tx.clone()); + // Current transaction is the last one included. + let tx_index = txs.len() - 1; + + self.fire(tx, |watcher| watcher.in_block(block_hash, tx_index)); while self.finality_watchers.len() > MAX_FINALITY_WATCHERS { if let Some((hash, txs)) = self.finality_watchers.pop_front() { for tx in txs { - self.fire(&tx, |s| s.finality_timeout(hash)); + self.fire(&tx, |watcher| watcher.finality_timeout(hash)); } } } @@ -120,7 +125,7 @@ impl Listener { pub fn retracted(&mut self, block_hash: BlockHash) { if let Some(hashes) = self.finality_watchers.remove(&block_hash) { for hash in hashes { - self.fire(&hash, |s| s.retracted(block_hash)) + self.fire(&hash, |watcher| watcher.retracted(block_hash)) } } } @@ -128,9 +133,9 @@ impl Listener { /// Notify all watchers that transactions have been finalized pub fn finalized(&mut self, block_hash: BlockHash) { if let Some(hashes) = self.finality_watchers.remove(&block_hash) { - for hash in hashes { + for (tx_index, hash) in hashes.into_iter().enumerate() { log::debug!(target: "txpool", "[{:?}] Sent finalization event (block {:?})", hash, block_hash); - self.fire(&hash, |s| s.finalized(block_hash)) + self.fire(&hash, |watcher| watcher.finalized(block_hash, tx_index)) } } } diff --git a/client/transaction-pool/src/graph/pool.rs b/client/transaction-pool/src/graph/pool.rs index 19acbddbe7843..d311e0d0c8f2f 100644 --- a/client/transaction-pool/src/graph/pool.rs +++ b/client/transaction-pool/src/graph/pool.rs @@ -20,6 +20,7 @@ use std::{collections::HashMap, sync::Arc, time::Duration}; use futures::{channel::mpsc::Receiver, Future}; use sc_transaction_pool_api::error; +use sp_blockchain::TreeRoute; use sp_runtime::{ generic::BlockId, traits::{self, Block as BlockT, SaturatedConversion}, @@ -97,6 +98,13 @@ pub trait ChainApi: Send + Sync { &self, at: &BlockId, ) -> Result::Header>, Self::Error>; + + /// Compute a tree-route between two blocks. See [`TreeRoute`] for more details. + fn tree_route( + &self, + from: ::Hash, + to: ::Hash, + ) -> Result, Self::Error>; } /// Pool configuration options. @@ -160,7 +168,7 @@ impl Pool { ) -> Result, B::Error>>, B::Error> { let xts = xts.into_iter().map(|xt| (source, xt)); let validated_transactions = self.verify(at, xts, CheckBannedBeforeVerify::Yes).await?; - Ok(self.validated_pool.submit(validated_transactions.into_iter().map(|(_, tx)| tx))) + Ok(self.validated_pool.submit(validated_transactions.into_values())) } /// Resubmit the given extrinsics to the pool. @@ -174,7 +182,7 @@ impl Pool { ) -> Result, B::Error>>, B::Error> { let xts = xts.into_iter().map(|xt| (source, xt)); let validated_transactions = self.verify(at, xts, CheckBannedBeforeVerify::No).await?; - Ok(self.validated_pool.submit(validated_transactions.into_iter().map(|(_, tx)| tx))) + Ok(self.validated_pool.submit(validated_transactions.into_values())) } /// Imports one unverified extrinsic to the pool @@ -341,7 +349,7 @@ impl Pool { at, known_imported_hashes, pruned_hashes, - reverified_transactions.into_iter().map(|(_, xt)| xt).collect(), + reverified_transactions.into_values().collect(), ) } @@ -770,7 +778,7 @@ mod tests { assert_eq!(stream.next(), Some(TransactionStatus::Ready)); assert_eq!( stream.next(), - Some(TransactionStatus::InBlock(H256::from_low_u64_be(2).into())), + Some(TransactionStatus::InBlock((H256::from_low_u64_be(2).into(), 0))), ); } @@ -803,7 +811,7 @@ mod tests { assert_eq!(stream.next(), Some(TransactionStatus::Ready)); assert_eq!( stream.next(), - Some(TransactionStatus::InBlock(H256::from_low_u64_be(2).into())), + Some(TransactionStatus::InBlock((H256::from_low_u64_be(2).into(), 0))), ); } diff --git a/client/transaction-pool/src/graph/watcher.rs b/client/transaction-pool/src/graph/watcher.rs index 8cd78cfc78240..0613300c8684b 100644 --- a/client/transaction-pool/src/graph/watcher.rs +++ b/client/transaction-pool/src/graph/watcher.rs @@ -84,13 +84,13 @@ impl Sender { } /// Extrinsic has been included in block with given hash. - pub fn in_block(&mut self, hash: BH) { - self.send(TransactionStatus::InBlock(hash)); + pub fn in_block(&mut self, hash: BH, index: usize) { + self.send(TransactionStatus::InBlock((hash, index))); } /// Extrinsic has been finalized by a finality gadget. - pub fn finalized(&mut self, hash: BH) { - self.send(TransactionStatus::Finalized(hash)); + pub fn finalized(&mut self, hash: BH, index: usize) { + self.send(TransactionStatus::Finalized((hash, index))); self.is_finalized = true; } diff --git a/client/transaction-pool/src/lib.rs b/client/transaction-pool/src/lib.rs index 00ce09ce3787b..fa735303c58f7 100644 --- a/client/transaction-pool/src/lib.rs +++ b/client/transaction-pool/src/lib.rs @@ -23,6 +23,7 @@ #![warn(unused_extern_crates)] mod api; +mod enactment_state; pub mod error; mod graph; mod metrics; @@ -32,6 +33,8 @@ use codec::Decode; mod tests; pub use crate::api::FullChainApi; +use async_trait::async_trait; +use enactment_state::EnactmentState; use futures::{ channel::oneshot, future::{self, ready}, @@ -63,6 +66,8 @@ use std::time::Instant; use crate::metrics::MetricsLink as PrometheusMetrics; use prometheus_endpoint::Registry as PrometheusRegistry; +use sp_blockchain::{HashAndNumber, TreeRoute}; + type BoxedReadyIterator = Box>> + Send>; @@ -86,6 +91,7 @@ where revalidation_queue: Arc>, ready_poll: Arc, Block>>>, metrics: PrometheusMetrics, + enactment_state: Arc>>, } struct ReadyPoll { @@ -164,7 +170,11 @@ where PoolApi: graph::ChainApi + 'static, { /// Create new basic transaction pool with provided api, for tests. - pub fn new_test(pool_api: Arc) -> (Self, Pin + Send>>) { + pub fn new_test( + pool_api: Arc, + best_block_hash: Block::Hash, + finalized_hash: Block::Hash, + ) -> (Self, Pin + Send>>) { let pool = Arc::new(graph::Pool::new(Default::default(), true.into(), pool_api.clone())); let (revalidation_queue, background_task) = revalidation::RevalidationQueue::new_background(pool_api.clone(), pool.clone()); @@ -176,6 +186,10 @@ where revalidation_strategy: Arc::new(Mutex::new(RevalidationStrategy::Always)), ready_poll: Default::default(), metrics: Default::default(), + enactment_state: Arc::new(Mutex::new(EnactmentState::new( + best_block_hash, + finalized_hash, + ))), }, background_task, ) @@ -191,6 +205,8 @@ where revalidation_type: RevalidationType, spawner: impl SpawnEssentialNamed, best_block_number: NumberFor, + best_block_hash: Block::Hash, + finalized_hash: Block::Hash, ) -> Self { let pool = Arc::new(graph::Pool::new(options, is_validator, pool_api.clone())); let (revalidation_queue, background_task) = match revalidation_type { @@ -218,6 +234,10 @@ where })), ready_poll: Arc::new(Mutex::new(ReadyPoll::new(best_block_number))), metrics: PrometheusMetrics::new(prometheus), + enactment_state: Arc::new(Mutex::new(EnactmentState::new( + best_block_hash, + finalized_hash, + ))), } } @@ -359,6 +379,7 @@ where + sp_runtime::traits::BlockIdTo + sc_client_api::ExecutorProvider + sc_client_api::UsageProvider + + sp_blockchain::HeaderMetadata + Send + Sync + 'static, @@ -381,6 +402,8 @@ where RevalidationType::Full, spawner, client.usage_info().chain.best_number, + client.usage_info().chain.best_hash, + client.usage_info().chain.finalized_hash, )); // make transaction pool available for off-chain runtime calls. @@ -397,7 +420,8 @@ where Client: sp_api::ProvideRuntimeApi + sc_client_api::BlockBackend + sc_client_api::blockchain::HeaderBackend - + sp_runtime::traits::BlockIdTo, + + sp_runtime::traits::BlockIdTo + + sp_blockchain::HeaderMetadata, Client: Send + Sync + 'static, Client::Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue, { @@ -582,166 +606,190 @@ async fn prune_known_txs_for_block MaintainedTransactionPool for BasicPool +impl BasicPool where Block: BlockT, PoolApi: 'static + graph::ChainApi, { - fn maintain(&self, event: ChainEvent) -> Pin + Send>> { - match event { - ChainEvent::NewBestBlock { hash, tree_route } => { - let pool = self.pool.clone(); - let api = self.api.clone(); - - let id = BlockId::hash(hash); - let block_number = match api.block_id_to_number(&id) { - Ok(Some(number)) => number, - _ => { - log::trace!( + /// Handles enactment and retraction of blocks, prunes stale transactions + /// (that have already been enacted) and resubmits transactions that were + /// retracted. + async fn handle_enactment(&self, tree_route: TreeRoute) { + log::trace!(target: "txpool", "handle_enactment tree_route: {tree_route:?}"); + let pool = self.pool.clone(); + let api = self.api.clone(); + + let (hash, block_number) = match tree_route.last() { + Some(HashAndNumber { hash, number }) => (hash, number), + None => { + log::warn!( + target: "txpool", + "Skipping ChainEvent - no last block in tree route {:?}", + tree_route, + ); + return + }, + }; + + let next_action = self.revalidation_strategy.lock().next( + *block_number, + Some(std::time::Duration::from_secs(60)), + Some(20u32.into()), + ); + + // We keep track of everything we prune so that later we won't add + // transactions with those hashes from the retracted blocks. + let mut pruned_log = HashSet::>::new(); + + // If there is a tree route, we use this to prune known tx based on the enacted + // blocks. Before pruning enacted transactions, we inform the listeners about + // retracted blocks and their transactions. This order is important, because + // if we enact and retract the same transaction at the same time, we want to + // send first the retract and than the prune event. + for retracted in tree_route.retracted() { + // notify txs awaiting finality that it has been retracted + pool.validated_pool().on_block_retracted(retracted.hash); + } + + future::join_all( + tree_route + .enacted() + .iter() + .map(|h| prune_known_txs_for_block(BlockId::Hash(h.hash), &*api, &*pool)), + ) + .await + .into_iter() + .for_each(|enacted_log| { + pruned_log.extend(enacted_log); + }); + + self.metrics + .report(|metrics| metrics.block_transactions_pruned.inc_by(pruned_log.len() as u64)); + + if next_action.resubmit { + let mut resubmit_transactions = Vec::new(); + + for retracted in tree_route.retracted() { + let hash = retracted.hash; + + let block_transactions = api + .block_body(&BlockId::hash(hash)) + .await + .unwrap_or_else(|e| { + log::warn!("Failed to fetch block body: {}", e); + None + }) + .unwrap_or_default() + .into_iter() + .filter(|tx| tx.is_signed().unwrap_or(true)); + + let mut resubmitted_to_report = 0; + + resubmit_transactions.extend(block_transactions.into_iter().filter(|tx| { + let tx_hash = pool.hash_of(tx); + let contains = pruned_log.contains(&tx_hash); + + // need to count all transactions, not just filtered, here + resubmitted_to_report += 1; + + if !contains { + log::debug!( target: "txpool", - "Skipping chain event - no number for that block {:?}", - id, + "[{:?}]: Resubmitting from retracted block {:?}", + tx_hash, + hash, ); - return Box::pin(ready(())) - }, - }; - - let next_action = self.revalidation_strategy.lock().next( - block_number, - Some(std::time::Duration::from_secs(60)), - Some(20u32.into()), - ); - let revalidation_strategy = self.revalidation_strategy.clone(); - let revalidation_queue = self.revalidation_queue.clone(); - let ready_poll = self.ready_poll.clone(); - let metrics = self.metrics.clone(); - - async move { - // We keep track of everything we prune so that later we won't add - // transactions with those hashes from the retracted blocks. - let mut pruned_log = HashSet::>::new(); - - // If there is a tree route, we use this to prune known tx based on the enacted - // blocks. Before pruning enacted transactions, we inform the listeners about - // retracted blocks and their transactions. This order is important, because - // if we enact and retract the same transaction at the same time, we want to - // send first the retract and than the prune event. - if let Some(ref tree_route) = tree_route { - for retracted in tree_route.retracted() { - // notify txs awaiting finality that it has been retracted - pool.validated_pool().on_block_retracted(retracted.hash); - } - - future::join_all(tree_route.enacted().iter().map(|h| { - prune_known_txs_for_block(BlockId::Hash(h.hash), &*api, &*pool) - })) - .await - .into_iter() - .for_each(|enacted_log| { - pruned_log.extend(enacted_log); - }) } + !contains + })); - pruned_log.extend(prune_known_txs_for_block(id, &*api, &*pool).await); - - metrics.report(|metrics| { - metrics.block_transactions_pruned.inc_by(pruned_log.len() as u64) - }); - - if let (true, Some(tree_route)) = (next_action.resubmit, tree_route) { - let mut resubmit_transactions = Vec::new(); - - for retracted in tree_route.retracted() { - let hash = retracted.hash; - - let block_transactions = api - .block_body(&BlockId::hash(hash)) - .await - .unwrap_or_else(|e| { - log::warn!("Failed to fetch block body: {}", e); - None - }) - .unwrap_or_default() - .into_iter() - .filter(|tx| tx.is_signed().unwrap_or(true)); - - let mut resubmitted_to_report = 0; - - resubmit_transactions.extend(block_transactions.into_iter().filter( - |tx| { - let tx_hash = pool.hash_of(tx); - let contains = pruned_log.contains(&tx_hash); - - // need to count all transactions, not just filtered, here - resubmitted_to_report += 1; - - if !contains { - log::debug!( - target: "txpool", - "[{:?}]: Resubmitting from retracted block {:?}", - tx_hash, - hash, - ); - } - !contains - }, - )); - - metrics.report(|metrics| { - metrics.block_transactions_resubmitted.inc_by(resubmitted_to_report) - }); - } - - if let Err(e) = pool - .resubmit_at( - &id, - // These transactions are coming from retracted blocks, we should - // simply consider them external. - TransactionSource::External, - resubmit_transactions, - ) - .await - { - log::debug!( - target: "txpool", - "[{:?}] Error re-submitting transactions: {}", - id, - e, - ) - } - } + self.metrics.report(|metrics| { + metrics.block_transactions_resubmitted.inc_by(resubmitted_to_report) + }); + } - let extra_pool = pool.clone(); - // After #5200 lands, this arguably might be moved to the - // handler of "all blocks notification". - ready_poll.lock().trigger(block_number, move || { - Box::new(extra_pool.validated_pool().ready()) - }); + if let Err(e) = pool + .resubmit_at( + &BlockId::Hash(*hash), + // These transactions are coming from retracted blocks, we should + // simply consider them external. + TransactionSource::External, + resubmit_transactions, + ) + .await + { + log::debug!( + target: "txpool", + "[{:?}] Error re-submitting transactions: {}", + hash, + e, + ) + } + } - if next_action.revalidate { - let hashes = pool.validated_pool().ready().map(|tx| tx.hash).collect(); - revalidation_queue.revalidate_later(block_number, hashes).await; + let extra_pool = pool.clone(); + // After #5200 lands, this arguably might be moved to the + // handler of "all blocks notification". + self.ready_poll + .lock() + .trigger(*block_number, move || Box::new(extra_pool.validated_pool().ready())); - revalidation_strategy.lock().clear(); - } - } - .boxed() + if next_action.revalidate { + let hashes = pool.validated_pool().ready().map(|tx| tx.hash).collect(); + self.revalidation_queue.revalidate_later(*block_number, hashes).await; + + self.revalidation_strategy.lock().clear(); + } + } +} + +#[async_trait] +impl MaintainedTransactionPool for BasicPool +where + Block: BlockT, + PoolApi: 'static + graph::ChainApi, +{ + async fn maintain(&self, event: ChainEvent) { + let prev_finalized_block = self.enactment_state.lock().recent_finalized_block(); + let compute_tree_route = |from, to| -> Result, String> { + match self.api.tree_route(from, to) { + Ok(tree_route) => Ok(tree_route), + Err(e) => + return Err(format!( + "Error occurred while computing tree_route from {from:?} to {to:?}: {e}" + )), + } + }; + + let result = self.enactment_state.lock().update(&event, &compute_tree_route); + + match result { + Err(msg) => { + log::warn!(target: "txpool", "{msg}"); + return }, - ChainEvent::Finalized { hash, tree_route } => { - let pool = self.pool.clone(); - async move { - for hash in tree_route.iter().chain(&[hash]) { - if let Err(e) = pool.validated_pool().on_block_finalized(*hash).await { - log::warn!( - target: "txpool", - "Error [{}] occurred while attempting to notify watchers of finalization {}", - e, hash - ) - } - } - } - .boxed() + Ok(None) => {}, + Ok(Some(tree_route)) => { + self.handle_enactment(tree_route).await; }, + }; + + if let ChainEvent::Finalized { hash, tree_route } = event { + log::trace!( + target: "txpool", + "on-finalized enacted: {tree_route:?}, previously finalized: \ + {prev_finalized_block:?}", + ); + + for hash in tree_route.iter().chain(std::iter::once(&hash)) { + if let Err(e) = self.pool.validated_pool().on_block_finalized(*hash).await { + log::warn!( + target: "txpool", + "Error occurred while attempting to notify watchers about finalization {}: {}", + hash, e + ) + } + } } } } diff --git a/client/transaction-pool/src/tests.rs b/client/transaction-pool/src/tests.rs index 79142e16a1b36..ce2c7872e32bb 100644 --- a/client/transaction-pool/src/tests.rs +++ b/client/transaction-pool/src/tests.rs @@ -22,6 +22,7 @@ use crate::graph::{BlockHash, ChainApi, ExtrinsicFor, NumberFor, Pool}; use codec::Encode; use parking_lot::Mutex; use sc_transaction_pool_api::error; +use sp_blockchain::TreeRoute; use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, Hash}, @@ -173,6 +174,14 @@ impl ChainApi for TestApi { ) -> Result::Header>, Self::Error> { Ok(None) } + + fn tree_route( + &self, + _from: ::Hash, + _to: ::Hash, + ) -> Result, Self::Error> { + unimplemented!() + } } pub(crate) fn uxt(transfer: Transfer) -> Extrinsic { diff --git a/client/transaction-pool/tests/pool.rs b/client/transaction-pool/tests/pool.rs index 17c2cfa8a1e06..27891432753a4 100644 --- a/client/transaction-pool/tests/pool.rs +++ b/client/transaction-pool/tests/pool.rs @@ -30,13 +30,14 @@ use sc_transaction_pool::*; use sc_transaction_pool_api::{ ChainEvent, MaintainedTransactionPool, TransactionPool, TransactionStatus, }; +use sp_blockchain::HeaderBackend; use sp_consensus::BlockOrigin; use sp_runtime::{ generic::BlockId, traits::Block as _, transaction_validity::{InvalidTransaction, TransactionSource, ValidTransaction}, }; -use std::{collections::BTreeSet, sync::Arc}; +use std::{collections::BTreeSet, pin::Pin, sync::Arc}; use substrate_test_runtime_client::{ runtime::{Block, Extrinsic, Hash, Header, Index, Transfer}, AccountKeyring::*, @@ -50,13 +51,32 @@ fn pool() -> Pool { fn maintained_pool() -> (BasicPool, Arc, futures::executor::ThreadPool) { let api = Arc::new(TestApi::with_alice_nonce(209)); - let (pool, background_task) = BasicPool::new_test(api.clone()); + let (pool, background_task) = create_basic_pool_with_genesis(api.clone()); let thread_pool = futures::executor::ThreadPool::new().unwrap(); thread_pool.spawn_ok(background_task); (pool, api, thread_pool) } +fn create_basic_pool_with_genesis( + test_api: Arc, +) -> (BasicPool, Pin + Send>>) { + let genesis_hash = { + test_api + .chain() + .read() + .block_by_number + .get(&0) + .map(|blocks| blocks[0].0.header.hash()) + .expect("there is block 0. qed") + }; + BasicPool::new_test(test_api, genesis_hash, genesis_hash) +} + +fn create_basic_pool(test_api: TestApi) -> BasicPool { + create_basic_pool_with_genesis(Arc::from(test_api)).0 +} + const SOURCE: TransactionSource = TransactionSource::External; #[test] @@ -328,7 +348,7 @@ fn should_revalidate_across_many_blocks() { block_on( watcher1 - .take_while(|s| future::ready(*s != TransactionStatus::InBlock(block_hash))) + .take_while(|s| future::ready(*s != TransactionStatus::InBlock((block_hash, 0)))) .collect::>(), ); @@ -398,24 +418,24 @@ fn should_push_watchers_during_maintenance() { futures::executor::block_on_stream(watcher0).collect::>(), vec![ TransactionStatus::Ready, - TransactionStatus::InBlock(header_hash), - TransactionStatus::Finalized(header_hash) + TransactionStatus::InBlock((header_hash, 0)), + TransactionStatus::Finalized((header_hash, 0)) ], ); assert_eq!( futures::executor::block_on_stream(watcher1).collect::>(), vec![ TransactionStatus::Ready, - TransactionStatus::InBlock(header_hash), - TransactionStatus::Finalized(header_hash) + TransactionStatus::InBlock((header_hash, 1)), + TransactionStatus::Finalized((header_hash, 1)) ], ); assert_eq!( futures::executor::block_on_stream(watcher2).collect::>(), vec![ TransactionStatus::Ready, - TransactionStatus::InBlock(header_hash), - TransactionStatus::Finalized(header_hash) + TransactionStatus::InBlock((header_hash, 2)), + TransactionStatus::Finalized((header_hash, 2)) ], ); } @@ -436,7 +456,7 @@ fn finalization() { let xt = uxt(Alice, 209); let api = TestApi::with_alice_nonce(209); api.push_block(1, vec![], true); - let (pool, _background) = BasicPool::new_test(api.into()); + let pool = create_basic_pool(api); let watcher = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, xt.clone())) .expect("1. Imported"); pool.api().push_block(2, vec![xt.clone()], true); @@ -450,8 +470,8 @@ fn finalization() { let mut stream = futures::executor::block_on_stream(watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(header.hash()))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((header.hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((header.hash(), 0)))); assert_eq!(stream.next(), None); } @@ -459,9 +479,9 @@ fn finalization() { fn fork_aware_finalization() { let api = TestApi::empty(); // starting block A1 (last finalized.) - api.push_block(1, vec![], true); + let a_header = api.push_block(1, vec![], true); - let (pool, _background) = BasicPool::new_test(api.into()); + let pool = create_basic_pool(api); let mut canon_watchers = vec![]; let from_alice = uxt(Alice, 1); @@ -476,10 +496,13 @@ fn fork_aware_finalization() { let from_dave_watcher; let from_bob_watcher; let b1; + let c1; let d1; let c2; let d2; + block_on(pool.maintain(block_event(a_header))); + // block B1 { let watcher = @@ -489,6 +512,7 @@ fn fork_aware_finalization() { canon_watchers.push((watcher, header.hash())); assert_eq!(pool.status().ready, 1); + log::trace!(target:"txpool", ">> B1: {:?} {:?}", header.hash(), header); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; b1 = header.hash(); block_on(pool.maintain(event)); @@ -504,6 +528,7 @@ fn fork_aware_finalization() { block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_dave.clone())) .expect("1. Imported"); assert_eq!(pool.status().ready, 1); + log::trace!(target:"txpool", ">> C2: {:?} {:?}", header.hash(), header); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; c2 = header.hash(); block_on(pool.maintain(event)); @@ -518,6 +543,7 @@ fn fork_aware_finalization() { assert_eq!(pool.status().ready, 1); let header = pool.api().push_block_with_parent(c2, vec![from_bob.clone()], true); + log::trace!(target:"txpool", ">> D2: {:?} {:?}", header.hash(), header); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; d2 = header.hash(); block_on(pool.maintain(event)); @@ -530,8 +556,9 @@ fn fork_aware_finalization() { block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_charlie.clone())) .expect("1.Imported"); assert_eq!(pool.status().ready, 1); - let header = pool.api().push_block(3, vec![from_charlie.clone()], true); - + let header = pool.api().push_block_with_parent(b1, vec![from_charlie.clone()], true); + log::trace!(target:"txpool", ">> C1: {:?} {:?}", header.hash(), header); + c1 = header.hash(); canon_watchers.push((watcher, header.hash())); let event = block_event_with_retracted(header.clone(), d2, pool.api()); block_on(pool.maintain(event)); @@ -547,11 +574,12 @@ fn fork_aware_finalization() { let w = block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, xt.clone())) .expect("1. Imported"); assert_eq!(pool.status().ready, 3); - let header = pool.api().push_block(4, vec![xt.clone()], true); + let header = pool.api().push_block_with_parent(c1, vec![xt.clone()], true); + log::trace!(target:"txpool", ">> D1: {:?} {:?}", header.hash(), header); + d1 = header.hash(); canon_watchers.push((w, header.hash())); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; - d1 = header.hash(); block_on(pool.maintain(event)); assert_eq!(pool.status().ready, 2); let event = ChainEvent::Finalized { hash: d1, tree_route: Arc::from(vec![]) }; @@ -560,9 +588,10 @@ fn fork_aware_finalization() { let e1; - // block e1 + // block E1 { - let header = pool.api().push_block(5, vec![from_dave, from_bob], true); + let header = pool.api().push_block_with_parent(d1, vec![from_dave, from_bob], true); + log::trace!(target:"txpool", ">> E1: {:?} {:?}", header.hash(), header); e1 = header.hash(); let event = ChainEvent::NewBestBlock { hash: header.hash(), tree_route: None }; block_on(pool.maintain(event)); @@ -573,30 +602,31 @@ fn fork_aware_finalization() { for (canon_watcher, h) in canon_watchers { let mut stream = futures::executor::block_on_stream(canon_watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(h))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(h))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((h, 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((h, 0)))); assert_eq!(stream.next(), None); } { let mut stream = futures::executor::block_on_stream(from_dave_watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(c2))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((c2, 0)))); assert_eq!(stream.next(), Some(TransactionStatus::Retracted(c2))); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(e1))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(e1))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((e1, 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((e1, 0)))); assert_eq!(stream.next(), None); } { let mut stream = futures::executor::block_on_stream(from_bob_watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(d2))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((d2, 0)))); assert_eq!(stream.next(), Some(TransactionStatus::Retracted(d2))); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(e1))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(e1))); + // In block e1 we submitted: [dave, bob] xts in this order. + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((e1, 1)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((e1, 1)))); assert_eq!(stream.next(), None); } } @@ -609,7 +639,7 @@ fn prune_and_retract_tx_at_same_time() { // starting block A1 (last finalized.) api.push_block(1, vec![], true); - let (pool, _background) = BasicPool::new_test(api.into()); + let pool = create_basic_pool(api); let from_alice = uxt(Alice, 1); pool.api().increment_nonce(Alice.into()); @@ -646,10 +676,10 @@ fn prune_and_retract_tx_at_same_time() { { let mut stream = futures::executor::block_on_stream(watcher); assert_eq!(stream.next(), Some(TransactionStatus::Ready)); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b1))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b1, 0)))); assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b1))); - assert_eq!(stream.next(), Some(TransactionStatus::InBlock(b2))); - assert_eq!(stream.next(), Some(TransactionStatus::Finalized(b2))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b2, 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((b2, 0)))); assert_eq!(stream.next(), None); } } @@ -675,7 +705,7 @@ fn resubmit_tx_of_fork_that_is_not_part_of_retracted() { // starting block A1 (last finalized.) api.push_block(1, vec![], true); - let (pool, _background) = BasicPool::new_test(api.into()); + let pool = create_basic_pool(api); let tx0 = uxt(Alice, 1); let tx1 = uxt(Dave, 2); @@ -720,7 +750,7 @@ fn resubmit_from_retracted_fork() { // starting block A1 (last finalized.) api.push_block(1, vec![], true); - let (pool, _background) = BasicPool::new_test(api.into()); + let pool = create_basic_pool(api); let tx0 = uxt(Alice, 1); let tx1 = uxt(Dave, 2); @@ -865,13 +895,14 @@ fn ready_set_should_eventually_resolve_when_block_update_arrives() { #[test] fn should_not_accept_old_signatures() { let client = Arc::new(substrate_test_runtime_client::new()); - + let best_hash = client.info().best_hash; + let finalized_hash = client.info().finalized_hash; let pool = Arc::new( - BasicPool::new_test(Arc::new(FullChainApi::new( - client, - None, - &sp_core::testing::TaskExecutor::new(), - ))) + BasicPool::new_test( + Arc::new(FullChainApi::new(client, None, &sp_core::testing::TaskExecutor::new())), + best_hash, + finalized_hash, + ) .0, ); @@ -880,7 +911,7 @@ fn should_not_accept_old_signatures() { // generated with schnorrkel 0.1.1 from `_bytes` let old_singature = sp_core::sr25519::Signature::try_from( - &hex::decode( + &array_bytes::hex2bytes( "c427eb672e8c441c86d31f1a81b22b43102058e9ce237cabe9897ea5099ffd426\ cd1c6a1f4f2869c3df57901d36bedcb295657adb3a4355add86ed234eb83108", ) @@ -907,12 +938,19 @@ fn should_not_accept_old_signatures() { fn import_notification_to_pool_maintain_works() { let mut client = Arc::new(substrate_test_runtime_client::new()); + let best_hash = client.info().best_hash; + let finalized_hash = client.info().finalized_hash; + let pool = Arc::new( - BasicPool::new_test(Arc::new(FullChainApi::new( - client.clone(), - None, - &sp_core::testing::TaskExecutor::new(), - ))) + BasicPool::new_test( + Arc::new(FullChainApi::new( + client.clone(), + None, + &sp_core::testing::TaskExecutor::new(), + )), + best_hash, + finalized_hash, + ) .0, ); @@ -997,3 +1035,540 @@ fn stale_transactions_are_pruned() { assert_eq!(pool.status().future, 0); assert_eq!(pool.status().ready, 0); } + +#[test] +fn finalized_only_handled_correctly() { + sp_tracing::try_init_simple(); + let xt = uxt(Alice, 209); + + let (pool, api, _guard) = maintained_pool(); + + let watcher = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, xt.clone())) + .expect("1. Imported"); + assert_eq!(pool.status().ready, 1); + + let header = api.push_block(1, vec![xt], false); + + let event = + ChainEvent::Finalized { hash: header.clone().hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + + assert_eq!(pool.status().ready, 0); + + { + let mut stream = futures::executor::block_on_stream(watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((header.clone().hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((header.hash(), 0)))); + assert_eq!(stream.next(), None); + } +} + +#[test] +fn best_block_after_finalized_handled_correctly() { + sp_tracing::try_init_simple(); + let xt = uxt(Alice, 209); + + let (pool, api, _guard) = maintained_pool(); + + let watcher = block_on(pool.submit_and_watch(&BlockId::number(0), SOURCE, xt.clone())) + .expect("1. Imported"); + assert_eq!(pool.status().ready, 1); + + let header = api.push_block(1, vec![xt], true); + + let event = + ChainEvent::Finalized { hash: header.clone().hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + block_on(pool.maintain(block_event(header.clone()))); + + assert_eq!(pool.status().ready, 0); + + { + let mut stream = futures::executor::block_on_stream(watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((header.clone().hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((header.hash(), 0)))); + assert_eq!(stream.next(), None); + } +} + +#[test] +fn switching_fork_with_finalized_works() { + sp_tracing::try_init_simple(); + let api = TestApi::empty(); + // starting block A1 (last finalized.) + let a_header = api.push_block(1, vec![], true); + + let pool = create_basic_pool(api); + + let from_alice = uxt(Alice, 1); + let from_bob = uxt(Bob, 2); + pool.api().increment_nonce(Alice.into()); + pool.api().increment_nonce(Bob.into()); + + let from_alice_watcher; + let from_bob_watcher; + let b1_header; + let b2_header; + + // block B1 + { + from_alice_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); + assert_eq!(pool.status().ready, 1); + log::trace!(target:"txpool", ">> B1: {:?} {:?}", header.hash(), header); + b1_header = header; + } + + // block B2 + { + from_bob_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())) + .expect("1. Imported"); + let header = pool.api().push_block_with_parent( + a_header.hash(), + vec![from_alice.clone(), from_bob.clone()], + true, + ); + assert_eq!(pool.status().ready, 2); + + log::trace!(target:"txpool", ">> B2: {:?} {:?}", header.hash(), header); + b2_header = header; + } + + { + let event = ChainEvent::NewBestBlock { hash: b1_header.hash(), tree_route: None }; + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 1); + } + + { + let event = ChainEvent::Finalized { hash: b2_header.hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + } + + { + let mut stream = futures::executor::block_on_stream(from_alice_watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b1_header.hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b2_header.hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((b2_header.hash(), 0)))); + assert_eq!(stream.next(), None); + } + + { + let mut stream = futures::executor::block_on_stream(from_bob_watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b2_header.hash(), 1)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((b2_header.hash(), 1)))); + assert_eq!(stream.next(), None); + } +} + +#[test] +fn switching_fork_multiple_times_works() { + sp_tracing::try_init_simple(); + let api = TestApi::empty(); + // starting block A1 (last finalized.) + let a_header = api.push_block(1, vec![], true); + + let pool = create_basic_pool(api); + + let from_alice = uxt(Alice, 1); + let from_bob = uxt(Bob, 2); + pool.api().increment_nonce(Alice.into()); + pool.api().increment_nonce(Bob.into()); + + let from_alice_watcher; + let from_bob_watcher; + let b1_header; + let b2_header; + + // block B1 + { + from_alice_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); + assert_eq!(pool.status().ready, 1); + log::trace!(target:"txpool", ">> B1: {:?} {:?}", header.hash(), header); + b1_header = header; + } + + // block B2 + { + from_bob_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())) + .expect("1. Imported"); + let header = pool.api().push_block_with_parent( + a_header.hash(), + vec![from_alice.clone(), from_bob.clone()], + true, + ); + assert_eq!(pool.status().ready, 2); + + log::trace!(target:"txpool", ">> B2: {:?} {:?}", header.hash(), header); + b2_header = header; + } + + { + // phase-0 + let event = ChainEvent::NewBestBlock { hash: b1_header.hash(), tree_route: None }; + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 1); + } + + { + // phase-1 + let event = block_event_with_retracted(b2_header.clone(), b1_header.hash(), pool.api()); + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 0); + } + + { + // phase-2 + let event = block_event_with_retracted(b1_header.clone(), b2_header.hash(), pool.api()); + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 1); + } + + { + // phase-3 + let event = ChainEvent::Finalized { hash: b2_header.hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + } + + { + let mut stream = futures::executor::block_on_stream(from_alice_watcher); + //phase-0 + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b1_header.hash(), 0)))); + //phase-1 + assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b2_header.hash(), 0)))); + //phase-2 + assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b2_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b1_header.hash(), 0)))); + //phase-3 + assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b1_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b2_header.hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((b2_header.hash(), 0)))); + assert_eq!(stream.next(), None); + } + + { + let mut stream = futures::executor::block_on_stream(from_bob_watcher); + //phase-1 + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b2_header.hash(), 1)))); + //phase-2 + assert_eq!(stream.next(), Some(TransactionStatus::Retracted(b2_header.hash()))); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + //phase-3 + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b2_header.hash(), 1)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((b2_header.hash(), 1)))); + assert_eq!(stream.next(), None); + } +} + +#[test] +fn two_blocks_delayed_finalization_works() { + sp_tracing::try_init_simple(); + let api = TestApi::empty(); + // starting block A1 (last finalized.) + let a_header = api.push_block(1, vec![], true); + + let pool = create_basic_pool(api); + + let from_alice = uxt(Alice, 1); + let from_bob = uxt(Bob, 2); + let from_charlie = uxt(Charlie, 3); + pool.api().increment_nonce(Alice.into()); + pool.api().increment_nonce(Bob.into()); + pool.api().increment_nonce(Charlie.into()); + + let from_alice_watcher; + let from_bob_watcher; + let from_charlie_watcher; + let b1_header; + let c1_header; + let d1_header; + + // block B1 + { + from_alice_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); + assert_eq!(pool.status().ready, 1); + + log::trace!(target:"txpool", ">> B1: {:?} {:?}", header.hash(), header); + b1_header = header; + } + + // block C1 + { + from_bob_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true); + assert_eq!(pool.status().ready, 2); + + log::trace!(target:"txpool", ">> C1: {:?} {:?}", header.hash(), header); + c1_header = header; + } + + // block D1 + { + from_charlie_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_charlie.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(c1_header.hash(), vec![from_charlie.clone()], true); + assert_eq!(pool.status().ready, 3); + + log::trace!(target:"txpool", ">> D1: {:?} {:?}", header.hash(), header); + d1_header = header; + } + + { + let event = ChainEvent::Finalized { hash: a_header.hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 3); + } + + { + let event = ChainEvent::NewBestBlock { hash: d1_header.hash(), tree_route: None }; + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 0); + } + + { + let event = ChainEvent::Finalized { + hash: c1_header.hash(), + tree_route: Arc::from(vec![b1_header.hash()]), + }; + block_on(pool.maintain(event)); + } + + // this is to collect events from_charlie_watcher and make sure nothing was retracted + { + let event = ChainEvent::Finalized { hash: d1_header.hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + } + + { + let mut stream = futures::executor::block_on_stream(from_alice_watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b1_header.hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((b1_header.hash(), 0)))); + assert_eq!(stream.next(), None); + } + + { + let mut stream = futures::executor::block_on_stream(from_bob_watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((c1_header.hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((c1_header.hash(), 0)))); + assert_eq!(stream.next(), None); + } + + { + let mut stream = futures::executor::block_on_stream(from_charlie_watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((d1_header.hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((d1_header.hash(), 0)))); + assert_eq!(stream.next(), None); + } +} + +#[test] +fn delayed_finalization_does_not_retract() { + sp_tracing::try_init_simple(); + let api = TestApi::empty(); + // starting block A1 (last finalized.) + let a_header = api.push_block(1, vec![], true); + + let pool = create_basic_pool(api); + + let from_alice = uxt(Alice, 1); + let from_bob = uxt(Bob, 2); + pool.api().increment_nonce(Alice.into()); + pool.api().increment_nonce(Bob.into()); + + let from_alice_watcher; + let from_bob_watcher; + let b1_header; + let c1_header; + + // block B1 + { + from_alice_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); + assert_eq!(pool.status().ready, 1); + + log::trace!(target:"txpool", ">> B1: {:?} {:?}", header.hash(), header); + b1_header = header; + } + + // block C1 + { + from_bob_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true); + assert_eq!(pool.status().ready, 2); + + log::trace!(target:"txpool", ">> C1: {:?} {:?}", header.hash(), header); + c1_header = header; + } + + { + // phase-0 + let event = ChainEvent::NewBestBlock { hash: b1_header.hash(), tree_route: None }; + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 1); + } + + { + // phase-1 + let event = ChainEvent::NewBestBlock { hash: c1_header.hash(), tree_route: None }; + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 0); + } + + { + // phase-2 + let event = ChainEvent::Finalized { hash: b1_header.hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + } + + { + // phase-3 + let event = ChainEvent::Finalized { hash: c1_header.hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + } + + { + let mut stream = futures::executor::block_on_stream(from_alice_watcher); + //phase-0 + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b1_header.hash(), 0)))); + //phase-2 + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((b1_header.hash(), 0)))); + assert_eq!(stream.next(), None); + } + + { + let mut stream = futures::executor::block_on_stream(from_bob_watcher); + //phase-0 + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + //phase-1 + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((c1_header.hash(), 0)))); + //phase-3 + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((c1_header.hash(), 0)))); + assert_eq!(stream.next(), None); + } +} + +#[test] +fn best_block_after_finalization_does_not_retract() { + sp_tracing::try_init_simple(); + let api = TestApi::empty(); + // starting block A1 (last finalized.) + let a_header = api.push_block(1, vec![], true); + + let pool = create_basic_pool(api); + + let from_alice = uxt(Alice, 1); + let from_bob = uxt(Bob, 2); + pool.api().increment_nonce(Alice.into()); + pool.api().increment_nonce(Bob.into()); + + let from_alice_watcher; + let from_bob_watcher; + let b1_header; + let c1_header; + + // block B1 + { + from_alice_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_alice.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(a_header.hash(), vec![from_alice.clone()], true); + assert_eq!(pool.status().ready, 1); + + log::trace!(target:"txpool", ">> B1: {:?} {:?}", header.hash(), header); + b1_header = header; + } + + // block C1 + { + from_bob_watcher = + block_on(pool.submit_and_watch(&BlockId::number(1), SOURCE, from_bob.clone())) + .expect("1. Imported"); + let header = + pool.api() + .push_block_with_parent(b1_header.hash(), vec![from_bob.clone()], true); + assert_eq!(pool.status().ready, 2); + + log::trace!(target:"txpool", ">> C1: {:?} {:?}", header.hash(), header); + c1_header = header; + } + + { + let event = ChainEvent::Finalized { hash: a_header.hash(), tree_route: Arc::from(vec![]) }; + block_on(pool.maintain(event)); + } + + { + let event = ChainEvent::Finalized { + hash: c1_header.hash(), + tree_route: Arc::from(vec![a_header.hash(), b1_header.hash()]), + }; + block_on(pool.maintain(event)); + assert_eq!(pool.status().ready, 0); + } + + { + let event = ChainEvent::NewBestBlock { hash: b1_header.hash(), tree_route: None }; + block_on(pool.maintain(event)); + } + + { + let mut stream = futures::executor::block_on_stream(from_alice_watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((b1_header.hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((b1_header.hash(), 0)))); + assert_eq!(stream.next(), None); + } + + { + let mut stream = futures::executor::block_on_stream(from_bob_watcher); + assert_eq!(stream.next(), Some(TransactionStatus::Ready)); + assert_eq!(stream.next(), Some(TransactionStatus::InBlock((c1_header.hash(), 0)))); + assert_eq!(stream.next(), Some(TransactionStatus::Finalized((c1_header.hash(), 0)))); + assert_eq!(stream.next(), None); + } +} diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index c867a245739ff..25f8e582c78fc 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -360,7 +360,7 @@ Runtime ------- * Introduce stacked filtering (#6273) -* Allow "anonymous" proxied accounts (#6236) +* Allow "pure" proxied accounts (#6236) * Allow over-weight collective proposals to be closed (#6163) * Fix Election when ForceNone V1 (#6166) diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index 0b9e6e7783058..133ba7b094d43 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -24,8 +24,19 @@ /.gitlab-ci.yml @paritytech/ci # Sandboxing capability of Substrate Runtime -/primitives/sr-sandbox/ @pepyakin -/primitives/core/src/sandbox.rs @pepyakin +/primitives/sandbox/ @pepyakin @koute + +# WASM executor, low-level client <-> WASM interface and other WASM-related code +/client/executor/ @koute +/client/allocator/ @koute +/primitives/wasm-interface/ @koute +/primitives/runtime-interface/ @koute +/primitives/panic-handler/ @koute +/utils/wasm-builder/ @koute + +# Systems-related bits and bobs on the client side +/client/sysinfo/ @koute +/client/tracing/ @koute # GRANDPA, BABE, consensus stuff /frame/babe/ @andresilva @@ -36,11 +47,13 @@ /client/consensus/pow/ @sorpaas /primitives/consensus/pow/ @sorpaas -# BEEFY +# BEEFY, MMR /client/beefy/ @acatangiu /frame/beefy/ @acatangiu /frame/beefy-mmr/ @acatangiu +/frame/merkle-mountain-range/ @acatangiu /primitives/beefy/ @acatangiu +/primitives/merkle-mountain-range/ @acatangiu # Contracts /frame/contracts/ @athei diff --git a/docs/Upgrading-2.0-to-3.0.md b/docs/Upgrading-2.0-to-3.0.md index bcba7d88047ce..7540e0d5b5b8c 100644 --- a/docs/Upgrading-2.0-to-3.0.md +++ b/docs/Upgrading-2.0-to-3.0.md @@ -147,8 +147,8 @@ And update the overall definition for weights on frame and a few related types a + type BlockWeights = RuntimeBlockWeights; + type BlockLength = RuntimeBlockLength; + type DbWeight = RocksDbWeight; - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = Index; @@ -171,25 +198,19 @@ impl frame_system::Trait for Runtime { type Header = generic::Header; diff --git a/frame/alliance/Cargo.toml b/frame/alliance/Cargo.toml index 706827708ce88..399822a2215f5 100644 --- a/frame/alliance/Cargo.toml +++ b/frame/alliance/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -hex = { version = "0.4", default-features = false, features = ["alloc"], optional = true } +array-bytes = { version = "4.1", optional = true } sha2 = { version = "0.10.1", default-features = false, optional = true } log = { version = "0.4.14", default-features = false } @@ -33,7 +33,7 @@ pallet-identity = { version = "4.0.0-dev", path = "../identity", default-feature pallet-collective = { version = "4.0.0-dev", path = "../collective", default-features = false, optional = true } [dev-dependencies] -hex-literal = "0.3.1" +array-bytes = "4.1" sha2 = "0.10.1" pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-collective = { version = "4.0.0-dev", path = "../collective" } @@ -41,6 +41,8 @@ pallet-collective = { version = "4.0.0-dev", path = "../collective" } [features] default = ["std"] std = [ + "pallet-collective?/std", + "frame-benchmarking?/std", "log/std", "codec/std", "scale-info/std", @@ -53,9 +55,9 @@ std = [ "pallet-identity/std", ] runtime-benchmarks = [ - "hex", + "array-bytes", "sha2", - "frame-benchmarking", + "frame-benchmarking/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", diff --git a/frame/alliance/src/benchmarking.rs b/frame/alliance/src/benchmarking.rs index de2fc392db8f1..e2e1579fcc9b4 100644 --- a/frame/alliance/src/benchmarking.rs +++ b/frame/alliance/src/benchmarking.rs @@ -35,7 +35,7 @@ const SEED: u32 = 0; const MAX_BYTES: u32 = 1_024; -fn assert_last_event, I: 'static>(generic_event: >::Event) { +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } @@ -832,8 +832,8 @@ benchmarks_instance_pallet! { } add_unscrupulous_items { - let n in 1 .. T::MaxUnscrupulousItems::get(); - let l in 1 .. T::MaxWebsiteUrlLength::get(); + let n in 0 .. T::MaxUnscrupulousItems::get(); + let l in 0 .. T::MaxWebsiteUrlLength::get(); set_members::(); @@ -856,8 +856,8 @@ benchmarks_instance_pallet! { } remove_unscrupulous_items { - let n in 1 .. T::MaxUnscrupulousItems::get(); - let l in 1 .. T::MaxWebsiteUrlLength::get(); + let n in 0 .. T::MaxUnscrupulousItems::get(); + let l in 0 .. T::MaxWebsiteUrlLength::get(); set_members::(); diff --git a/frame/alliance/src/lib.rs b/frame/alliance/src/lib.rs index 8f39b6b51cabd..fca17e69c7652 100644 --- a/frame/alliance/src/lib.rs +++ b/frame/alliance/src/lib.rs @@ -120,7 +120,7 @@ use frame_support::{ ChangeMembers, Currency, Get, InitializeMembers, IsSubType, OnUnbalanced, ReservableCurrency, }, - weights::Weight, + weights::{OldWeight, Weight}, }; use pallet_identity::IdentityField; @@ -240,25 +240,26 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; - /// The outer call dispatch type. + /// The runtime call dispatch type. type Proposal: Parameter - + Dispatchable + + Dispatchable + From> + From> + GetDispatchInfo + IsSubType> - + IsType<::Call>; + + IsType<::RuntimeCall>; /// Origin for admin-level operations, like setting the Alliance's rules. - type AdminOrigin: EnsureOrigin; + type AdminOrigin: EnsureOrigin; /// Origin that manages entry and forcible discharge from the Alliance. - type MembershipManager: EnsureOrigin; + type MembershipManager: EnsureOrigin; /// Origin for making announcements and adding/removing unscrupulous items. - type AnnouncementOrigin: EnsureOrigin; + type AnnouncementOrigin: EnsureOrigin; /// The currency used for deposits. type Currency: ReservableCurrency; @@ -619,25 +620,22 @@ pub mod pallet { .max(T::WeightInfo::close_early_disapproved(x, y, p2)) .max(T::WeightInfo::close_approved(b, x, y, p2)) .max(T::WeightInfo::close_disapproved(x, y, p2)) - .saturating_add(p1) + .saturating_add(p1.into()) })] - pub fn close( + #[allow(deprecated)] + #[deprecated(note = "1D weight is used in this extrinsic, please migrate to use `close`")] + pub fn close_old_weight( origin: OriginFor, proposal_hash: T::Hash, #[pallet::compact] index: ProposalIndex, - #[pallet::compact] proposal_weight_bound: Weight, + #[pallet::compact] proposal_weight_bound: OldWeight, #[pallet::compact] length_bound: u32, ) -> DispatchResultWithPostInfo { + let proposal_weight_bound: Weight = proposal_weight_bound.into(); let who = ensure_signed(origin)?; ensure!(Self::has_voting_rights(&who), Error::::NoVotingRights); - let info = T::ProposalProvider::close_proposal( - proposal_hash, - index, - proposal_weight_bound, - length_bound, - )?; - Ok(info.into()) + Self::do_close(proposal_hash, index, proposal_weight_bound, length_bound) } /// Initialize the Alliance, onboard founders, fellows, and allies. @@ -708,7 +706,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::disband( witness.voting_members, witness.ally_members, - witness.voting_members + witness.ally_members, + witness.voting_members.saturating_add(witness.ally_members), ))] pub fn disband( origin: OriginFor, @@ -984,6 +982,34 @@ pub mod pallet { Self::deposit_event(Event::UnscrupulousItemRemoved { items }); Ok(()) } + + /// Close a vote that is either approved, disapproved, or whose voting period has ended. + /// + /// Requires the sender to be a founder or fellow. + #[pallet::weight({ + let b = *length_bound; + let x = T::MaxFounders::get(); + let y = T::MaxFellows::get(); + let p1 = *proposal_weight_bound; + let p2 = T::MaxProposals::get(); + T::WeightInfo::close_early_approved(b, x, y, p2) + .max(T::WeightInfo::close_early_disapproved(x, y, p2)) + .max(T::WeightInfo::close_approved(b, x, y, p2)) + .max(T::WeightInfo::close_disapproved(x, y, p2)) + .saturating_add(p1) + })] + pub fn close( + origin: OriginFor, + proposal_hash: T::Hash, + #[pallet::compact] index: ProposalIndex, + proposal_weight_bound: Weight, + #[pallet::compact] length_bound: u32, + ) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + ensure!(Self::has_voting_rights(&who), Error::::NoVotingRights); + + Self::do_close(proposal_hash, index, proposal_weight_bound, length_bound) + } } } @@ -1196,4 +1222,19 @@ impl, I: 'static> Pallet { } res } + + fn do_close( + proposal_hash: T::Hash, + index: ProposalIndex, + proposal_weight_bound: Weight, + length_bound: u32, + ) -> DispatchResultWithPostInfo { + let info = T::ProposalProvider::close_proposal( + proposal_hash, + index, + proposal_weight_bound, + length_bound, + )?; + Ok(info.into()) + } } diff --git a/frame/alliance/src/mock.rs b/frame/alliance/src/mock.rs index c140c040fbd0f..196e0003b537f 100644 --- a/frame/alliance/src/mock.rs +++ b/frame/alliance/src/mock.rs @@ -47,8 +47,8 @@ impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = BlockNumber; type Hash = H256; @@ -56,7 +56,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = BlockHashCount; type DbWeight = (); type Version = (); @@ -77,7 +77,7 @@ parameter_types! { impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); @@ -95,9 +95,9 @@ parameter_types! { } type AllianceCollective = pallet_collective::Instance1; impl pallet_collective::Config for Test { - type Origin = Origin; - type Proposal = Call; - type Event = Event; + type RuntimeOrigin = RuntimeOrigin; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type MotionDuration = MotionDuration; type MaxProposals = MaxProposals; type MaxMembers = MaxMembers; @@ -124,7 +124,7 @@ type EnsureOneOrRoot = EitherOfDiverse, EnsureSignedBy type EnsureTwoOrRoot = EitherOfDiverse, EnsureSignedBy>; impl pallet_identity::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type BasicDeposit = BasicDeposit; type FieldDeposit = FieldDeposit; @@ -162,11 +162,11 @@ impl IdentityVerifier for AllianceIdentityVerifier { } pub struct AllianceProposalProvider; -impl ProposalProvider for AllianceProposalProvider { +impl ProposalProvider for AllianceProposalProvider { fn propose_proposal( who: u64, threshold: u32, - proposal: Box, + proposal: Box, length_bound: u32, ) -> Result<(u32, u32), DispatchError> { AllianceMotion::do_propose_proposed(who, threshold, proposal, length_bound) @@ -194,7 +194,7 @@ impl ProposalProvider for AllianceProposalProvider { AllianceMotion::do_close(proposal_hash, proposal_index, proposal_weight_bound, length_bound) } - fn proposal_of(proposal_hash: H256) -> Option { + fn proposal_of(proposal_hash: H256) -> Option { AllianceMotion::proposal_of(proposal_hash) } } @@ -207,8 +207,8 @@ parameter_types! { pub const RetirementPeriod: BlockNumber = MOTION_DURATION_IN_BLOCKS + 1; } impl Config for Test { - type Event = Event; - type Proposal = Call; + type RuntimeEvent = RuntimeEvent; + type Proposal = RuntimeCall; type AdminOrigin = EnsureSignedBy; type MembershipManager = EnsureSignedBy; type AnnouncementOrigin = EnsureSignedBy; @@ -283,7 +283,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| { - assert_ok!(Identity::add_registrar(Origin::signed(1), 1)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 1)); let info = IdentityInfo { additional: BoundedVec::default(), @@ -296,29 +296,71 @@ pub fn new_test_ext() -> sp_io::TestExternalities { image: Data::default(), twitter: Data::default(), }; - assert_ok!(Identity::set_identity(Origin::signed(1), Box::new(info.clone()))); - assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 1, Judgement::KnownGood)); - assert_ok!(Identity::set_identity(Origin::signed(2), Box::new(info.clone()))); - assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 2, Judgement::KnownGood)); - assert_ok!(Identity::set_identity(Origin::signed(3), Box::new(info.clone()))); - assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 3, Judgement::KnownGood)); - assert_ok!(Identity::set_identity(Origin::signed(4), Box::new(info.clone()))); - assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 4, Judgement::KnownGood)); - assert_ok!(Identity::set_identity(Origin::signed(5), Box::new(info.clone()))); - assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 5, Judgement::KnownGood)); - assert_ok!(Identity::set_identity(Origin::signed(6), Box::new(info.clone()))); - assert_ok!(Identity::set_identity(Origin::signed(8), Box::new(info.clone()))); - assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 8, Judgement::KnownGood)); - assert_ok!(Identity::set_identity(Origin::signed(9), Box::new(info.clone()))); - assert_ok!(Identity::provide_judgement(Origin::signed(1), 0, 9, Judgement::KnownGood)); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(1), Box::new(info.clone()))); + assert_ok!(Identity::provide_judgement( + RuntimeOrigin::signed(1), + 0, + 1, + Judgement::KnownGood, + BlakeTwo256::hash_of(&info) + )); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(2), Box::new(info.clone()))); + assert_ok!(Identity::provide_judgement( + RuntimeOrigin::signed(1), + 0, + 2, + Judgement::KnownGood, + BlakeTwo256::hash_of(&info) + )); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(3), Box::new(info.clone()))); + assert_ok!(Identity::provide_judgement( + RuntimeOrigin::signed(1), + 0, + 3, + Judgement::KnownGood, + BlakeTwo256::hash_of(&info) + )); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(4), Box::new(info.clone()))); + assert_ok!(Identity::provide_judgement( + RuntimeOrigin::signed(1), + 0, + 4, + Judgement::KnownGood, + BlakeTwo256::hash_of(&info) + )); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(5), Box::new(info.clone()))); + assert_ok!(Identity::provide_judgement( + RuntimeOrigin::signed(1), + 0, + 5, + Judgement::KnownGood, + BlakeTwo256::hash_of(&info) + )); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(6), Box::new(info.clone()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(8), Box::new(info.clone()))); + assert_ok!(Identity::provide_judgement( + RuntimeOrigin::signed(1), + 0, + 8, + Judgement::KnownGood, + BlakeTwo256::hash_of(&info) + )); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(9), Box::new(info.clone()))); + assert_ok!(Identity::provide_judgement( + RuntimeOrigin::signed(1), + 0, + 9, + Judgement::KnownGood, + BlakeTwo256::hash_of(&info) + )); // Joining before init should fail. assert_noop!( - Alliance::join_alliance(Origin::signed(1)), + Alliance::join_alliance(RuntimeOrigin::signed(1)), Error::::AllianceNotYetInitialized ); - assert_ok!(Alliance::init_members(Origin::root(), vec![1, 2], vec![3], vec![])); + assert_ok!(Alliance::init_members(RuntimeOrigin::root(), vec![1, 2], vec![3], vec![])); System::set_block_number(1); }); @@ -338,19 +380,19 @@ pub fn test_cid() -> Cid { Cid::new_v0(&*result) } -pub fn make_remark_proposal(value: u64) -> (Call, u32, H256) { - make_proposal(Call::System(frame_system::Call::remark { remark: value.encode() })) +pub fn make_remark_proposal(value: u64) -> (RuntimeCall, u32, H256) { + make_proposal(RuntimeCall::System(frame_system::Call::remark { remark: value.encode() })) } -pub fn make_set_rule_proposal(rule: Cid) -> (Call, u32, H256) { - make_proposal(Call::Alliance(pallet_alliance::Call::set_rule { rule })) +pub fn make_set_rule_proposal(rule: Cid) -> (RuntimeCall, u32, H256) { + make_proposal(RuntimeCall::Alliance(pallet_alliance::Call::set_rule { rule })) } -pub fn make_kick_member_proposal(who: u64) -> (Call, u32, H256) { - make_proposal(Call::Alliance(pallet_alliance::Call::kick_member { who })) +pub fn make_kick_member_proposal(who: u64) -> (RuntimeCall, u32, H256) { + make_proposal(RuntimeCall::Alliance(pallet_alliance::Call::kick_member { who })) } -pub fn make_proposal(proposal: Call) -> (Call, u32, H256) { +pub fn make_proposal(proposal: RuntimeCall) -> (RuntimeCall, u32, H256) { let len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash = BlakeTwo256::hash_of(&proposal); (proposal, len, hash) diff --git a/frame/alliance/src/tests.rs b/frame/alliance/src/tests.rs index 943c39a2d69c0..c55826768c695 100644 --- a/frame/alliance/src/tests.rs +++ b/frame/alliance/src/tests.rs @@ -30,28 +30,31 @@ fn init_members_works() { new_test_ext().execute_with(|| { // alliance must be reset first, no witness data assert_noop!( - Alliance::init_members(Origin::root(), vec![8], vec![], vec![],), + Alliance::init_members(RuntimeOrigin::root(), vec![8], vec![], vec![],), Error::::AllianceAlreadyInitialized, ); // give a retirement notice to check later a retiring member not removed - assert_ok!(Alliance::give_retirement_notice(Origin::signed(2))); + assert_ok!(Alliance::give_retirement_notice(RuntimeOrigin::signed(2))); assert!(Alliance::is_member_of(&2, MemberRole::Retiring)); // disband the Alliance to init new - assert_ok!(Alliance::disband(Origin::root(), DisbandWitness::new(2, 0))); + assert_ok!(Alliance::disband(RuntimeOrigin::root(), DisbandWitness::new(2, 0))); // fails without root - assert_noop!(Alliance::init_members(Origin::signed(1), vec![], vec![], vec![]), BadOrigin); + assert_noop!( + Alliance::init_members(RuntimeOrigin::signed(1), vec![], vec![], vec![]), + BadOrigin + ); // founders missing, other members given assert_noop!( - Alliance::init_members(Origin::root(), vec![], vec![4], vec![2],), + Alliance::init_members(RuntimeOrigin::root(), vec![], vec![4], vec![2],), Error::::FoundersMissing, ); // success call - assert_ok!(Alliance::init_members(Origin::root(), vec![8, 5], vec![4], vec![2],)); + assert_ok!(Alliance::init_members(RuntimeOrigin::root(), vec![8, 5], vec![4], vec![2],)); // assert new set of voting members assert_eq!(Alliance::voting_members_sorted(), vec![4, 5, 8]); @@ -63,7 +66,7 @@ fn init_members_works() { // assert a retiring member from previous Alliance not removed assert!(Alliance::is_member_of(&2, MemberRole::Retiring)); - System::assert_last_event(mock::Event::Alliance(crate::Event::MembersInitialized { + System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::MembersInitialized { founders: vec![5, 8], fellows: vec![4], allies: vec![2], @@ -78,36 +81,36 @@ fn disband_works() { assert_eq!(Alliance::voting_members_sorted(), vec![1, 2, 3]); // give a retirement notice to check later a retiring member not removed - assert_ok!(Alliance::give_retirement_notice(Origin::signed(2))); + assert_ok!(Alliance::give_retirement_notice(RuntimeOrigin::signed(2))); assert!(Alliance::is_member_of(&2, MemberRole::Retiring)); // join alliance and reserve funds assert_eq!(Balances::free_balance(9), 40); - assert_ok!(Alliance::join_alliance(Origin::signed(9))); + assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(9))); assert_eq!(Alliance::deposit_of(9), Some(25)); assert_eq!(Balances::free_balance(9), 15); assert!(Alliance::is_member_of(&9, MemberRole::Ally)); // fails without root - assert_noop!(Alliance::disband(Origin::signed(1), Default::default()), BadOrigin); + assert_noop!(Alliance::disband(RuntimeOrigin::signed(1), Default::default()), BadOrigin); // bad witness data checks assert_noop!( - Alliance::disband(Origin::root(), Default::default(),), + Alliance::disband(RuntimeOrigin::root(), Default::default(),), Error::::BadWitness ); assert_noop!( - Alliance::disband(Origin::root(), DisbandWitness::new(1, 1)), + Alliance::disband(RuntimeOrigin::root(), DisbandWitness::new(1, 1)), Error::::BadWitness, ); assert_noop!( - Alliance::disband(Origin::root(), DisbandWitness::new(2, 0)), + Alliance::disband(RuntimeOrigin::root(), DisbandWitness::new(2, 0)), Error::::BadWitness, ); // success call - assert_ok!(Alliance::disband(Origin::root(), DisbandWitness::new(2, 1))); + assert_ok!(Alliance::disband(RuntimeOrigin::root(), DisbandWitness::new(2, 1))); // assert members disband assert!(!Alliance::is_member(&1)); @@ -117,7 +120,7 @@ fn disband_works() { // deposit unreserved assert_eq!(Balances::free_balance(9), 40); - System::assert_last_event(mock::Event::Alliance(crate::Event::AllianceDisbanded { + System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::AllianceDisbanded { voting_members: 2, ally_members: 1, unreserved: 1, @@ -125,7 +128,7 @@ fn disband_works() { // the Alliance must be set first assert_noop!( - Alliance::disband(Origin::root(), DisbandWitness::new(100, 100)), + Alliance::disband(RuntimeOrigin::root(), DisbandWitness::new(100, 100)), Error::::AllianceNotYetInitialized, ); }) @@ -138,12 +141,17 @@ fn propose_works() { // only voting member can propose proposal, 4 is ally not have vote rights assert_noop!( - Alliance::propose(Origin::signed(4), 3, Box::new(proposal.clone()), proposal_len), + Alliance::propose( + RuntimeOrigin::signed(4), + 3, + Box::new(proposal.clone()), + proposal_len + ), Error::::NoVotingRights ); assert_ok!(Alliance::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len @@ -154,7 +162,7 @@ fn propose_works() { System::events(), vec![EventRecord { phase: Phase::Initialization, - event: mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { + event: mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, @@ -171,24 +179,24 @@ fn vote_works() { new_test_ext().execute_with(|| { let (proposal, proposal_len, hash) = make_remark_proposal(42); assert_ok!(Alliance::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Alliance::vote(Origin::signed(2), hash, 0, true)); + assert_ok!(Alliance::vote(RuntimeOrigin::signed(2), hash, 0, true)); let record = |event| EventRecord { phase: Phase::Initialization, event, topics: vec![] }; assert_eq!( System::events(), vec![ - record(mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 3 })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Voted { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Voted { account: 2, proposal_hash: hash, voted: true, @@ -205,21 +213,21 @@ fn veto_works() { new_test_ext().execute_with(|| { let (proposal, proposal_len, hash) = make_remark_proposal(42); assert_ok!(Alliance::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); // only set_rule/elevate_ally can be veto assert_noop!( - Alliance::veto(Origin::signed(1), hash), + Alliance::veto(RuntimeOrigin::signed(1), hash), Error::::NotVetoableProposal ); let cid = test_cid(); let (vetoable_proposal, vetoable_proposal_len, vetoable_hash) = make_set_rule_proposal(cid); assert_ok!(Alliance::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(vetoable_proposal.clone()), vetoable_proposal_len @@ -227,28 +235,28 @@ fn veto_works() { // only founder have veto rights, 3 is fellow assert_noop!( - Alliance::veto(Origin::signed(3), vetoable_hash), + Alliance::veto(RuntimeOrigin::signed(3), vetoable_hash), Error::::NotFounder ); - assert_ok!(Alliance::veto(Origin::signed(2), vetoable_hash)); + assert_ok!(Alliance::veto(RuntimeOrigin::signed(2), vetoable_hash)); let record = |event| EventRecord { phase: Phase::Initialization, event, topics: vec![] }; assert_eq!( System::events(), vec![ - record(mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 3 })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Proposed { account: 1, proposal_index: 1, proposal_hash: vetoable_hash, threshold: 3 })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Disapproved { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Disapproved { proposal_hash: vetoable_hash })), ] @@ -262,56 +270,62 @@ fn close_works() { let (proposal, proposal_len, hash) = make_remark_proposal(42); let proposal_weight = proposal.get_dispatch_info().weight; assert_ok!(Alliance::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Alliance::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Alliance::vote(Origin::signed(2), hash, 0, true)); - assert_ok!(Alliance::vote(Origin::signed(3), hash, 0, true)); - assert_ok!(Alliance::close(Origin::signed(1), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Alliance::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Alliance::vote(RuntimeOrigin::signed(2), hash, 0, true)); + assert_ok!(Alliance::vote(RuntimeOrigin::signed(3), hash, 0, true)); + assert_ok!(Alliance::close( + RuntimeOrigin::signed(1), + hash, + 0, + proposal_weight, + proposal_len + )); let record = |event| EventRecord { phase: Phase::Initialization, event, topics: vec![] }; assert_eq!( System::events(), vec![ - record(mock::Event::AllianceMotion(AllianceMotionEvent::Proposed { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 3 })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Voted { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0, })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Voted { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0, })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Voted { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Voted { account: 3, proposal_hash: hash, voted: true, yes: 3, no: 0, })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Closed { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Closed { proposal_hash: hash, yes: 3, no: 0, })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Approved { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Approved { proposal_hash: hash })), - record(mock::Event::AllianceMotion(AllianceMotionEvent::Executed { + record(mock::RuntimeEvent::AllianceMotion(AllianceMotionEvent::Executed { proposal_hash: hash, result: Err(DispatchError::BadOrigin), })) @@ -324,10 +338,12 @@ fn close_works() { fn set_rule_works() { new_test_ext().execute_with(|| { let cid = test_cid(); - assert_ok!(Alliance::set_rule(Origin::signed(1), cid.clone())); + assert_ok!(Alliance::set_rule(RuntimeOrigin::signed(1), cid.clone())); assert_eq!(Alliance::rule(), Some(cid.clone())); - System::assert_last_event(mock::Event::Alliance(crate::Event::NewRuleSet { rule: cid })); + System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::NewRuleSet { + rule: cid, + })); }); } @@ -336,12 +352,12 @@ fn announce_works() { new_test_ext().execute_with(|| { let cid = test_cid(); - assert_noop!(Alliance::announce(Origin::signed(2), cid.clone()), BadOrigin); + assert_noop!(Alliance::announce(RuntimeOrigin::signed(2), cid.clone()), BadOrigin); - assert_ok!(Alliance::announce(Origin::signed(3), cid.clone())); + assert_ok!(Alliance::announce(RuntimeOrigin::signed(3), cid.clone())); assert_eq!(Alliance::announcements(), vec![cid.clone()]); - System::assert_last_event(mock::Event::Alliance(crate::Event::Announced { + System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::Announced { announcement: cid, })); }); @@ -351,19 +367,19 @@ fn announce_works() { fn remove_announcement_works() { new_test_ext().execute_with(|| { let cid = test_cid(); - assert_ok!(Alliance::announce(Origin::signed(3), cid.clone())); + assert_ok!(Alliance::announce(RuntimeOrigin::signed(3), cid.clone())); assert_eq!(Alliance::announcements(), vec![cid.clone()]); - System::assert_last_event(mock::Event::Alliance(crate::Event::Announced { + System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::Announced { announcement: cid.clone(), })); System::set_block_number(2); - assert_ok!(Alliance::remove_announcement(Origin::signed(3), cid.clone())); + assert_ok!(Alliance::remove_announcement(RuntimeOrigin::signed(3), cid.clone())); assert_eq!(Alliance::announcements(), vec![]); - System::assert_last_event(mock::Event::Alliance(crate::Event::AnnouncementRemoved { - announcement: cid, - })); + System::assert_last_event(mock::RuntimeEvent::Alliance( + crate::Event::AnnouncementRemoved { announcement: cid }, + )); }); } @@ -371,46 +387,52 @@ fn remove_announcement_works() { fn join_alliance_works() { new_test_ext().execute_with(|| { // check already member - assert_noop!(Alliance::join_alliance(Origin::signed(1)), Error::::AlreadyMember); + assert_noop!( + Alliance::join_alliance(RuntimeOrigin::signed(1)), + Error::::AlreadyMember + ); // check already listed as unscrupulous assert_ok!(Alliance::add_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(4)] )); assert_noop!( - Alliance::join_alliance(Origin::signed(4)), + Alliance::join_alliance(RuntimeOrigin::signed(4)), Error::::AccountNonGrata ); assert_ok!(Alliance::remove_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(4)] )); // check deposit funds assert_noop!( - Alliance::join_alliance(Origin::signed(5)), + Alliance::join_alliance(RuntimeOrigin::signed(5)), Error::::InsufficientFunds ); // success to submit - assert_ok!(Alliance::join_alliance(Origin::signed(4))); + assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(4))); assert_eq!(Alliance::deposit_of(4), Some(25)); assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); // check already member - assert_noop!(Alliance::join_alliance(Origin::signed(4)), Error::::AlreadyMember); + assert_noop!( + Alliance::join_alliance(RuntimeOrigin::signed(4)), + Error::::AlreadyMember + ); // check missing identity judgement #[cfg(not(feature = "runtime-benchmarks"))] assert_noop!( - Alliance::join_alliance(Origin::signed(6)), + Alliance::join_alliance(RuntimeOrigin::signed(6)), Error::::WithoutGoodIdentityJudgement ); // check missing identity info #[cfg(not(feature = "runtime-benchmarks"))] assert_noop!( - Alliance::join_alliance(Origin::signed(7)), + Alliance::join_alliance(RuntimeOrigin::signed(7)), Error::::WithoutIdentityDisplayAndWebsite ); }); @@ -421,51 +443,51 @@ fn nominate_ally_works() { new_test_ext().execute_with(|| { // check already member assert_noop!( - Alliance::nominate_ally(Origin::signed(1), 2), + Alliance::nominate_ally(RuntimeOrigin::signed(1), 2), Error::::AlreadyMember ); // only voting member(founder/fellow) have nominate right assert_noop!( - Alliance::nominate_ally(Origin::signed(5), 4), + Alliance::nominate_ally(RuntimeOrigin::signed(5), 4), Error::::NoVotingRights ); // check already listed as unscrupulous assert_ok!(Alliance::add_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(4)] )); assert_noop!( - Alliance::nominate_ally(Origin::signed(1), 4), + Alliance::nominate_ally(RuntimeOrigin::signed(1), 4), Error::::AccountNonGrata ); assert_ok!(Alliance::remove_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(4)] )); // success to nominate - assert_ok!(Alliance::nominate_ally(Origin::signed(1), 4)); + assert_ok!(Alliance::nominate_ally(RuntimeOrigin::signed(1), 4)); assert_eq!(Alliance::deposit_of(4), None); assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); // check already member assert_noop!( - Alliance::nominate_ally(Origin::signed(1), 4), + Alliance::nominate_ally(RuntimeOrigin::signed(1), 4), Error::::AlreadyMember ); // check missing identity judgement #[cfg(not(feature = "runtime-benchmarks"))] assert_noop!( - Alliance::join_alliance(Origin::signed(6)), + Alliance::join_alliance(RuntimeOrigin::signed(6)), Error::::WithoutGoodIdentityJudgement ); // check missing identity info #[cfg(not(feature = "runtime-benchmarks"))] assert_noop!( - Alliance::join_alliance(Origin::signed(7)), + Alliance::join_alliance(RuntimeOrigin::signed(7)), Error::::WithoutIdentityDisplayAndWebsite ); }); @@ -474,13 +496,16 @@ fn nominate_ally_works() { #[test] fn elevate_ally_works() { new_test_ext().execute_with(|| { - assert_noop!(Alliance::elevate_ally(Origin::signed(2), 4), Error::::NotAlly); + assert_noop!( + Alliance::elevate_ally(RuntimeOrigin::signed(2), 4), + Error::::NotAlly + ); - assert_ok!(Alliance::join_alliance(Origin::signed(4))); + assert_ok!(Alliance::join_alliance(RuntimeOrigin::signed(4))); assert_eq!(Alliance::members(MemberRole::Ally), vec![4]); assert_eq!(Alliance::members(MemberRole::Fellow), vec![3]); - assert_ok!(Alliance::elevate_ally(Origin::signed(2), 4)); + assert_ok!(Alliance::elevate_ally(RuntimeOrigin::signed(2), 4)); assert_eq!(Alliance::members(MemberRole::Ally), Vec::::new()); assert_eq!(Alliance::members(MemberRole::Fellow), vec![3, 4]); }); @@ -490,20 +515,20 @@ fn elevate_ally_works() { fn give_retirement_notice_work() { new_test_ext().execute_with(|| { assert_noop!( - Alliance::give_retirement_notice(Origin::signed(4)), + Alliance::give_retirement_notice(RuntimeOrigin::signed(4)), Error::::NotMember ); assert_eq!(Alliance::members(MemberRole::Fellow), vec![3]); - assert_ok!(Alliance::give_retirement_notice(Origin::signed(3))); + assert_ok!(Alliance::give_retirement_notice(RuntimeOrigin::signed(3))); assert_eq!(Alliance::members(MemberRole::Fellow), Vec::::new()); assert_eq!(Alliance::members(MemberRole::Retiring), vec![3]); - System::assert_last_event(mock::Event::Alliance( + System::assert_last_event(mock::RuntimeEvent::Alliance( crate::Event::MemberRetirementPeriodStarted { member: (3) }, )); assert_noop!( - Alliance::give_retirement_notice(Origin::signed(3)), + Alliance::give_retirement_notice(RuntimeOrigin::signed(3)), Error::::AlreadyRetiring ); }); @@ -513,25 +538,25 @@ fn give_retirement_notice_work() { fn retire_works() { new_test_ext().execute_with(|| { assert_noop!( - Alliance::retire(Origin::signed(2)), + Alliance::retire(RuntimeOrigin::signed(2)), Error::::RetirementNoticeNotGiven ); assert_noop!( - Alliance::retire(Origin::signed(4)), + Alliance::retire(RuntimeOrigin::signed(4)), Error::::RetirementNoticeNotGiven ); assert_eq!(Alliance::members(MemberRole::Fellow), vec![3]); - assert_ok!(Alliance::give_retirement_notice(Origin::signed(3))); + assert_ok!(Alliance::give_retirement_notice(RuntimeOrigin::signed(3))); assert_noop!( - Alliance::retire(Origin::signed(3)), + Alliance::retire(RuntimeOrigin::signed(3)), Error::::RetirementPeriodNotPassed ); System::set_block_number(System::block_number() + RetirementPeriod::get()); - assert_ok!(Alliance::retire(Origin::signed(3))); + assert_ok!(Alliance::retire(RuntimeOrigin::signed(3))); assert_eq!(Alliance::members(MemberRole::Fellow), Vec::::new()); - System::assert_last_event(mock::Event::Alliance(crate::Event::MemberRetired { + System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::MemberRetired { member: (3), unreserved: None, })); @@ -539,11 +564,11 @@ fn retire_works() { // Move time on: System::set_block_number(System::block_number() + RetirementPeriod::get()); - assert_powerless(Origin::signed(3)); + assert_powerless(RuntimeOrigin::signed(3)); }); } -fn assert_powerless(user: Origin) { +fn assert_powerless(user: RuntimeOrigin) { //vote / veto with a valid propsal let cid = test_cid(); let (proposal, _, _) = make_kick_member_proposal(42); @@ -576,16 +601,19 @@ fn assert_powerless(user: Origin) { #[test] fn kick_member_works() { new_test_ext().execute_with(|| { - assert_noop!(Alliance::kick_member(Origin::signed(4), 4), BadOrigin); + assert_noop!(Alliance::kick_member(RuntimeOrigin::signed(4), 4), BadOrigin); - assert_noop!(Alliance::kick_member(Origin::signed(2), 4), Error::::NotMember); + assert_noop!( + Alliance::kick_member(RuntimeOrigin::signed(2), 4), + Error::::NotMember + ); >::insert(2, 25); assert_eq!(Alliance::members(MemberRole::Founder), vec![1, 2]); - assert_ok!(Alliance::kick_member(Origin::signed(2), 2)); + assert_ok!(Alliance::kick_member(RuntimeOrigin::signed(2), 2)); assert_eq!(Alliance::members(MemberRole::Founder), vec![1]); assert_eq!(>::get(2), None); - System::assert_last_event(mock::Event::Alliance(crate::Event::MemberKicked { + System::assert_last_event(mock::RuntimeEvent::Alliance(crate::Event::MemberKicked { member: (2), slashed: Some(25), })); @@ -595,10 +623,10 @@ fn kick_member_works() { #[test] fn add_unscrupulous_items_works() { new_test_ext().execute_with(|| { - assert_noop!(Alliance::add_unscrupulous_items(Origin::signed(2), vec![]), BadOrigin); + assert_noop!(Alliance::add_unscrupulous_items(RuntimeOrigin::signed(2), vec![]), BadOrigin); assert_ok!(Alliance::add_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![ UnscrupulousItem::AccountId(3), UnscrupulousItem::Website("abc".as_bytes().to_vec().try_into().unwrap()) @@ -609,7 +637,7 @@ fn add_unscrupulous_items_works() { assert_noop!( Alliance::add_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(3)] ), Error::::AlreadyUnscrupulous @@ -620,23 +648,26 @@ fn add_unscrupulous_items_works() { #[test] fn remove_unscrupulous_items_works() { new_test_ext().execute_with(|| { - assert_noop!(Alliance::remove_unscrupulous_items(Origin::signed(2), vec![]), BadOrigin); + assert_noop!( + Alliance::remove_unscrupulous_items(RuntimeOrigin::signed(2), vec![]), + BadOrigin + ); assert_noop!( Alliance::remove_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(3)] ), Error::::NotListedAsUnscrupulous ); assert_ok!(Alliance::add_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(3)] )); assert_eq!(Alliance::unscrupulous_accounts(), vec![3]); assert_ok!(Alliance::remove_unscrupulous_items( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![UnscrupulousItem::AccountId(3)] )); assert_eq!(Alliance::unscrupulous_accounts(), Vec::::new()); diff --git a/frame/assets/Cargo.toml b/frame/assets/Cargo.toml index 9e98d4e15aed4..7e750f7618437 100644 --- a/frame/assets/Cargo.toml +++ b/frame/assets/Cargo.toml @@ -39,7 +39,7 @@ std = [ "sp-runtime/std", "frame-support/std", "frame-system/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/frame/assets/src/benchmarking.rs b/frame/assets/src/benchmarking.rs index 043d3f1a1aef4..ca891c2f42e4a 100644 --- a/frame/assets/src/benchmarking.rs +++ b/frame/assets/src/benchmarking.rs @@ -140,11 +140,11 @@ fn add_approvals, I: 'static>(minter: T::AccountId, n: u32) { } } -fn assert_last_event, I: 'static>(generic_event: >::Event) { +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } -fn assert_event, I: 'static>(generic_event: >::Event) { +fn assert_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_has_event(generic_event.into()); } diff --git a/frame/assets/src/impl_fungibles.rs b/frame/assets/src/impl_fungibles.rs index 6b263bc0c7bef..842ee5c102c1d 100644 --- a/frame/assets/src/impl_fungibles.rs +++ b/frame/assets/src/impl_fungibles.rs @@ -263,3 +263,23 @@ impl, I: 'static> fungibles::approvals::Mutate<: Self::do_transfer_approved(asset, owner, delegate, dest, amount) } } + +impl, I: 'static> fungibles::roles::Inspect<::AccountId> + for Pallet +{ + fn owner(asset: T::AssetId) -> Option<::AccountId> { + Asset::::get(asset).map(|x| x.owner) + } + + fn issuer(asset: T::AssetId) -> Option<::AccountId> { + Asset::::get(asset).map(|x| x.issuer) + } + + fn admin(asset: T::AssetId) -> Option<::AccountId> { + Asset::::get(asset).map(|x| x.admin) + } + + fn freezer(asset: T::AssetId) -> Option<::AccountId> { + Asset::::get(asset).map(|x| x.freezer) + } +} diff --git a/frame/assets/src/lib.rs b/frame/assets/src/lib.rs index d7ca83c8a84e3..28743f917d323 100644 --- a/frame/assets/src/lib.rs +++ b/frame/assets/src/lib.rs @@ -180,7 +180,8 @@ pub mod pallet { /// The module configuration trait. pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// The units in which we record balances. type Balance: Member @@ -207,7 +208,7 @@ pub mod pallet { /// The origin which may forcibly create or destroy an asset or otherwise alter privileged /// attributes. - type ForceOrigin: EnsureOrigin; + type ForceOrigin: EnsureOrigin; /// The basic amount of funds that must be reserved for an asset. #[pallet::constant] diff --git a/frame/assets/src/mock.rs b/frame/assets/src/mock.rs index 0fd4dd3281516..1f105eb6b4fbc 100644 --- a/frame/assets/src/mock.rs +++ b/frame/assets/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as pallet_assets; use frame_support::{ - construct_runtime, + construct_runtime, parameter_types, traits::{ConstU32, ConstU64, GenesisBuild}, }; use sp_core::H256; @@ -49,8 +49,8 @@ impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -58,7 +58,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); @@ -75,7 +75,7 @@ impl frame_system::Config for Test { impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); @@ -85,7 +85,7 @@ impl pallet_balances::Config for Test { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Balance = u64; type AssetId = u32; type Currency = Balances; @@ -101,44 +101,49 @@ impl Config for Test { type Extra = (); } -use std::{cell::RefCell, collections::HashMap}; +use std::collections::HashMap; #[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub(crate) enum Hook { +pub enum Hook { Died(u32, u64), } -thread_local! { - static FROZEN: RefCell> = RefCell::new(Default::default()); - static HOOKS: RefCell> = RefCell::new(Default::default()); +parameter_types! { + static Frozen: HashMap<(u32, u64), u64> = Default::default(); + static Hooks: Vec = Default::default(); } pub struct TestFreezer; impl FrozenBalance for TestFreezer { fn frozen_balance(asset: u32, who: &u64) -> Option { - FROZEN.with(|f| f.borrow().get(&(asset, *who)).cloned()) + Frozen::get().get(&(asset, *who)).cloned() } fn died(asset: u32, who: &u64) { - HOOKS.with(|h| h.borrow_mut().push(Hook::Died(asset, *who))); + Hooks::mutate(|v| v.push(Hook::Died(asset, *who))); + // Sanity check: dead accounts have no balance. assert!(Assets::balance(asset, *who).is_zero()); } } pub(crate) fn set_frozen_balance(asset: u32, who: u64, amount: u64) { - FROZEN.with(|f| f.borrow_mut().insert((asset, who), amount)); + Frozen::mutate(|v| { + v.insert((asset, who), amount); + }); } pub(crate) fn clear_frozen_balance(asset: u32, who: u64) { - FROZEN.with(|f| f.borrow_mut().remove(&(asset, who))); + Frozen::mutate(|v| { + v.remove(&(asset, who)); + }); } pub(crate) fn hooks() -> Vec { - HOOKS.with(|h| h.borrow().clone()) + Hooks::get().clone() } pub(crate) fn take_hooks() -> Vec { - HOOKS.with(|h| h.take()) + Hooks::take() } pub(crate) fn new_test_ext() -> sp_io::TestExternalities { diff --git a/frame/assets/src/tests.rs b/frame/assets/src/tests.rs index 50ab04111edff..48cfad45a49fc 100644 --- a/frame/assets/src/tests.rs +++ b/frame/assets/src/tests.rs @@ -26,10 +26,10 @@ use sp_runtime::{traits::ConvertInto, TokenError}; #[test] fn basic_minting_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::mint(Origin::signed(1), 0, 2, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 100)); assert_eq!(Assets::balance(0, 2), 100); }); } @@ -37,46 +37,46 @@ fn basic_minting_should_work() { #[test] fn minting_too_many_insufficient_assets_fails() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); - assert_ok!(Assets::force_create(Origin::root(), 1, 1, false, 1)); - assert_ok!(Assets::force_create(Origin::root(), 2, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 1, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 2, 1, false, 1)); Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); - assert_ok!(Assets::mint(Origin::signed(1), 1, 1, 100)); - assert_noop!(Assets::mint(Origin::signed(1), 2, 1, 100), TokenError::CannotCreate); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 1, 1, 100)); + assert_noop!(Assets::mint(RuntimeOrigin::signed(1), 2, 1, 100), TokenError::CannotCreate); Balances::make_free_balance_be(&2, 1); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 100)); - assert_ok!(Assets::mint(Origin::signed(1), 2, 1, 100)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 2, 1, 100)); }); } #[test] fn minting_insufficient_asset_with_deposit_should_work_when_consumers_exhausted() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); - assert_ok!(Assets::force_create(Origin::root(), 1, 1, false, 1)); - assert_ok!(Assets::force_create(Origin::root(), 2, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 1, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 2, 1, false, 1)); Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); - assert_ok!(Assets::mint(Origin::signed(1), 1, 1, 100)); - assert_noop!(Assets::mint(Origin::signed(1), 2, 1, 100), TokenError::CannotCreate); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 1, 1, 100)); + assert_noop!(Assets::mint(RuntimeOrigin::signed(1), 2, 1, 100), TokenError::CannotCreate); - assert_ok!(Assets::touch(Origin::signed(1), 2)); + assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 2)); assert_eq!(Balances::reserved_balance(&1), 10); - assert_ok!(Assets::mint(Origin::signed(1), 2, 1, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 2, 1, 100)); }); } #[test] fn minting_insufficient_assets_with_deposit_without_consumer_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); - assert_noop!(Assets::mint(Origin::signed(1), 0, 1, 100), TokenError::CannotCreate); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_noop!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100), TokenError::CannotCreate); Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::touch(Origin::signed(1), 0)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Balances::reserved_balance(&1), 10); assert_eq!(System::consumers(&1), 0); }); @@ -85,11 +85,11 @@ fn minting_insufficient_assets_with_deposit_without_consumer_should_work() { #[test] fn refunding_asset_deposit_with_burn_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::touch(Origin::signed(1), 0)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); - assert_ok!(Assets::refund(Origin::signed(1), 0, true)); + assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_ok!(Assets::refund(RuntimeOrigin::signed(1), 0, true)); assert_eq!(Balances::reserved_balance(&1), 0); assert_eq!(Assets::balance(1, 0), 0); }); @@ -98,28 +98,28 @@ fn refunding_asset_deposit_with_burn_should_work() { #[test] fn refunding_asset_deposit_with_burn_disallowed_should_fail() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::touch(Origin::signed(1), 0)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); - assert_noop!(Assets::refund(Origin::signed(1), 0, false), Error::::WouldBurn); + assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_noop!(Assets::refund(RuntimeOrigin::signed(1), 0, false), Error::::WouldBurn); }); } #[test] fn refunding_asset_deposit_without_burn_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); - assert_noop!(Assets::mint(Origin::signed(1), 0, 1, 100), TokenError::CannotCreate); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); + assert_noop!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100), TokenError::CannotCreate); Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::touch(Origin::signed(1), 0)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&2, 100); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 100)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 100)); assert_eq!(Assets::balance(0, 2), 100); assert_eq!(Assets::balance(0, 1), 0); assert_eq!(Balances::reserved_balance(&1), 10); - assert_ok!(Assets::refund(Origin::signed(1), 0, false)); + assert_ok!(Assets::refund(RuntimeOrigin::signed(1), 0, false)); assert_eq!(Balances::reserved_balance(&1), 0); assert_eq!(Assets::balance(1, 0), 0); }); @@ -129,11 +129,11 @@ fn refunding_asset_deposit_without_burn_should_work() { #[test] fn refunding_calls_died_hook() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::touch(Origin::signed(1), 0)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); - assert_ok!(Assets::refund(Origin::signed(1), 0, true)); + assert_ok!(Assets::touch(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_ok!(Assets::refund(RuntimeOrigin::signed(1), 0, true)); assert_eq!(Asset::::get(0).unwrap().accounts, 0); assert_eq!(hooks(), vec![Hook::Died(0, 1)]); @@ -144,17 +144,20 @@ fn refunding_calls_died_hook() { fn approval_lifecycle_works() { new_test_ext().execute_with(|| { // can't approve non-existent token - assert_noop!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50), Error::::Unknown); + assert_noop!( + Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50), + Error::::Unknown + ); // so we create it :) - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 1); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Asset::::get(0).unwrap().approvals, 1); assert_eq!(Balances::reserved_balance(&1), 1); - assert_ok!(Assets::transfer_approved(Origin::signed(2), 0, 1, 3, 40)); + assert_ok!(Assets::transfer_approved(RuntimeOrigin::signed(2), 0, 1, 3, 40)); assert_eq!(Asset::::get(0).unwrap().approvals, 1); - assert_ok!(Assets::cancel_approval(Origin::signed(1), 0, 2)); + assert_ok!(Assets::cancel_approval(RuntimeOrigin::signed(1), 0, 2)); assert_eq!(Asset::::get(0).unwrap().approvals, 0); assert_eq!(Assets::balance(0, 1), 60); assert_eq!(Assets::balance(0, 3), 40); @@ -166,17 +169,20 @@ fn approval_lifecycle_works() { fn transfer_approved_all_funds() { new_test_ext().execute_with(|| { // can't approve non-existent token - assert_noop!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50), Error::::Unknown); + assert_noop!( + Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50), + Error::::Unknown + ); // so we create it :) - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 1); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Asset::::get(0).unwrap().approvals, 1); assert_eq!(Balances::reserved_balance(&1), 1); // transfer the full amount, which should trigger auto-cleanup - assert_ok!(Assets::transfer_approved(Origin::signed(2), 0, 1, 3, 50)); + assert_ok!(Assets::transfer_approved(RuntimeOrigin::signed(2), 0, 1, 3, 50)); assert_eq!(Asset::::get(0).unwrap().approvals, 0); assert_eq!(Assets::balance(0, 1), 50); assert_eq!(Assets::balance(0, 3), 50); @@ -187,20 +193,20 @@ fn transfer_approved_all_funds() { #[test] fn approval_deposits_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); let e = BalancesError::::InsufficientBalance; - assert_noop!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50), e); + assert_noop!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50), e); Balances::make_free_balance_be(&1, 1); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Balances::reserved_balance(&1), 1); - assert_ok!(Assets::transfer_approved(Origin::signed(2), 0, 1, 3, 50)); + assert_ok!(Assets::transfer_approved(RuntimeOrigin::signed(2), 0, 1, 3, 50)); assert_eq!(Balances::reserved_balance(&1), 0); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); - assert_ok!(Assets::cancel_approval(Origin::signed(1), 0, 2)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); + assert_ok!(Assets::cancel_approval(RuntimeOrigin::signed(1), 0, 2)); assert_eq!(Balances::reserved_balance(&1), 0); }); } @@ -208,72 +214,84 @@ fn approval_deposits_work() { #[test] fn cannot_transfer_more_than_approved() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 1); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); let e = Error::::Unapproved; - assert_noop!(Assets::transfer_approved(Origin::signed(2), 0, 1, 3, 51), e); + assert_noop!(Assets::transfer_approved(RuntimeOrigin::signed(2), 0, 1, 3, 51), e); }); } #[test] fn cannot_transfer_more_than_exists() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 1); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 101)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 101)); let e = Error::::BalanceLow; - assert_noop!(Assets::transfer_approved(Origin::signed(2), 0, 1, 3, 101), e); + assert_noop!(Assets::transfer_approved(RuntimeOrigin::signed(2), 0, 1, 3, 101), e); }); } #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 1); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Asset::::get(0).unwrap().approvals, 1); - assert_noop!(Assets::cancel_approval(Origin::signed(1), 1, 2), Error::::Unknown); - assert_noop!(Assets::cancel_approval(Origin::signed(2), 0, 2), Error::::Unknown); - assert_noop!(Assets::cancel_approval(Origin::signed(1), 0, 3), Error::::Unknown); + assert_noop!( + Assets::cancel_approval(RuntimeOrigin::signed(1), 1, 2), + Error::::Unknown + ); + assert_noop!( + Assets::cancel_approval(RuntimeOrigin::signed(2), 0, 2), + Error::::Unknown + ); + assert_noop!( + Assets::cancel_approval(RuntimeOrigin::signed(1), 0, 3), + Error::::Unknown + ); assert_eq!(Asset::::get(0).unwrap().approvals, 1); - assert_ok!(Assets::cancel_approval(Origin::signed(1), 0, 2)); + assert_ok!(Assets::cancel_approval(RuntimeOrigin::signed(1), 0, 2)); assert_eq!(Asset::::get(0).unwrap().approvals, 0); - assert_noop!(Assets::cancel_approval(Origin::signed(1), 0, 2), Error::::Unknown); + assert_noop!( + Assets::cancel_approval(RuntimeOrigin::signed(1), 0, 2), + Error::::Unknown + ); }); } #[test] fn force_cancel_approval_works() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 1); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Asset::::get(0).unwrap().approvals, 1); let e = Error::::NoPermission; - assert_noop!(Assets::force_cancel_approval(Origin::signed(2), 0, 1, 2), e); + assert_noop!(Assets::force_cancel_approval(RuntimeOrigin::signed(2), 0, 1, 2), e); assert_noop!( - Assets::force_cancel_approval(Origin::signed(1), 1, 1, 2), + Assets::force_cancel_approval(RuntimeOrigin::signed(1), 1, 1, 2), Error::::Unknown ); assert_noop!( - Assets::force_cancel_approval(Origin::signed(1), 0, 2, 2), + Assets::force_cancel_approval(RuntimeOrigin::signed(1), 0, 2, 2), Error::::Unknown ); assert_noop!( - Assets::force_cancel_approval(Origin::signed(1), 0, 1, 3), + Assets::force_cancel_approval(RuntimeOrigin::signed(1), 0, 1, 3), Error::::Unknown ); assert_eq!(Asset::::get(0).unwrap().approvals, 1); - assert_ok!(Assets::force_cancel_approval(Origin::signed(1), 0, 1, 2)); + assert_ok!(Assets::force_cancel_approval(RuntimeOrigin::signed(1), 0, 1, 2)); assert_eq!(Asset::::get(0).unwrap().approvals, 0); assert_noop!( - Assets::force_cancel_approval(Origin::signed(1), 0, 1, 2), + Assets::force_cancel_approval(RuntimeOrigin::signed(1), 0, 1, 2), Error::::Unknown ); }); @@ -283,42 +301,42 @@ fn force_cancel_approval_works() { fn lifecycle_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::create(Origin::signed(1), 0, 1, 1)); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 1)); assert_eq!(Balances::reserved_balance(&1), 1); assert!(Asset::::contains_key(0)); - assert_ok!(Assets::set_metadata(Origin::signed(1), 0, vec![0], vec![0], 12)); + assert_ok!(Assets::set_metadata(RuntimeOrigin::signed(1), 0, vec![0], vec![0], 12)); assert_eq!(Balances::reserved_balance(&1), 4); assert!(Metadata::::contains_key(0)); Balances::make_free_balance_be(&10, 100); - assert_ok!(Assets::mint(Origin::signed(1), 0, 10, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 10, 100)); Balances::make_free_balance_be(&20, 100); - assert_ok!(Assets::mint(Origin::signed(1), 0, 20, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 20, 100)); assert_eq!(Account::::iter_prefix(0).count(), 2); let w = Asset::::get(0).unwrap().destroy_witness(); - assert_ok!(Assets::destroy(Origin::signed(1), 0, w)); + assert_ok!(Assets::destroy(RuntimeOrigin::signed(1), 0, w)); assert_eq!(Balances::reserved_balance(&1), 0); assert!(!Asset::::contains_key(0)); assert!(!Metadata::::contains_key(0)); assert_eq!(Account::::iter_prefix(0).count(), 0); - assert_ok!(Assets::create(Origin::signed(1), 0, 1, 1)); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 1)); assert_eq!(Balances::reserved_balance(&1), 1); assert!(Asset::::contains_key(0)); - assert_ok!(Assets::set_metadata(Origin::signed(1), 0, vec![0], vec![0], 12)); + assert_ok!(Assets::set_metadata(RuntimeOrigin::signed(1), 0, vec![0], vec![0], 12)); assert_eq!(Balances::reserved_balance(&1), 4); assert!(Metadata::::contains_key(0)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 10, 100)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 20, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 10, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 20, 100)); assert_eq!(Account::::iter_prefix(0).count(), 2); let w = Asset::::get(0).unwrap().destroy_witness(); - assert_ok!(Assets::destroy(Origin::root(), 0, w)); + assert_ok!(Assets::destroy(RuntimeOrigin::root(), 0, w)); assert_eq!(Balances::reserved_balance(&1), 0); assert!(!Asset::::contains_key(0)); @@ -331,15 +349,15 @@ fn lifecycle_should_work() { fn destroy_with_bad_witness_should_not_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); let mut w = Asset::::get(0).unwrap().destroy_witness(); - assert_ok!(Assets::mint(Origin::signed(1), 0, 10, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 10, 100)); // witness too low - assert_noop!(Assets::destroy(Origin::signed(1), 0, w), Error::::BadWitness); + assert_noop!(Assets::destroy(RuntimeOrigin::signed(1), 0, w), Error::::BadWitness); // witness too high is okay though w.accounts += 2; w.sufficients += 2; - assert_ok!(Assets::destroy(Origin::signed(1), 0, w)); + assert_ok!(Assets::destroy(RuntimeOrigin::signed(1), 0, w)); }); } @@ -347,15 +365,15 @@ fn destroy_with_bad_witness_should_not_work() { fn destroy_should_refund_approvals() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 10, 100)); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 3, 50)); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 4, 50)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 10, 100)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 3, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 4, 50)); assert_eq!(Balances::reserved_balance(&1), 3); let w = Asset::::get(0).unwrap().destroy_witness(); - assert_ok!(Assets::destroy(Origin::signed(1), 0, w)); + assert_ok!(Assets::destroy(RuntimeOrigin::signed(1), 0, w)); assert_eq!(Balances::reserved_balance(&1), 0); // all approvals are removed @@ -366,69 +384,72 @@ fn destroy_should_refund_approvals() { #[test] fn non_providing_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, false, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, false, 1)); Balances::make_free_balance_be(&0, 100); - assert_ok!(Assets::mint(Origin::signed(1), 0, 0, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 0, 100)); // Cannot mint into account 2 since it doesn't (yet) exist... - assert_noop!(Assets::mint(Origin::signed(1), 0, 1, 100), TokenError::CannotCreate); + assert_noop!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100), TokenError::CannotCreate); // ...or transfer... - assert_noop!(Assets::transfer(Origin::signed(0), 0, 1, 50), TokenError::CannotCreate); + assert_noop!( + Assets::transfer(RuntimeOrigin::signed(0), 0, 1, 50), + TokenError::CannotCreate + ); // ...or force-transfer assert_noop!( - Assets::force_transfer(Origin::signed(1), 0, 0, 1, 50), + Assets::force_transfer(RuntimeOrigin::signed(1), 0, 0, 1, 50), TokenError::CannotCreate ); Balances::make_free_balance_be(&1, 100); Balances::make_free_balance_be(&2, 100); - assert_ok!(Assets::transfer(Origin::signed(0), 0, 1, 25)); - assert_ok!(Assets::force_transfer(Origin::signed(1), 0, 0, 2, 25)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(0), 0, 1, 25)); + assert_ok!(Assets::force_transfer(RuntimeOrigin::signed(1), 0, 0, 2, 25)); }); } #[test] fn min_balance_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 10)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 10)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Asset::::get(0).unwrap().accounts, 1); // Cannot create a new account with a balance that is below minimum... - assert_noop!(Assets::mint(Origin::signed(1), 0, 2, 9), TokenError::BelowMinimum); - assert_noop!(Assets::transfer(Origin::signed(1), 0, 2, 9), TokenError::BelowMinimum); + assert_noop!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 9), TokenError::BelowMinimum); + assert_noop!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 9), TokenError::BelowMinimum); assert_noop!( - Assets::force_transfer(Origin::signed(1), 0, 1, 2, 9), + Assets::force_transfer(RuntimeOrigin::signed(1), 0, 1, 2, 9), TokenError::BelowMinimum ); // When deducting from an account to below minimum, it should be reaped. // Death by `transfer`. - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 91)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 91)); assert!(Assets::maybe_balance(0, 1).is_none()); assert_eq!(Assets::balance(0, 2), 100); assert_eq!(Asset::::get(0).unwrap().accounts, 1); assert_eq!(take_hooks(), vec![Hook::Died(0, 1)]); // Death by `force_transfer`. - assert_ok!(Assets::force_transfer(Origin::signed(1), 0, 2, 1, 91)); + assert_ok!(Assets::force_transfer(RuntimeOrigin::signed(1), 0, 2, 1, 91)); assert!(Assets::maybe_balance(0, 2).is_none()); assert_eq!(Assets::balance(0, 1), 100); assert_eq!(Asset::::get(0).unwrap().accounts, 1); assert_eq!(take_hooks(), vec![Hook::Died(0, 2)]); // Death by `burn`. - assert_ok!(Assets::burn(Origin::signed(1), 0, 1, 91)); + assert_ok!(Assets::burn(RuntimeOrigin::signed(1), 0, 1, 91)); assert!(Assets::maybe_balance(0, 1).is_none()); assert_eq!(Asset::::get(0).unwrap().accounts, 0); assert_eq!(take_hooks(), vec![Hook::Died(0, 1)]); // Death by `transfer_approved`. - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 1); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 100)); - assert_ok!(Assets::transfer_approved(Origin::signed(2), 0, 1, 3, 91)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 100)); + assert_ok!(Assets::transfer_approved(RuntimeOrigin::signed(2), 0, 1, 3, 91)); assert_eq!(take_hooks(), vec![Hook::Died(0, 1)]); }); } @@ -436,17 +457,17 @@ fn min_balance_should_work() { #[test] fn querying_total_supply_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Assets::balance(0, 1), 50); assert_eq!(Assets::balance(0, 2), 50); - assert_ok!(Assets::transfer(Origin::signed(2), 0, 3, 31)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(2), 0, 3, 31)); assert_eq!(Assets::balance(0, 1), 50); assert_eq!(Assets::balance(0, 2), 19); assert_eq!(Assets::balance(0, 3), 31); - assert_ok!(Assets::burn(Origin::signed(1), 0, 3, u64::MAX)); + assert_ok!(Assets::burn(RuntimeOrigin::signed(1), 0, 3, u64::MAX)); assert_eq!(Assets::total_supply(0), 69); }); } @@ -454,10 +475,10 @@ fn querying_total_supply_should_work() { #[test] fn transferring_amount_below_available_balance_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Assets::balance(0, 1), 50); assert_eq!(Assets::balance(0, 2), 50); }); @@ -466,14 +487,14 @@ fn transferring_amount_below_available_balance_should_work() { #[test] fn transferring_enough_to_kill_source_when_keep_alive_should_fail() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 10)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 10)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_noop!( - Assets::transfer_keep_alive(Origin::signed(1), 0, 2, 91), + Assets::transfer_keep_alive(RuntimeOrigin::signed(1), 0, 2, 91), Error::::BalanceLow ); - assert_ok!(Assets::transfer_keep_alive(Origin::signed(1), 0, 2, 90)); + assert_ok!(Assets::transfer_keep_alive(RuntimeOrigin::signed(1), 0, 2, 90)); assert_eq!(Assets::balance(0, 1), 10); assert_eq!(Assets::balance(0, 2), 90); assert!(hooks().is_empty()); @@ -483,26 +504,26 @@ fn transferring_enough_to_kill_source_when_keep_alive_should_fail() { #[test] fn transferring_frozen_user_should_not_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::freeze(Origin::signed(1), 0, 1)); - assert_noop!(Assets::transfer(Origin::signed(1), 0, 2, 50), Error::::Frozen); - assert_ok!(Assets::thaw(Origin::signed(1), 0, 1)); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::freeze(RuntimeOrigin::signed(1), 0, 1)); + assert_noop!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50), Error::::Frozen); + assert_ok!(Assets::thaw(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); }); } #[test] fn transferring_frozen_asset_should_not_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::freeze_asset(Origin::signed(1), 0)); - assert_noop!(Assets::transfer(Origin::signed(1), 0, 2, 50), Error::::Frozen); - assert_ok!(Assets::thaw_asset(Origin::signed(1), 0)); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0)); + assert_noop!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50), Error::::Frozen); + assert_ok!(Assets::thaw_asset(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); }); } @@ -510,36 +531,48 @@ fn transferring_frozen_asset_should_not_work() { fn approve_transfer_frozen_asset_should_not_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::freeze_asset(Origin::signed(1), 0)); - assert_noop!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50), Error::::Frozen); - assert_ok!(Assets::thaw_asset(Origin::signed(1), 0)); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::freeze_asset(RuntimeOrigin::signed(1), 0)); + assert_noop!( + Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50), + Error::::Frozen + ); + assert_ok!(Assets::thaw_asset(RuntimeOrigin::signed(1), 0)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); }); } #[test] fn origin_guards_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_noop!( + Assets::transfer_ownership(RuntimeOrigin::signed(2), 0, 2), + Error::::NoPermission + ); assert_noop!( - Assets::transfer_ownership(Origin::signed(2), 0, 2), + Assets::set_team(RuntimeOrigin::signed(2), 0, 2, 2, 2), Error::::NoPermission ); - assert_noop!(Assets::set_team(Origin::signed(2), 0, 2, 2, 2), Error::::NoPermission); - assert_noop!(Assets::freeze(Origin::signed(2), 0, 1), Error::::NoPermission); - assert_noop!(Assets::thaw(Origin::signed(2), 0, 2), Error::::NoPermission); - assert_noop!(Assets::mint(Origin::signed(2), 0, 2, 100), Error::::NoPermission); - assert_noop!(Assets::burn(Origin::signed(2), 0, 1, 100), Error::::NoPermission); + assert_noop!(Assets::freeze(RuntimeOrigin::signed(2), 0, 1), Error::::NoPermission); + assert_noop!(Assets::thaw(RuntimeOrigin::signed(2), 0, 2), Error::::NoPermission); assert_noop!( - Assets::force_transfer(Origin::signed(2), 0, 1, 2, 100), + Assets::mint(RuntimeOrigin::signed(2), 0, 2, 100), + Error::::NoPermission + ); + assert_noop!( + Assets::burn(RuntimeOrigin::signed(2), 0, 1, 100), + Error::::NoPermission + ); + assert_noop!( + Assets::force_transfer(RuntimeOrigin::signed(2), 0, 1, 2, 100), Error::::NoPermission ); let w = Asset::::get(0).unwrap().destroy_witness(); - assert_noop!(Assets::destroy(Origin::signed(2), 0, w), Error::::NoPermission); + assert_noop!(Assets::destroy(RuntimeOrigin::signed(2), 0, w), Error::::NoPermission); }); } @@ -548,22 +581,28 @@ fn transfer_owner_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); Balances::make_free_balance_be(&2, 100); - assert_ok!(Assets::create(Origin::signed(1), 0, 1, 1)); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 1)); assert_eq!(Balances::reserved_balance(&1), 1); - assert_ok!(Assets::transfer_ownership(Origin::signed(1), 0, 2)); + assert_ok!(Assets::transfer_ownership(RuntimeOrigin::signed(1), 0, 2)); assert_eq!(Balances::reserved_balance(&2), 1); assert_eq!(Balances::reserved_balance(&1), 0); assert_noop!( - Assets::transfer_ownership(Origin::signed(1), 0, 1), + Assets::transfer_ownership(RuntimeOrigin::signed(1), 0, 1), Error::::NoPermission ); // Set metadata now and make sure that deposit gets transferred back. - assert_ok!(Assets::set_metadata(Origin::signed(2), 0, vec![0u8; 10], vec![0u8; 10], 12)); - assert_ok!(Assets::transfer_ownership(Origin::signed(2), 0, 1)); + assert_ok!(Assets::set_metadata( + RuntimeOrigin::signed(2), + 0, + vec![0u8; 10], + vec![0u8; 10], + 12 + )); + assert_ok!(Assets::transfer_ownership(RuntimeOrigin::signed(2), 0, 1)); assert_eq!(Balances::reserved_balance(&1), 22); assert_eq!(Balances::reserved_balance(&2), 0); }); @@ -572,27 +611,27 @@ fn transfer_owner_should_work() { #[test] fn set_team_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::set_team(Origin::signed(1), 0, 2, 3, 4)); - - assert_ok!(Assets::mint(Origin::signed(2), 0, 2, 100)); - assert_ok!(Assets::freeze(Origin::signed(4), 0, 2)); - assert_ok!(Assets::thaw(Origin::signed(3), 0, 2)); - assert_ok!(Assets::force_transfer(Origin::signed(3), 0, 2, 3, 100)); - assert_ok!(Assets::burn(Origin::signed(3), 0, 3, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::set_team(RuntimeOrigin::signed(1), 0, 2, 3, 4)); + + assert_ok!(Assets::mint(RuntimeOrigin::signed(2), 0, 2, 100)); + assert_ok!(Assets::freeze(RuntimeOrigin::signed(4), 0, 2)); + assert_ok!(Assets::thaw(RuntimeOrigin::signed(3), 0, 2)); + assert_ok!(Assets::force_transfer(RuntimeOrigin::signed(3), 0, 2, 3, 100)); + assert_ok!(Assets::burn(RuntimeOrigin::signed(3), 0, 3, 100)); }); } #[test] fn transferring_to_frozen_account_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 2, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 100)); assert_eq!(Assets::balance(0, 1), 100); assert_eq!(Assets::balance(0, 2), 100); - assert_ok!(Assets::freeze(Origin::signed(1), 0, 2)); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::freeze(RuntimeOrigin::signed(1), 0, 2)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Assets::balance(0, 2), 150); }); } @@ -600,26 +639,32 @@ fn transferring_to_frozen_account_should_work() { #[test] fn transferring_amount_more_than_available_balance_should_not_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(Assets::balance(0, 1), 50); assert_eq!(Assets::balance(0, 2), 50); - assert_ok!(Assets::burn(Origin::signed(1), 0, 1, u64::MAX)); + assert_ok!(Assets::burn(RuntimeOrigin::signed(1), 0, 1, u64::MAX)); assert_eq!(Assets::balance(0, 1), 0); - assert_noop!(Assets::transfer(Origin::signed(1), 0, 1, 50), Error::::NoAccount); - assert_noop!(Assets::transfer(Origin::signed(2), 0, 1, 51), Error::::BalanceLow); + assert_noop!( + Assets::transfer(RuntimeOrigin::signed(1), 0, 1, 50), + Error::::NoAccount + ); + assert_noop!( + Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 51), + Error::::BalanceLow + ); }); } #[test] fn transferring_less_than_one_unit_is_fine() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 0)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 0)); // `ForceCreated` and `Issued` but no `Transferred` event. assert_eq!(System::events().len(), 2); }); @@ -628,20 +673,23 @@ fn transferring_less_than_one_unit_is_fine() { #[test] fn transferring_more_units_than_total_supply_should_not_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_noop!(Assets::transfer(Origin::signed(1), 0, 2, 101), Error::::BalanceLow); + assert_noop!( + Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 101), + Error::::BalanceLow + ); }); } #[test] fn burning_asset_balance_with_positive_balance_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); - assert_ok!(Assets::burn(Origin::signed(1), 0, 1, u64::MAX)); + assert_ok!(Assets::burn(RuntimeOrigin::signed(1), 0, 1, u64::MAX)); assert_eq!(Assets::balance(0, 1), 0); }); } @@ -649,10 +697,13 @@ fn burning_asset_balance_with_positive_balance_should_work() { #[test] fn burning_asset_balance_with_zero_balance_does_nothing() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 2), 0); - assert_noop!(Assets::burn(Origin::signed(1), 0, 2, u64::MAX), Error::::NoAccount); + assert_noop!( + Assets::burn(RuntimeOrigin::signed(1), 0, 2, u64::MAX), + Error::::NoAccount + ); assert_eq!(Assets::balance(0, 2), 0); assert_eq!(Assets::total_supply(0), 100); }); @@ -663,48 +714,69 @@ fn set_metadata_should_work() { new_test_ext().execute_with(|| { // Cannot add metadata to unknown asset assert_noop!( - Assets::set_metadata(Origin::signed(1), 0, vec![0u8; 10], vec![0u8; 10], 12), + Assets::set_metadata(RuntimeOrigin::signed(1), 0, vec![0u8; 10], vec![0u8; 10], 12), Error::::Unknown, ); - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); // Cannot add metadata to unowned asset assert_noop!( - Assets::set_metadata(Origin::signed(2), 0, vec![0u8; 10], vec![0u8; 10], 12), + Assets::set_metadata(RuntimeOrigin::signed(2), 0, vec![0u8; 10], vec![0u8; 10], 12), Error::::NoPermission, ); // Cannot add oversized metadata assert_noop!( - Assets::set_metadata(Origin::signed(1), 0, vec![0u8; 100], vec![0u8; 10], 12), + Assets::set_metadata(RuntimeOrigin::signed(1), 0, vec![0u8; 100], vec![0u8; 10], 12), Error::::BadMetadata, ); assert_noop!( - Assets::set_metadata(Origin::signed(1), 0, vec![0u8; 10], vec![0u8; 100], 12), + Assets::set_metadata(RuntimeOrigin::signed(1), 0, vec![0u8; 10], vec![0u8; 100], 12), Error::::BadMetadata, ); // Successfully add metadata and take deposit Balances::make_free_balance_be(&1, 30); - assert_ok!(Assets::set_metadata(Origin::signed(1), 0, vec![0u8; 10], vec![0u8; 10], 12)); + assert_ok!(Assets::set_metadata( + RuntimeOrigin::signed(1), + 0, + vec![0u8; 10], + vec![0u8; 10], + 12 + )); assert_eq!(Balances::free_balance(&1), 9); // Update deposit - assert_ok!(Assets::set_metadata(Origin::signed(1), 0, vec![0u8; 10], vec![0u8; 5], 12)); + assert_ok!(Assets::set_metadata( + RuntimeOrigin::signed(1), + 0, + vec![0u8; 10], + vec![0u8; 5], + 12 + )); assert_eq!(Balances::free_balance(&1), 14); - assert_ok!(Assets::set_metadata(Origin::signed(1), 0, vec![0u8; 10], vec![0u8; 15], 12)); + assert_ok!(Assets::set_metadata( + RuntimeOrigin::signed(1), + 0, + vec![0u8; 10], + vec![0u8; 15], + 12 + )); assert_eq!(Balances::free_balance(&1), 4); // Cannot over-reserve assert_noop!( - Assets::set_metadata(Origin::signed(1), 0, vec![0u8; 20], vec![0u8; 20], 12), + Assets::set_metadata(RuntimeOrigin::signed(1), 0, vec![0u8; 20], vec![0u8; 20], 12), BalancesError::::InsufficientBalance, ); // Clear Metadata assert!(Metadata::::contains_key(0)); - assert_noop!(Assets::clear_metadata(Origin::signed(2), 0), Error::::NoPermission); - assert_noop!(Assets::clear_metadata(Origin::signed(1), 1), Error::::Unknown); - assert_ok!(Assets::clear_metadata(Origin::signed(1), 0)); + assert_noop!( + Assets::clear_metadata(RuntimeOrigin::signed(2), 0), + Error::::NoPermission + ); + assert_noop!(Assets::clear_metadata(RuntimeOrigin::signed(1), 1), Error::::Unknown); + assert_ok!(Assets::clear_metadata(RuntimeOrigin::signed(1), 0)); assert!(!Metadata::::contains_key(0)); }); } @@ -713,13 +785,13 @@ fn set_metadata_should_work() { #[test] fn destroy_calls_died_hooks() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 50)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 50)); // Create account 1 and 2. - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 2, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 100)); // Destroy the asset. let w = Asset::::get(0).unwrap().destroy_witness(); - assert_ok!(Assets::destroy(Origin::signed(1), 0, w)); + assert_ok!(Assets::destroy(RuntimeOrigin::signed(1), 0, w)); // Asset is gone and accounts 1 and 2 died. assert!(Asset::::get(0).is_none()); @@ -730,36 +802,39 @@ fn destroy_calls_died_hooks() { #[test] fn freezer_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 10)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 10)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); assert_eq!(Assets::balance(0, 1), 100); // freeze 50 of it. set_frozen_balance(0, 1, 50); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 20)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 20)); // cannot transfer another 21 away as this would take the non-frozen balance (30) to below // the minimum balance (10). - assert_noop!(Assets::transfer(Origin::signed(1), 0, 2, 21), Error::::BalanceLow); + assert_noop!( + Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 21), + Error::::BalanceLow + ); // create an approved transfer... Balances::make_free_balance_be(&1, 100); - assert_ok!(Assets::approve_transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::approve_transfer(RuntimeOrigin::signed(1), 0, 2, 50)); let e = Error::::BalanceLow; // ...but that wont work either: - assert_noop!(Assets::transfer_approved(Origin::signed(2), 0, 1, 2, 21), e); + assert_noop!(Assets::transfer_approved(RuntimeOrigin::signed(2), 0, 1, 2, 21), e); // a force transfer won't work also. let e = Error::::BalanceLow; - assert_noop!(Assets::force_transfer(Origin::signed(1), 0, 1, 2, 21), e); + assert_noop!(Assets::force_transfer(RuntimeOrigin::signed(1), 0, 1, 2, 21), e); // reduce it to only 49 frozen... set_frozen_balance(0, 1, 49); // ...and it's all good: - assert_ok!(Assets::force_transfer(Origin::signed(1), 0, 1, 2, 21)); + assert_ok!(Assets::force_transfer(RuntimeOrigin::signed(1), 0, 1, 2, 21)); // and if we clear it, we can remove the account completely. clear_frozen_balance(0, 1); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 50)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 50)); assert_eq!(hooks(), vec![Hook::Died(0, 1)]); }); } @@ -769,7 +844,7 @@ fn imbalances_should_work() { use frame_support::traits::tokens::fungibles::Balanced; new_test_ext().execute_with(|| { - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); let imb = Assets::issue(0, 100); assert_eq!(Assets::total_supply(0), 100); @@ -792,9 +867,9 @@ fn imbalances_should_work() { fn force_metadata_should_work() { new_test_ext().execute_with(|| { // force set metadata works - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); assert_ok!(Assets::force_set_metadata( - Origin::root(), + RuntimeOrigin::root(), 0, vec![0u8; 10], vec![0u8; 10], @@ -806,7 +881,7 @@ fn force_metadata_should_work() { // overwrites existing metadata let asset_original_metadata = Metadata::::get(0); assert_ok!(Assets::force_set_metadata( - Origin::root(), + RuntimeOrigin::root(), 0, vec![1u8; 10], vec![1u8; 10], @@ -817,7 +892,14 @@ fn force_metadata_should_work() { // attempt to set metadata for non-existent asset class assert_noop!( - Assets::force_set_metadata(Origin::root(), 1, vec![0u8; 10], vec![0u8; 10], 8, false), + Assets::force_set_metadata( + RuntimeOrigin::root(), + 1, + vec![0u8; 10], + vec![0u8; 10], + 8, + false + ), Error::::Unknown ); @@ -825,7 +907,7 @@ fn force_metadata_should_work() { let limit = 50usize; assert_noop!( Assets::force_set_metadata( - Origin::root(), + RuntimeOrigin::root(), 0, vec![0u8; limit + 1], vec![0u8; 10], @@ -836,7 +918,7 @@ fn force_metadata_should_work() { ); assert_noop!( Assets::force_set_metadata( - Origin::root(), + RuntimeOrigin::root(), 0, vec![0u8; 10], vec![0u8; limit + 1], @@ -848,11 +930,14 @@ fn force_metadata_should_work() { // force clear metadata works assert!(Metadata::::contains_key(0)); - assert_ok!(Assets::force_clear_metadata(Origin::root(), 0)); + assert_ok!(Assets::force_clear_metadata(RuntimeOrigin::root(), 0)); assert!(!Metadata::::contains_key(0)); // Error handles clearing non-existent asset class - assert_noop!(Assets::force_clear_metadata(Origin::root(), 1), Error::::Unknown); + assert_noop!( + Assets::force_clear_metadata(RuntimeOrigin::root(), 1), + Error::::Unknown + ); }); } @@ -861,34 +946,57 @@ fn force_asset_status_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 10); Balances::make_free_balance_be(&2, 10); - assert_ok!(Assets::create(Origin::signed(1), 0, 1, 30)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 50)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 2, 150)); + assert_ok!(Assets::create(RuntimeOrigin::signed(1), 0, 1, 30)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 50)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 2, 150)); // force asset status to change min_balance > balance - assert_ok!(Assets::force_asset_status(Origin::root(), 0, 1, 1, 1, 1, 100, true, false)); + assert_ok!(Assets::force_asset_status( + RuntimeOrigin::root(), + 0, + 1, + 1, + 1, + 1, + 100, + true, + false + )); assert_eq!(Assets::balance(0, 1), 50); // account can recieve assets for balance < min_balance - assert_ok!(Assets::transfer(Origin::signed(2), 0, 1, 1)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 1)); assert_eq!(Assets::balance(0, 1), 51); // account on outbound transfer will cleanup for balance < min_balance - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, 1)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, 1)); assert_eq!(Assets::balance(0, 1), 0); // won't create new account with balance below min_balance - assert_noop!(Assets::transfer(Origin::signed(2), 0, 3, 50), TokenError::BelowMinimum); + assert_noop!( + Assets::transfer(RuntimeOrigin::signed(2), 0, 3, 50), + TokenError::BelowMinimum + ); // force asset status will not execute for non-existent class assert_noop!( - Assets::force_asset_status(Origin::root(), 1, 1, 1, 1, 1, 90, true, false), + Assets::force_asset_status(RuntimeOrigin::root(), 1, 1, 1, 1, 1, 90, true, false), Error::::Unknown ); // account drains to completion when funds dip below min_balance - assert_ok!(Assets::force_asset_status(Origin::root(), 0, 1, 1, 1, 1, 110, true, false)); - assert_ok!(Assets::transfer(Origin::signed(2), 0, 1, 110)); + assert_ok!(Assets::force_asset_status( + RuntimeOrigin::root(), + 0, + 1, + 1, + 1, + 1, + 110, + true, + false + )); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(2), 0, 1, 110)); assert_eq!(Assets::balance(0, 1), 200); assert_eq!(Assets::balance(0, 2), 0); assert_eq!(Assets::total_supply(0), 200); @@ -901,9 +1009,9 @@ fn balance_conversion_should_work() { use frame_support::traits::tokens::BalanceConversion; let id = 42; - assert_ok!(Assets::force_create(Origin::root(), id, 1, true, 10)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), id, 1, true, 10)); let not_sufficient = 23; - assert_ok!(Assets::force_create(Origin::root(), not_sufficient, 1, false, 10)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), not_sufficient, 1, false, 10)); assert_eq!( BalanceToAssetBalance::::to_asset_balance(100, 1234), @@ -938,9 +1046,9 @@ fn assets_from_genesis_should_exist() { fn querying_name_symbol_and_decimals_should_work() { new_test_ext().execute_with(|| { use frame_support::traits::tokens::fungibles::metadata::Inspect; - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); assert_ok!(Assets::force_set_metadata( - Origin::root(), + RuntimeOrigin::root(), 0, vec![0u8; 10], vec![1u8; 10], @@ -957,8 +1065,8 @@ fn querying_name_symbol_and_decimals_should_work() { fn querying_allowance_should_work() { new_test_ext().execute_with(|| { use frame_support::traits::tokens::fungibles::approvals::{Inspect, Mutate}; - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, 100)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, 100)); Balances::make_free_balance_be(&1, 1); assert_ok!(Assets::approve(0, &1, &2, 50)); assert_eq!(Assets::allowance(0, &1, &2), 50); @@ -972,8 +1080,30 @@ fn querying_allowance_should_work() { fn transfer_large_asset() { new_test_ext().execute_with(|| { let amount = u64::pow(2, 63) + 2; - assert_ok!(Assets::force_create(Origin::root(), 0, 1, true, 1)); - assert_ok!(Assets::mint(Origin::signed(1), 0, 1, amount)); - assert_ok!(Assets::transfer(Origin::signed(1), 0, 2, amount - 1)); + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(1), 0, 1, amount)); + assert_ok!(Assets::transfer(RuntimeOrigin::signed(1), 0, 2, amount - 1)); }) } + +#[test] +fn querying_roles_should_work() { + new_test_ext().execute_with(|| { + use frame_support::traits::tokens::fungibles::roles::Inspect; + assert_ok!(Assets::force_create(RuntimeOrigin::root(), 0, 1, true, 1)); + assert_ok!(Assets::set_team( + RuntimeOrigin::signed(1), + 0, + // Issuer + 2, + // Admin + 3, + // Freezer + 4, + )); + assert_eq!(Assets::owner(0), Some(1)); + assert_eq!(Assets::issuer(0), Some(2)); + assert_eq!(Assets::admin(0), Some(3)); + assert_eq!(Assets::freezer(0), Some(4)); + }); +} diff --git a/frame/assets/src/weights.rs b/frame/assets/src/weights.rs index cba78f12c218c..c260da70e3480 100644 --- a/frame/assets/src/weights.rs +++ b/frame/assets/src/weights.rs @@ -18,22 +18,25 @@ //! Autogenerated weights for pallet_assets //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-10-20, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_assets // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_assets +// --chain=dev // --output=./frame/assets/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -74,13 +77,15 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - Weight::from_ref_time(27_167_000 as u64) + // Minimum execution time: 32_200 nanoseconds. + Weight::from_ref_time(32_739_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - Weight::from_ref_time(15_473_000 as u64) + // Minimum execution time: 19_192 nanoseconds. + Weight::from_ref_time(19_615_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -89,14 +94,16 @@ impl WeightInfo for SubstrateWeight { // Storage: System Account (r:5000 w:5000) // Storage: Assets Metadata (r:1 w:0) // Storage: Assets Approvals (r:501 w:500) + /// The range of component `c` is `[0, 5000]`. + /// The range of component `s` is `[0, 5000]`. + /// The range of component `a` is `[0, 500]`. fn destroy(c: u32, s: u32, a: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(17_145_000 as u64).saturating_mul(c as u64)) - // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(19_333_000 as u64).saturating_mul(s as u64)) - // Standard Error: 375_000 - .saturating_add(Weight::from_ref_time(17_046_000 as u64).saturating_mul(a as u64)) + // Minimum execution time: 75_299_531 nanoseconds. + Weight::from_ref_time(75_567_795_000 as u64) + // Standard Error: 126_181 + .saturating_add(Weight::from_ref_time(8_378_363 as u64).saturating_mul(c as u64)) + // Standard Error: 126_181 + .saturating_add(Weight::from_ref_time(10_950_076 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(c as u64))) .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(s as u64))) @@ -109,14 +116,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - Weight::from_ref_time(30_819_000 as u64) + // Minimum execution time: 35_066 nanoseconds. + Weight::from_ref_time(36_217_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - Weight::from_ref_time(35_212_000 as u64) + // Minimum execution time: 44_915 nanoseconds. + Weight::from_ref_time(45_807_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -124,7 +133,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - Weight::from_ref_time(47_401_000 as u64) + // Minimum execution time: 57_245 nanoseconds. + Weight::from_ref_time(58_179_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -132,7 +142,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - Weight::from_ref_time(42_300_000 as u64) + // Minimum execution time: 47_028 nanoseconds. + Weight::from_ref_time(47_571_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -140,93 +151,108 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - Weight::from_ref_time(47_946_000 as u64) + // Minimum execution time: 57_069 nanoseconds. + Weight::from_ref_time(58_245_000 as u64) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - Weight::from_ref_time(21_670_000 as u64) + // Minimum execution time: 26_823 nanoseconds. + Weight::from_ref_time(27_689_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - Weight::from_ref_time(21_503_000 as u64) + // Minimum execution time: 26_984 nanoseconds. + Weight::from_ref_time(27_591_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - Weight::from_ref_time(18_158_000 as u64) + // Minimum execution time: 23_803 nanoseconds. + Weight::from_ref_time(24_269_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - Weight::from_ref_time(18_525_000 as u64) + // Minimum execution time: 22_977 nanoseconds. + Weight::from_ref_time(23_527_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - Weight::from_ref_time(19_858_000 as u64) + // Minimum execution time: 23_815 nanoseconds. + Weight::from_ref_time(24_597_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - Weight::from_ref_time(18_045_000 as u64) + // Minimum execution time: 22_691 nanoseconds. + Weight::from_ref_time(23_173_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn set_metadata(n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_395_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(n as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + fn set_metadata(_n: u32, _s: u32, ) -> Weight { + // Minimum execution time: 40_675 nanoseconds. + Weight::from_ref_time(42_869_113 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - Weight::from_ref_time(32_893_000 as u64) + // Minimum execution time: 42_361 nanoseconds. + Weight::from_ref_time(42_912_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn force_set_metadata(_n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(19_586_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(s as u64)) + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + fn force_set_metadata(n: u32, s: u32, ) -> Weight { + // Minimum execution time: 22_998 nanoseconds. + Weight::from_ref_time(23_844_675 as u64) + // Standard Error: 506 + .saturating_add(Weight::from_ref_time(2_874 as u64).saturating_mul(n as u64)) + // Standard Error: 506 + .saturating_add(Weight::from_ref_time(3_817 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - Weight::from_ref_time(32_478_000 as u64) + // Minimum execution time: 42_305 nanoseconds. + Weight::from_ref_time(42_678_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - Weight::from_ref_time(17_143_000 as u64) + // Minimum execution time: 22_052 nanoseconds. + Weight::from_ref_time(22_610_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - Weight::from_ref_time(36_389_000 as u64) + // Minimum execution time: 44_900 nanoseconds. + Weight::from_ref_time(46_032_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -235,21 +261,24 @@ impl WeightInfo for SubstrateWeight { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - Weight::from_ref_time(61_854_000 as u64) + // Minimum execution time: 72_261 nanoseconds. + Weight::from_ref_time(73_186_000 as u64) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - Weight::from_ref_time(36_759_000 as u64) + // Minimum execution time: 47_268 nanoseconds. + Weight::from_ref_time(47_712_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - Weight::from_ref_time(37_753_000 as u64) + // Minimum execution time: 47_363 nanoseconds. + Weight::from_ref_time(48_696_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -259,13 +288,15 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Assets Asset (r:1 w:1) fn create() -> Weight { - Weight::from_ref_time(27_167_000 as u64) + // Minimum execution time: 32_200 nanoseconds. + Weight::from_ref_time(32_739_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn force_create() -> Weight { - Weight::from_ref_time(15_473_000 as u64) + // Minimum execution time: 19_192 nanoseconds. + Weight::from_ref_time(19_615_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -274,14 +305,16 @@ impl WeightInfo for () { // Storage: System Account (r:5000 w:5000) // Storage: Assets Metadata (r:1 w:0) // Storage: Assets Approvals (r:501 w:500) + /// The range of component `c` is `[0, 5000]`. + /// The range of component `s` is `[0, 5000]`. + /// The range of component `a` is `[0, 500]`. fn destroy(c: u32, s: u32, a: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(17_145_000 as u64).saturating_mul(c as u64)) - // Standard Error: 37_000 - .saturating_add(Weight::from_ref_time(19_333_000 as u64).saturating_mul(s as u64)) - // Standard Error: 375_000 - .saturating_add(Weight::from_ref_time(17_046_000 as u64).saturating_mul(a as u64)) + // Minimum execution time: 75_299_531 nanoseconds. + Weight::from_ref_time(75_567_795_000 as u64) + // Standard Error: 126_181 + .saturating_add(Weight::from_ref_time(8_378_363 as u64).saturating_mul(c as u64)) + // Standard Error: 126_181 + .saturating_add(Weight::from_ref_time(10_950_076 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(c as u64))) .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(s as u64))) @@ -294,14 +327,16 @@ impl WeightInfo for () { // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn mint() -> Weight { - Weight::from_ref_time(30_819_000 as u64) + // Minimum execution time: 35_066 nanoseconds. + Weight::from_ref_time(36_217_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Account (r:1 w:1) fn burn() -> Weight { - Weight::from_ref_time(35_212_000 as u64) + // Minimum execution time: 44_915 nanoseconds. + Weight::from_ref_time(45_807_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -309,7 +344,8 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer() -> Weight { - Weight::from_ref_time(47_401_000 as u64) + // Minimum execution time: 57_245 nanoseconds. + Weight::from_ref_time(58_179_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -317,7 +353,8 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_keep_alive() -> Weight { - Weight::from_ref_time(42_300_000 as u64) + // Minimum execution time: 47_028 nanoseconds. + Weight::from_ref_time(47_571_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -325,93 +362,108 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn force_transfer() -> Weight { - Weight::from_ref_time(47_946_000 as u64) + // Minimum execution time: 57_069 nanoseconds. + Weight::from_ref_time(58_245_000 as u64) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn freeze() -> Weight { - Weight::from_ref_time(21_670_000 as u64) + // Minimum execution time: 26_823 nanoseconds. + Weight::from_ref_time(27_689_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Account (r:1 w:1) fn thaw() -> Weight { - Weight::from_ref_time(21_503_000 as u64) + // Minimum execution time: 26_984 nanoseconds. + Weight::from_ref_time(27_591_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn freeze_asset() -> Weight { - Weight::from_ref_time(18_158_000 as u64) + // Minimum execution time: 23_803 nanoseconds. + Weight::from_ref_time(24_269_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn thaw_asset() -> Weight { - Weight::from_ref_time(18_525_000 as u64) + // Minimum execution time: 22_977 nanoseconds. + Weight::from_ref_time(23_527_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Metadata (r:1 w:0) fn transfer_ownership() -> Weight { - Weight::from_ref_time(19_858_000 as u64) + // Minimum execution time: 23_815 nanoseconds. + Weight::from_ref_time(24_597_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn set_team() -> Weight { - Weight::from_ref_time(18_045_000 as u64) + // Minimum execution time: 22_691 nanoseconds. + Weight::from_ref_time(23_173_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn set_metadata(n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(32_395_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(5_000 as u64).saturating_mul(n as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + fn set_metadata(_n: u32, _s: u32, ) -> Weight { + // Minimum execution time: 40_675 nanoseconds. + Weight::from_ref_time(42_869_113 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn clear_metadata() -> Weight { - Weight::from_ref_time(32_893_000 as u64) + // Minimum execution time: 42_361 nanoseconds. + Weight::from_ref_time(42_912_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) - fn force_set_metadata(_n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(19_586_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(s as u64)) + /// The range of component `n` is `[0, 50]`. + /// The range of component `s` is `[0, 50]`. + fn force_set_metadata(n: u32, s: u32, ) -> Weight { + // Minimum execution time: 22_998 nanoseconds. + Weight::from_ref_time(23_844_675 as u64) + // Standard Error: 506 + .saturating_add(Weight::from_ref_time(2_874 as u64).saturating_mul(n as u64)) + // Standard Error: 506 + .saturating_add(Weight::from_ref_time(3_817 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:0) // Storage: Assets Metadata (r:1 w:1) fn force_clear_metadata() -> Weight { - Weight::from_ref_time(32_478_000 as u64) + // Minimum execution time: 42_305 nanoseconds. + Weight::from_ref_time(42_678_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) fn force_asset_status() -> Weight { - Weight::from_ref_time(17_143_000 as u64) + // Minimum execution time: 22_052 nanoseconds. + Weight::from_ref_time(22_610_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn approve_transfer() -> Weight { - Weight::from_ref_time(36_389_000 as u64) + // Minimum execution time: 44_900 nanoseconds. + Weight::from_ref_time(46_032_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -420,21 +472,24 @@ impl WeightInfo for () { // Storage: Assets Account (r:2 w:2) // Storage: System Account (r:1 w:1) fn transfer_approved() -> Weight { - Weight::from_ref_time(61_854_000 as u64) + // Minimum execution time: 72_261 nanoseconds. + Weight::from_ref_time(73_186_000 as u64) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn cancel_approval() -> Weight { - Weight::from_ref_time(36_759_000 as u64) + // Minimum execution time: 47_268 nanoseconds. + Weight::from_ref_time(47_712_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Assets Asset (r:1 w:1) // Storage: Assets Approvals (r:1 w:1) fn force_cancel_approval() -> Weight { - Weight::from_ref_time(37_753_000 as u64) + // Minimum execution time: 47_363 nanoseconds. + Weight::from_ref_time(48_696_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } diff --git a/frame/atomic-swap/src/lib.rs b/frame/atomic-swap/src/lib.rs index 1b6c62c55ee20..9c6056497118c 100644 --- a/frame/atomic-swap/src/lib.rs +++ b/frame/atomic-swap/src/lib.rs @@ -166,7 +166,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Swap action. type SwapAction: SwapAction + Parameter + MaxEncodedLen; /// Limit of proof size. diff --git a/frame/atomic-swap/src/tests.rs b/frame/atomic-swap/src/tests.rs index ffb548a1f29ed..5ad63dfce55b4 100644 --- a/frame/atomic-swap/src/tests.rs +++ b/frame/atomic-swap/src/tests.rs @@ -37,16 +37,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -65,14 +65,14 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SwapAction = BalanceSwapAction; type ProofLimit = ConstU32<1024>; } @@ -100,7 +100,7 @@ fn two_party_successful_swap() { // A creates the swap on chain1. chain1.execute_with(|| { AtomicSwap::create_swap( - Origin::signed(A), + RuntimeOrigin::signed(A), B, hashed_proof, BalanceSwapAction::new(50), @@ -115,7 +115,7 @@ fn two_party_successful_swap() { // B creates the swap on chain2. chain2.execute_with(|| { AtomicSwap::create_swap( - Origin::signed(B), + RuntimeOrigin::signed(B), A, hashed_proof, BalanceSwapAction::new(75), @@ -129,8 +129,12 @@ fn two_party_successful_swap() { // A reveals the proof and claims the swap on chain2. chain2.execute_with(|| { - AtomicSwap::claim_swap(Origin::signed(A), proof.to_vec(), BalanceSwapAction::new(75)) - .unwrap(); + AtomicSwap::claim_swap( + RuntimeOrigin::signed(A), + proof.to_vec(), + BalanceSwapAction::new(75), + ) + .unwrap(); assert_eq!(Balances::free_balance(A), 100 + 75); assert_eq!(Balances::free_balance(B), 200 - 75); @@ -138,8 +142,12 @@ fn two_party_successful_swap() { // B use the revealed proof to claim the swap on chain1. chain1.execute_with(|| { - AtomicSwap::claim_swap(Origin::signed(B), proof.to_vec(), BalanceSwapAction::new(50)) - .unwrap(); + AtomicSwap::claim_swap( + RuntimeOrigin::signed(B), + proof.to_vec(), + BalanceSwapAction::new(50), + ) + .unwrap(); assert_eq!(Balances::free_balance(A), 100 - 50); assert_eq!(Balances::free_balance(B), 200 + 50); diff --git a/frame/aura/src/mock.rs b/frame/aura/src/mock.rs index 5023feeaf8aea..07fa9aa680e80 100644 --- a/frame/aura/src/mock.rs +++ b/frame/aura/src/mock.rs @@ -30,7 +30,6 @@ use sp_runtime::{ testing::{Header, UintAuthorityId}, traits::IdentityLookup, }; -use sp_std::cell::RefCell; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -57,16 +56,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -86,18 +85,17 @@ impl pallet_timestamp::Config for Test { type WeightInfo = (); } -thread_local! { - static DISABLED_VALIDATORS: RefCell> = RefCell::new(Default::default()); +parameter_types! { + static DisabledValidatorTestValue: Vec = Default::default(); } pub struct MockDisabledValidators; impl MockDisabledValidators { pub fn disable_validator(index: AuthorityIndex) { - DISABLED_VALIDATORS.with(|v| { - let mut disabled = v.borrow_mut(); - if let Err(i) = disabled.binary_search(&index) { - disabled.insert(i, index); + DisabledValidatorTestValue::mutate(|v| { + if let Err(i) = v.binary_search(&index) { + v.insert(i, index); } }) } @@ -105,7 +103,7 @@ impl MockDisabledValidators { impl DisabledValidators for MockDisabledValidators { fn is_disabled(index: AuthorityIndex) -> bool { - DISABLED_VALIDATORS.with(|v| v.borrow().binary_search(&index).is_ok()) + DisabledValidatorTestValue::get().binary_search(&index).is_ok() } } diff --git a/frame/authority-discovery/src/lib.rs b/frame/authority-discovery/src/lib.rs index d5f9783f153c8..b642a9ac283f2 100644 --- a/frame/authority-discovery/src/lib.rs +++ b/frame/authority-discovery/src/lib.rs @@ -209,7 +209,7 @@ mod tests { type Keys = UintAuthorityId; type ShouldEndSession = pallet_session::PeriodicSessions; type SessionHandler = TestSessionHandler; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = AuthorityId; type ValidatorIdOf = ConvertInto; type NextSessionRotation = pallet_session::PeriodicSessions; @@ -235,16 +235,16 @@ mod tests { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AuthorityId; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; diff --git a/frame/authorship/src/lib.rs b/frame/authorship/src/lib.rs index ff18e047db048..c08e773abe3a7 100644 --- a/frame/authorship/src/lib.rs +++ b/frame/authorship/src/lib.rs @@ -468,16 +468,16 @@ mod tests { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -738,7 +738,7 @@ mod tests { System::reset_events(); System::initialize(¤t_depth, &parent_hash, &Default::default()); Authorship::on_initialize(current_depth); - Authorship::set_uncles(Origin::none(), uncles).unwrap(); + Authorship::set_uncles(RuntimeOrigin::none(), uncles).unwrap(); Authorship::on_finalize(current_depth); max_item_count = std::cmp::max(max_item_count, ::Uncles::get().len()); diff --git a/frame/babe/Cargo.toml b/frame/babe/Cargo.toml index dd76726df3017..9f79a404724e0 100644 --- a/frame/babe/Cargo.toml +++ b/frame/babe/Cargo.toml @@ -43,7 +43,7 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/babe/src/benchmarking.rs b/frame/babe/src/benchmarking.rs index 4f51acbbef4dd..3e2d91d5371fd 100644 --- a/frame/babe/src/benchmarking.rs +++ b/frame/babe/src/benchmarking.rs @@ -17,6 +17,8 @@ //! Benchmarks for the BABE Pallet. +#![cfg(feature = "runtime-benchmarks")] + use super::*; use frame_benchmarking::benchmarks; @@ -49,30 +51,3 @@ benchmarks! { crate::mock::Test, ) } - -#[cfg(test)] -mod tests { - use super::*; - use crate::mock::*; - - #[test] - fn test_generate_equivocation_report_blob() { - let (pairs, mut ext) = new_test_ext_with_pairs(3); - - let offending_authority_index = 0; - let offending_authority_pair = &pairs[0]; - - ext.execute_with(|| { - start_era(1); - - let equivocation_proof = generate_equivocation_proof( - offending_authority_index, - offending_authority_pair, - CurrentSlot::::get() + 1, - ); - - println!("equivocation_proof: {:?}", equivocation_proof); - println!("equivocation_proof.encode(): {:?}", equivocation_proof.encode()); - }); - } -} diff --git a/frame/babe/src/lib.rs b/frame/babe/src/lib.rs index 9a99d8ed995ab..eadaa036332fa 100644 --- a/frame/babe/src/lib.rs +++ b/frame/babe/src/lib.rs @@ -23,13 +23,13 @@ use codec::{Decode, Encode}; use frame_support::{ - dispatch::DispatchResultWithPostInfo, + dispatch::{DispatchResultWithPostInfo, Pays}, ensure, traits::{ ConstU32, DisabledValidators, FindAuthor, Get, KeyOwnerProofSystem, OnTimestampSet, OneSessionHandler, }, - weights::{Pays, Weight}, + weights::Weight, BoundedVec, WeakBoundedVec, }; use sp_application_crypto::ByteArray; diff --git a/frame/babe/src/mock.rs b/frame/babe/src/mock.rs index 3a6348404b9a7..46aeabe743fe2 100644 --- a/frame/babe/src/mock.rs +++ b/frame/babe/src/mock.rs @@ -74,17 +74,17 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Version = (); type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = DummyValidatorId; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -98,10 +98,10 @@ impl frame_system::Config for Test { impl frame_system::offchain::SendTransactionTypes for Test where - Call: From, + RuntimeCall: From, { - type OverarchingCall = Call; - type Extrinsic = TestXt; + type OverarchingCall = RuntimeCall; + type Extrinsic = TestXt; } impl_opaque_keys! { @@ -111,7 +111,7 @@ impl_opaque_keys! { } impl pallet_session::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = ::AccountId; type ValidatorIdOf = pallet_staking::StashOf; type ShouldEndSession = Babe; @@ -147,7 +147,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type Balance = u128; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU128<1>; type AccountStore = System; type WeightInfo = (); @@ -184,7 +184,7 @@ impl pallet_staking::Config for Test { type MaxNominations = ConstU32<16>; type RewardRemainder = (); type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type CurrencyBalance = ::Balance; type Slash = (); @@ -202,14 +202,16 @@ impl pallet_staking::Config for Test { type ElectionProvider = onchain::UnboundedExecution; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; + type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = ConstU32<84>; type OnStakerSlash = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); } impl pallet_offences::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type IdentificationTuple = pallet_session::historical::IdentificationTuple; type OnOffenceHandler = Staking; } diff --git a/frame/babe/src/tests.rs b/frame/babe/src/tests.rs index 2f967b658e396..d4132e6378540 100644 --- a/frame/babe/src/tests.rs +++ b/frame/babe/src/tests.rs @@ -20,8 +20,8 @@ use super::{Call, *}; use frame_support::{ assert_err, assert_noop, assert_ok, + dispatch::{GetDispatchInfo, Pays}, traits::{Currency, EstimateNextSessionRotation, OnFinalize}, - weights::{GetDispatchInfo, Pays}, }; use mock::*; use pallet_session::ShouldEndSession; @@ -289,7 +289,7 @@ fn can_enact_next_config() { assert_eq!(NextEpochConfig::::get(), Some(next_config.clone())); Babe::plan_config_change( - Origin::root(), + RuntimeOrigin::root(), NextConfigDescriptor::V1 { c: next_next_config.c, allowed_slots: next_next_config.allowed_slots, @@ -323,15 +323,15 @@ fn only_root_can_enact_config_change() { let next_config = NextConfigDescriptor::V1 { c: (1, 4), allowed_slots: AllowedSlots::PrimarySlots }; - let res = Babe::plan_config_change(Origin::none(), next_config.clone()); + let res = Babe::plan_config_change(RuntimeOrigin::none(), next_config.clone()); assert_noop!(res, DispatchError::BadOrigin); - let res = Babe::plan_config_change(Origin::signed(1), next_config.clone()); + let res = Babe::plan_config_change(RuntimeOrigin::signed(1), next_config.clone()); assert_noop!(res, DispatchError::BadOrigin); - let res = Babe::plan_config_change(Origin::root(), next_config); + let res = Babe::plan_config_change(RuntimeOrigin::root(), next_config); assert!(res.is_ok()); }); @@ -464,7 +464,7 @@ fn report_equivocation_current_session_works() { // report the equivocation Babe::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ) @@ -536,7 +536,7 @@ fn report_equivocation_old_session_works() { // report the equivocation Babe::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ) @@ -588,7 +588,7 @@ fn report_equivocation_invalid_key_owner_proof() { key_owner_proof.session = 0; assert_err!( Babe::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof.clone()), key_owner_proof ), @@ -608,7 +608,7 @@ fn report_equivocation_invalid_key_owner_proof() { assert_err!( Babe::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ), @@ -642,7 +642,7 @@ fn report_equivocation_invalid_equivocation_proof() { let assert_invalid_equivocation = |equivocation_proof| { assert_err!( Babe::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof.clone(), ), @@ -784,7 +784,7 @@ fn report_equivocation_validate_unsigned_prevents_duplicates() { // we submit the report Babe::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ) @@ -823,7 +823,7 @@ fn report_equivocation_has_valid_weight() { .map(::WeightInfo::report_equivocation) .collect::>() .windows(2) - .all(|w| w[0] < w[1])); + .all(|w| w[0].ref_time() < w[1].ref_time())); } #[test] @@ -852,12 +852,13 @@ fn valid_equivocation_reports_dont_pay_fees() { .get_dispatch_info(); // it should have non-zero weight and the fee has to be paid. - assert!(info.weight > Weight::zero()); + // TODO: account for proof size weight + assert!(info.weight.ref_time() > 0); assert_eq!(info.pays_fee, Pays::Yes); // report the equivocation. let post_info = Babe::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof.clone()), key_owner_proof.clone(), ) @@ -871,7 +872,7 @@ fn valid_equivocation_reports_dont_pay_fees() { // report the equivocation again which is invalid now since it is // duplicate. let post_info = Babe::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ) @@ -926,3 +927,24 @@ fn add_epoch_configurations_migration_works() { assert_eq!(PendingEpochConfigChange::::get(), Some(next_config_descriptor)); }); } + +#[test] +fn generate_equivocation_report_blob() { + let (pairs, mut ext) = new_test_ext_with_pairs(3); + + let offending_authority_index = 0; + let offending_authority_pair = &pairs[0]; + + ext.execute_with(|| { + start_era(1); + + let equivocation_proof = generate_equivocation_proof( + offending_authority_index, + offending_authority_pair, + CurrentSlot::::get() + 1, + ); + + println!("equivocation_proof: {:?}", equivocation_proof); + println!("equivocation_proof.encode(): {:?}", equivocation_proof.encode()); + }); +} diff --git a/frame/bags-list/Cargo.toml b/frame/bags-list/Cargo.toml index 9590d3d3ec4a4..19eb66ae624af 100644 --- a/frame/bags-list/Cargo.toml +++ b/frame/bags-list/Cargo.toml @@ -41,12 +41,18 @@ sp-core = { version = "6.0.0", path = "../../primitives/core"} sp-io = { version = "6.0.0", path = "../../primitives/io"} sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } -frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support", features = ["runtime-benchmarks"] } +frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } [features] default = ["std"] std = [ + "sp-tracing?/std", + "sp-io?/std", + "sp-core?/std", + "pallet-balances?/std", + "frame-benchmarking?/std", + "scale-info/std", "codec/std", "sp-runtime/std", "sp-std/std", @@ -59,7 +65,7 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "sp-core", "sp-io", - "pallet-balances", + "pallet-balances/runtime-benchmarks", "sp-tracing", "frame-election-provider-support/runtime-benchmarks", ] @@ -68,5 +74,6 @@ fuzz = [ "sp-io", "pallet-balances", "sp-tracing", + "frame-election-provider-support/fuzz", ] try-runtime = [ "frame-support/try-runtime" ] diff --git a/frame/bags-list/fuzzer/Cargo.toml b/frame/bags-list/fuzzer/Cargo.toml index ec7d98255b019..0f10077dcbce8 100644 --- a/frame/bags-list/fuzzer/Cargo.toml +++ b/frame/bags-list/fuzzer/Cargo.toml @@ -13,7 +13,7 @@ publish = false [dependencies] honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } -frame-election-provider-support = { version = "4.0.0-dev", features = ["runtime-benchmarks"], path = "../../election-provider-support" } +frame-election-provider-support = { version = "4.0.0-dev", features = ["fuzz"], path = "../../election-provider-support" } pallet-bags-list = { version = "4.0.0-dev", features = ["fuzz"], path = ".." } [[bin]] diff --git a/frame/bags-list/remote-tests/src/lib.rs b/frame/bags-list/remote-tests/src/lib.rs index 927c3dc91cb58..fc25e3b65ddb1 100644 --- a/frame/bags-list/remote-tests/src/lib.rs +++ b/frame/bags-list/remote-tests/src/lib.rs @@ -18,6 +18,7 @@ //! Utilities for remote-testing pallet-bags-list. use frame_election_provider_support::ScoreProvider; +use pallet_bags_list::Instance1; use sp_std::prelude::*; /// A common log target to use. @@ -30,18 +31,26 @@ pub mod try_state; /// A wrapper for a runtime that the functions of this crate expect. /// /// For example, this can be the `Runtime` type of the Polkadot runtime. -pub trait RuntimeT: - pallet_staking::Config + pallet_bags_list::Config + frame_system::Config +pub trait RuntimeT: + pallet_staking::Config + pallet_bags_list::Config + frame_system::Config +{ +} +impl< + I: 'static, + T: pallet_staking::Config + pallet_bags_list::Config + frame_system::Config, + > RuntimeT for T { } -impl RuntimeT for T {} fn percent(portion: u32, total: u32) -> f64 { (portion as f64 / total as f64) * 100f64 } /// Display the number of nodes in each bag, while identifying those that need a rebag. -pub fn display_and_check_bags(currency_unit: u64, currency_name: &'static str) { +pub fn display_and_check_bags>( + currency_unit: u64, + currency_name: &'static str, +) { use frame_election_provider_support::SortedListProvider; use frame_support::traits::Get; @@ -55,7 +64,8 @@ pub fn display_and_check_bags(currency_unit: u64, currency_na let mut seen_in_bags = 0; let mut rebaggable = 0; let mut active_bags = 0; - for vote_weight_thresh in ::BagThresholds::get() { + for vote_weight_thresh in >::BagThresholds::get() + { let vote_weight_thresh_u64: u64 = (*vote_weight_thresh) .try_into() .map_err(|_| "runtime must configure score to at most u64 to use this test") @@ -64,7 +74,9 @@ pub fn display_and_check_bags(currency_unit: u64, currency_na let vote_weight_thresh_as_unit = vote_weight_thresh_u64 as f64 / currency_unit as f64; let pretty_thresh = format!("Threshold: {}. {}", vote_weight_thresh_as_unit, currency_name); - let bag = match pallet_bags_list::Pallet::::list_bags_get(*vote_weight_thresh) { + let bag = match pallet_bags_list::Pallet::::list_bags_get( + *vote_weight_thresh, + ) { Some(bag) => bag, None => { log::info!(target: LOG_TARGET, "{} NO VOTERS.", pretty_thresh); @@ -75,7 +87,8 @@ pub fn display_and_check_bags(currency_unit: u64, currency_na active_bags += 1; for id in bag.std_iter().map(|node| node.std_id().clone()) { - let vote_weight = ::ScoreProvider::score(&id); + let vote_weight = + >::ScoreProvider::score(&id); let vote_weight_thresh_u64: u64 = (*vote_weight_thresh) .try_into() .map_err(|_| "runtime must configure score to at most u64 to use this test") @@ -92,8 +105,8 @@ pub fn display_and_check_bags(currency_unit: u64, currency_na ); } - let node = - pallet_bags_list::Node::::get(&id).expect("node in bag must exist."); + let node = pallet_bags_list::Node::::get(&id) + .expect("node in bag must exist."); if node.is_misplaced(vote_weight) { rebaggable += 1; let notional_bag = pallet_bags_list::notional_bag_for::(vote_weight); @@ -141,7 +154,7 @@ pub fn display_and_check_bags(currency_unit: u64, currency_na "a total of {} nodes are in {} active bags [{} total bags], {} of which can be rebagged.", voter_list_count, active_bags, - ::BagThresholds::get().len(), + >::BagThresholds::get().len(), rebaggable, ); } diff --git a/frame/bags-list/remote-tests/src/migration.rs b/frame/bags-list/remote-tests/src/migration.rs index c4cd73c45d377..b013472b4c90e 100644 --- a/frame/bags-list/remote-tests/src/migration.rs +++ b/frame/bags-list/remote-tests/src/migration.rs @@ -24,11 +24,15 @@ use sp_runtime::{traits::Block as BlockT, DeserializeOwned}; /// Test voter bags migration. `currency_unit` is the number of planks per the the runtimes `UNITS` /// (i.e. number of decimal places per DOT, KSM etc) -pub async fn execute( +pub async fn execute( currency_unit: u64, currency_name: &'static str, ws_url: String, -) { +) where + Runtime: RuntimeT, + Block: BlockT, + Block::Header: DeserializeOwned, +{ let mut ext = Builder::::new() .mode(Mode::Online(OnlineConfig { transport: ws_url.to_string().into(), diff --git a/frame/bags-list/remote-tests/src/snapshot.rs b/frame/bags-list/remote-tests/src/snapshot.rs index 408f5f2bd8aa2..cfe065924bd92 100644 --- a/frame/bags-list/remote-tests/src/snapshot.rs +++ b/frame/bags-list/remote-tests/src/snapshot.rs @@ -22,11 +22,12 @@ use remote_externalities::{Builder, Mode, OnlineConfig}; use sp_runtime::{traits::Block as BlockT, DeserializeOwned}; /// Execute create a snapshot from pallet-staking. -pub async fn execute( - voter_limit: Option, - currency_unit: u64, - ws_url: String, -) { +pub async fn execute(voter_limit: Option, currency_unit: u64, ws_url: String) +where + Runtime: crate::RuntimeT, + Block: BlockT, + Block::Header: DeserializeOwned, +{ use frame_support::storage::generator::StorageMap; let mut ext = Builder::::new() @@ -34,7 +35,8 @@ pub async fn execute transport: ws_url.to_string().into(), // NOTE: we don't scrape pallet-staking, this kinda ensures that the source of the data // is bags-list. - pallets: vec![pallet_bags_list::Pallet::::name().to_string()], + pallets: vec![pallet_bags_list::Pallet::::name() + .to_string()], at: None, ..Default::default() })) diff --git a/frame/bags-list/remote-tests/src/try_state.rs b/frame/bags-list/remote-tests/src/try_state.rs index 11278c20eb8ed..d3fb63f045a64 100644 --- a/frame/bags-list/remote-tests/src/try_state.rs +++ b/frame/bags-list/remote-tests/src/try_state.rs @@ -25,15 +25,20 @@ use remote_externalities::{Builder, Mode, OnlineConfig}; use sp_runtime::{traits::Block as BlockT, DeserializeOwned}; /// Execute the sanity check of the bags-list. -pub async fn execute( +pub async fn execute( currency_unit: u64, currency_name: &'static str, ws_url: String, -) { +) where + Runtime: crate::RuntimeT, + Block: BlockT, + Block::Header: DeserializeOwned, +{ let mut ext = Builder::::new() .mode(Mode::Online(OnlineConfig { transport: ws_url.to_string().into(), - pallets: vec![pallet_bags_list::Pallet::::name().to_string()], + pallets: vec![pallet_bags_list::Pallet::::name() + .to_string()], ..Default::default() })) .inject_hashed_prefix(&>::prefix_hash()) @@ -44,7 +49,7 @@ pub async fn execute ext.execute_with(|| { sp_core::crypto::set_default_ss58_version(Runtime::SS58Prefix::get().try_into().unwrap()); - pallet_bags_list::Pallet::::try_state().unwrap(); + pallet_bags_list::Pallet::::try_state().unwrap(); log::info!(target: crate::LOG_TARGET, "executed bags-list sanity check with no errors."); crate::display_and_check_bags::(currency_unit, currency_name); diff --git a/frame/bags-list/src/lib.rs b/frame/bags-list/src/lib.rs index 70f8b2a32f817..2b48fbf0ca630 100644 --- a/frame/bags-list/src/lib.rs +++ b/frame/bags-list/src/lib.rs @@ -105,7 +105,8 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. type WeightInfo: weights::WeightInfo; @@ -386,7 +387,7 @@ impl, I: 'static> ScoreProvider for Pallet { Node::::get(id).map(|node| node.score()).unwrap_or_default() } - #[cfg(any(feature = "runtime-benchmarks", test))] + #[cfg(any(feature = "runtime-benchmarks", feature = "fuzz", test))] fn set_score_of(id: &T::AccountId, new_score: T::Score) { ListNodes::::mutate(id, |maybe_node| { if let Some(node) = maybe_node.as_mut() { diff --git a/frame/bags-list/src/list/mod.rs b/frame/bags-list/src/list/mod.rs index cfa7daf198937..272526ad1a636 100644 --- a/frame/bags-list/src/list/mod.rs +++ b/frame/bags-list/src/list/mod.rs @@ -882,7 +882,7 @@ impl, I: 'static> Node { &self.id } - #[cfg(any(feature = "runtime-benchmarks", test))] + #[cfg(any(feature = "runtime-benchmarks", feature = "fuzz", test))] pub fn set_score(&mut self, s: T::Score) { self.score = s } diff --git a/frame/bags-list/src/migrations.rs b/frame/bags-list/src/migrations.rs index 49b7d136125e2..e1dc9f777e537 100644 --- a/frame/bags-list/src/migrations.rs +++ b/frame/bags-list/src/migrations.rs @@ -24,6 +24,8 @@ use frame_support::traits::OnRuntimeUpgrade; #[cfg(feature = "try-runtime")] use frame_support::ensure; +#[cfg(feature = "try-runtime")] +use sp_std::vec::Vec; /// A struct that does not migration, but only checks that the counter prefix exists and is correct. pub struct CheckCounterPrefix, I: 'static>(sp_std::marker::PhantomData<(T, I)>); @@ -33,7 +35,7 @@ impl, I: 'static> OnRuntimeUpgrade for CheckCounterPrefix Result<(), &'static str> { + fn pre_upgrade() -> Result, &'static str> { // The old explicit storage item. #[frame_support::storage_alias] type CounterForListNodes, I: 'static> = @@ -51,7 +53,7 @@ impl, I: 'static> OnRuntimeUpgrade for CheckCounterPrefix::count() ); - Ok(()) + Ok(Vec::new()) } } @@ -80,17 +82,13 @@ mod old { #[frame_support::storage_alias] pub type CounterForListNodes, I: 'static> = StorageValue, u32, ValueQuery>; - - #[frame_support::storage_alias] - pub type TempStorage, I: 'static> = - StorageValue, u32, ValueQuery>; } /// A struct that migrates all bags lists to contain a score value. pub struct AddScore, I: 'static = ()>(sp_std::marker::PhantomData<(T, I)>); impl, I: 'static> OnRuntimeUpgrade for AddScore { #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { + fn pre_upgrade() -> Result, &'static str> { // The list node data should be corrupt at this point, so this is zero. ensure!(crate::ListNodes::::iter().count() == 0, "list node data is not corrupt"); // We can use the helper `old::ListNode` to get the existing data. @@ -98,8 +96,7 @@ impl, I: 'static> OnRuntimeUpgrade for AddScore { let tracked_node_count: u32 = old::CounterForListNodes::::get(); crate::log!(info, "number of nodes before: {:?} {:?}", iter_node_count, tracked_node_count); ensure!(iter_node_count == tracked_node_count, "Node count is wrong."); - old::TempStorage::::put(iter_node_count); - Ok(()) + Ok(iter_node_count.encode()) } fn on_runtime_upgrade() -> frame_support::weights::Weight { @@ -122,9 +119,10 @@ impl, I: 'static> OnRuntimeUpgrade for AddScore { } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { - let node_count_before = old::TempStorage::::take(); - // Now, the list node data is not corrupt anymore. + fn post_upgrade(node_count_before: Vec) -> Result<(), &'static str> { + let node_count_before: u32 = Decode::decode(&mut node_count_before.as_slice()) + .expect("the state parameter should be something that was generated by pre_upgrade"); + // Now the list node data is not corrupt anymore. let iter_node_count_after: u32 = crate::ListNodes::::iter().count() as u32; let tracked_node_count_after: u32 = crate::ListNodes::::count(); crate::log!( diff --git a/frame/bags-list/src/mock.rs b/frame/bags-list/src/mock.rs index 3bc1b34657262..8cc96a988e72a 100644 --- a/frame/bags-list/src/mock.rs +++ b/frame/bags-list/src/mock.rs @@ -40,7 +40,7 @@ impl frame_election_provider_support::ScoreProvider for StakingMock { *NextVoteWeightMap::get().get(id).unwrap_or(&NextVoteWeight::get()) } - #[cfg(any(feature = "runtime-benchmarks", test))] + #[cfg(any(feature = "runtime-benchmarks", feature = "fuzz", test))] fn set_score_of(id: &AccountId, weight: Self::Score) { NEXT_VOTE_WEIGHT_MAP.with(|m| m.borrow_mut().insert(*id, weight)); } @@ -49,16 +49,16 @@ impl frame_election_provider_support::ScoreProvider for StakingMock { impl frame_system::Config for Runtime { type SS58Prefix = (); type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_core::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = sp_runtime::traits::IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type DbWeight = (); type BlockLength = (); @@ -78,7 +78,7 @@ parameter_types! { } impl bags_list::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type BagThresholds = BagThresholds; type ScoreProvider = StakingMock; @@ -108,6 +108,7 @@ pub struct ExtBuilder { skip_genesis_ids: bool, } +#[cfg(any(feature = "runtime-benchmarks", feature = "fuzz", test))] impl ExtBuilder { /// Skip adding the default genesis ids to the list. #[cfg(test)] diff --git a/frame/bags-list/src/tests.rs b/frame/bags-list/src/tests.rs index 01c1642f882c1..63a395ed0d65a 100644 --- a/frame/bags-list/src/tests.rs +++ b/frame/bags-list/src/tests.rs @@ -37,7 +37,7 @@ mod pallet { // when increasing score to the level of non-existent bag assert_eq!(List::::get_score(&42).unwrap(), 20); StakingMock::set_score_of(&42, 2_000); - assert_ok!(BagsList::rebag(Origin::signed(0), 42)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 42)); assert_eq!(List::::get_score(&42).unwrap(), 2_000); // then a new bag is created and the id moves into it @@ -48,7 +48,7 @@ mod pallet { // when decreasing score within the range of the current bag StakingMock::set_score_of(&42, 1_001); - assert_ok!(BagsList::rebag(Origin::signed(0), 42)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 42)); // then the id does not move assert_eq!( @@ -60,7 +60,7 @@ mod pallet { // when reducing score to the level of a non-existent bag StakingMock::set_score_of(&42, 30); - assert_ok!(BagsList::rebag(Origin::signed(0), 42)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 42)); // then a new bag is created and the id moves into it assert_eq!( @@ -71,7 +71,7 @@ mod pallet { // when increasing score to the level of a pre-existing bag StakingMock::set_score_of(&42, 500); - assert_ok!(BagsList::rebag(Origin::signed(0), 42)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 42)); // then the id moves into that bag assert_eq!( @@ -92,7 +92,7 @@ mod pallet { // when StakingMock::set_score_of(&4, 10); - assert_ok!(BagsList::rebag(Origin::signed(0), 4)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 4)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1, 4]), (1_000, vec![2, 3])]); @@ -100,7 +100,7 @@ mod pallet { // when StakingMock::set_score_of(&3, 10); - assert_ok!(BagsList::rebag(Origin::signed(0), 3)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 3)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1, 4, 3]), (1_000, vec![2])]); @@ -111,7 +111,7 @@ mod pallet { // when StakingMock::set_score_of(&2, 10); - assert_ok!(BagsList::rebag(Origin::signed(0), 2)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 2)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1, 4, 3, 2])]); @@ -126,7 +126,7 @@ mod pallet { ExtBuilder::default().build_and_execute(|| { // when StakingMock::set_score_of(&2, 10); - assert_ok!(BagsList::rebag(Origin::signed(0), 2)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 2)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1, 2]), (1_000, vec![3, 4])]); @@ -134,7 +134,7 @@ mod pallet { // when StakingMock::set_score_of(&3, 10); - assert_ok!(BagsList::rebag(Origin::signed(0), 3)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 3)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1, 2, 3]), (1_000, vec![4])]); @@ -142,7 +142,7 @@ mod pallet { // when StakingMock::set_score_of(&4, 10); - assert_ok!(BagsList::rebag(Origin::signed(0), 4)); + assert_ok!(BagsList::rebag(RuntimeOrigin::signed(0), 4)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1, 2, 3, 4])]); @@ -159,12 +159,15 @@ mod pallet { assert!(!node_3.is_misplaced(500)); // then calling rebag on account 3 with score 500 is a noop - assert_storage_noop!(assert_eq!(BagsList::rebag(Origin::signed(0), 3), Ok(()))); + assert_storage_noop!(assert_eq!(BagsList::rebag(RuntimeOrigin::signed(0), 3), Ok(()))); // when account 42 is not in the list assert!(!BagsList::contains(&42)); // then rebag-ing account 42 is an error - assert_storage_noop!(assert!(matches!(BagsList::rebag(Origin::signed(0), 42), Err(_)))); + assert_storage_noop!(assert!(matches!( + BagsList::rebag(RuntimeOrigin::signed(0), 42), + Err(_) + ))); }); } @@ -200,7 +203,7 @@ mod pallet { ); // any rebag is noop. - assert_storage_noop!(assert_eq!(BagsList::rebag(Origin::signed(0), 1), Ok(()))); + assert_storage_noop!(assert_eq!(BagsList::rebag(RuntimeOrigin::signed(0), 1), Ok(()))); }) } @@ -214,7 +217,7 @@ mod pallet { assert_eq!(List::::get_bags(), vec![(20, vec![10, 11])]); // when - assert_ok!(BagsList::put_in_front_of(Origin::signed(11), 10)); + assert_ok!(BagsList::put_in_front_of(RuntimeOrigin::signed(11), 10)); // then assert_eq!(List::::get_bags(), vec![(20, vec![11, 10])]); @@ -231,7 +234,7 @@ mod pallet { assert_eq!(List::::get_bags(), vec![(20, vec![11, 10])]); // when - assert_ok!(BagsList::put_in_front_of(Origin::signed(11), 10)); + assert_ok!(BagsList::put_in_front_of(RuntimeOrigin::signed(11), 10)); // then assert_eq!(List::::get_bags(), vec![(20, vec![11, 10])]); @@ -247,7 +250,7 @@ mod pallet { StakingMock::set_score_of(&3, 999); // when - assert_ok!(BagsList::put_in_front_of(Origin::signed(4), 3)); + assert_ok!(BagsList::put_in_front_of(RuntimeOrigin::signed(4), 3)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 4, 3, 5])]); @@ -268,7 +271,7 @@ mod pallet { StakingMock::set_score_of(&5, 999); // when - assert_ok!(BagsList::put_in_front_of(Origin::signed(3), 5)); + assert_ok!(BagsList::put_in_front_of(RuntimeOrigin::signed(3), 5)); // then assert_eq!( @@ -287,7 +290,7 @@ mod pallet { StakingMock::set_score_of(&2, 999); // when - assert_ok!(BagsList::put_in_front_of(Origin::signed(3), 2)); + assert_ok!(BagsList::put_in_front_of(RuntimeOrigin::signed(3), 2)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![3, 2, 4])]); @@ -303,7 +306,7 @@ mod pallet { StakingMock::set_score_of(&3, 999); // when - assert_ok!(BagsList::put_in_front_of(Origin::signed(4), 3)); + assert_ok!(BagsList::put_in_front_of(RuntimeOrigin::signed(4), 3)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 4, 3])]); @@ -319,7 +322,7 @@ mod pallet { StakingMock::set_score_of(&2, 999); // when - assert_ok!(BagsList::put_in_front_of(Origin::signed(5), 2)); + assert_ok!(BagsList::put_in_front_of(RuntimeOrigin::signed(5), 2)); // then assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![5, 2, 3, 4])]); @@ -335,7 +338,7 @@ mod pallet { StakingMock::set_score_of(&4, 999); // when - BagsList::put_in_front_of(Origin::signed(2), 4).unwrap(); + BagsList::put_in_front_of(RuntimeOrigin::signed(2), 4).unwrap(); // then assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![3, 2, 4, 5])]); @@ -349,7 +352,7 @@ mod pallet { assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 3, 4, 5])]); // when - BagsList::put_in_front_of(Origin::signed(3), 5).unwrap(); + BagsList::put_in_front_of(RuntimeOrigin::signed(3), 5).unwrap(); // then assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![2, 4, 3, 5])]); @@ -365,7 +368,7 @@ mod pallet { StakingMock::set_score_of(&4, 999); // when - BagsList::put_in_front_of(Origin::signed(2), 4).unwrap(); + BagsList::put_in_front_of(RuntimeOrigin::signed(2), 4).unwrap(); // then assert_eq!(List::::get_bags(), vec![(10, vec![1]), (1_000, vec![3, 2, 4])]); @@ -382,7 +385,7 @@ mod pallet { // then assert_noop!( - BagsList::put_in_front_of(Origin::signed(3), 2), + BagsList::put_in_front_of(RuntimeOrigin::signed(3), 2), crate::pallet::Error::::List(ListError::NotHeavier) ); }); @@ -396,7 +399,7 @@ mod pallet { // then assert_noop!( - BagsList::put_in_front_of(Origin::signed(3), 4), + BagsList::put_in_front_of(RuntimeOrigin::signed(3), 4), crate::pallet::Error::::List(ListError::NotHeavier) ); }); @@ -413,7 +416,7 @@ mod pallet { // then assert_noop!( - BagsList::put_in_front_of(Origin::signed(5), 4), + BagsList::put_in_front_of(RuntimeOrigin::signed(5), 4), crate::pallet::Error::::List(ListError::NodeNotFound) ); }); @@ -427,7 +430,7 @@ mod pallet { // then assert_noop!( - BagsList::put_in_front_of(Origin::signed(4), 5), + BagsList::put_in_front_of(RuntimeOrigin::signed(4), 5), crate::pallet::Error::::List(ListError::NodeNotFound) ); }); @@ -441,7 +444,7 @@ mod pallet { // then assert_noop!( - BagsList::put_in_front_of(Origin::signed(4), 1), + BagsList::put_in_front_of(RuntimeOrigin::signed(4), 1), crate::pallet::Error::::List(ListError::NotInSameBag) ); }); diff --git a/frame/balances/Cargo.toml b/frame/balances/Cargo.toml index 10150f0895906..fd2312993b7e7 100644 --- a/frame/balances/Cargo.toml +++ b/frame/balances/Cargo.toml @@ -31,7 +31,7 @@ sp-io = { version = "6.0.0", path = "../../primitives/io" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/balances/src/lib.rs b/frame/balances/src/lib.rs index 0a45350366449..4014efdd26e4e 100644 --- a/frame/balances/src/lib.rs +++ b/frame/balances/src/lib.rs @@ -185,7 +185,7 @@ use sp_runtime::{ AtLeast32BitUnsigned, Bounded, CheckedAdd, CheckedSub, MaybeSerializeDeserialize, Saturating, StaticLookup, Zero, }, - ArithmeticError, DispatchError, RuntimeDebug, + ArithmeticError, DispatchError, FixedPointOperand, RuntimeDebug, }; use sp_std::{cmp, fmt::Debug, mem, ops::BitOr, prelude::*, result}; pub use weights::WeightInfo; @@ -212,13 +212,15 @@ pub mod pallet { + MaybeSerializeDeserialize + Debug + MaxEncodedLen - + TypeInfo; + + TypeInfo + + FixedPointOperand; /// Handler for the unbalanced reduction when removing a dust account. type DustRemoval: OnUnbalanced>; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// The minimum amount required to keep an account open. #[pallet::constant] @@ -492,6 +494,7 @@ pub mod pallet { /// The total units issued in the system. #[pallet::storage] #[pallet::getter(fn total_issuance)] + #[pallet::whitelist_storage] pub type TotalIssuance, I: 'static = ()> = StorageValue<_, T::Balance, ValueQuery>; /// The Balances pallet example of storing the balance of an account. diff --git a/frame/balances/src/tests.rs b/frame/balances/src/tests.rs index 96bee9be1991c..faf53e16cb028 100644 --- a/frame/balances/src/tests.rs +++ b/frame/balances/src/tests.rs @@ -38,15 +38,15 @@ macro_rules! decl_tests { const ID_1: LockIdentifier = *b"1 "; const ID_2: LockIdentifier = *b"2 "; - pub const CALL: &<$test as frame_system::Config>::Call = - &Call::Balances(pallet_balances::Call::transfer { dest: 0, value: 0 }); + pub const CALL: &<$test as frame_system::Config>::RuntimeCall = + &RuntimeCall::Balances(pallet_balances::Call::transfer { dest: 0, value: 0 }); /// create a transaction info struct from weight. Handy to avoid building the whole struct. pub fn info_from_weight(w: Weight) -> DispatchInfo { DispatchInfo { weight: w, ..Default::default() } } - fn events() -> Vec { + fn events() -> Vec { let evt = System::events().into_iter().map(|evt| evt.event).collect::>(); System::reset_events(); @@ -314,7 +314,7 @@ macro_rules! decl_tests { <$ext_builder>::default().monied(true).build().execute_with(|| { assert_eq!(Balances::total_balance(&1), 10); assert_ok!(Balances::deposit_into_existing(&1, 10).map(drop)); - System::assert_last_event(Event::Balances(crate::Event::Deposit { who: 1, amount: 10 })); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Deposit { who: 1, amount: 10 })); assert_eq!(Balances::total_balance(&1), 20); assert_eq!(>::get(), 120); }); @@ -342,7 +342,7 @@ macro_rules! decl_tests { fn balance_works() { <$ext_builder>::default().build().execute_with(|| { let _ = Balances::deposit_creating(&1, 42); - System::assert_has_event(Event::Balances(crate::Event::Deposit { who: 1, amount: 42 })); + System::assert_has_event(RuntimeEvent::Balances(crate::Event::Deposit { who: 1, amount: 42 })); assert_eq!(Balances::free_balance(1), 42); assert_eq!(Balances::reserved_balance(1), 0); assert_eq!(Balances::total_balance(&1), 42); @@ -444,7 +444,7 @@ macro_rules! decl_tests { let _ = Balances::withdraw( &2, 11, WithdrawReasons::TRANSFER, ExistenceRequirement::KeepAlive ); - System::assert_last_event(Event::Balances(crate::Event::Withdraw { who: 2, amount: 11 })); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Withdraw { who: 2, amount: 11 })); assert_eq!(Balances::free_balance(2), 100); assert_eq!(>::get(), 100); }); @@ -505,7 +505,7 @@ macro_rules! decl_tests { assert_ok!(Balances::reserve(&1, 110)); assert_ok!(Balances::repatriate_reserved(&1, &2, 41, Status::Free), 0); System::assert_last_event( - Event::Balances(crate::Event::ReserveRepatriated { from: 1, to: 2, amount: 41, destination_status: Status::Free }) + RuntimeEvent::Balances(crate::Event::ReserveRepatriated { from: 1, to: 2, amount: 41, destination_status: Status::Free }) ); assert_eq!(Balances::reserved_balance(1), 69); assert_eq!(Balances::free_balance(1), 0); @@ -740,18 +740,18 @@ macro_rules! decl_tests { System::set_block_number(2); assert_ok!(Balances::reserve(&1, 10)); - System::assert_last_event(Event::Balances(crate::Event::Reserved { who: 1, amount: 10 })); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Reserved { who: 1, amount: 10 })); System::set_block_number(3); assert!(Balances::unreserve(&1, 5).is_zero()); - System::assert_last_event(Event::Balances(crate::Event::Unreserved { who: 1, amount: 5 })); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Unreserved { who: 1, amount: 5 })); System::set_block_number(4); assert_eq!(Balances::unreserve(&1, 6), 1); // should only unreserve 5 - System::assert_last_event(Event::Balances(crate::Event::Unreserved { who: 1, amount: 5 })); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Unreserved { who: 1, amount: 5 })); }); } @@ -766,9 +766,9 @@ macro_rules! decl_tests { assert_eq!( events(), [ - Event::System(system::Event::NewAccount { account: 1 }), - Event::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), - Event::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), + RuntimeEvent::System(system::Event::NewAccount { account: 1 }), + RuntimeEvent::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), + RuntimeEvent::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), ] ); @@ -778,9 +778,9 @@ macro_rules! decl_tests { assert_eq!( events(), [ - Event::System(system::Event::KilledAccount { account: 1 }), - Event::Balances(crate::Event::DustLost { account: 1, amount: 99 }), - Event::Balances(crate::Event::Slashed { who: 1, amount: 1 }), + RuntimeEvent::System(system::Event::KilledAccount { account: 1 }), + RuntimeEvent::Balances(crate::Event::DustLost { account: 1, amount: 99 }), + RuntimeEvent::Balances(crate::Event::Slashed { who: 1, amount: 1 }), ] ); }); @@ -797,9 +797,9 @@ macro_rules! decl_tests { assert_eq!( events(), [ - Event::System(system::Event::NewAccount { account: 1 }), - Event::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), - Event::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), + RuntimeEvent::System(system::Event::NewAccount { account: 1 }), + RuntimeEvent::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), + RuntimeEvent::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), ] ); @@ -809,8 +809,8 @@ macro_rules! decl_tests { assert_eq!( events(), [ - Event::System(system::Event::KilledAccount { account: 1 }), - Event::Balances(crate::Event::Slashed { who: 1, amount: 100 }), + RuntimeEvent::System(system::Event::KilledAccount { account: 1 }), + RuntimeEvent::Balances(crate::Event::Slashed { who: 1, amount: 100 }), ] ); }); @@ -825,43 +825,43 @@ macro_rules! decl_tests { /* User has no reference counter, so they can die in these scenarios */ // SCENARIO: Slash would not kill account. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 0)); // Slashed completed in full assert_eq!(Balances::slash(&1, 900), (NegativeImbalance::new(900), 0)); // Account is still alive assert!(System::account_exists(&1)); - System::assert_last_event(Event::Balances(crate::Event::Slashed { who: 1, amount: 900 })); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Slashed { who: 1, amount: 900 })); // SCENARIO: Slash will kill account because not enough balance left. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 0)); // Slashed completed in full assert_eq!(Balances::slash(&1, 950), (NegativeImbalance::new(950), 0)); // Account is killed assert!(!System::account_exists(&1)); // SCENARIO: Over-slash will kill account, and report missing slash amount. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 0)); // Slashed full free_balance, and reports 300 not slashed assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1000), 300)); // Account is dead assert!(!System::account_exists(&1)); // SCENARIO: Over-slash can take from reserved, but keep alive. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 400)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 400)); // Slashed full free_balance and 300 of reserved balance assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1300), 0)); // Account is still alive assert!(System::account_exists(&1)); // SCENARIO: Over-slash can take from reserved, and kill. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 350)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 350)); // Slashed full free_balance and 300 of reserved balance assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1300), 0)); // Account is dead because 50 reserved balance is not enough to keep alive assert!(!System::account_exists(&1)); // SCENARIO: Over-slash can take as much as possible from reserved, kill, and report missing amount. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 250)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 250)); // Slashed full free_balance and 300 of reserved balance assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1250), 50)); // Account is super dead @@ -870,7 +870,7 @@ macro_rules! decl_tests { /* User will now have a reference counter on them, keeping them alive in these scenarios */ // SCENARIO: Slash would not kill account. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 0)); assert_ok!(System::inc_consumers(&1)); // <-- Reference counter added here is enough for all tests // Slashed completed in full assert_eq!(Balances::slash(&1, 900), (NegativeImbalance::new(900), 0)); @@ -878,35 +878,35 @@ macro_rules! decl_tests { assert!(System::account_exists(&1)); // SCENARIO: Slash will take as much as possible without killing account. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 0)); // Slashed completed in full assert_eq!(Balances::slash(&1, 950), (NegativeImbalance::new(900), 50)); // Account is still alive assert!(System::account_exists(&1)); // SCENARIO: Over-slash will not kill account, and report missing slash amount. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 0)); // Slashed full free_balance minus ED, and reports 400 not slashed assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(900), 400)); // Account is still alive assert!(System::account_exists(&1)); // SCENARIO: Over-slash can take from reserved, but keep alive. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 400)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 400)); // Slashed full free_balance and 300 of reserved balance assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1300), 0)); // Account is still alive assert!(System::account_exists(&1)); // SCENARIO: Over-slash can take from reserved, but keep alive. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 350)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 350)); // Slashed full free_balance and 250 of reserved balance to leave ED assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1250), 50)); // Account is still alive assert!(System::account_exists(&1)); // SCENARIO: Over-slash can take as much as possible from reserved and report missing amount. - assert_ok!(Balances::set_balance(Origin::root(), 1, 1_000, 250)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 1_000, 250)); // Slashed full free_balance and 300 of reserved balance assert_eq!(Balances::slash(&1, 1_300), (NegativeImbalance::new(1150), 150)); // Account is still alive @@ -926,28 +926,28 @@ macro_rules! decl_tests { /* User has no reference counter, so they can die in these scenarios */ // SCENARIO: Slash would not kill account. - assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 50, 1_000)); // Slashed completed in full assert_eq!(Balances::slash_reserved(&1, 900), (NegativeImbalance::new(900), 0)); // Account is still alive assert!(System::account_exists(&1)); // SCENARIO: Slash would kill account. - assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 50, 1_000)); // Slashed completed in full assert_eq!(Balances::slash_reserved(&1, 1_000), (NegativeImbalance::new(1_000), 0)); // Account is dead assert!(!System::account_exists(&1)); // SCENARIO: Over-slash would kill account, and reports left over slash. - assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 50, 1_000)); // Slashed completed in full assert_eq!(Balances::slash_reserved(&1, 1_300), (NegativeImbalance::new(1_000), 300)); // Account is dead assert!(!System::account_exists(&1)); // SCENARIO: Over-slash does not take from free balance. - assert_ok!(Balances::set_balance(Origin::root(), 1, 300, 1_000)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 300, 1_000)); // Slashed completed in full assert_eq!(Balances::slash_reserved(&1, 1_300), (NegativeImbalance::new(1_000), 300)); // Account is alive because of free balance @@ -956,7 +956,7 @@ macro_rules! decl_tests { /* User has a reference counter, so they cannot die */ // SCENARIO: Slash would not kill account. - assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 50, 1_000)); assert_ok!(System::inc_consumers(&1)); // <-- Reference counter added here is enough for all tests // Slashed completed in full assert_eq!(Balances::slash_reserved(&1, 900), (NegativeImbalance::new(900), 0)); @@ -964,21 +964,21 @@ macro_rules! decl_tests { assert!(System::account_exists(&1)); // SCENARIO: Slash as much as possible without killing. - assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 50, 1_000)); // Slashed as much as possible assert_eq!(Balances::slash_reserved(&1, 1_000), (NegativeImbalance::new(950), 50)); // Account is still alive assert!(System::account_exists(&1)); // SCENARIO: Over-slash reports correctly, where reserved is needed to keep alive. - assert_ok!(Balances::set_balance(Origin::root(), 1, 50, 1_000)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 50, 1_000)); // Slashed as much as possible assert_eq!(Balances::slash_reserved(&1, 1_300), (NegativeImbalance::new(950), 350)); // Account is still alive assert!(System::account_exists(&1)); // SCENARIO: Over-slash reports correctly, where full reserved is removed. - assert_ok!(Balances::set_balance(Origin::root(), 1, 200, 1_000)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 200, 1_000)); // Slashed as much as possible assert_eq!(Balances::slash_reserved(&1, 1_300), (NegativeImbalance::new(1_000), 300)); // Account is still alive @@ -1018,7 +1018,7 @@ macro_rules! decl_tests { .existential_deposit(100) .build() .execute_with(|| { - assert_ok!(Balances::set_balance(Origin::root(), 1, 100, 100)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 100, 100)); assert_ok!(Balances::transfer_keep_alive(Some(1).into(), 2, 100)); assert_eq!(Balances::total_balance(&1), 100); assert_eq!(Balances::total_balance(&2), 100); @@ -1032,32 +1032,32 @@ macro_rules! decl_tests { .build() .execute_with(|| { // setup - assert_ok!(Balances::set_balance(Origin::root(), 1, 200, 0)); - assert_ok!(Balances::set_balance(Origin::root(), 2, 0, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 200, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 2, 0, 0)); // transfer all and allow death assert_ok!(Balances::transfer_all(Some(1).into(), 2, false)); assert_eq!(Balances::total_balance(&1), 0); assert_eq!(Balances::total_balance(&2), 200); // setup - assert_ok!(Balances::set_balance(Origin::root(), 1, 200, 0)); - assert_ok!(Balances::set_balance(Origin::root(), 2, 0, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 200, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 2, 0, 0)); // transfer all and keep alive assert_ok!(Balances::transfer_all(Some(1).into(), 2, true)); assert_eq!(Balances::total_balance(&1), 100); assert_eq!(Balances::total_balance(&2), 100); // setup - assert_ok!(Balances::set_balance(Origin::root(), 1, 200, 10)); - assert_ok!(Balances::set_balance(Origin::root(), 2, 0, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 200, 10)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 2, 0, 0)); // transfer all and allow death w/ reserved assert_ok!(Balances::transfer_all(Some(1).into(), 2, false)); assert_eq!(Balances::total_balance(&1), 0); assert_eq!(Balances::total_balance(&2), 200); // setup - assert_ok!(Balances::set_balance(Origin::root(), 1, 200, 10)); - assert_ok!(Balances::set_balance(Origin::root(), 2, 0, 0)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1, 200, 10)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 2, 0, 0)); // transfer all and keep alive w/ reserved assert_ok!(Balances::transfer_all(Some(1).into(), 2, true)); assert_eq!(Balances::total_balance(&1), 100); @@ -1281,7 +1281,7 @@ macro_rules! decl_tests { let _ = Balances::deposit_creating(&1, 111); assert_ok!(frame_system::Pallet::::inc_consumers(&1)); assert_noop!( - Balances::set_balance(Origin::root(), 1, 0, 0), + Balances::set_balance(RuntimeOrigin::root(), 1, 0, 0), DispatchError::ConsumerRemaining, ); }); @@ -1291,7 +1291,7 @@ macro_rules! decl_tests { fn set_balance_handles_total_issuance() { <$ext_builder>::default().build().execute_with(|| { let old_total_issuance = Balances::total_issuance(); - assert_ok!(Balances::set_balance(Origin::root(), 1337, 69, 42)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 1337, 69, 42)); assert_eq!(Balances::total_issuance(), old_total_issuance + 69 + 42); assert_eq!(Balances::total_balance(&1337), 69 + 42); assert_eq!(Balances::free_balance(&1337), 69); diff --git a/frame/balances/src/tests_composite.rs b/frame/balances/src/tests_composite.rs index 266c37063d2f8..f8a8fdd1851d4 100644 --- a/frame/balances/src/tests_composite.rs +++ b/frame/balances/src/tests_composite.rs @@ -21,9 +21,10 @@ use crate::{self as pallet_balances, decl_tests, Config, Pallet}; use frame_support::{ + dispatch::DispatchInfo, parameter_types, traits::{ConstU32, ConstU64, ConstU8}, - weights::{DispatchInfo, IdentityFee, Weight}, + weights::{IdentityFee, Weight}, }; use pallet_transaction_payment::CurrencyAdapter; use sp_core::H256; @@ -46,7 +47,9 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); + frame_system::limits::BlockWeights::simple_max( + frame_support::weights::Weight::from_ref_time(1024).set_proof_size(u64::MAX), + ); pub static ExistentialDeposit: u64 = 0; } impl frame_system::Config for Test { @@ -54,16 +57,16 @@ impl frame_system::Config for Test { type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -77,7 +80,7 @@ impl frame_system::Config for Test { } impl pallet_transaction_payment::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter, ()>; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; @@ -88,7 +91,7 @@ impl pallet_transaction_payment::Config for Test { impl Config for Test { type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ExistentialDeposit; type AccountStore = frame_system::Pallet; type MaxLocks = (); diff --git a/frame/balances/src/tests_local.rs b/frame/balances/src/tests_local.rs index ebb82f41a545c..152a5da37410f 100644 --- a/frame/balances/src/tests_local.rs +++ b/frame/balances/src/tests_local.rs @@ -21,9 +21,10 @@ use crate::{self as pallet_balances, decl_tests, Config, Pallet}; use frame_support::{ + dispatch::DispatchInfo, parameter_types, traits::{ConstU32, ConstU64, ConstU8, StorageMapShim}, - weights::{DispatchInfo, IdentityFee, Weight}, + weights::{IdentityFee, Weight}, }; use pallet_transaction_payment::CurrencyAdapter; use sp_core::H256; @@ -47,7 +48,9 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); + frame_system::limits::BlockWeights::simple_max( + frame_support::weights::Weight::from_ref_time(1024).set_proof_size(u64::MAX), + ); pub static ExistentialDeposit: u64 = 0; } impl frame_system::Config for Test { @@ -55,16 +58,16 @@ impl frame_system::Config for Test { type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -78,7 +81,7 @@ impl frame_system::Config for Test { } impl pallet_transaction_payment::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter, ()>; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; @@ -89,7 +92,7 @@ impl pallet_transaction_payment::Config for Test { impl Config for Test { type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ExistentialDeposit; type AccountStore = StorageMapShim, system::Provider, u64, super::AccountData>; @@ -158,9 +161,9 @@ fn emit_events_with_no_existential_deposit_suicide_with_dust() { assert_eq!( events(), [ - Event::System(system::Event::NewAccount { account: 1 }), - Event::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), - Event::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), + RuntimeEvent::System(system::Event::NewAccount { account: 1 }), + RuntimeEvent::Balances(crate::Event::Endowed { account: 1, free_balance: 100 }), + RuntimeEvent::Balances(crate::Event::BalanceSet { who: 1, free: 100, reserved: 0 }), ] ); @@ -168,7 +171,10 @@ fn emit_events_with_no_existential_deposit_suicide_with_dust() { assert_eq!(res, (NegativeImbalance::new(98), 0)); // no events - assert_eq!(events(), [Event::Balances(crate::Event::Slashed { who: 1, amount: 98 })]); + assert_eq!( + events(), + [RuntimeEvent::Balances(crate::Event::Slashed { who: 1, amount: 98 })] + ); let res = Balances::slash(&1, 1); assert_eq!(res, (NegativeImbalance::new(1), 0)); @@ -176,9 +182,9 @@ fn emit_events_with_no_existential_deposit_suicide_with_dust() { assert_eq!( events(), [ - Event::System(system::Event::KilledAccount { account: 1 }), - Event::Balances(crate::Event::DustLost { account: 1, amount: 1 }), - Event::Balances(crate::Event::Slashed { who: 1, amount: 1 }) + RuntimeEvent::System(system::Event::KilledAccount { account: 1 }), + RuntimeEvent::Balances(crate::Event::DustLost { account: 1, amount: 1 }), + RuntimeEvent::Balances(crate::Event::Slashed { who: 1, amount: 1 }) ] ); }); diff --git a/frame/balances/src/tests_reentrancy.rs b/frame/balances/src/tests_reentrancy.rs index fbfd62eb63259..90363140000e8 100644 --- a/frame/balances/src/tests_reentrancy.rs +++ b/frame/balances/src/tests_reentrancy.rs @@ -51,7 +51,9 @@ frame_support::construct_runtime!( parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); + frame_system::limits::BlockWeights::simple_max( + frame_support::weights::Weight::from_ref_time(1024).set_proof_size(u64::MAX), + ); pub static ExistentialDeposit: u64 = 0; } impl frame_system::Config for Test { @@ -59,16 +61,16 @@ impl frame_system::Config for Test { type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -91,7 +93,7 @@ impl OnUnbalanced> for OnDustRemoval { impl Config for Test { type Balance = u64; type DustRemoval = OnDustRemoval; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ExistentialDeposit; type AccountStore = StorageMapShim, system::Provider, u64, super::AccountData>; @@ -157,16 +159,19 @@ fn transfer_dust_removal_tst1_should_work() { // Verify the events assert_eq!(System::events().len(), 12); - System::assert_has_event(Event::Balances(crate::Event::Transfer { + System::assert_has_event(RuntimeEvent::Balances(crate::Event::Transfer { from: 2, to: 3, amount: 450, })); - System::assert_has_event(Event::Balances(crate::Event::DustLost { + System::assert_has_event(RuntimeEvent::Balances(crate::Event::DustLost { account: 2, amount: 50, })); - System::assert_has_event(Event::Balances(crate::Event::Deposit { who: 1, amount: 50 })); + System::assert_has_event(RuntimeEvent::Balances(crate::Event::Deposit { + who: 1, + amount: 50, + })); }); } @@ -192,16 +197,19 @@ fn transfer_dust_removal_tst2_should_work() { // Verify the events assert_eq!(System::events().len(), 10); - System::assert_has_event(Event::Balances(crate::Event::Transfer { + System::assert_has_event(RuntimeEvent::Balances(crate::Event::Transfer { from: 2, to: 1, amount: 450, })); - System::assert_has_event(Event::Balances(crate::Event::DustLost { + System::assert_has_event(RuntimeEvent::Balances(crate::Event::DustLost { account: 2, amount: 50, })); - System::assert_has_event(Event::Balances(crate::Event::Deposit { who: 1, amount: 50 })); + System::assert_has_event(RuntimeEvent::Balances(crate::Event::Deposit { + who: 1, + amount: 50, + })); }); } @@ -236,18 +244,21 @@ fn repatriating_reserved_balance_dust_removal_should_work() { // Verify the events assert_eq!(System::events().len(), 11); - System::assert_has_event(Event::Balances(crate::Event::ReserveRepatriated { + System::assert_has_event(RuntimeEvent::Balances(crate::Event::ReserveRepatriated { from: 2, to: 1, amount: 450, destination_status: Status::Free, })); - System::assert_has_event(Event::Balances(crate::Event::DustLost { + System::assert_has_event(RuntimeEvent::Balances(crate::Event::DustLost { account: 2, amount: 50, })); - System::assert_last_event(Event::Balances(crate::Event::Deposit { who: 1, amount: 50 })); + System::assert_last_event(RuntimeEvent::Balances(crate::Event::Deposit { + who: 1, + amount: 50, + })); }); } diff --git a/frame/beefy-mmr/Cargo.toml b/frame/beefy-mmr/Cargo.toml index e8366943c85b0..62fabd387a167 100644 --- a/frame/beefy-mmr/Cargo.toml +++ b/frame/beefy-mmr/Cargo.toml @@ -9,8 +9,8 @@ repository = "https://github.com/paritytech/substrate" homepage = "https://substrate.io" [dependencies] +array-bytes = { version = "4.1", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -hex = { version = "0.4", optional = true } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } @@ -27,18 +27,18 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primit sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] -hex-literal = "0.3" +array-bytes = "4.1" sp-staking = { version = "4.0.0-dev", path = "../../primitives/staking" } [features] default = ["std"] std = [ + "array-bytes", "beefy-merkle-tree/std", "beefy-primitives/std", "codec/std", "frame-support/std", "frame-system/std", - "hex", "log/std", "pallet-beefy/std", "pallet-mmr/std", diff --git a/frame/beefy-mmr/primitives/Cargo.toml b/frame/beefy-mmr/primitives/Cargo.toml index f30a418def042..a097da0fc30fd 100644 --- a/frame/beefy-mmr/primitives/Cargo.toml +++ b/frame/beefy-mmr/primitives/Cargo.toml @@ -9,23 +9,22 @@ description = "A no-std/Substrate compatible library to construct binary merkle homepage = "https://substrate.io" [dependencies] -hex = { version = "0.4", default-features = false, optional = true } +array-bytes = { version = "4.1", optional = true } log = { version = "0.4", default-features = false, optional = true } -tiny-keccak = { version = "2.0.2", features = ["keccak"], optional = true } beefy-primitives = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/beefy" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } [dev-dependencies] +array-bytes = "4.1" env_logger = "0.9" -hex = "0.4" -hex-literal = "0.3" [features] -debug = ["hex", "hex/std", "log"] -default = ["debug", "keccak", "std"] -keccak = ["tiny-keccak"] +debug = ["array-bytes", "log"] +default = ["debug", "std"] std = [ "beefy-primitives/std", - "sp-api/std" + "sp-api/std", + "sp-runtime/std" ] diff --git a/frame/beefy-mmr/primitives/src/lib.rs b/frame/beefy-mmr/primitives/src/lib.rs index 664fd18199dd0..f56be8bcafe5b 100644 --- a/frame/beefy-mmr/primitives/src/lib.rs +++ b/frame/beefy-mmr/primitives/src/lib.rs @@ -25,88 +25,49 @@ //! compilation targets. //! //! Merkle Tree is constructed from arbitrary-length leaves, that are initially hashed using the -//! same [Hasher] as the inner nodes. +//! same hasher as the inner nodes. //! Inner nodes are created by concatenating child hashes and hashing again. The implementation //! does not perform any sorting of the input data (leaves) nor when inner nodes are created. //! //! If the number of leaves is not even, last leave (hash of) is promoted to the upper layer. -#[cfg(not(feature = "std"))] -extern crate alloc; -#[cfg(not(feature = "std"))] -use alloc::vec::Vec; +pub use sp_runtime::traits::Keccak256; +use sp_runtime::{app_crypto::sp_core, sp_std, traits::Hash as HashT}; +use sp_std::{vec, vec::Vec}; use beefy_primitives::mmr::{BeefyAuthoritySet, BeefyNextAuthoritySet}; -/// Supported hashing output size. -/// -/// The size is restricted to 32 bytes to allow for a more optimised implementation. -pub type Hash = [u8; 32]; - -/// Generic hasher trait. -/// -/// Implement the function to support custom way of hashing data. -/// The implementation must return a [Hash](type@Hash) type, so only 32-byte output hashes are -/// supported. -pub trait Hasher { - /// Hash given arbitrary-length piece of data. - fn hash(data: &[u8]) -> Hash; -} - -#[cfg(feature = "keccak")] -mod keccak256 { - use tiny_keccak::{Hasher as _, Keccak}; - - /// Keccak256 hasher implementation. - pub struct Keccak256; - impl Keccak256 { - /// Hash given data. - pub fn hash(data: &[u8]) -> super::Hash { - ::hash(data) - } - } - impl super::Hasher for Keccak256 { - fn hash(data: &[u8]) -> super::Hash { - let mut keccak = Keccak::v256(); - keccak.update(data); - let mut output = [0_u8; 32]; - keccak.finalize(&mut output); - output - } - } -} -#[cfg(feature = "keccak")] -pub use keccak256::Keccak256; - /// Construct a root hash of a Binary Merkle Tree created from given leaves. /// /// See crate-level docs for details about Merkle Tree construction. /// /// In case an empty list of leaves is passed the function returns a 0-filled hash. -pub fn merkle_root(leaves: I) -> Hash +pub fn merkle_root(leaves: I) -> H::Output where - H: Hasher, - I: IntoIterator, - T: AsRef<[u8]>, + H: HashT, + H::Output: Default + AsRef<[u8]>, + I: IntoIterator, + I::Item: AsRef<[u8]>, { - let iter = leaves.into_iter().map(|l| H::hash(l.as_ref())); - merkelize::(iter, &mut ()) + let iter = leaves.into_iter().map(|l| ::hash(l.as_ref())); + merkelize::(iter, &mut ()).into() } -fn merkelize(leaves: I, visitor: &mut V) -> Hash +fn merkelize(leaves: I, visitor: &mut V) -> H::Output where - H: Hasher, - V: Visitor, - I: Iterator, + H: HashT, + H::Output: Default + AsRef<[u8]>, + V: Visitor, + I: Iterator, { - let upper = Vec::with_capacity(leaves.size_hint().0); + let upper = Vec::with_capacity((leaves.size_hint().1.unwrap_or(0).saturating_add(1)) / 2); let mut next = match merkelize_row::(leaves, upper, visitor) { Ok(root) => return root, - Err(next) if next.is_empty() => return Hash::default(), + Err(next) if next.is_empty() => return H::Output::default(), Err(next) => next, }; - let mut upper = Vec::with_capacity((next.len() + 1) / 2); + let mut upper = Vec::with_capacity((next.len().saturating_add(1)) / 2); loop { visitor.move_up(); @@ -125,14 +86,14 @@ where /// /// The structure contains all necessary data to later on verify the proof and the leaf itself. #[derive(Debug, PartialEq, Eq)] -pub struct MerkleProof { +pub struct MerkleProof { /// Root hash of generated merkle tree. - pub root: Hash, + pub root: H, /// Proof items (does not contain the leaf hash, nor the root obviously). /// /// This vec contains all inner node hashes necessary to reconstruct the root hash given the /// leaf hash. - pub proof: Vec, + pub proof: Vec, /// Number of leaves in the original tree. /// /// This is needed to detect a case where we have an odd number of leaves that "get promoted" @@ -141,14 +102,14 @@ pub struct MerkleProof { /// Index of the leaf the proof is for (0-based). pub leaf_index: usize, /// Leaf content. - pub leaf: T, + pub leaf: L, } /// A trait of object inspecting merkle root creation. /// /// It can be passed to [`merkelize_row`] or [`merkelize`] functions and will be notified /// about tree traversal. -trait Visitor { +trait Visitor { /// We are moving one level up in the tree. fn move_up(&mut self); @@ -158,13 +119,13 @@ trait Visitor { /// The method will also visit the `root` hash (level 0). /// /// The `index` is an index of `left` item. - fn visit(&mut self, index: usize, left: &Option, right: &Option); + fn visit(&mut self, index: usize, left: &Option, right: &Option); } /// No-op implementation of the visitor. -impl Visitor for () { +impl Visitor for () { fn move_up(&mut self) {} - fn visit(&mut self, _index: usize, _left: &Option, _right: &Option) {} + fn visit(&mut self, _index: usize, _left: &Option, _right: &Option) {} } /// Construct a Merkle Proof for leaves given by indices. @@ -177,16 +138,17 @@ impl Visitor for () { /// # Panic /// /// The function will panic if given `leaf_index` is greater than the number of leaves. -pub fn merkle_proof(leaves: I, leaf_index: usize) -> MerkleProof +pub fn merkle_proof(leaves: I, leaf_index: usize) -> MerkleProof where - H: Hasher, + H: HashT, + H::Output: Default + Copy + AsRef<[u8]>, I: IntoIterator, I::IntoIter: ExactSizeIterator, T: AsRef<[u8]>, { let mut leaf = None; let iter = leaves.into_iter().enumerate().map(|(idx, l)| { - let hash = H::hash(l.as_ref()); + let hash = ::hash(l.as_ref()); if idx == leaf_index { leaf = Some(l); } @@ -194,23 +156,23 @@ where }); /// The struct collects a proof for single leaf. - struct ProofCollection { - proof: Vec, + struct ProofCollection { + proof: Vec, position: usize, } - impl ProofCollection { + impl ProofCollection { fn new(position: usize) -> Self { ProofCollection { proof: Default::default(), position } } } - impl Visitor for ProofCollection { + impl Visitor for ProofCollection { fn move_up(&mut self) { self.position /= 2; } - fn visit(&mut self, index: usize, left: &Option, right: &Option) { + fn visit(&mut self, index: usize, left: &Option, right: &Option) { // we are at left branch - right goes to the proof. if self.position == index { if let Some(right) = right { @@ -235,7 +197,11 @@ where #[cfg(feature = "debug")] log::debug!( "[merkle_proof] Proof: {:?}", - collect_proof.proof.iter().map(hex::encode).collect::>() + collect_proof + .proof + .iter() + .map(|s| array_bytes::bytes2hex("", s.as_ref())) + .collect::>() ); MerkleProof { root, proof: collect_proof.proof, number_of_leaves, leaf_index, leaf } @@ -246,25 +212,19 @@ where /// Can be either a value that needs to be hashed first, /// or the hash itself. #[derive(Debug, PartialEq, Eq)] -pub enum Leaf<'a> { +pub enum Leaf<'a, H> { /// Leaf content. Value(&'a [u8]), /// Hash of the leaf content. - Hash(Hash), + Hash(H), } -impl<'a, T: AsRef<[u8]>> From<&'a T> for Leaf<'a> { +impl<'a, H, T: AsRef<[u8]>> From<&'a T> for Leaf<'a, H> { fn from(v: &'a T) -> Self { Leaf::Value(v.as_ref()) } } -impl<'a> From for Leaf<'a> { - fn from(v: Hash) -> Self { - Leaf::Hash(v) - } -} - /// Verify Merkle Proof correctness versus given root hash. /// /// The proof is NOT expected to contain leaf hash as the first @@ -273,45 +233,47 @@ impl<'a> From for Leaf<'a> { /// /// The proof must not contain the root hash. pub fn verify_proof<'a, H, P, L>( - root: &'a Hash, + root: &'a H::Output, proof: P, number_of_leaves: usize, leaf_index: usize, leaf: L, ) -> bool where - H: Hasher, - P: IntoIterator, - L: Into>, + H: HashT, + H::Output: PartialEq + AsRef<[u8]>, + P: IntoIterator, + L: Into>, { if leaf_index >= number_of_leaves { return false } let leaf_hash = match leaf.into() { - Leaf::Value(content) => H::hash(content), + Leaf::Value(content) => ::hash(content), Leaf::Hash(hash) => hash, }; - let mut combined = [0_u8; 64]; + let hash_len = ::LENGTH; + let mut combined = vec![0_u8; hash_len * 2]; let mut position = leaf_index; let mut width = number_of_leaves; let computed = proof.into_iter().fold(leaf_hash, |a, b| { if position % 2 == 1 || position + 1 == width { - combined[0..32].copy_from_slice(&b); - combined[32..64].copy_from_slice(&a); + combined[..hash_len].copy_from_slice(&b.as_ref()); + combined[hash_len..].copy_from_slice(&a.as_ref()); } else { - combined[0..32].copy_from_slice(&a); - combined[32..64].copy_from_slice(&b); + combined[..hash_len].copy_from_slice(&a.as_ref()); + combined[hash_len..].copy_from_slice(&b.as_ref()); } - let hash = H::hash(&combined); + let hash = ::hash(&combined); #[cfg(feature = "debug")] log::debug!( "[verify_proof]: (a, b) {:?}, {:?} => {:?} ({:?}) hash", - hex::encode(a), - hex::encode(b), - hex::encode(hash), - hex::encode(combined) + array_bytes::bytes2hex("", &a.as_ref()), + array_bytes::bytes2hex("", &b.as_ref()), + array_bytes::bytes2hex("", &hash.as_ref()), + array_bytes::bytes2hex("", &combined.as_ref()) ); position /= 2; width = ((width - 1) / 2) + 1; @@ -328,35 +290,41 @@ where /// empty iterator) an `Err` with the inner nodes of upper layer is returned. fn merkelize_row( mut iter: I, - mut next: Vec, + mut next: Vec, visitor: &mut V, -) -> Result> +) -> Result> where - H: Hasher, - V: Visitor, - I: Iterator, + H: HashT, + H::Output: AsRef<[u8]>, + V: Visitor, + I: Iterator, { #[cfg(feature = "debug")] log::debug!("[merkelize_row]"); next.clear(); + let hash_len = ::LENGTH; let mut index = 0; - let mut combined = [0_u8; 64]; + let mut combined = vec![0_u8; hash_len * 2]; loop { let a = iter.next(); let b = iter.next(); visitor.visit(index, &a, &b); #[cfg(feature = "debug")] - log::debug!(" {:?}\n {:?}", a.as_ref().map(hex::encode), b.as_ref().map(hex::encode)); + log::debug!( + " {:?}\n {:?}", + a.as_ref().map(|s| array_bytes::bytes2hex("", s.as_ref())), + b.as_ref().map(|s| array_bytes::bytes2hex("", s.as_ref())) + ); index += 2; match (a, b) { (Some(a), Some(b)) => { - combined[0..32].copy_from_slice(&a); - combined[32..64].copy_from_slice(&b); + combined[..hash_len].copy_from_slice(a.as_ref()); + combined[hash_len..].copy_from_slice(b.as_ref()); - next.push(H::hash(&combined)); + next.push(::hash(&combined)); }, // Odd number of items. Promote the item to the upper layer. (Some(a), None) if !next.is_empty() => { @@ -369,7 +337,7 @@ where #[cfg(feature = "debug")] log::debug!( "[merkelize_row] Next: {:?}", - next.iter().map(hex::encode).collect::>() + next.iter().map(|s| array_bytes::bytes2hex("", s.as_ref())).collect::>() ); return Err(next) }, @@ -381,7 +349,6 @@ sp_api::decl_runtime_apis! { /// API useful for BEEFY light clients. pub trait BeefyMmrApi where - H: From + Into, BeefyAuthoritySet: sp_api::Decode, { /// Return the currently active BEEFY authority set proof. @@ -395,7 +362,7 @@ sp_api::decl_runtime_apis! { #[cfg(test)] mod tests { use super::*; - use hex_literal::hex; + use crate::sp_core::H256; #[test] fn should_generate_empty_root() { @@ -404,11 +371,11 @@ mod tests { let data: Vec<[u8; 1]> = Default::default(); // when - let out = merkle_root::(data); + let out = merkle_root::(data); // then assert_eq!( - hex::encode(&out), + array_bytes::bytes2hex("", out.as_ref()), "0000000000000000000000000000000000000000000000000000000000000000" ); } @@ -417,14 +384,16 @@ mod tests { fn should_generate_single_root() { // given let _ = env_logger::try_init(); - let data = vec![hex!("E04CC55ebEE1cBCE552f250e85c57B70B2E2625b")]; + let data = vec![array_bytes::hex2array_unchecked::<20>( + "E04CC55ebEE1cBCE552f250e85c57B70B2E2625b", + )]; // when - let out = merkle_root::(data); + let out = merkle_root::(data); // then assert_eq!( - hex::encode(&out), + array_bytes::bytes2hex("", out.as_ref()), "aeb47a269393297f4b0a3c9c9cfd00c7a4195255274cf39d83dabc2fcc9ff3d7" ); } @@ -434,16 +403,16 @@ mod tests { // given let _ = env_logger::try_init(); let data = vec![ - hex!("E04CC55ebEE1cBCE552f250e85c57B70B2E2625b"), - hex!("25451A4de12dcCc2D166922fA938E900fCc4ED24"), + array_bytes::hex2array_unchecked::<20>("E04CC55ebEE1cBCE552f250e85c57B70B2E2625b"), + array_bytes::hex2array_unchecked::<20>("25451A4de12dcCc2D166922fA938E900fCc4ED24"), ]; // when - let out = merkle_root::(data); + let out = merkle_root::(data); // then assert_eq!( - hex::encode(&out), + array_bytes::bytes2hex("", out.as_ref()), "697ea2a8fe5b03468548a7a413424a6292ab44a82a6f5cc594c3fa7dda7ce402" ); } @@ -452,7 +421,10 @@ mod tests { fn should_generate_root_complex() { let _ = env_logger::try_init(); let test = |root, data| { - assert_eq!(hex::encode(&merkle_root::(data)), root); + assert_eq!( + array_bytes::bytes2hex("", &merkle_root::(data).as_ref()), + root + ); }; test( @@ -511,11 +483,20 @@ mod tests { )); // then - assert_eq!(hex::encode(proof0.root), hex::encode(proof1.root)); - assert_eq!(hex::encode(proof2.root), hex::encode(proof1.root)); + assert_eq!( + array_bytes::bytes2hex("", &proof0.root.as_ref()), + array_bytes::bytes2hex("", &proof1.root.as_ref()) + ); + assert_eq!( + array_bytes::bytes2hex("", &proof2.root.as_ref()), + array_bytes::bytes2hex("", &proof1.root.as_ref()) + ); assert!(!verify_proof::( - &hex!("fb3b3be94be9e983ba5e094c9c51a7d96a4fa2e5d8e891df00ca89ba05bb1239"), + &array_bytes::hex2array_unchecked( + "fb3b3be94be9e983ba5e094c9c51a7d96a4fa2e5d8e891df00ca89ba05bb1239" + ) + .into(), proof0.proof, data.len(), proof0.leaf_index, @@ -523,7 +504,7 @@ mod tests { )); assert!(!verify_proof::( - &proof0.root, + &proof0.root.into(), vec![], data.len(), proof0.leaf_index, @@ -779,17 +760,23 @@ mod tests { "0xA4cDc98593CE52d01Fe5Ca47CB3dA5320e0D7592", "0xc26B34D375533fFc4c5276282Fa5D660F3d8cbcB", ]; - let root = hex!("72b0acd7c302a84f1f6b6cefe0ba7194b7398afb440e1b44a9dbbe270394ca53"); + let root: H256 = array_bytes::hex2array_unchecked( + "72b0acd7c302a84f1f6b6cefe0ba7194b7398afb440e1b44a9dbbe270394ca53", + ) + .into(); let data = addresses .into_iter() - .map(|address| hex::decode(&address[2..]).unwrap()) + .map(|address| array_bytes::hex2bytes_unchecked(&address)) .collect::>(); for l in 0..data.len() { // when let proof = merkle_proof::(data.clone(), l); - assert_eq!(hex::encode(&proof.root), hex::encode(&root)); + assert_eq!( + array_bytes::bytes2hex("", &proof.root.as_ref()), + array_bytes::bytes2hex("", &root.as_ref()) + ); assert_eq!(proof.leaf_index, l); assert_eq!(&proof.leaf, &data[l]); @@ -810,14 +797,29 @@ mod tests { MerkleProof { root, proof: vec![ - hex!("340bcb1d49b2d82802ddbcf5b85043edb3427b65d09d7f758fbc76932ad2da2f"), - hex!("ba0580e5bd530bc93d61276df7969fb5b4ae8f1864b4a28c280249575198ff1f"), - hex!("d02609d2bbdb28aa25f58b85afec937d5a4c85d37925bce6d0cf802f9d76ba79"), - hex!("ae3f8991955ed884613b0a5f40295902eea0e0abe5858fc520b72959bc016d4e"), + array_bytes::hex2array_unchecked( + "340bcb1d49b2d82802ddbcf5b85043edb3427b65d09d7f758fbc76932ad2da2f" + ) + .into(), + array_bytes::hex2array_unchecked( + "ba0580e5bd530bc93d61276df7969fb5b4ae8f1864b4a28c280249575198ff1f" + ) + .into(), + array_bytes::hex2array_unchecked( + "d02609d2bbdb28aa25f58b85afec937d5a4c85d37925bce6d0cf802f9d76ba79" + ) + .into(), + array_bytes::hex2array_unchecked( + "ae3f8991955ed884613b0a5f40295902eea0e0abe5858fc520b72959bc016d4e" + ) + .into(), ], number_of_leaves: data.len(), leaf_index: data.len() - 1, - leaf: hex!("c26B34D375533fFc4c5276282Fa5D660F3d8cbcB").to_vec(), + leaf: array_bytes::hex2array_unchecked::<20>( + "c26B34D375533fFc4c5276282Fa5D660F3d8cbcB" + ) + .to_vec(), } ); } diff --git a/frame/beefy-mmr/src/lib.rs b/frame/beefy-mmr/src/lib.rs index 456d6e77aa8eb..0b7fc22cd279b 100644 --- a/frame/beefy-mmr/src/lib.rs +++ b/frame/beefy-mmr/src/lib.rs @@ -33,7 +33,7 @@ //! //! and thanks to versioning can be easily updated in the future. -use sp_runtime::traits::{Convert, Hash, Member}; +use sp_runtime::traits::{Convert, Member}; use sp_std::prelude::*; use beefy_primitives::{ @@ -73,12 +73,8 @@ where /// Convert BEEFY secp256k1 public keys into Ethereum addresses pub struct BeefyEcdsaToEthereum; impl Convert> for BeefyEcdsaToEthereum { - fn convert(a: beefy_primitives::crypto::AuthorityId) -> Vec { - sp_core::ecdsa::Public::try_from(a.as_ref()) - .map_err(|_| { - log::error!(target: "runtime::beefy", "Invalid BEEFY PublicKey format!"); - }) - .unwrap_or(sp_core::ecdsa::Public::from_raw([0u8; 33])) + fn convert(beefy_id: beefy_primitives::crypto::AuthorityId) -> Vec { + sp_core::ecdsa::Public::from(beefy_id) .to_eth_address() .map(|v| v.to_vec()) .map_err(|_| { @@ -142,10 +138,7 @@ pub mod pallet { StorageValue<_, BeefyNextAuthoritySet>, ValueQuery>; } -impl LeafDataProvider for Pallet -where - MerkleRootOf: From + Into, -{ +impl LeafDataProvider for Pallet { type LeafData = MmrLeaf< ::BlockNumber, ::Hash, @@ -163,19 +156,9 @@ where } } -impl beefy_merkle_tree::Hasher for Pallet -where - MerkleRootOf: Into, -{ - fn hash(data: &[u8]) -> beefy_merkle_tree::Hash { - ::Hashing::hash(data).into() - } -} - impl beefy_primitives::OnNewValidatorSet<::BeefyId> for Pallet where T: pallet::Config, - MerkleRootOf: From + Into, { /// Compute and cache BEEFY authority sets based on updated BEEFY validator sets. fn on_new_validator_set( @@ -190,10 +173,7 @@ where } } -impl Pallet -where - MerkleRootOf: From + Into, -{ +impl Pallet { /// Return the currently active BEEFY authority set proof. pub fn authority_set_proof() -> BeefyAuthoritySet> { Pallet::::beefy_authorities() @@ -220,7 +200,10 @@ where .map(T::BeefyAuthorityToMerkleLeaf::convert) .collect::>(); let len = beefy_addresses.len() as u32; - let root = beefy_merkle_tree::merkle_root::(beefy_addresses).into(); + let root = beefy_merkle_tree::merkle_root::<::Hashing, _>( + beefy_addresses, + ) + .into(); BeefyAuthoritySet { id, len, root } } } diff --git a/frame/beefy-mmr/src/mock.rs b/frame/beefy-mmr/src/mock.rs index 8a673c9d4e914..0a64ad3fc9976 100644 --- a/frame/beefy-mmr/src/mock.rs +++ b/frame/beefy-mmr/src/mock.rs @@ -67,16 +67,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -90,7 +90,7 @@ impl frame_system::Config for Test { } impl pallet_session::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = u64; type ValidatorIdOf = ConvertInto; type ShouldEndSession = pallet_session::PeriodicSessions, ConstU64<0>>; @@ -147,9 +147,10 @@ impl BeefyDataProvider> for DummyDataProvider { fn extra_data() -> Vec { let mut col = vec![(15, vec![1, 2, 3]), (5, vec![4, 5, 6])]; col.sort(); - beefy_merkle_tree::merkle_root::, _, _>( + beefy_merkle_tree::merkle_root::<::Hashing, _>( col.into_iter().map(|pair| pair.encode()), ) + .as_ref() .to_vec() } } diff --git a/frame/beefy-mmr/src/tests.rs b/frame/beefy-mmr/src/tests.rs index eaa50004ae848..1826331f59e53 100644 --- a/frame/beefy-mmr/src/tests.rs +++ b/frame/beefy-mmr/src/tests.rs @@ -22,7 +22,6 @@ use beefy_primitives::{ ValidatorSet, }; use codec::{Decode, Encode}; -use hex_literal::hex; use sp_core::H256; use sp_io::TestExternalities; @@ -70,9 +69,9 @@ fn should_contain_mmr_digest() { beefy_log(ConsensusLog::AuthoritiesChange( ValidatorSet::new(vec![mock_beefy_id(1), mock_beefy_id(2)], 1).unwrap() )), - beefy_log(ConsensusLog::MmrRoot( - hex!("95803defe6ea9f41e7ec6afa497064f21bfded027d8812efacbdf984e630cbdc").into() - )) + beefy_log(ConsensusLog::MmrRoot(array_bytes::hex_n_into_unchecked( + "95803defe6ea9f41e7ec6afa497064f21bfded027d8812efacbdf984e630cbdc" + ))) ] ); @@ -85,15 +84,15 @@ fn should_contain_mmr_digest() { beefy_log(ConsensusLog::AuthoritiesChange( ValidatorSet::new(vec![mock_beefy_id(1), mock_beefy_id(2)], 1).unwrap() )), - beefy_log(ConsensusLog::MmrRoot( - hex!("95803defe6ea9f41e7ec6afa497064f21bfded027d8812efacbdf984e630cbdc").into() - )), + beefy_log(ConsensusLog::MmrRoot(array_bytes::hex_n_into_unchecked( + "95803defe6ea9f41e7ec6afa497064f21bfded027d8812efacbdf984e630cbdc" + ))), beefy_log(ConsensusLog::AuthoritiesChange( ValidatorSet::new(vec![mock_beefy_id(3), mock_beefy_id(4)], 2).unwrap() )), - beefy_log(ConsensusLog::MmrRoot( - hex!("a73271a0974f1e67d6e9b8dd58e506177a2e556519a330796721e98279a753e2").into() - )), + beefy_log(ConsensusLog::MmrRoot(array_bytes::hex_n_into_unchecked( + "a73271a0974f1e67d6e9b8dd58e506177a2e556519a330796721e98279a753e2" + ))), ] ); }); @@ -101,8 +100,8 @@ fn should_contain_mmr_digest() { #[test] fn should_contain_valid_leaf_data() { - fn node_offchain_key(parent_hash: H256, pos: usize) -> Vec { - (::INDEXING_PREFIX, parent_hash, pos as u64).encode() + fn node_offchain_key(pos: usize, parent_hash: H256) -> Vec { + (::INDEXING_PREFIX, pos as u64, parent_hash).encode() } let mut ext = new_test_ext(vec![1, 2, 3, 4]); @@ -111,7 +110,7 @@ fn should_contain_valid_leaf_data() { >::parent_hash() }); - let mmr_leaf = read_mmr_leaf(&mut ext, node_offchain_key(parent_hash, 0)); + let mmr_leaf = read_mmr_leaf(&mut ext, node_offchain_key(0, parent_hash)); assert_eq!( mmr_leaf, MmrLeaf { @@ -120,11 +119,13 @@ fn should_contain_valid_leaf_data() { beefy_next_authority_set: BeefyNextAuthoritySet { id: 2, len: 2, - root: hex!("9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5") - .into(), + root: array_bytes::hex_n_into_unchecked( + "9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5" + ) }, - leaf_extra: hex!("55b8e9e1cc9f0db7776fac0ca66318ef8acfb8ec26db11e373120583e07ee648") - .to_vec(), + leaf_extra: array_bytes::hex2bytes_unchecked( + "55b8e9e1cc9f0db7776fac0ca66318ef8acfb8ec26db11e373120583e07ee648" + ) } ); @@ -134,7 +135,7 @@ fn should_contain_valid_leaf_data() { >::parent_hash() }); - let mmr_leaf = read_mmr_leaf(&mut ext, node_offchain_key(parent_hash, 1)); + let mmr_leaf = read_mmr_leaf(&mut ext, node_offchain_key(1, parent_hash)); assert_eq!( mmr_leaf, MmrLeaf { @@ -143,11 +144,13 @@ fn should_contain_valid_leaf_data() { beefy_next_authority_set: BeefyNextAuthoritySet { id: 3, len: 2, - root: hex!("9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5") - .into(), + root: array_bytes::hex_n_into_unchecked( + "9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5" + ) }, - leaf_extra: hex!("55b8e9e1cc9f0db7776fac0ca66318ef8acfb8ec26db11e373120583e07ee648") - .to_vec() + leaf_extra: array_bytes::hex2bytes_unchecked( + "55b8e9e1cc9f0db7776fac0ca66318ef8acfb8ec26db11e373120583e07ee648" + ) } ); } @@ -161,8 +164,9 @@ fn should_update_authorities() { // check current authority set assert_eq!(0, auth_set.id); assert_eq!(2, auth_set.len); - let want: H256 = - hex!("176e73f1bf656478b728e28dd1a7733c98621b8acf830bff585949763dca7a96").into(); + let want = array_bytes::hex_n_into_unchecked::( + "176e73f1bf656478b728e28dd1a7733c98621b8acf830bff585949763dca7a96", + ); assert_eq!(want, auth_set.root); // next authority set should have same validators but different id @@ -180,8 +184,9 @@ fn should_update_authorities() { assert_eq!(1, auth_set.id); // check next auth set assert_eq!(2, next_auth_set.id); - let want: H256 = - hex!("9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5").into(); + let want = array_bytes::hex_n_into_unchecked::( + "9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5", + ); assert_eq!(2, next_auth_set.len); assert_eq!(want, next_auth_set.root); @@ -195,8 +200,9 @@ fn should_update_authorities() { assert_eq!(2, auth_set.id); // check next auth set assert_eq!(3, next_auth_set.id); - let want: H256 = - hex!("9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5").into(); + let want = array_bytes::hex_n_into_unchecked::( + "9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5", + ); assert_eq!(2, next_auth_set.len); assert_eq!(want, next_auth_set.root); }); diff --git a/frame/beefy/src/mock.rs b/frame/beefy/src/mock.rs index 3bb59c7c39485..ad3a672333dd5 100644 --- a/frame/beefy/src/mock.rs +++ b/frame/beefy/src/mock.rs @@ -62,16 +62,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -95,7 +95,7 @@ parameter_types! { } impl pallet_session::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = u64; type ValidatorIdOf = ConvertInto; type ShouldEndSession = pallet_session::PeriodicSessions, ConstU64<0>>; diff --git a/frame/benchmarking/Cargo.toml b/frame/benchmarking/Cargo.toml index d5f2c53e0943d..2b8081f4251f3 100644 --- a/frame/benchmarking/Cargo.toml +++ b/frame/benchmarking/Cargo.toml @@ -32,7 +32,7 @@ sp-storage = { version = "6.0.0", default-features = false, path = "../../primit futures = "0.3.21" [dev-dependencies] -hex-literal = "0.3.4" +array-bytes = "4.1" rusty-fork = { version = "0.3.0", default-features = false } sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } @@ -55,4 +55,6 @@ std = [ "sp-std/std", "sp-storage/std", ] -runtime-benchmarks = [] +runtime-benchmarks = [ + "frame-system/runtime-benchmarks", +] diff --git a/frame/benchmarking/README.md b/frame/benchmarking/README.md index 6316cd5903c8b..76673c5f69b33 100644 --- a/frame/benchmarking/README.md +++ b/frame/benchmarking/README.md @@ -185,7 +185,7 @@ Then you can run a benchmark like so: ``` This will output a file `pallet_name.rs` which implements the `WeightInfo` trait you should include -in your pallet. Each blockchain should generate their own benchmark file with their custom +in your pallet. Double colons `::` will be replaced with a `_` in the output name if you specify a directory. Each blockchain should generate their own benchmark file with their custom implementation of the `WeightInfo` trait. This means that you will be able to use these modular Substrate pallets while still keeping your network safe for your specific configuration and requirements. diff --git a/frame/benchmarking/src/analysis.rs b/frame/benchmarking/src/analysis.rs index c19af781234f8..db8ee599ef731 100644 --- a/frame/benchmarking/src/analysis.rs +++ b/frame/benchmarking/src/analysis.rs @@ -18,17 +18,16 @@ //! Tools for analyzing the benchmark results. use crate::BenchmarkResult; -use linregress::{FormulaRegressionBuilder, RegressionDataBuilder}; use std::collections::BTreeMap; -pub use linregress::RegressionModel; - pub struct Analysis { pub base: u128, pub slopes: Vec, pub names: Vec, pub value_dists: Option, u128, u128)>>, - pub model: Option, + pub errors: Option>, + pub minimum: u128, + selector: BenchmarkSelector, } #[derive(Clone, Copy)] @@ -40,6 +39,65 @@ pub enum BenchmarkSelector { ProofSize, } +/// Multiplies the value by 1000 and converts it into an u128. +fn mul_1000_into_u128(value: f64) -> u128 { + // This is slighly more precise than the alternative of `(value * 1000.0) as u128`. + (value as u128) + .saturating_mul(1000) + .saturating_add((value.fract() * 1000.0) as u128) +} + +impl BenchmarkSelector { + fn scale_and_cast_weight(self, value: f64, round_up: bool) -> u128 { + if let BenchmarkSelector::ExtrinsicTime = self { + // We add a very slight bias here to counteract the numerical imprecision of the linear + // regression where due to rounding issues it can emit a number like `2999999.999999998` + // which we most certainly always want to round up instead of truncating. + mul_1000_into_u128(value + 0.000_000_005) + } else { + if round_up { + (value + 0.5) as u128 + } else { + value as u128 + } + } + } + + fn scale_weight(self, value: u128) -> u128 { + if let BenchmarkSelector::ExtrinsicTime = self { + value.saturating_mul(1000) + } else { + value + } + } + + fn nanos_from_weight(self, value: u128) -> u128 { + if let BenchmarkSelector::ExtrinsicTime = self { + value / 1000 + } else { + value + } + } + + fn get_value(self, result: &BenchmarkResult) -> u128 { + match self { + BenchmarkSelector::ExtrinsicTime => result.extrinsic_time, + BenchmarkSelector::StorageRootTime => result.storage_root_time, + BenchmarkSelector::Reads => result.reads.into(), + BenchmarkSelector::Writes => result.writes.into(), + BenchmarkSelector::ProofSize => result.proof_size.into(), + } + } + + fn get_minimum(self, results: &[BenchmarkResult]) -> u128 { + results + .iter() + .map(|result| self.get_value(result)) + .min() + .expect("results cannot be empty") + } +} + #[derive(Debug)] pub enum AnalysisChoice { /// Use minimum squares regression for analyzing the benchmarking results. @@ -72,6 +130,69 @@ impl TryFrom> for AnalysisChoice { } } +fn raw_linear_regression( + xs: &[f64], + ys: &[f64], + x_vars: usize, + with_intercept: bool, +) -> Option<(f64, Vec, Vec)> { + let mut data: Vec = Vec::new(); + + // Here we build a raw matrix of linear equations for the `linregress` crate to solve for us + // and build a linear regression model around it. + // + // Each row of the matrix contains as the first column the actual value which we want + // the model to predict for us (the `y`), and the rest of the columns contain the input + // parameters on which the model will base its predictions on (the `xs`). + // + // In machine learning terms this is essentially the training data for the model. + // + // As a special case the very first input parameter represents the constant factor + // of the linear equation: the so called "intercept value". Since it's supposed to + // be constant we can just put a dummy input parameter of either a `1` (in case we want it) + // or a `0` (in case we do not). + for (&y, xs) in ys.iter().zip(xs.chunks_exact(x_vars)) { + data.push(y); + if with_intercept { + data.push(1.0); + } else { + data.push(0.0); + } + data.extend(xs); + } + let model = linregress::fit_low_level_regression_model(&data, ys.len(), x_vars + 2).ok()?; + Some((model.parameters[0], model.parameters[1..].to_vec(), model.se)) +} + +fn linear_regression( + xs: Vec, + mut ys: Vec, + x_vars: usize, +) -> Option<(f64, Vec, Vec)> { + let (intercept, params, errors) = raw_linear_regression(&xs, &ys, x_vars, true)?; + if intercept > 0.0 { + return Some((intercept, params, errors[1..].to_vec())) + } + + // The intercept is negative. + // The weights must be always positive, so we can't have that. + + let mut min = ys[0]; + for &value in &ys { + if value < min { + min = value; + } + } + + for value in &mut ys { + *value -= min; + } + + let (intercept, params, errors) = raw_linear_regression(&xs, &ys, x_vars, false)?; + assert!(intercept.abs() <= 0.0001); + Some((min, params, errors[1..].to_vec())) +} + impl Analysis { // Useful for when there are no components, and we just need an median value of the benchmark // results. Note: We choose the median value because it is more robust to outliers. @@ -91,15 +212,17 @@ impl Analysis { }) .collect(); - values.sort_unstable(); + values.sort(); let mid = values.len() / 2; Some(Self { - base: values[mid], + base: selector.scale_weight(values[mid]), slopes: Vec::new(), names: Vec::new(), value_dists: None, - model: None, + errors: None, + minimum: selector.get_minimum(&r), + selector, }) } @@ -186,15 +309,20 @@ impl Analysis { }) .collect::>(); - let base = models[0].0.max(0f64) as u128; - let slopes = models.iter().map(|x| x.1.max(0f64) as u128).collect::>(); + let base = selector.scale_and_cast_weight(models[0].0.max(0f64), false); + let slopes = models + .iter() + .map(|x| selector.scale_and_cast_weight(x.1.max(0f64), false)) + .collect::>(); Some(Self { base, slopes, names: results.into_iter().map(|x| x.0).collect::>(), value_dists: None, - model: None, + errors: None, + minimum: selector.get_minimum(&r), + selector, }) } @@ -216,41 +344,12 @@ impl Analysis { } for (_, rs) in results.iter_mut() { - rs.sort_unstable(); + rs.sort(); let ql = rs.len() / 4; *rs = rs[ql..rs.len() - ql].to_vec(); } - let mut data = - vec![("Y", results.iter().flat_map(|x| x.1.iter().map(|v| *v as f64)).collect())]; - let names = r[0].components.iter().map(|x| format!("{:?}", x.0)).collect::>(); - data.extend(names.iter().enumerate().map(|(i, p)| { - ( - p.as_str(), - results - .iter() - .flat_map(|x| Some(x.0[i] as f64).into_iter().cycle().take(x.1.len())) - .collect::>(), - ) - })); - - let data = RegressionDataBuilder::new().build_from(data).ok()?; - - let model = FormulaRegressionBuilder::new() - .data(&data) - .formula(format!("Y ~ {}", names.join(" + "))) - .fit() - .ok()?; - - let slopes = model - .parameters - .regressor_values - .iter() - .enumerate() - .map(|(_, x)| (*x + 0.5) as u128) - .collect(); - let value_dists = results .iter() .map(|(p, vs)| { @@ -269,12 +368,34 @@ impl Analysis { }) .collect::>(); + let mut ys: Vec = Vec::new(); + let mut xs: Vec = Vec::new(); + for result in results { + let x: Vec = result.0.iter().map(|value| *value as f64).collect(); + for y in result.1 { + xs.extend(x.iter().copied()); + ys.push(y as f64); + } + } + + let (intercept, slopes, errors) = linear_regression(xs, ys, r[0].components.len())?; + Some(Self { - base: (model.parameters.intercept_value + 0.5) as u128, - slopes, + base: selector.scale_and_cast_weight(intercept, true), + slopes: slopes + .into_iter() + .map(|value| selector.scale_and_cast_weight(value, true)) + .collect(), names, value_dists: Some(value_dists), - model: Some(model), + errors: Some( + errors + .into_iter() + .map(|value| selector.scale_and_cast_weight(value, false)) + .collect(), + ), + minimum: selector.get_minimum(&r), + selector, }) } @@ -304,9 +425,10 @@ impl Analysis { .for_each(|(a, b)| assert!(a == b, "benchmark results not in the same order")); let names = median_slopes.names; let value_dists = min_squares.value_dists; - let model = min_squares.model; + let errors = min_squares.errors; + let minimum = selector.get_minimum(&r); - Some(Self { base, slopes, names, value_dists, model }) + Some(Self { base, slopes, names, value_dists, errors, selector, minimum }) } } @@ -363,18 +485,19 @@ impl std::fmt::Display for Analysis { } } } - if let Some(ref model) = self.model { + + if let Some(ref errors) = self.errors { writeln!(f, "\nQuality and confidence:")?; writeln!(f, "param error")?; - for (p, se) in self.names.iter().zip(model.se.regressor_values.iter()) { - writeln!(f, "{} {:>8}", p, ms(*se as u128))?; + for (p, se) in self.names.iter().zip(errors.iter()) { + writeln!(f, "{} {:>8}", p, ms(self.selector.nanos_from_weight(*se)))?; } } writeln!(f, "\nModel:")?; - writeln!(f, "Time ~= {:>8}", ms(self.base))?; + writeln!(f, "Time ~= {:>8}", ms(self.selector.nanos_from_weight(self.base)))?; for (&t, n) in self.slopes.iter().zip(self.names.iter()) { - writeln!(f, " + {} {:>8}", n, ms(t))?; + writeln!(f, " + {} {:>8}", n, ms(self.selector.nanos_from_weight(t)))?; } writeln!(f, " µs") } @@ -415,6 +538,52 @@ mod tests { } } + #[test] + fn test_linear_regression() { + let ys = vec![ + 3797981.0, + 37857779.0, + 70569402.0, + 104004114.0, + 137233924.0, + 169826237.0, + 203521133.0, + 237552333.0, + 271082065.0, + 305554637.0, + 335218347.0, + 371759065.0, + 405086197.0, + 438353555.0, + 472891417.0, + 505339532.0, + 527784778.0, + 562590596.0, + 635291991.0, + 673027090.0, + 708119408.0, + ]; + let xs = vec![ + 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, + 16.0, 17.0, 18.0, 19.0, 20.0, + ]; + + let (intercept, params, errors) = raw_linear_regression(&xs, &ys, 1, true).unwrap(); + assert_eq!(intercept as i64, -2712997); + assert_eq!(params.len(), 1); + assert_eq!(params[0] as i64, 34444926); + assert_eq!(errors.len(), 2); + assert_eq!(errors[0] as i64, 4805766); + assert_eq!(errors[1] as i64, 411084); + + let (intercept, params, errors) = linear_regression(xs, ys, 1).unwrap(); + assert_eq!(intercept as i64, 3797981); + assert_eq!(params.len(), 1); + assert_eq!(params[0] as i64, 33968513); + assert_eq!(errors.len(), 1); + assert_eq!(errors[0] as i64, 217331); + } + #[test] fn analysis_median_slopes_should_work() { let data = vec![ @@ -478,8 +647,8 @@ mod tests { let extrinsic_time = Analysis::median_slopes(&data, BenchmarkSelector::ExtrinsicTime).unwrap(); - assert_eq!(extrinsic_time.base, 10_000_000); - assert_eq!(extrinsic_time.slopes, vec![1_000_000, 100_000]); + assert_eq!(extrinsic_time.base, 10_000_000_000); + assert_eq!(extrinsic_time.slopes, vec![1_000_000_000, 100_000_000]); let reads = Analysis::median_slopes(&data, BenchmarkSelector::Reads).unwrap(); assert_eq!(reads.base, 2); @@ -553,8 +722,8 @@ mod tests { let extrinsic_time = Analysis::min_squares_iqr(&data, BenchmarkSelector::ExtrinsicTime).unwrap(); - assert_eq!(extrinsic_time.base, 10_000_000); - assert_eq!(extrinsic_time.slopes, vec![1_000_000, 100_000]); + assert_eq!(extrinsic_time.base, 10_000_000_000); + assert_eq!(extrinsic_time.slopes, vec![1000000000, 100000000]); let reads = Analysis::min_squares_iqr(&data, BenchmarkSelector::Reads).unwrap(); assert_eq!(reads.base, 2); @@ -564,4 +733,19 @@ mod tests { assert_eq!(writes.base, 0); assert_eq!(writes.slopes, vec![0, 2]); } + + #[test] + fn analysis_min_squares_iqr_uses_multiple_samples_for_same_parameters() { + let data = vec![ + benchmark_result(vec![(BenchmarkParameter::n, 0)], 2_000_000, 0, 0, 0), + benchmark_result(vec![(BenchmarkParameter::n, 0)], 4_000_000, 0, 0, 0), + benchmark_result(vec![(BenchmarkParameter::n, 1)], 4_000_000, 0, 0, 0), + benchmark_result(vec![(BenchmarkParameter::n, 1)], 8_000_000, 0, 0, 0), + ]; + + let extrinsic_time = + Analysis::min_squares_iqr(&data, BenchmarkSelector::ExtrinsicTime).unwrap(); + assert_eq!(extrinsic_time.base, 3_000_000_000); + assert_eq!(extrinsic_time.slopes, vec![3_000_000_000]); + } } diff --git a/frame/benchmarking/src/baseline.rs b/frame/benchmarking/src/baseline.rs index 1ceb9a4f8904c..5fd845551daca 100644 --- a/frame/benchmarking/src/baseline.rs +++ b/frame/benchmarking/src/baseline.rs @@ -90,7 +90,7 @@ benchmarks! { } sr25519_verification { - let i in 1 .. 100; + let i in 0 .. 100; let public = SignerId::generate_pair(None); @@ -176,16 +176,16 @@ pub mod mock { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = AccountIndex; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type Version = (); type PalletInfo = PalletInfo; diff --git a/frame/benchmarking/src/lib.rs b/frame/benchmarking/src/lib.rs index 18472595f15b9..a221eccb82c85 100644 --- a/frame/benchmarking/src/lib.rs +++ b/frame/benchmarking/src/lib.rs @@ -30,7 +30,7 @@ mod utils; pub mod baseline; #[cfg(feature = "std")] -pub use analysis::{Analysis, AnalysisChoice, BenchmarkSelector, RegressionModel}; +pub use analysis::{Analysis, AnalysisChoice, BenchmarkSelector}; #[doc(hidden)] pub use frame_support; #[doc(hidden)] @@ -86,12 +86,12 @@ macro_rules! whitelist { /// ``` /// /// Note that due to parsing restrictions, if the `from` expression is not a single token (i.e. a -/// literal or constant), then it must be parenthesised. +/// literal or constant), then it must be parenthesized. /// /// The macro allows for a number of "arms", each representing an individual benchmark. Using the /// simple syntax, the associated dispatchable function maps 1:1 with the benchmark and the name of /// the benchmark is the same as that of the associated function. However, extended syntax allows -/// for arbitrary expresions to be evaluated in a benchmark (including for example, +/// for arbitrary expressions to be evaluated in a benchmark (including for example, /// `on_initialize`). /// /// Note that the ranges are *inclusive* on both sides. This is in contrast to ranges in Rust which @@ -112,14 +112,14 @@ macro_rules! whitelist { /// foo { /// let caller = account::(b"caller", 0, benchmarks_seed); /// let l in 1 .. MAX_LENGTH => initialize_l(l); -/// }: _(Origin::Signed(caller), vec![0u8; l]) +/// }: _(RuntimeOrigin::Signed(caller), vec![0u8; l]) /// /// // second dispatchable: bar; this is a root dispatchable and accepts a `u8` vector of size /// // `l`. /// // In this case, we explicitly name the call using `bar` instead of `_`. /// bar { /// let l in 1 .. MAX_LENGTH => initialize_l(l); -/// }: bar(Origin::Root, vec![0u8; l]) +/// }: bar(RuntimeOrigin::Root, vec![0u8; l]) /// /// // third dispatchable: baz; this is a user dispatchable. It isn't dependent on length like the /// // other two but has its own complexity `c` that needs setting up. It uses `caller` (in the @@ -128,20 +128,20 @@ macro_rules! whitelist { /// baz1 { /// let caller = account::(b"caller", 0, benchmarks_seed); /// let c = 0 .. 10 => setup_c(&caller, c); -/// }: baz(Origin::Signed(caller)) +/// }: baz(RuntimeOrigin::Signed(caller)) /// /// // this is a second benchmark of the baz dispatchable with a different setup. /// baz2 { /// let caller = account::(b"caller", 0, benchmarks_seed); /// let c = 0 .. 10 => setup_c_in_some_other_way(&caller, c); -/// }: baz(Origin::Signed(caller)) +/// }: baz(RuntimeOrigin::Signed(caller)) /// /// // You may optionally specify the origin type if it can't be determined automatically like /// // this. /// baz3 { /// let caller = account::(b"caller", 0, benchmarks_seed); /// let l in 1 .. MAX_LENGTH => initialize_l(l); -/// }: baz(Origin::Signed(caller), vec![0u8; l]) +/// }: baz(RuntimeOrigin::Signed(caller), vec![0u8; l]) /// /// // this is benchmarking some code that is not a dispatchable. /// populate_a_set { @@ -617,7 +617,7 @@ macro_rules! to_origin { $origin.into() }; ($origin:expr, $origin_type:ty) => { - <::Origin as From<$origin_type>>::from($origin) + <::RuntimeOrigin as From<$origin_type>>::from($origin) }; } @@ -975,6 +975,8 @@ macro_rules! impl_benchmark { ( $( $name_extra:ident ),* ) ( $( $name_skip_meta:ident ),* ) ) => { + // We only need to implement benchmarks for the runtime-benchmarks feature or testing. + #[cfg(any(feature = "runtime-benchmarks", test))] impl, $instance: $instance_bound )? > $crate::Benchmarking for Pallet where T: frame_system::Config, $( $where_clause )* @@ -1693,13 +1695,13 @@ pub fn show_benchmark_debug_info( /// use frame_benchmarking::TrackedStorageKey; /// let whitelist: Vec = vec![ /// // Block Number -/// hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(), +/// array_bytes::hex_into_unchecked("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac"), /// // Total Issuance -/// hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(), +/// array_bytes::hex_into_unchecked("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80"), /// // Execution Phase -/// hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(), +/// array_bytes::hex_into_unchecked("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a"), /// // Event Count -/// hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(), +/// array_bytes::hex_into_unchecked("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850"), /// ]; /// ``` /// diff --git a/frame/benchmarking/src/tests.rs b/frame/benchmarking/src/tests.rs index b8a888767bf2c..88a7d6d0286b2 100644 --- a/frame/benchmarking/src/tests.rs +++ b/frame/benchmarking/src/tests.rs @@ -36,7 +36,7 @@ mod pallet_test { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(_); + pub struct Pallet(PhantomData); #[pallet::config] pub trait Config: frame_system::Config { @@ -46,21 +46,21 @@ mod pallet_test { } #[pallet::storage] - #[pallet::getter(fn heartbeat_after)] + #[pallet::getter(fn value)] pub(crate) type Value = StorageValue<_, u32, OptionQuery>; #[pallet::call] impl Pallet { #[pallet::weight(0)] pub fn set_value(origin: OriginFor, n: u32) -> DispatchResult { - let _sender = frame_system::ensure_signed(origin)?; + let _sender = ensure_signed(origin)?; Value::::put(n); Ok(()) } #[pallet::weight(0)] pub fn dummy(origin: OriginFor, _n: u32) -> DispatchResult { - let _sender = frame_system::ensure_none(origin)?; + let _sender = ensure_none(origin)?; Ok(()) } @@ -90,16 +90,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type Version = (); type PalletInfo = PalletInfo; @@ -148,7 +148,7 @@ mod benchmarks { crate::benchmarks! { where_clause { where - crate::tests::Origin: From::AccountId>>, + crate::tests::RuntimeOrigin: From::AccountId>>, } set_value { diff --git a/frame/benchmarking/src/tests_instance.rs b/frame/benchmarking/src/tests_instance.rs index ef8351d37e957..7e1cd48840687 100644 --- a/frame/benchmarking/src/tests_instance.rs +++ b/frame/benchmarking/src/tests_instance.rs @@ -28,48 +28,52 @@ use sp_runtime::{ }; use sp_std::prelude::*; +#[frame_support::pallet] mod pallet_test { - use frame_support::pallet_prelude::Get; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; - frame_support::decl_storage! { - trait Store for Module, I: Instance = DefaultInstance> as Test where - ::OtherEvent: Into<>::Event> - { - pub Value get(fn value): Option; - } - } - - frame_support::decl_module! { - pub struct Module, I: Instance = DefaultInstance> for enum Call where - origin: T::Origin, ::OtherEvent: Into<>::Event> - { - #[weight = 0] - fn set_value(origin, n: u32) -> frame_support::dispatch::DispatchResult { - let _sender = frame_system::ensure_signed(origin)?; - Value::::put(n); - Ok(()) - } - - #[weight = 0] - fn dummy(origin, _n: u32) -> frame_support::dispatch::DispatchResult { - let _sender = frame_system::ensure_none(origin)?; - Ok(()) - } - } - } + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(PhantomData<(T, I)>); pub trait OtherConfig { type OtherEvent; } - pub trait Config: frame_system::Config + OtherConfig - where - Self::OtherEvent: Into<>::Event>, - { - type Event; + #[pallet::config] + pub trait Config: frame_system::Config + OtherConfig { + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; type LowerBound: Get; type UpperBound: Get; } + + #[pallet::storage] + #[pallet::getter(fn value)] + pub(crate) type Value, I: 'static = ()> = StorageValue<_, u32, OptionQuery>; + + #[pallet::event] + pub enum Event, I: 'static = ()> {} + + #[pallet::call] + impl, I: 'static> Pallet + where + ::OtherEvent: Into<>::RuntimeEvent>, + { + #[pallet::weight(0)] + pub fn set_value(origin: OriginFor, n: u32) -> DispatchResult { + let _sender = ensure_signed(origin)?; + Value::::put(n); + Ok(()) + } + + #[pallet::weight(0)] + pub fn dummy(origin: OriginFor, _n: u32) -> DispatchResult { + let _sender = ensure_none(origin)?; + Ok(()) + } + } } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; @@ -82,7 +86,7 @@ frame_support::construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic, { System: frame_system::{Pallet, Call, Config, Storage, Event}, - TestPallet: pallet_test::{Pallet, Call, Storage}, + TestPallet: pallet_test::{Pallet, Call, Storage, Event}, } ); @@ -90,18 +94,18 @@ impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); + type DbWeight = (); type Version = (); type PalletInfo = PalletInfo; type AccountData = (); @@ -110,17 +114,17 @@ impl frame_system::Config for Test { type SystemWeightInfo = (); type SS58Prefix = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = ConstU32<16>; } impl pallet_test::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type LowerBound = ConstU32<1>; type UpperBound = ConstU32<100>; } impl pallet_test::OtherConfig for Test { - type OtherEvent = Event; + type OtherEvent = RuntimeEvent; } fn new_test_ext() -> sp_io::TestExternalities { @@ -130,20 +134,19 @@ fn new_test_ext() -> sp_io::TestExternalities { mod benchmarks { use super::pallet_test::{self, Value}; use crate::account; - use frame_support::{ensure, StorageValue}; + use frame_support::ensure; use frame_system::RawOrigin; use sp_std::prelude::*; // Additional used internally by the benchmark macro. use super::pallet_test::{Call, Config, Pallet}; - use frame_support::traits::Instance; - crate::benchmarks_instance! { + crate::benchmarks_instance_pallet! { where_clause { where ::OtherEvent: Clone - + Into<>::Event>, - >::Event: Clone, + + Into<>::RuntimeEvent>, + >::RuntimeEvent: Clone, } set_value { @@ -151,7 +154,7 @@ mod benchmarks { let caller = account::("caller", 0, 0); }: _ (RawOrigin::Signed(caller), b.into()) verify { - assert_eq!(Value::::get(), Some(b)); + assert_eq!(Value::::get(), Some(b)); } other_name { diff --git a/frame/benchmarking/src/utils.rs b/frame/benchmarking/src/utils.rs index b483208e3ef69..753e8c1c684ee 100644 --- a/frame/benchmarking/src/utils.rs +++ b/frame/benchmarking/src/utils.rs @@ -23,14 +23,14 @@ use frame_support::{ traits::StorageInfo, }; #[cfg(feature = "std")] -use serde::Serialize; +use serde::{Deserialize, Serialize}; use sp_io::hashing::blake2_256; use sp_runtime::traits::TrailingZeroInput; use sp_std::{prelude::Box, vec::Vec}; use sp_storage::TrackedStorageKey; /// An alphabet of possible parameters to use for benchmarking. -#[cfg_attr(feature = "std", derive(Serialize))] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[derive(Encode, Decode, Clone, Copy, PartialEq, Debug)] #[allow(missing_docs)] #[allow(non_camel_case_types)] @@ -71,7 +71,7 @@ impl std::fmt::Display for BenchmarkParameter { } /// The results of a single of benchmark. -#[cfg_attr(feature = "std", derive(Serialize))] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[derive(Encode, Decode, Clone, PartialEq, Debug)] pub struct BenchmarkBatch { /// The pallet containing this benchmark. @@ -89,7 +89,7 @@ pub struct BenchmarkBatch { // TODO: could probably make API cleaner here. /// The results of a single of benchmark, where time and db results are separated. -#[cfg_attr(feature = "std", derive(Serialize))] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[derive(Encode, Decode, Clone, PartialEq, Debug)] pub struct BenchmarkBatchSplitResults { /// The pallet containing this benchmark. @@ -110,7 +110,7 @@ pub struct BenchmarkBatchSplitResults { /// Result from running benchmarks on a FRAME pallet. /// Contains duration of the function call in nanoseconds along with the benchmark parameters /// used for that benchmark result. -#[cfg_attr(feature = "std", derive(Serialize))] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[derive(Encode, Decode, Default, Clone, PartialEq, Debug)] pub struct BenchmarkResult { pub components: Vec<(BenchmarkParameter, u32)>, @@ -121,7 +121,7 @@ pub struct BenchmarkResult { pub writes: u32, pub repeat_writes: u32, pub proof_size: u32, - #[cfg_attr(feature = "std", serde(skip_serializing))] + #[cfg_attr(feature = "std", serde(skip))] pub keys: Vec<(Vec, u32, u32, bool)>, } @@ -141,6 +141,14 @@ mod serde_as_str { let s = std::str::from_utf8(value).map_err(serde::ser::Error::custom)?; serializer.collect_str(s) } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: serde::de::Deserializer<'de>, + { + let s: &str = serde::de::Deserialize::deserialize(deserializer)?; + Ok(s.into()) + } } /// Possible errors returned from the benchmarking pipeline. diff --git a/frame/bounties/Cargo.toml b/frame/bounties/Cargo.toml index 645772fb27669..4aaf088abb5b6 100644 --- a/frame/bounties/Cargo.toml +++ b/frame/bounties/Cargo.toml @@ -33,6 +33,7 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/bounties/src/benchmarking.rs b/frame/bounties/src/benchmarking.rs index 0c8c875dc611c..07dd781c29af3 100644 --- a/frame/bounties/src/benchmarking.rs +++ b/frame/bounties/src/benchmarking.rs @@ -82,7 +82,7 @@ fn setup_pot_account, I: 'static>() { let _ = T::Currency::make_free_balance_be(&pot_account, value); } -fn assert_last_event, I: 'static>(generic_event: >::Event) { +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } @@ -98,7 +98,7 @@ benchmarks_instance_pallet! { Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; let approve_origin = T::ApproveOrigin::successful_origin(); - }: _(approve_origin, bounty_id) + }: _(approve_origin, bounty_id) propose_curator { setup_pot_account::(); @@ -110,7 +110,7 @@ benchmarks_instance_pallet! { Bounties::::approve_bounty(approve_origin, bounty_id)?; Treasury::::on_initialize(T::BlockNumber::zero()); let approve_origin = T::ApproveOrigin::successful_origin(); - }: _(approve_origin, bounty_id, curator_lookup, fee) + }: _(approve_origin, bounty_id, curator_lookup, fee) // Worst case when curator is inactive and any sender unassigns the curator. unassign_curator { @@ -171,7 +171,7 @@ benchmarks_instance_pallet! { Bounties::::propose_bounty(RawOrigin::Signed(caller).into(), value, reason)?; let bounty_id = BountyCount::::get() - 1; let approve_origin = T::ApproveOrigin::successful_origin(); - }: close_bounty(approve_origin, bounty_id) + }: close_bounty(approve_origin, bounty_id) close_bounty_active { setup_pot_account::(); @@ -179,7 +179,7 @@ benchmarks_instance_pallet! { Treasury::::on_initialize(T::BlockNumber::zero()); let bounty_id = BountyCount::::get() - 1; let approve_origin = T::ApproveOrigin::successful_origin(); - }: close_bounty(approve_origin, bounty_id) + }: close_bounty(approve_origin, bounty_id) verify { assert_last_event::(Event::BountyCanceled { index: bounty_id }.into()) } @@ -197,7 +197,7 @@ benchmarks_instance_pallet! { } spend_funds { - let b in 1 .. 100; + let b in 0 .. 100; setup_pot_account::(); create_approved_bounties::(b)?; @@ -214,9 +214,13 @@ benchmarks_instance_pallet! { ); } verify { - ensure!(budget_remaining < BalanceOf::::max_value(), "Budget not used"); ensure!(missed_any == false, "Missed some"); - assert_last_event::(Event::BountyBecameActive { index: b - 1 }.into()) + if b > 0 { + ensure!(budget_remaining < BalanceOf::::max_value(), "Budget not used"); + assert_last_event::(Event::BountyBecameActive { index: b - 1 }.into()) + } else { + ensure!(budget_remaining == BalanceOf::::max_value(), "Budget used"); + } } impl_benchmark_test_suite!(Bounties, crate::tests::new_test_ext(), crate::tests::Test) diff --git a/frame/bounties/src/lib.rs b/frame/bounties/src/lib.rs index 74e67b7ea5b92..d947226f87fa0 100644 --- a/frame/bounties/src/lib.rs +++ b/frame/bounties/src/lib.rs @@ -230,7 +230,8 @@ pub mod pallet { type DataDepositPerByte: Get>; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Maximum acceptable reason length. /// @@ -818,7 +819,7 @@ impl, I: 'static> Pallet { value: BalanceOf, ) -> DispatchResult { let bounded_description: BoundedVec<_, _> = - description.try_into().map_err(|()| Error::::ReasonTooBig)?; + description.try_into().map_err(|_| Error::::ReasonTooBig)?; ensure!(value >= T::BountyValueMinimum::get(), Error::::InvalidValue); let index = Self::bounty_count(); diff --git a/frame/bounties/src/tests.rs b/frame/bounties/src/tests.rs index b4ce039b35fbc..68aa56ccdde7f 100644 --- a/frame/bounties/src/tests.rs +++ b/frame/bounties/src/tests.rs @@ -21,7 +21,6 @@ use super::*; use crate as pallet_bounties; -use std::cell::RefCell; use frame_support::{ assert_noop, assert_ok, @@ -69,16 +68,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u128; // u64 is not enough to hold bytes used to generate bounty account type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -96,15 +95,12 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } -thread_local! { - static TEN_TO_FOURTEEN: RefCell> = RefCell::new(vec![10,11,12,13,14]); -} parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub static Burn: Permill = Permill::from_percent(50); @@ -117,7 +113,7 @@ impl pallet_treasury::Config for Test { type Currency = pallet_balances::Pallet; type ApproveOrigin = frame_system::EnsureRoot; type RejectOrigin = frame_system::EnsureRoot; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ConstU64<1>; @@ -136,7 +132,7 @@ impl pallet_treasury::Config for Test { type Currency = pallet_balances::Pallet; type ApproveOrigin = frame_system::EnsureRoot; type RejectOrigin = frame_system::EnsureRoot; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ConstU64<1>; @@ -159,7 +155,7 @@ parameter_types! { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BountyDepositBase = ConstU64<80>; type BountyDepositPayoutDelay = ConstU64<3>; type BountyUpdatePeriod = ConstU64<20>; @@ -174,7 +170,7 @@ impl Config for Test { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BountyDepositBase = ConstU64<80>; type BountyDepositPayoutDelay = ConstU64<3>; type BountyUpdatePeriod = ConstU64<20>; @@ -208,7 +204,7 @@ fn last_event() -> BountiesEvent { System::events() .into_iter() .map(|r| r.event) - .filter_map(|e| if let Event::Bounties(inner) = e { Some(inner) } else { None }) + .filter_map(|e| if let RuntimeEvent::Bounties(inner) = e { Some(inner) } else { None }) .last() .unwrap() } @@ -233,7 +229,7 @@ fn minting_works() { #[test] fn spend_proposal_takes_min_deposit() { new_test_ext().execute_with(|| { - assert_ok!(Treasury::propose_spend(Origin::signed(0), 1, 3)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 1, 3)); assert_eq!(Balances::free_balance(0), 99); assert_eq!(Balances::reserved_balance(0), 1); }); @@ -242,7 +238,7 @@ fn spend_proposal_takes_min_deposit() { #[test] fn spend_proposal_takes_proportional_deposit() { new_test_ext().execute_with(|| { - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); assert_eq!(Balances::free_balance(0), 95); assert_eq!(Balances::reserved_balance(0), 5); }); @@ -252,7 +248,7 @@ fn spend_proposal_takes_proportional_deposit() { fn spend_proposal_fails_when_proposer_poor() { new_test_ext().execute_with(|| { assert_noop!( - Treasury::propose_spend(Origin::signed(2), 100, 3), + Treasury::propose_spend(RuntimeOrigin::signed(2), 100, 3), TreasuryError::InsufficientProposersBalance, ); }); @@ -263,8 +259,8 @@ fn accepted_spend_proposal_ignored_outside_spend_period() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(1); assert_eq!(Balances::free_balance(3), 0); @@ -290,8 +286,8 @@ fn rejected_spend_proposal_ignored_on_spend_period() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::reject_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::reject_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(2); assert_eq!(Balances::free_balance(3), 0); @@ -304,9 +300,12 @@ fn reject_already_rejected_spend_proposal_fails() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::reject_proposal(Origin::root(), 0)); - assert_noop!(Treasury::reject_proposal(Origin::root(), 0), TreasuryError::InvalidIndex); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::reject_proposal(RuntimeOrigin::root(), 0)); + assert_noop!( + Treasury::reject_proposal(RuntimeOrigin::root(), 0), + TreasuryError::InvalidIndex + ); }); } @@ -314,7 +313,7 @@ fn reject_already_rejected_spend_proposal_fails() { fn reject_non_existent_spend_proposal_fails() { new_test_ext().execute_with(|| { assert_noop!( - Treasury::reject_proposal(Origin::root(), 0), + Treasury::reject_proposal(RuntimeOrigin::root(), 0), pallet_treasury::Error::::InvalidIndex ); }); @@ -323,7 +322,10 @@ fn reject_non_existent_spend_proposal_fails() { #[test] fn accept_non_existent_spend_proposal_fails() { new_test_ext().execute_with(|| { - assert_noop!(Treasury::approve_proposal(Origin::root(), 0), TreasuryError::InvalidIndex); + assert_noop!( + Treasury::approve_proposal(RuntimeOrigin::root(), 0), + TreasuryError::InvalidIndex + ); }); } @@ -332,9 +334,12 @@ fn accept_already_rejected_spend_proposal_fails() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::reject_proposal(Origin::root(), 0)); - assert_noop!(Treasury::approve_proposal(Origin::root(), 0), TreasuryError::InvalidIndex); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::reject_proposal(RuntimeOrigin::root(), 0)); + assert_noop!( + Treasury::approve_proposal(RuntimeOrigin::root(), 0), + TreasuryError::InvalidIndex + ); }); } @@ -344,8 +349,8 @@ fn accepted_spend_proposal_enacted_on_spend_period() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(2); assert_eq!(Balances::free_balance(3), 100); @@ -359,8 +364,8 @@ fn pot_underflow_should_not_diminish() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 150, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 150, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(2); assert_eq!(Treasury::pot(), 100); // Pot hasn't changed @@ -381,14 +386,14 @@ fn treasury_account_doesnt_get_deleted() { assert_eq!(Treasury::pot(), 100); let treasury_balance = Balances::free_balance(&Treasury::account_id()); - assert_ok!(Treasury::propose_spend(Origin::signed(0), treasury_balance, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), treasury_balance, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(2); assert_eq!(Treasury::pot(), 100); // Pot hasn't changed - assert_ok!(Treasury::propose_spend(Origin::signed(0), Treasury::pot(), 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 1)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), Treasury::pot(), 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 1)); >::on_initialize(4); assert_eq!(Treasury::pot(), 0); // Pot is emptied @@ -411,10 +416,10 @@ fn inexistent_account_works() { assert_eq!(Balances::free_balance(Treasury::account_id()), 0); // Account does not exist assert_eq!(Treasury::pot(), 0); // Pot is empty - assert_ok!(Treasury::propose_spend(Origin::signed(0), 99, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 1, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 1)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 99, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 1, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 1)); >::on_initialize(2); assert_eq!(Treasury::pot(), 0); // Pot hasn't changed assert_eq!(Balances::free_balance(3), 0); // Balance of `3` hasn't changed @@ -438,7 +443,7 @@ fn propose_bounty_works() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 10, b"1234567890".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 10, b"1234567890".to_vec())); assert_eq!(last_event(), BountiesEvent::BountyProposed { index: 0 }); @@ -473,17 +478,21 @@ fn propose_bounty_validation_works() { assert_eq!(Treasury::pot(), 100); assert_noop!( - Bounties::propose_bounty(Origin::signed(1), 0, [0; 17_000].to_vec()), + Bounties::propose_bounty(RuntimeOrigin::signed(1), 0, [0; 17_000].to_vec()), Error::::ReasonTooBig ); assert_noop!( - Bounties::propose_bounty(Origin::signed(1), 10, b"12345678901234567890".to_vec()), + Bounties::propose_bounty( + RuntimeOrigin::signed(1), + 10, + b"12345678901234567890".to_vec() + ), Error::::InsufficientProposersBalance ); assert_noop!( - Bounties::propose_bounty(Origin::signed(1), 0, b"12345678901234567890".to_vec()), + Bounties::propose_bounty(RuntimeOrigin::signed(1), 0, b"12345678901234567890".to_vec()), Error::::InvalidValue ); }); @@ -494,11 +503,11 @@ fn close_bounty_works() { new_test_ext().execute_with(|| { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_noop!(Bounties::close_bounty(Origin::root(), 0), Error::::InvalidIndex); + assert_noop!(Bounties::close_bounty(RuntimeOrigin::root(), 0), Error::::InvalidIndex); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 10, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 10, b"12345".to_vec())); - assert_ok!(Bounties::close_bounty(Origin::root(), 0)); + assert_ok!(Bounties::close_bounty(RuntimeOrigin::root(), 0)); let deposit: u64 = 80 + 5; @@ -519,11 +528,14 @@ fn approve_bounty_works() { new_test_ext().execute_with(|| { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_noop!(Bounties::approve_bounty(Origin::root(), 0), Error::::InvalidIndex); + assert_noop!( + Bounties::approve_bounty(RuntimeOrigin::root(), 0), + Error::::InvalidIndex + ); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); let deposit: u64 = 80 + 5; @@ -540,7 +552,10 @@ fn approve_bounty_works() { ); assert_eq!(Bounties::bounty_approvals(), vec![0]); - assert_noop!(Bounties::close_bounty(Origin::root(), 0), Error::::UnexpectedStatus); + assert_noop!( + Bounties::close_bounty(RuntimeOrigin::root(), 0), + Error::::UnexpectedStatus + ); // deposit not returned yet assert_eq!(Balances::reserved_balance(0), deposit); @@ -576,24 +591,24 @@ fn assign_curator_works() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_noop!( - Bounties::propose_curator(Origin::root(), 0, 4, 4), + Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 4), Error::::InvalidIndex ); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); assert_noop!( - Bounties::propose_curator(Origin::root(), 0, 4, 50), + Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 50), Error::::InvalidFee ); let fee = 4; - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, fee)); assert_eq!( Bounties::bounties(0).unwrap(), @@ -607,15 +622,18 @@ fn assign_curator_works() { } ); - assert_noop!(Bounties::accept_curator(Origin::signed(1), 0), Error::::RequireCurator); assert_noop!( - Bounties::accept_curator(Origin::signed(4), 0), + Bounties::accept_curator(RuntimeOrigin::signed(1), 0), + Error::::RequireCurator + ); + assert_noop!( + Bounties::accept_curator(RuntimeOrigin::signed(4), 0), pallet_balances::Error::::InsufficientBalance ); Balances::make_free_balance_be(&4, 10); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); let expected_deposit = Bounties::calculate_curator_deposit(&fee); @@ -641,18 +659,18 @@ fn unassign_curator_works() { new_test_ext().execute_with(|| { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); let fee = 4; - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); - assert_noop!(Bounties::unassign_curator(Origin::signed(1), 0), BadOrigin); - assert_ok!(Bounties::unassign_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, fee)); + assert_noop!(Bounties::unassign_curator(RuntimeOrigin::signed(1), 0), BadOrigin); + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(4), 0)); assert_eq!( Bounties::bounties(0).unwrap(), @@ -666,11 +684,11 @@ fn unassign_curator_works() { } ); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, fee)); Balances::make_free_balance_be(&4, 10); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); let expected_deposit = Bounties::calculate_curator_deposit(&fee); - assert_ok!(Bounties::unassign_curator(Origin::root(), 0)); + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::root(), 0)); assert_eq!( Bounties::bounties(0).unwrap(), @@ -695,26 +713,26 @@ fn award_and_claim_bounty_works() { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); Balances::make_free_balance_be(&4, 10); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); let fee = 4; - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, fee)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); let expected_deposit = Bounties::calculate_curator_deposit(&fee); assert_eq!(Balances::free_balance(4), 10 - expected_deposit); assert_noop!( - Bounties::award_bounty(Origin::signed(1), 0, 3), + Bounties::award_bounty(RuntimeOrigin::signed(1), 0, 3), Error::::RequireCurator ); - assert_ok!(Bounties::award_bounty(Origin::signed(4), 0, 3)); + assert_ok!(Bounties::award_bounty(RuntimeOrigin::signed(4), 0, 3)); assert_eq!( Bounties::bounties(0).unwrap(), @@ -728,14 +746,18 @@ fn award_and_claim_bounty_works() { } ); - assert_noop!(Bounties::claim_bounty(Origin::signed(1), 0), Error::::Premature); + assert_noop!(Bounties::claim_bounty(RuntimeOrigin::signed(1), 0), Error::::Premature); System::set_block_number(5); >::on_initialize(5); - assert_ok!(Balances::transfer(Origin::signed(0), Bounties::bounty_account_id(0), 10)); + assert_ok!(Balances::transfer( + RuntimeOrigin::signed(0), + Bounties::bounty_account_id(0), + 10 + )); - assert_ok!(Bounties::claim_bounty(Origin::signed(1), 0)); + assert_ok!(Bounties::claim_bounty(RuntimeOrigin::signed(1), 0)); assert_eq!( last_event(), @@ -758,17 +780,17 @@ fn claim_handles_high_fee() { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); Balances::make_free_balance_be(&4, 30); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 49)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 49)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); - assert_ok!(Bounties::award_bounty(Origin::signed(4), 0, 3)); + assert_ok!(Bounties::award_bounty(RuntimeOrigin::signed(4), 0, 3)); System::set_block_number(5); >::on_initialize(5); @@ -777,7 +799,7 @@ fn claim_handles_high_fee() { let res = Balances::slash(&Bounties::bounty_account_id(0), 10); assert_eq!(res.0.peek(), 10); - assert_ok!(Bounties::claim_bounty(Origin::signed(1), 0)); + assert_ok!(Bounties::claim_bounty(RuntimeOrigin::signed(1), 0)); assert_eq!( last_event(), @@ -800,14 +822,18 @@ fn cancel_and_refund() { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Balances::transfer(Origin::signed(0), Bounties::bounty_account_id(0), 10)); + assert_ok!(Balances::transfer( + RuntimeOrigin::signed(0), + Bounties::bounty_account_id(0), + 10 + )); assert_eq!( Bounties::bounties(0).unwrap(), @@ -823,9 +849,9 @@ fn cancel_and_refund() { assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 60); - assert_noop!(Bounties::close_bounty(Origin::signed(0), 0), BadOrigin); + assert_noop!(Bounties::close_bounty(RuntimeOrigin::signed(0), 0), BadOrigin); - assert_ok!(Bounties::close_bounty(Origin::root(), 0)); + assert_ok!(Bounties::close_bounty(RuntimeOrigin::root(), 0)); // `- 25 + 10` assert_eq!(Treasury::pot(), 85); @@ -837,27 +863,30 @@ fn award_and_cancel() { new_test_ext().execute_with(|| { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 0, 10)); - assert_ok!(Bounties::accept_curator(Origin::signed(0), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 0, 10)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(0), 0)); assert_eq!(Balances::free_balance(0), 95); assert_eq!(Balances::reserved_balance(0), 5); - assert_ok!(Bounties::award_bounty(Origin::signed(0), 0, 3)); + assert_ok!(Bounties::award_bounty(RuntimeOrigin::signed(0), 0, 3)); // Cannot close bounty directly when payout is happening... - assert_noop!(Bounties::close_bounty(Origin::root(), 0), Error::::PendingPayout); + assert_noop!( + Bounties::close_bounty(RuntimeOrigin::root(), 0), + Error::::PendingPayout + ); // Instead unassign the curator to slash them and then close. - assert_ok!(Bounties::unassign_curator(Origin::root(), 0)); - assert_ok!(Bounties::close_bounty(Origin::root(), 0)); + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::root(), 0)); + assert_ok!(Bounties::close_bounty(RuntimeOrigin::root(), 0)); assert_eq!(last_event(), BountiesEvent::BountyCanceled { index: 0 }); @@ -877,15 +906,15 @@ fn expire_and_unassign() { new_test_ext().execute_with(|| { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 1, 10)); - assert_ok!(Bounties::accept_curator(Origin::signed(1), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 1, 10)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(1), 0)); assert_eq!(Balances::free_balance(1), 93); assert_eq!(Balances::reserved_balance(1), 5); @@ -893,12 +922,15 @@ fn expire_and_unassign() { System::set_block_number(22); >::on_initialize(22); - assert_noop!(Bounties::unassign_curator(Origin::signed(0), 0), Error::::Premature); + assert_noop!( + Bounties::unassign_curator(RuntimeOrigin::signed(0), 0), + Error::::Premature + ); System::set_block_number(23); >::on_initialize(23); - assert_ok!(Bounties::unassign_curator(Origin::signed(0), 0)); + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(0), 0)); assert_eq!( Bounties::bounties(0).unwrap(), @@ -923,20 +955,20 @@ fn extend_expiry() { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); Balances::make_free_balance_be(&4, 10); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); assert_noop!( - Bounties::extend_bounty_expiry(Origin::signed(1), 0, Vec::new()), + Bounties::extend_bounty_expiry(RuntimeOrigin::signed(1), 0, Vec::new()), Error::::UnexpectedStatus ); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 10)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 10)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); assert_eq!(Balances::free_balance(4), 5); assert_eq!(Balances::reserved_balance(4), 5); @@ -945,10 +977,10 @@ fn extend_expiry() { >::on_initialize(10); assert_noop!( - Bounties::extend_bounty_expiry(Origin::signed(0), 0, Vec::new()), + Bounties::extend_bounty_expiry(RuntimeOrigin::signed(0), 0, Vec::new()), Error::::RequireCurator ); - assert_ok!(Bounties::extend_bounty_expiry(Origin::signed(4), 0, Vec::new())); + assert_ok!(Bounties::extend_bounty_expiry(RuntimeOrigin::signed(4), 0, Vec::new())); assert_eq!( Bounties::bounties(0).unwrap(), @@ -962,7 +994,7 @@ fn extend_expiry() { } ); - assert_ok!(Bounties::extend_bounty_expiry(Origin::signed(4), 0, Vec::new())); + assert_ok!(Bounties::extend_bounty_expiry(RuntimeOrigin::signed(4), 0, Vec::new())); assert_eq!( Bounties::bounties(0).unwrap(), @@ -979,8 +1011,11 @@ fn extend_expiry() { System::set_block_number(25); >::on_initialize(25); - assert_noop!(Bounties::unassign_curator(Origin::signed(0), 0), Error::::Premature); - assert_ok!(Bounties::unassign_curator(Origin::signed(4), 0)); + assert_noop!( + Bounties::unassign_curator(RuntimeOrigin::signed(0), 0), + Error::::Premature + ); + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(4), 0)); assert_eq!(Balances::free_balance(4), 10); // not slashed assert_eq!(Balances::reserved_balance(4), 0); @@ -1053,14 +1088,14 @@ fn unassign_curator_self() { new_test_ext().execute_with(|| { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 1, 10)); - assert_ok!(Bounties::accept_curator(Origin::signed(1), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 1, 10)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(1), 0)); assert_eq!(Balances::free_balance(1), 93); assert_eq!(Balances::reserved_balance(1), 5); @@ -1068,7 +1103,7 @@ fn unassign_curator_self() { System::set_block_number(8); >::on_initialize(8); - assert_ok!(Bounties::unassign_curator(Origin::signed(1), 0)); + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(1), 0)); assert_eq!( Bounties::bounties(0).unwrap(), @@ -1101,14 +1136,14 @@ fn accept_curator_handles_different_deposit_calculations() { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); Balances::make_free_balance_be(&user, 100); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), value, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), bounty_index)); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), value, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), bounty_index)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), bounty_index, user, fee)); - assert_ok!(Bounties::accept_curator(Origin::signed(user), bounty_index)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), bounty_index, user, fee)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(user), bounty_index)); let expected_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!(Balances::free_balance(&user), 100 - expected_deposit); @@ -1123,14 +1158,14 @@ fn accept_curator_handles_different_deposit_calculations() { Balances::make_free_balance_be(&Treasury::account_id(), 101); Balances::make_free_balance_be(&user, 100); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), value, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), bounty_index)); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), value, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), bounty_index)); System::set_block_number(4); >::on_initialize(4); - assert_ok!(Bounties::propose_curator(Origin::root(), bounty_index, user, fee)); - assert_ok!(Bounties::accept_curator(Origin::signed(user), bounty_index)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), bounty_index, user, fee)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(user), bounty_index)); let expected_deposit = CuratorDepositMin::get(); assert_eq!(Balances::free_balance(&user), 100 - expected_deposit); @@ -1147,14 +1182,14 @@ fn accept_curator_handles_different_deposit_calculations() { Balances::make_free_balance_be(&user, starting_balance); Balances::make_free_balance_be(&0, starting_balance); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), value, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), bounty_index)); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), value, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), bounty_index)); System::set_block_number(6); >::on_initialize(6); - assert_ok!(Bounties::propose_curator(Origin::root(), bounty_index, user, fee)); - assert_ok!(Bounties::accept_curator(Origin::signed(user), bounty_index)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), bounty_index, user, fee)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(user), bounty_index)); let expected_deposit = CuratorDepositMax::get(); assert_eq!(Balances::free_balance(&user), starting_balance - expected_deposit); @@ -1174,8 +1209,8 @@ fn approve_bounty_works_second_instance() { assert_eq!(Balances::free_balance(&Treasury::account_id()), 101); assert_eq!(Balances::free_balance(&Treasury1::account_id()), 201); - assert_ok!(Bounties1::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties1::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties1::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties1::approve_bounty(RuntimeOrigin::root(), 0)); >::on_initialize(2); >::on_initialize(2); diff --git a/frame/child-bounties/Cargo.toml b/frame/child-bounties/Cargo.toml index 575f3e38c8183..ee9a838744d25 100644 --- a/frame/child-bounties/Cargo.toml +++ b/frame/child-bounties/Cargo.toml @@ -34,6 +34,7 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/child-bounties/src/benchmarking.rs b/frame/child-bounties/src/benchmarking.rs index ca5af50276b9d..697ed40e0071f 100644 --- a/frame/child-bounties/src/benchmarking.rs +++ b/frame/child-bounties/src/benchmarking.rs @@ -160,7 +160,7 @@ fn setup_pot_account() { let _ = T::Currency::make_free_balance_be(&pot_account, value); } -fn assert_last_event(generic_event: ::Event) { +fn assert_last_event(generic_event: ::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } diff --git a/frame/child-bounties/src/lib.rs b/frame/child-bounties/src/lib.rs index 5f396cd2d4567..2dfe0660ad68e 100644 --- a/frame/child-bounties/src/lib.rs +++ b/frame/child-bounties/src/lib.rs @@ -146,7 +146,7 @@ pub mod pallet { type ChildBountyValueMinimum: Get>; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; diff --git a/frame/child-bounties/src/tests.rs b/frame/child-bounties/src/tests.rs index f42715f14bbee..67983b15f4579 100644 --- a/frame/child-bounties/src/tests.rs +++ b/frame/child-bounties/src/tests.rs @@ -21,7 +21,6 @@ use super::*; use crate as pallet_child_bounties; -use std::cell::RefCell; use frame_support::{ assert_noop, assert_ok, @@ -72,16 +71,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u128; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -99,15 +98,12 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } -thread_local! { - static TEN_TO_FOURTEEN: RefCell> = RefCell::new(vec![10,11,12,13,14]); -} parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub const Burn: Permill = Permill::from_percent(50); @@ -119,7 +115,7 @@ impl pallet_treasury::Config for Test { type Currency = pallet_balances::Pallet; type ApproveOrigin = frame_system::EnsureRoot; type RejectOrigin = frame_system::EnsureRoot; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ConstU64<1>; @@ -140,7 +136,7 @@ parameter_types! { } impl pallet_bounties::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BountyDepositBase = ConstU64<80>; type BountyDepositPayoutDelay = ConstU64<3>; type BountyUpdatePeriod = ConstU64<10>; @@ -154,7 +150,7 @@ impl pallet_bounties::Config for Test { type ChildBountyManager = ChildBounties; } impl pallet_child_bounties::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type MaxActiveChildBountyCount = ConstU32<2>; type ChildBountyValueMinimum = ConstU64<1>; type WeightInfo = (); @@ -176,7 +172,7 @@ fn last_event() -> ChildBountiesEvent { System::events() .into_iter() .map(|r| r.event) - .filter_map(|e| if let Event::ChildBounties(inner) = e { Some(inner) } else { None }) + .filter_map(|e| if let RuntimeEvent::ChildBounties(inner) = e { Some(inner) } else { None }) .last() .unwrap() } @@ -215,19 +211,19 @@ fn add_child_bounty() { System::set_block_number(1); Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); let fee = 8; - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, fee)); Balances::make_free_balance_be(&4, 10); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // This verifies that the accept curator logic took a deposit. let expected_deposit = CuratorDepositMultiplier::get() * fee; @@ -238,7 +234,7 @@ fn add_child_bounty() { // Acc-4 is the parent curator. // Call from invalid origin & check for error "RequireCurator". assert_noop!( - ChildBounties::add_child_bounty(Origin::signed(0), 0, 10, b"12345-p1".to_vec()), + ChildBounties::add_child_bounty(RuntimeOrigin::signed(0), 0, 10, b"12345-p1".to_vec()), BountiesError::RequireCurator, ); @@ -250,17 +246,22 @@ fn add_child_bounty() { assert_eq!(Balances::reserved_balance(Bounties::bounty_account_id(0)), 0); assert_noop!( - ChildBounties::add_child_bounty(Origin::signed(4), 0, 50, b"12345-p1".to_vec()), + ChildBounties::add_child_bounty(RuntimeOrigin::signed(4), 0, 50, b"12345-p1".to_vec()), pallet_balances::Error::::KeepAlive, ); assert_noop!( - ChildBounties::add_child_bounty(Origin::signed(4), 0, 100, b"12345-p1".to_vec()), + ChildBounties::add_child_bounty(RuntimeOrigin::signed(4), 0, 100, b"12345-p1".to_vec()), Error::::InsufficientBountyBalance, ); // Add child-bounty with valid value, which can be funded by parent bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); // Check for the event child-bounty added. assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); @@ -303,16 +304,16 @@ fn child_bounty_assign_curator() { Balances::make_free_balance_be(&4, 101); Balances::make_free_balance_be(&8, 101); - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); let fee = 4; - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, fee)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, fee)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Bounty account status before adding child-bounty. assert_eq!(Balances::free_balance(Bounties::bounty_account_id(0)), 50); @@ -326,7 +327,12 @@ fn child_bounty_assign_curator() { // Add child-bounty. // Acc-4 is the parent curator & make sure enough deposit. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); @@ -339,7 +345,7 @@ fn child_bounty_assign_curator() { assert_eq!(Balances::reserved_balance(ChildBounties::child_bounty_account_id(0)), 0); let fee = 6u64; - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, fee)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, fee)); assert_eq!( ChildBounties::child_bounties(0, 0).unwrap(), @@ -357,11 +363,11 @@ fn child_bounty_assign_curator() { assert_eq!(Balances::reserved_balance(4), expected_deposit); assert_noop!( - ChildBounties::accept_curator(Origin::signed(3), 0, 0), + ChildBounties::accept_curator(RuntimeOrigin::signed(3), 0, 0), BountiesError::RequireCurator, ); - assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); let expected_child_deposit = CuratorDepositMultiplier::get() * fee; @@ -407,34 +413,39 @@ fn award_claim_child_bounty() { Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. Balances::make_free_balance_be(&8, 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); // Propose and accept curator for child-bounty. let fee = 8; - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, fee)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, fee)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); // Award child-bounty. // Test for non child-bounty curator. assert_noop!( - ChildBounties::award_child_bounty(Origin::signed(3), 0, 0, 7), + ChildBounties::award_child_bounty(RuntimeOrigin::signed(3), 0, 0, 7), BountiesError::RequireCurator, ); - assert_ok!(ChildBounties::award_child_bounty(Origin::signed(8), 0, 0, 7)); + assert_ok!(ChildBounties::award_child_bounty(RuntimeOrigin::signed(8), 0, 0, 7)); let expected_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!( @@ -455,13 +466,13 @@ fn award_claim_child_bounty() { // Claim child-bounty. // Test for Premature condition. assert_noop!( - ChildBounties::claim_child_bounty(Origin::signed(7), 0, 0), + ChildBounties::claim_child_bounty(RuntimeOrigin::signed(7), 0, 0), BountiesError::Premature ); System::set_block_number(9); - assert_ok!(ChildBounties::claim_child_bounty(Origin::signed(7), 0, 0)); + assert_ok!(ChildBounties::claim_child_bounty(RuntimeOrigin::signed(7), 0, 0)); // Ensure child-bounty curator is paid with curator fee & deposit refund. assert_eq!(Balances::free_balance(8), 101 + fee); @@ -493,19 +504,24 @@ fn close_child_bounty_added() { Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. Balances::make_free_balance_be(&8, 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); @@ -513,11 +529,11 @@ fn close_child_bounty_added() { // Close child-bounty. // Wrong origin. - assert_noop!(ChildBounties::close_child_bounty(Origin::signed(7), 0, 0), BadOrigin); - assert_noop!(ChildBounties::close_child_bounty(Origin::signed(8), 0, 0), BadOrigin); + assert_noop!(ChildBounties::close_child_bounty(RuntimeOrigin::signed(7), 0, 0), BadOrigin); + assert_noop!(ChildBounties::close_child_bounty(RuntimeOrigin::signed(8), 0, 0), BadOrigin); // Correct origin - parent curator. - assert_ok!(ChildBounties::close_child_bounty(Origin::signed(4), 0, 0)); + assert_ok!(ChildBounties::close_child_bounty(RuntimeOrigin::signed(4), 0, 0)); // Check the child-bounty count. assert_eq!(ChildBounties::parent_child_bounties(0), 0); @@ -545,28 +561,33 @@ fn close_child_bounty_active() { Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. Balances::make_free_balance_be(&8, 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); // Propose and accept curator for child-bounty. - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, 2)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); // Close child-bounty in active state. - assert_ok!(ChildBounties::close_child_bounty(Origin::signed(4), 0, 0)); + assert_ok!(ChildBounties::close_child_bounty(RuntimeOrigin::signed(4), 0, 0)); // Check the child-bounty count. assert_eq!(ChildBounties::parent_child_bounties(0), 0); @@ -598,33 +619,38 @@ fn close_child_bounty_pending() { Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. Balances::make_free_balance_be(&8, 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); let parent_fee = 6; - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, parent_fee)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, parent_fee)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); // Propose and accept curator for child-bounty. let child_fee = 4; - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, child_fee)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, child_fee)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); let expected_child_deposit = CuratorDepositMin::get(); - assert_ok!(ChildBounties::award_child_bounty(Origin::signed(8), 0, 0, 7)); + assert_ok!(ChildBounties::award_child_bounty(RuntimeOrigin::signed(8), 0, 0, 7)); // Close child-bounty in pending_payout state. assert_noop!( - ChildBounties::close_child_bounty(Origin::signed(4), 0, 0), + ChildBounties::close_child_bounty(RuntimeOrigin::signed(4), 0, 0), BountiesError::PendingPayout ); @@ -654,25 +680,30 @@ fn child_bounty_added_unassign_curator() { Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. Balances::make_free_balance_be(&8, 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); // Unassign curator in added state. assert_noop!( - ChildBounties::unassign_curator(Origin::signed(4), 0, 0), + ChildBounties::unassign_curator(RuntimeOrigin::signed(4), 0, 0), BountiesError::UnexpectedStatus ); }); @@ -691,24 +722,29 @@ fn child_bounty_curator_proposed_unassign_curator() { Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. Balances::make_free_balance_be(&8, 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); // Propose curator for child-bounty. - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, 2)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, 2)); assert_eq!( ChildBounties::child_bounties(0, 0).unwrap(), @@ -722,10 +758,10 @@ fn child_bounty_curator_proposed_unassign_curator() { ); // Random account cannot unassign the curator when in proposed state. - assert_noop!(ChildBounties::unassign_curator(Origin::signed(99), 0, 0), BadOrigin); + assert_noop!(ChildBounties::unassign_curator(RuntimeOrigin::signed(99), 0, 0), BadOrigin); // Unassign curator. - assert_ok!(ChildBounties::unassign_curator(Origin::signed(4), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(4), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -763,18 +799,23 @@ fn child_bounty_active_unassign_curator() { Balances::make_free_balance_be(&7, 101); // Child-bounty curator 2. Balances::make_free_balance_be(&8, 101); // Child-bounty curator 3. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Create Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); System::set_block_number(3); @@ -782,8 +823,8 @@ fn child_bounty_active_unassign_curator() { // Propose and accept curator for child-bounty. let fee = 6; - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, fee)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, fee)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); let expected_child_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!( @@ -801,7 +842,7 @@ fn child_bounty_active_unassign_curator() { >::on_initialize(4); // Unassign curator - from reject origin. - assert_ok!(ChildBounties::unassign_curator(Origin::root(), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::root(), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -821,8 +862,8 @@ fn child_bounty_active_unassign_curator() { // Propose and accept curator for child-bounty again. let fee = 2; - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 7, fee)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(7), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 7, fee)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(7), 0, 0)); let expected_child_deposit = CuratorDepositMin::get(); assert_eq!( @@ -840,7 +881,7 @@ fn child_bounty_active_unassign_curator() { >::on_initialize(5); // Unassign curator again - from parent curator. - assert_ok!(ChildBounties::unassign_curator(Origin::signed(4), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(4), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -859,8 +900,8 @@ fn child_bounty_active_unassign_curator() { assert_eq!(Balances::reserved_balance(7), 0); // slashed // Propose and accept curator for child-bounty again. - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 6, 2)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(6), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 6, 2)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(6), 0, 0)); assert_eq!( ChildBounties::child_bounties(0, 0).unwrap(), @@ -877,7 +918,7 @@ fn child_bounty_active_unassign_curator() { >::on_initialize(6); // Unassign curator again - from child-bounty curator. - assert_ok!(ChildBounties::unassign_curator(Origin::signed(6), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(6), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -897,8 +938,8 @@ fn child_bounty_active_unassign_curator() { // Propose and accept curator for child-bounty one last time. let fee = 2; - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 6, fee)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(6), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 6, fee)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(6), 0, 0)); let expected_child_deposit = CuratorDepositMin::get(); assert_eq!( @@ -918,7 +959,7 @@ fn child_bounty_active_unassign_curator() { // Unassign curator again - from non curator; non reject origin; some random guy. // Bounty update period is not yet complete. assert_noop!( - ChildBounties::unassign_curator(Origin::signed(3), 0, 0), + ChildBounties::unassign_curator(RuntimeOrigin::signed(3), 0, 0), BountiesError::Premature ); @@ -926,7 +967,7 @@ fn child_bounty_active_unassign_curator() { >::on_initialize(20); // Unassign child curator from random account after inactivity. - assert_ok!(ChildBounties::unassign_curator(Origin::signed(3), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(3), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -964,17 +1005,22 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { Balances::make_free_balance_be(&7, 101); // Child-bounty curator 2. Balances::make_free_balance_be(&8, 101); // Child-bounty curator 3. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Create Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); System::set_block_number(3); @@ -982,8 +1028,8 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { // Propose and accept curator for child-bounty. let fee = 8; - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, fee)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, fee)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); let expected_child_deposit = CuratorDepositMultiplier::get() * fee; assert_eq!( @@ -1001,7 +1047,7 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { >::on_initialize(4); // Unassign parent bounty curator. - assert_ok!(Bounties::unassign_curator(Origin::root(), 0)); + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::root(), 0)); System::set_block_number(5); >::on_initialize(5); @@ -1009,12 +1055,12 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { // Try unassign child-bounty curator - from non curator; non reject // origin; some random guy. Bounty update period is not yet complete. assert_noop!( - ChildBounties::unassign_curator(Origin::signed(3), 0, 0), + ChildBounties::unassign_curator(RuntimeOrigin::signed(3), 0, 0), Error::::ParentBountyNotActive ); // Unassign curator - from reject origin. - assert_ok!(ChildBounties::unassign_curator(Origin::root(), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::root(), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -1036,16 +1082,16 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { >::on_initialize(6); // Propose and accept curator for parent-bounty again. - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 5, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(5), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 5, 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(5), 0)); System::set_block_number(7); >::on_initialize(7); // Propose and accept curator for child-bounty again. let fee = 2; - assert_ok!(ChildBounties::propose_curator(Origin::signed(5), 0, 0, 7, fee)); - assert_ok!(ChildBounties::accept_curator(Origin::signed(7), 0, 0)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(5), 0, 0, 7, fee)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(7), 0, 0)); let expected_deposit = CuratorDepositMin::get(); assert_eq!( @@ -1063,18 +1109,18 @@ fn parent_bounty_inactive_unassign_curator_child_bounty() { >::on_initialize(8); assert_noop!( - ChildBounties::unassign_curator(Origin::signed(3), 0, 0), + ChildBounties::unassign_curator(RuntimeOrigin::signed(3), 0, 0), BountiesError::Premature ); // Unassign parent bounty curator again. - assert_ok!(Bounties::unassign_curator(Origin::signed(5), 0)); + assert_ok!(Bounties::unassign_curator(RuntimeOrigin::signed(5), 0)); System::set_block_number(9); >::on_initialize(9); // Unassign curator again - from parent curator. - assert_ok!(ChildBounties::unassign_curator(Origin::signed(7), 0, 0)); + assert_ok!(ChildBounties::unassign_curator(RuntimeOrigin::signed(7), 0, 0)); // Verify updated child-bounty status. assert_eq!( @@ -1107,24 +1153,29 @@ fn close_parent_with_child_bounty() { Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. Balances::make_free_balance_be(&8, 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); // Try add child-bounty. // Should fail, parent bounty not active yet. assert_noop!( - ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec()), + ChildBounties::add_child_bounty(RuntimeOrigin::signed(4), 0, 10, b"12345-p1".to_vec()), Error::::ParentBountyNotActive ); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); System::set_block_number(4); @@ -1133,21 +1184,21 @@ fn close_parent_with_child_bounty() { // Try close parent-bounty. // Child bounty active, can't close parent. assert_noop!( - Bounties::close_bounty(Origin::root(), 0), + Bounties::close_bounty(RuntimeOrigin::root(), 0), BountiesError::HasActiveChildBounty ); System::set_block_number(2); // Close child-bounty. - assert_ok!(ChildBounties::close_child_bounty(Origin::root(), 0, 0)); + assert_ok!(ChildBounties::close_child_bounty(RuntimeOrigin::root(), 0, 0)); // Check the child-bounty count. assert_eq!(ChildBounties::parent_child_bounties(0), 0); // Try close parent-bounty again. // Should pass this time. - assert_ok!(Bounties::close_bounty(Origin::root(), 0)); + assert_ok!(Bounties::close_bounty(RuntimeOrigin::root(), 0)); }); } @@ -1166,17 +1217,22 @@ fn children_curator_fee_calculation_test() { Balances::make_free_balance_be(&4, 101); // Parent-bounty curator. Balances::make_free_balance_be(&8, 101); // Child-bounty curator. - assert_ok!(Bounties::propose_bounty(Origin::signed(0), 50, b"12345".to_vec())); - assert_ok!(Bounties::approve_bounty(Origin::root(), 0)); + assert_ok!(Bounties::propose_bounty(RuntimeOrigin::signed(0), 50, b"12345".to_vec())); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), 0)); System::set_block_number(2); >::on_initialize(2); - assert_ok!(Bounties::propose_curator(Origin::root(), 0, 4, 6)); - assert_ok!(Bounties::accept_curator(Origin::signed(4), 0)); + assert_ok!(Bounties::propose_curator(RuntimeOrigin::root(), 0, 4, 6)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(4), 0)); // Child-bounty. - assert_ok!(ChildBounties::add_child_bounty(Origin::signed(4), 0, 10, b"12345-p1".to_vec())); + assert_ok!(ChildBounties::add_child_bounty( + RuntimeOrigin::signed(4), + 0, + 10, + b"12345-p1".to_vec() + )); assert_eq!(last_event(), ChildBountiesEvent::Added { index: 0, child_index: 0 }); System::set_block_number(4); @@ -1185,13 +1241,13 @@ fn children_curator_fee_calculation_test() { let fee = 6; // Propose curator for child-bounty. - assert_ok!(ChildBounties::propose_curator(Origin::signed(4), 0, 0, 8, fee)); + assert_ok!(ChildBounties::propose_curator(RuntimeOrigin::signed(4), 0, 0, 8, fee)); // Check curator fee added to the sum. assert_eq!(ChildBounties::children_curator_fees(0), fee); // Accept curator for child-bounty. - assert_ok!(ChildBounties::accept_curator(Origin::signed(8), 0, 0)); + assert_ok!(ChildBounties::accept_curator(RuntimeOrigin::signed(8), 0, 0)); // Award child-bounty. - assert_ok!(ChildBounties::award_child_bounty(Origin::signed(8), 0, 0, 7)); + assert_ok!(ChildBounties::award_child_bounty(RuntimeOrigin::signed(8), 0, 0, 7)); let expected_child_deposit = CuratorDepositMultiplier::get() * fee; @@ -1213,18 +1269,18 @@ fn children_curator_fee_calculation_test() { System::set_block_number(9); // Claim child-bounty. - assert_ok!(ChildBounties::claim_child_bounty(Origin::signed(7), 0, 0)); + assert_ok!(ChildBounties::claim_child_bounty(RuntimeOrigin::signed(7), 0, 0)); // Check the child-bounty count. assert_eq!(ChildBounties::parent_child_bounties(0), 0); // Award the parent bounty. - assert_ok!(Bounties::award_bounty(Origin::signed(4), 0, 9)); + assert_ok!(Bounties::award_bounty(RuntimeOrigin::signed(4), 0, 9)); System::set_block_number(15); // Claim the parent bounty. - assert_ok!(Bounties::claim_bounty(Origin::signed(9), 0)); + assert_ok!(Bounties::claim_bounty(RuntimeOrigin::signed(9), 0)); // Ensure parent-bounty curator received correctly reduced fee. assert_eq!(Balances::free_balance(4), 101 + 6 - fee); // 101 + 6 - 2 @@ -1251,22 +1307,22 @@ fn accept_curator_handles_different_deposit_calculations() { Balances::make_free_balance_be(&Treasury::account_id(), parent_value * 3); Balances::make_free_balance_be(&parent_curator, parent_fee * 100); assert_ok!(Bounties::propose_bounty( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_value, b"12345".to_vec() )); - assert_ok!(Bounties::approve_bounty(Origin::root(), parent_index)); + assert_ok!(Bounties::approve_bounty(RuntimeOrigin::root(), parent_index)); System::set_block_number(2); >::on_initialize(2); assert_ok!(Bounties::propose_curator( - Origin::root(), + RuntimeOrigin::root(), parent_index, parent_curator, parent_fee )); - assert_ok!(Bounties::accept_curator(Origin::signed(parent_curator), parent_index)); + assert_ok!(Bounties::accept_curator(RuntimeOrigin::signed(parent_curator), parent_index)); // Now we can start creating some child bounties. // Case 1: Parent and child curator are not the same. @@ -1279,7 +1335,7 @@ fn accept_curator_handles_different_deposit_calculations() { Balances::make_free_balance_be(&child_curator, starting_balance); assert_ok!(ChildBounties::add_child_bounty( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_index, child_value, b"12345-p1".to_vec() @@ -1287,14 +1343,14 @@ fn accept_curator_handles_different_deposit_calculations() { System::set_block_number(3); >::on_initialize(3); assert_ok!(ChildBounties::propose_curator( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_index, child_index, child_curator, child_fee )); assert_ok!(ChildBounties::accept_curator( - Origin::signed(child_curator), + RuntimeOrigin::signed(child_curator), parent_index, child_index )); @@ -1314,7 +1370,7 @@ fn accept_curator_handles_different_deposit_calculations() { let reserved_before = Balances::reserved_balance(&parent_curator); assert_ok!(ChildBounties::add_child_bounty( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_index, child_value, b"12345-p1".to_vec() @@ -1322,14 +1378,14 @@ fn accept_curator_handles_different_deposit_calculations() { System::set_block_number(4); >::on_initialize(4); assert_ok!(ChildBounties::propose_curator( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_index, child_index, child_curator, child_fee )); assert_ok!(ChildBounties::accept_curator( - Origin::signed(child_curator), + RuntimeOrigin::signed(child_curator), parent_index, child_index )); @@ -1347,7 +1403,7 @@ fn accept_curator_handles_different_deposit_calculations() { Balances::make_free_balance_be(&child_curator, starting_balance); assert_ok!(ChildBounties::add_child_bounty( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_index, child_value, b"12345-p1".to_vec() @@ -1355,14 +1411,14 @@ fn accept_curator_handles_different_deposit_calculations() { System::set_block_number(5); >::on_initialize(5); assert_ok!(ChildBounties::propose_curator( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_index, child_index, child_curator, child_fee )); assert_ok!(ChildBounties::accept_curator( - Origin::signed(child_curator), + RuntimeOrigin::signed(child_curator), parent_index, child_index )); @@ -1383,7 +1439,7 @@ fn accept_curator_handles_different_deposit_calculations() { Balances::make_free_balance_be(&child_curator, starting_balance); assert_ok!(ChildBounties::add_child_bounty( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_index, child_value, b"12345-p1".to_vec() @@ -1391,14 +1447,14 @@ fn accept_curator_handles_different_deposit_calculations() { System::set_block_number(5); >::on_initialize(5); assert_ok!(ChildBounties::propose_curator( - Origin::signed(parent_curator), + RuntimeOrigin::signed(parent_curator), parent_index, child_index, child_curator, child_fee )); assert_ok!(ChildBounties::accept_curator( - Origin::signed(child_curator), + RuntimeOrigin::signed(child_curator), parent_index, child_index )); diff --git a/frame/collective-mangata/src/benchmarking.rs b/frame/collective-mangata/src/benchmarking.rs index fcfe1e3e601c0..4ec816f06d3e1 100644 --- a/frame/collective-mangata/src/benchmarking.rs +++ b/frame/collective-mangata/src/benchmarking.rs @@ -30,7 +30,7 @@ const SEED: u32 = 0; const MAX_BYTES: u32 = 1_024; -fn assert_last_event, I: 'static>(generic_event: >::Event) { +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } diff --git a/frame/collective-mangata/src/lib.rs b/frame/collective-mangata/src/lib.rs index c0b87ffc05cce..6c38e6dfc11c4 100644 --- a/frame/collective-mangata/src/lib.rs +++ b/frame/collective-mangata/src/lib.rs @@ -52,12 +52,15 @@ use sp_std::{marker::PhantomData, prelude::*, result, vec}; use frame_support::{ codec::{Decode, Encode, MaxEncodedLen}, - dispatch::{DispatchError, DispatchResultWithPostInfo, Dispatchable, PostDispatchInfo}, + dispatch::{ + DispatchError, DispatchResultWithPostInfo, Dispatchable, GetDispatchInfo, Pays, + PostDispatchInfo, + }, ensure, traits::{ Backing, ChangeMembers, EnsureOrigin, Get, GetBacking, InitializeMembers, StorageVersion, }, - weights::{GetDispatchInfo, Pays, Weight}, + weights::Weight, }; #[cfg(test)] @@ -195,16 +198,19 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The outer origin type. - type Origin: From>; + type RuntimeOrigin: From>; /// The outer call dispatch type. type Proposal: Parameter - + Dispatchable>::Origin, PostInfo = PostDispatchInfo> - + From> + + Dispatchable< + RuntimeOrigin = >::RuntimeOrigin, + PostInfo = PostDispatchInfo, + > + From> + GetDispatchInfo; /// The outer event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// The minimum amount of time after proposal creation before it can be closed type ProposalCloseDelay: Get; @@ -662,7 +668,7 @@ pub mod pallet { origin: OriginFor, proposal_hash: T::Hash, #[pallet::compact] index: ProposalIndex, - #[pallet::compact] proposal_weight_bound: Weight, + proposal_weight_bound: Weight, #[pallet::compact] length_bound: u32, ) -> DispatchResultWithPostInfo { let _ = ensure_signed(origin)?; @@ -979,7 +985,7 @@ impl, I: 'static> Pallet { ensure!(proposal_len <= length_bound, Error::::WrongProposalLength); let proposal = ProposalOf::::get(hash).ok_or(Error::::ProposalMissing)?; let proposal_weight = proposal.get_dispatch_info().weight; - ensure!(proposal_weight <= weight_bound, Error::::WrongProposalWeight); + ensure!(proposal_weight.all_lte(weight_bound), Error::::WrongProposalWeight); Ok((proposal, proposal_len as usize)) } diff --git a/frame/collective/Cargo.toml b/frame/collective/Cargo.toml index a68c9f73027dd..82df7fd6ca67c 100644 --- a/frame/collective/Cargo.toml +++ b/frame/collective/Cargo.toml @@ -28,7 +28,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/collective/src/benchmarking.rs b/frame/collective/src/benchmarking.rs index b80a4aef28d38..fcebacf5762e7 100644 --- a/frame/collective/src/benchmarking.rs +++ b/frame/collective/src/benchmarking.rs @@ -30,74 +30,75 @@ const SEED: u32 = 0; const MAX_BYTES: u32 = 1_024; -fn assert_last_event, I: 'static>(generic_event: >::Event) { +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } benchmarks_instance_pallet! { set_members { - let m in 1 .. T::MaxMembers::get(); - let n in 1 .. T::MaxMembers::get(); - let p in 1 .. T::MaxProposals::get(); + let m in 0 .. T::MaxMembers::get(); + let n in 0 .. T::MaxMembers::get(); + let p in 0 .. T::MaxProposals::get(); // Set old members. // We compute the difference of old and new members, so it should influence timing. let mut old_members = vec![]; - let mut last_old_member = account::("old member", 0, SEED); for i in 0 .. m { - last_old_member = account::("old member", i, SEED); - old_members.push(last_old_member.clone()); + let old_member = account::("old member", i, SEED); + old_members.push(old_member); } let old_members_count = old_members.len() as u32; Collective::::set_members( SystemOrigin::Root.into(), old_members.clone(), - Some(last_old_member.clone()), + old_members.last().cloned(), T::MaxMembers::get(), )?; - // Set a high threshold for proposals passing so that they stay around. - let threshold = m.max(2); - // Length of the proposals should be irrelevant to `set_members`. - let length = 100; - for i in 0 .. p { - // Proposals should be different so that different proposal hashes are generated - let proposal: T::Proposal = SystemCall::::remark { - remark: vec![i as u8; length] - }.into(); - Collective::::propose( - SystemOrigin::Signed(last_old_member.clone()).into(), - threshold, - Box::new(proposal.clone()), - MAX_BYTES, - )?; - let hash = T::Hashing::hash_of(&proposal); - // Vote on the proposal to increase state relevant for `set_members`. - // Not voting for `last_old_member` because they proposed and not voting for the first member - // to keep the proposal from passing. - for j in 2 .. m - 1 { - let voter = &old_members[j as usize]; - let approve = true; - Collective::::vote( - SystemOrigin::Signed(voter.clone()).into(), - hash, - i, - approve, + // If there were any old members generate a bunch of proposals. + if m > 0 { + // Set a high threshold for proposals passing so that they stay around. + let threshold = m.max(2); + // Length of the proposals should be irrelevant to `set_members`. + let length = 100; + for i in 0 .. p { + // Proposals should be different so that different proposal hashes are generated + let proposal: T::Proposal = SystemCall::::remark { + remark: vec![i as u8; length] + }.into(); + Collective::::propose( + SystemOrigin::Signed(old_members.last().unwrap().clone()).into(), + threshold, + Box::new(proposal.clone()), + MAX_BYTES, )?; + let hash = T::Hashing::hash_of(&proposal); + // Vote on the proposal to increase state relevant for `set_members`. + // Not voting for last old member because they proposed and not voting for the first member + // to keep the proposal from passing. + for j in 2 .. m - 1 { + let voter = &old_members[j as usize]; + let approve = true; + Collective::::vote( + SystemOrigin::Signed(voter.clone()).into(), + hash, + i, + approve, + )?; + } } } // Construct `new_members`. // It should influence timing since it will sort this vector. let mut new_members = vec![]; - let mut last_member = account::("member", 0, SEED); for i in 0 .. n { - last_member = account::("member", i, SEED); - new_members.push(last_member.clone()); + let member = account::("member", i, SEED); + new_members.push(member); } - }: _(SystemOrigin::Root, new_members.clone(), Some(last_member), T::MaxMembers::get()) + }: _(SystemOrigin::Root, new_members.clone(), new_members.last().cloned(), T::MaxMembers::get()) verify { new_members.sort(); assert_eq!(Collective::::members(), new_members); diff --git a/frame/collective/src/lib.rs b/frame/collective/src/lib.rs index 5a39ed7e099c3..897c54a9b90c0 100644 --- a/frame/collective/src/lib.rs +++ b/frame/collective/src/lib.rs @@ -49,12 +49,15 @@ use sp_std::{marker::PhantomData, prelude::*, result, vec}; use frame_support::{ codec::{Decode, Encode, MaxEncodedLen}, - dispatch::{DispatchError, DispatchResultWithPostInfo, Dispatchable, PostDispatchInfo}, + dispatch::{ + DispatchError, DispatchResultWithPostInfo, Dispatchable, GetDispatchInfo, Pays, + PostDispatchInfo, + }, ensure, traits::{ Backing, ChangeMembers, EnsureOrigin, Get, GetBacking, InitializeMembers, StorageVersion, }, - weights::{GetDispatchInfo, Pays, Weight}, + weights::{OldWeight, Weight}, }; #[cfg(test)] @@ -177,17 +180,20 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { - /// The outer origin type. - type Origin: From>; + /// The runtime origin type. + type RuntimeOrigin: From>; - /// The outer call dispatch type. + /// The runtime call dispatch type. type Proposal: Parameter - + Dispatchable>::Origin, PostInfo = PostDispatchInfo> - + From> + + Dispatchable< + RuntimeOrigin = >::RuntimeOrigin, + PostInfo = PostDispatchInfo, + > + From> + GetDispatchInfo; - /// The outer event type. - type Event: From> + IsType<::Event>; + /// The runtime event type. + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// The time-out for council motions. type MotionDuration: Get; @@ -614,17 +620,20 @@ pub mod pallet { .max(T::WeightInfo::close_early_disapproved(m, p2)) .max(T::WeightInfo::close_approved(b, m, p2)) .max(T::WeightInfo::close_disapproved(m, p2)) - .saturating_add(p1) + .saturating_add(p1.into()) }, DispatchClass::Operational ))] - pub fn close( + #[allow(deprecated)] + #[deprecated(note = "1D weight is used in this extrinsic, please migrate to `close`")] + pub fn close_old_weight( origin: OriginFor, proposal_hash: T::Hash, #[pallet::compact] index: ProposalIndex, - #[pallet::compact] proposal_weight_bound: Weight, + #[pallet::compact] proposal_weight_bound: OldWeight, #[pallet::compact] length_bound: u32, ) -> DispatchResultWithPostInfo { + let proposal_weight_bound: Weight = proposal_weight_bound.into(); let _ = ensure_signed(origin)?; Self::do_close(proposal_hash, index, proposal_weight_bound, length_bound) @@ -653,6 +662,64 @@ pub mod pallet { let proposal_count = Self::do_disapprove_proposal(proposal_hash); Ok(Some(T::WeightInfo::disapprove_proposal(proposal_count)).into()) } + + /// Close a vote that is either approved, disapproved or whose voting period has ended. + /// + /// May be called by any signed account in order to finish voting and close the proposal. + /// + /// If called before the end of the voting period it will only close the vote if it is + /// has enough votes to be approved or disapproved. + /// + /// If called after the end of the voting period abstentions are counted as rejections + /// unless there is a prime member set and the prime member cast an approval. + /// + /// If the close operation completes successfully with disapproval, the transaction fee will + /// be waived. Otherwise execution of the approved operation will be charged to the caller. + /// + /// + `proposal_weight_bound`: The maximum amount of weight consumed by executing the closed + /// proposal. + /// + `length_bound`: The upper bound for the length of the proposal in storage. Checked via + /// `storage::read` so it is `size_of::() == 4` larger than the pure length. + /// + /// # + /// ## Weight + /// - `O(B + M + P1 + P2)` where: + /// - `B` is `proposal` size in bytes (length-fee-bounded) + /// - `M` is members-count (code- and governance-bounded) + /// - `P1` is the complexity of `proposal` preimage. + /// - `P2` is proposal-count (code-bounded) + /// - DB: + /// - 2 storage reads (`Members`: codec `O(M)`, `Prime`: codec `O(1)`) + /// - 3 mutations (`Voting`: codec `O(M)`, `ProposalOf`: codec `O(B)`, `Proposals`: codec + /// `O(P2)`) + /// - any mutations done while executing `proposal` (`P1`) + /// - up to 3 events + /// # + #[pallet::weight(( + { + let b = *length_bound; + let m = T::MaxMembers::get(); + let p1 = *proposal_weight_bound; + let p2 = T::MaxProposals::get(); + T::WeightInfo::close_early_approved(b, m, p2) + .max(T::WeightInfo::close_early_disapproved(m, p2)) + .max(T::WeightInfo::close_approved(b, m, p2)) + .max(T::WeightInfo::close_disapproved(m, p2)) + .saturating_add(p1) + }, + DispatchClass::Operational + ))] + pub fn close( + origin: OriginFor, + proposal_hash: T::Hash, + #[pallet::compact] index: ProposalIndex, + proposal_weight_bound: Weight, + #[pallet::compact] length_bound: u32, + ) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + + Self::do_close(proposal_hash, index, proposal_weight_bound, length_bound) + } } } @@ -881,7 +948,7 @@ impl, I: 'static> Pallet { ensure!(proposal_len <= length_bound, Error::::WrongProposalLength); let proposal = ProposalOf::::get(hash).ok_or(Error::::ProposalMissing)?; let proposal_weight = proposal.get_dispatch_info().weight; - ensure!(proposal_weight <= weight_bound, Error::::WrongProposalWeight); + ensure!(proposal_weight.all_lte(weight_bound), Error::::WrongProposalWeight); Ok((proposal, proposal_len as usize)) } diff --git a/frame/collective/src/tests.rs b/frame/collective/src/tests.rs index e7b97a39e020a..19c54e0493c7b 100644 --- a/frame/collective/src/tests.rs +++ b/frame/collective/src/tests.rs @@ -18,9 +18,10 @@ use super::{Event as CollectiveEvent, *}; use crate as pallet_collective; use frame_support::{ - assert_noop, assert_ok, parameter_types, + assert_noop, assert_ok, + dispatch::Pays, + parameter_types, traits::{ConstU32, ConstU64, GenesisBuild, StorageVersion}, - weights::Pays, Hashable, }; use frame_system::{EventRecord, Phase}; @@ -32,7 +33,7 @@ use sp_runtime::{ }; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Test where @@ -61,8 +62,9 @@ mod mock_democracy { #[pallet::config] pub trait Config: frame_system::Config + Sized { - type Event: From> + IsType<::Event>; - type ExternalMajorityOrigin: EnsureOrigin; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + type ExternalMajorityOrigin: EnsureOrigin; } #[pallet::call] @@ -96,16 +98,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -118,9 +120,9 @@ impl frame_system::Config for Test { type MaxConsumers = ConstU32<16>; } impl Config for Test { - type Origin = Origin; - type Proposal = Call; - type Event = Event; + type RuntimeOrigin = RuntimeOrigin; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type MotionDuration = ConstU64<3>; type MaxProposals = MaxProposals; type MaxMembers = MaxMembers; @@ -128,9 +130,9 @@ impl Config for Test { type WeightInfo = (); } impl Config for Test { - type Origin = Origin; - type Proposal = Call; - type Event = Event; + type RuntimeOrigin = RuntimeOrigin; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type MotionDuration = ConstU64<3>; type MaxProposals = MaxProposals; type MaxMembers = MaxMembers; @@ -138,13 +140,13 @@ impl Config for Test { type WeightInfo = (); } impl mock_democracy::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExternalMajorityOrigin = EnsureProportionAtLeast; } impl Config for Test { - type Origin = Origin; - type Proposal = Call; - type Event = Event; + type RuntimeOrigin = RuntimeOrigin; + type Proposal = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type MotionDuration = ConstU64<3>; type MaxProposals = MaxProposals; type MaxMembers = MaxMembers; @@ -171,11 +173,13 @@ pub fn new_test_ext() -> sp_io::TestExternalities { ext } -fn make_proposal(value: u64) -> Call { - Call::System(frame_system::Call::remark_with_event { remark: value.to_be_bytes().to_vec() }) +fn make_proposal(value: u64) -> RuntimeCall { + RuntimeCall::System(frame_system::Call::remark_with_event { + remark: value.to_be_bytes().to_vec(), + }) } -fn record(event: Event) -> EventRecord { +fn record(event: RuntimeEvent) -> EventRecord { EventRecord { phase: Phase::Initialization, event, topics: vec![] } } @@ -196,52 +200,60 @@ fn close_works() { let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); System::set_block_number(3); assert_noop!( - Collective::close(Origin::signed(4), hash, 0, proposal_weight, proposal_len), + Collective::close(RuntimeOrigin::signed(4), hash, 0, proposal_weight, proposal_len), Error::::TooEarly ); System::set_block_number(4); - assert_ok!(Collective::close(Origin::signed(4), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(4), + hash, + 0, + proposal_weight, + proposal_len + )); assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 3 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Closed { + record(RuntimeEvent::Collective(CollectiveEvent::Closed { proposal_hash: hash, yes: 2, no: 1 })), - record(Event::Collective(CollectiveEvent::Disapproved { proposal_hash: hash })) + record(RuntimeEvent::Collective(CollectiveEvent::Disapproved { + proposal_hash: hash + })) ] ); }); @@ -250,7 +262,7 @@ fn close_works() { #[test] fn proposal_weight_limit_works_on_approve() { new_test_ext().execute_with(|| { - let proposal = Call::Collective(crate::Call::set_members { + let proposal = RuntimeCall::Collective(crate::Call::set_members { new_members: vec![1, 2, 3], prime: None, old_count: MaxMembers::get(), @@ -261,17 +273,17 @@ fn proposal_weight_limit_works_on_approve() { // Set 1 as prime voter Prime::::set(Some(1)); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); // With 1's prime vote, this should pass System::set_block_number(4); assert_noop!( Collective::close( - Origin::signed(4), + RuntimeOrigin::signed(4), hash, 0, proposal_weight - Weight::from_ref_time(100), @@ -279,14 +291,20 @@ fn proposal_weight_limit_works_on_approve() { ), Error::::WrongProposalWeight ); - assert_ok!(Collective::close(Origin::signed(4), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(4), + hash, + 0, + proposal_weight, + proposal_len + )); }) } #[test] fn proposal_weight_limit_ignored_on_disapprove() { new_test_ext().execute_with(|| { - let proposal = Call::Collective(crate::Call::set_members { + let proposal = RuntimeCall::Collective(crate::Call::set_members { new_members: vec![1, 2, 3], prime: None, old_count: MaxMembers::get(), @@ -296,7 +314,7 @@ fn proposal_weight_limit_ignored_on_disapprove() { let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len @@ -304,7 +322,7 @@ fn proposal_weight_limit_ignored_on_disapprove() { // No votes, this proposal wont pass System::set_block_number(4); assert_ok!(Collective::close( - Origin::signed(4), + RuntimeOrigin::signed(4), hash, 0, proposal_weight - Weight::from_ref_time(100), @@ -321,53 +339,61 @@ fn close_with_prime_works() { let proposal_weight = proposal.get_dispatch_info().weight; let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Collective::set_members( - Origin::root(), + RuntimeOrigin::root(), vec![1, 2, 3], Some(3), MaxMembers::get() )); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); System::set_block_number(4); - assert_ok!(Collective::close(Origin::signed(4), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(4), + hash, + 0, + proposal_weight, + proposal_len + )); assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 3 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Closed { + record(RuntimeEvent::Collective(CollectiveEvent::Closed { proposal_hash: hash, yes: 2, no: 1 })), - record(Event::Collective(CollectiveEvent::Disapproved { proposal_hash: hash })) + record(RuntimeEvent::Collective(CollectiveEvent::Disapproved { + proposal_hash: hash + })) ] ); }); @@ -381,54 +407,60 @@ fn close_with_voting_prime_works() { let proposal_weight = proposal.get_dispatch_info().weight; let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Collective::set_members( - Origin::root(), + RuntimeOrigin::root(), vec![1, 2, 3], Some(1), MaxMembers::get() )); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); System::set_block_number(4); - assert_ok!(Collective::close(Origin::signed(4), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(4), + hash, + 0, + proposal_weight, + proposal_len + )); assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 3 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Closed { + record(RuntimeEvent::Collective(CollectiveEvent::Closed { proposal_hash: hash, yes: 3, no: 0 })), - record(Event::Collective(CollectiveEvent::Approved { proposal_hash: hash })), - record(Event::Collective(CollectiveEvent::Executed { + record(RuntimeEvent::Collective(CollectiveEvent::Approved { proposal_hash: hash })), + record(RuntimeEvent::Collective(CollectiveEvent::Executed { proposal_hash: hash, result: Err(DispatchError::BadOrigin) })) @@ -445,25 +477,25 @@ fn close_with_no_prime_but_majority_works() { let proposal_weight = proposal.get_dispatch_info().weight; let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(CollectiveMajority::set_members( - Origin::root(), + RuntimeOrigin::root(), vec![1, 2, 3, 4, 5], Some(5), MaxMembers::get() )); assert_ok!(CollectiveMajority::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 5, Box::new(proposal.clone()), proposal_len )); - assert_ok!(CollectiveMajority::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(CollectiveMajority::vote(Origin::signed(2), hash, 0, true)); - assert_ok!(CollectiveMajority::vote(Origin::signed(3), hash, 0, true)); + assert_ok!(CollectiveMajority::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(CollectiveMajority::vote(RuntimeOrigin::signed(2), hash, 0, true)); + assert_ok!(CollectiveMajority::vote(RuntimeOrigin::signed(3), hash, 0, true)); System::set_block_number(4); assert_ok!(CollectiveMajority::close( - Origin::signed(4), + RuntimeOrigin::signed(4), hash, 0, proposal_weight, @@ -473,42 +505,42 @@ fn close_with_no_prime_but_majority_works() { assert_eq!( System::events(), vec![ - record(Event::CollectiveMajority(CollectiveEvent::Proposed { + record(RuntimeEvent::CollectiveMajority(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 5 })), - record(Event::CollectiveMajority(CollectiveEvent::Voted { + record(RuntimeEvent::CollectiveMajority(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::CollectiveMajority(CollectiveEvent::Voted { + record(RuntimeEvent::CollectiveMajority(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0 })), - record(Event::CollectiveMajority(CollectiveEvent::Voted { + record(RuntimeEvent::CollectiveMajority(CollectiveEvent::Voted { account: 3, proposal_hash: hash, voted: true, yes: 3, no: 0 })), - record(Event::CollectiveMajority(CollectiveEvent::Closed { + record(RuntimeEvent::CollectiveMajority(CollectiveEvent::Closed { proposal_hash: hash, yes: 5, no: 0 })), - record(Event::CollectiveMajority(CollectiveEvent::Approved { + record(RuntimeEvent::CollectiveMajority(CollectiveEvent::Approved { proposal_hash: hash })), - record(Event::CollectiveMajority(CollectiveEvent::Executed { + record(RuntimeEvent::CollectiveMajority(CollectiveEvent::Executed { proposal_hash: hash, result: Err(DispatchError::BadOrigin) })) @@ -525,13 +557,13 @@ fn removal_of_old_voters_votes_works() { let hash = BlakeTwo256::hash_of(&proposal); let end = 4; assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); assert_eq!( Collective::voting(&hash), Some(Votes { index: 0, threshold: 3, ayes: vec![1, 2], nays: vec![], end }) @@ -546,13 +578,13 @@ fn removal_of_old_voters_votes_works() { let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Collective::propose( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(2), hash, 1, true)); - assert_ok!(Collective::vote(Origin::signed(3), hash, 1, false)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 1, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(3), hash, 1, false)); assert_eq!( Collective::voting(&hash), Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![3], end }) @@ -573,18 +605,23 @@ fn removal_of_old_voters_votes_works_with_set_members() { let hash = BlakeTwo256::hash_of(&proposal); let end = 4; assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); assert_eq!( Collective::voting(&hash), Some(Votes { index: 0, threshold: 3, ayes: vec![1, 2], nays: vec![], end }) ); - assert_ok!(Collective::set_members(Origin::root(), vec![2, 3, 4], None, MaxMembers::get())); + assert_ok!(Collective::set_members( + RuntimeOrigin::root(), + vec![2, 3, 4], + None, + MaxMembers::get() + )); assert_eq!( Collective::voting(&hash), Some(Votes { index: 0, threshold: 3, ayes: vec![2], nays: vec![], end }) @@ -594,18 +631,23 @@ fn removal_of_old_voters_votes_works_with_set_members() { let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash = BlakeTwo256::hash_of(&proposal); assert_ok!(Collective::propose( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(2), hash, 1, true)); - assert_ok!(Collective::vote(Origin::signed(3), hash, 1, false)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 1, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(3), hash, 1, false)); assert_eq!( Collective::voting(&hash), Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![3], end }) ); - assert_ok!(Collective::set_members(Origin::root(), vec![2, 4], None, MaxMembers::get())); + assert_ok!(Collective::set_members( + RuntimeOrigin::root(), + vec![2, 4], + None, + MaxMembers::get() + )); assert_eq!( Collective::voting(&hash), Some(Votes { index: 1, threshold: 2, ayes: vec![2], nays: vec![], end }) @@ -621,7 +663,7 @@ fn propose_works() { let hash = proposal.blake2_256().into(); let end = 4; assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len @@ -635,7 +677,7 @@ fn propose_works() { assert_eq!( System::events(), - vec![record(Event::Collective(CollectiveEvent::Proposed { + vec![record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, @@ -652,7 +694,7 @@ fn limit_active_proposals() { let proposal = make_proposal(i as u64); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len @@ -661,7 +703,12 @@ fn limit_active_proposals() { let proposal = make_proposal(MaxProposals::get() as u64 + 1); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); assert_noop!( - Collective::propose(Origin::signed(1), 3, Box::new(proposal.clone()), proposal_len), + Collective::propose( + RuntimeOrigin::signed(1), + 3, + Box::new(proposal.clone()), + proposal_len + ), Error::::TooManyProposals ); }) @@ -670,13 +717,18 @@ fn limit_active_proposals() { #[test] fn correct_validate_and_get_proposal() { new_test_ext().execute_with(|| { - let proposal = Call::Collective(crate::Call::set_members { + let proposal = RuntimeCall::Collective(crate::Call::set_members { new_members: vec![1, 2, 3], prime: None, old_count: MaxMembers::get(), }); let length = proposal.encode().len() as u32; - assert_ok!(Collective::propose(Origin::signed(1), 3, Box::new(proposal.clone()), length)); + assert_ok!(Collective::propose( + RuntimeOrigin::signed(1), + 3, + Box::new(proposal.clone()), + length + )); let hash = BlakeTwo256::hash_of(&proposal); let weight = proposal.get_dispatch_info().weight; @@ -714,7 +766,12 @@ fn motions_ignoring_non_collective_proposals_works() { let proposal = make_proposal(42); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); assert_noop!( - Collective::propose(Origin::signed(42), 3, Box::new(proposal.clone()), proposal_len), + Collective::propose( + RuntimeOrigin::signed(42), + 3, + Box::new(proposal.clone()), + proposal_len + ), Error::::NotMember ); }); @@ -727,13 +784,13 @@ fn motions_ignoring_non_collective_votes_works() { let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); assert_noop!( - Collective::vote(Origin::signed(42), hash, 0, true), + Collective::vote(RuntimeOrigin::signed(42), hash, 0, true), Error::::NotMember, ); }); @@ -747,13 +804,13 @@ fn motions_ignoring_bad_index_collective_vote_works() { let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); assert_noop!( - Collective::vote(Origin::signed(2), hash, 1, true), + Collective::vote(RuntimeOrigin::signed(2), hash, 1, true), Error::::WrongIndex, ); }); @@ -767,7 +824,7 @@ fn motions_vote_after_works() { let hash: H256 = proposal.blake2_256().into(); let end = 4; assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, Box::new(proposal.clone()), proposal_len @@ -778,45 +835,45 @@ fn motions_vote_after_works() { Some(Votes { index: 0, threshold: 2, ayes: vec![], nays: vec![], end }) ); // Cast first aye vote. - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); assert_eq!( Collective::voting(&hash), Some(Votes { index: 0, threshold: 2, ayes: vec![1], nays: vec![], end }) ); // Try to cast a duplicate aye vote. assert_noop!( - Collective::vote(Origin::signed(1), hash, 0, true), + Collective::vote(RuntimeOrigin::signed(1), hash, 0, true), Error::::DuplicateVote, ); // Cast a nay vote. - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, false)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, false)); assert_eq!( Collective::voting(&hash), Some(Votes { index: 0, threshold: 2, ayes: vec![], nays: vec![1], end }) ); // Try to cast a duplicate nay vote. assert_noop!( - Collective::vote(Origin::signed(1), hash, 0, false), + Collective::vote(RuntimeOrigin::signed(1), hash, 0, false), Error::::DuplicateVote, ); assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 2 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: false, @@ -836,7 +893,7 @@ fn motions_all_first_vote_free_works() { let hash: H256 = proposal.blake2_256().into(); let end = 4; assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, Box::new(proposal.clone()), proposal_len, @@ -848,40 +905,40 @@ fn motions_all_first_vote_free_works() { // For the motion, acc 2's first vote, expecting Ok with Pays::No. let vote_rval: DispatchResultWithPostInfo = - Collective::vote(Origin::signed(2), hash, 0, true); + Collective::vote(RuntimeOrigin::signed(2), hash, 0, true); assert_eq!(vote_rval.unwrap().pays_fee, Pays::No); // Duplicate vote, expecting error with Pays::Yes. let vote_rval: DispatchResultWithPostInfo = - Collective::vote(Origin::signed(2), hash, 0, true); + Collective::vote(RuntimeOrigin::signed(2), hash, 0, true); assert_eq!(vote_rval.unwrap_err().post_info.pays_fee, Pays::Yes); // Modifying vote, expecting ok with Pays::Yes. let vote_rval: DispatchResultWithPostInfo = - Collective::vote(Origin::signed(2), hash, 0, false); + Collective::vote(RuntimeOrigin::signed(2), hash, 0, false); assert_eq!(vote_rval.unwrap().pays_fee, Pays::Yes); // For the motion, acc 3's first vote, expecting Ok with Pays::No. let vote_rval: DispatchResultWithPostInfo = - Collective::vote(Origin::signed(3), hash, 0, true); + Collective::vote(RuntimeOrigin::signed(3), hash, 0, true); assert_eq!(vote_rval.unwrap().pays_fee, Pays::No); // acc 3 modify the vote, expecting Ok with Pays::Yes. let vote_rval: DispatchResultWithPostInfo = - Collective::vote(Origin::signed(3), hash, 0, false); + Collective::vote(RuntimeOrigin::signed(3), hash, 0, false); assert_eq!(vote_rval.unwrap().pays_fee, Pays::Yes); // Test close() Extrincis | Check DispatchResultWithPostInfo with Pay Info let proposal_weight = proposal.get_dispatch_info().weight; let close_rval: DispatchResultWithPostInfo = - Collective::close(Origin::signed(2), hash, 0, proposal_weight, proposal_len); + Collective::close(RuntimeOrigin::signed(2), hash, 0, proposal_weight, proposal_len); assert_eq!(close_rval.unwrap().pays_fee, Pays::No); // trying to close the proposal, which is already closed. // Expecting error "ProposalMissing" with Pays::Yes let close_rval: DispatchResultWithPostInfo = - Collective::close(Origin::signed(2), hash, 0, proposal_weight, proposal_len); + Collective::close(RuntimeOrigin::signed(2), hash, 0, proposal_weight, proposal_len); assert_eq!(close_rval.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -894,16 +951,22 @@ fn motions_reproposing_disapproved_works() { let proposal_weight = proposal.get_dispatch_info().weight; let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, false)); - assert_ok!(Collective::close(Origin::signed(2), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, false)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(2), + hash, + 0, + proposal_weight, + proposal_len + )); assert_eq!(*Collective::proposals(), vec![]); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, Box::new(proposal.clone()), proposal_len @@ -915,7 +978,7 @@ fn motions_reproposing_disapproved_works() { #[test] fn motions_approval_with_enough_votes_and_lower_voting_threshold_works() { new_test_ext().execute_with(|| { - let proposal = Call::Democracy(mock_democracy::Call::external_propose_majority {}); + let proposal = RuntimeCall::Democracy(mock_democracy::Call::external_propose_majority {}); let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let proposal_weight = proposal.get_dispatch_info().weight; let hash: H256 = proposal.blake2_256().into(); @@ -925,44 +988,50 @@ fn motions_approval_with_enough_votes_and_lower_voting_threshold_works() { // // Failed to execute with only 2 yes votes. assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); - assert_ok!(Collective::close(Origin::signed(2), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(2), + hash, + 0, + proposal_weight, + proposal_len + )); assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 2 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Closed { + record(RuntimeEvent::Collective(CollectiveEvent::Closed { proposal_hash: hash, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Approved { proposal_hash: hash })), - record(Event::Collective(CollectiveEvent::Executed { + record(RuntimeEvent::Collective(CollectiveEvent::Approved { proposal_hash: hash })), + record(RuntimeEvent::Collective(CollectiveEvent::Executed { proposal_hash: hash, result: Err(DispatchError::BadOrigin) })), @@ -973,53 +1042,61 @@ fn motions_approval_with_enough_votes_and_lower_voting_threshold_works() { // Executed with 3 yes votes. assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 1, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 1, true)); - assert_ok!(Collective::vote(Origin::signed(3), hash, 1, true)); - assert_ok!(Collective::close(Origin::signed(2), hash, 1, proposal_weight, proposal_len)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 1, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 1, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(3), hash, 1, true)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(2), + hash, + 1, + proposal_weight, + proposal_len + )); assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 1, proposal_hash: hash, threshold: 2 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 3, proposal_hash: hash, voted: true, yes: 3, no: 0 })), - record(Event::Collective(CollectiveEvent::Closed { + record(RuntimeEvent::Collective(CollectiveEvent::Closed { proposal_hash: hash, yes: 3, no: 0 })), - record(Event::Collective(CollectiveEvent::Approved { proposal_hash: hash })), - record(Event::Democracy(mock_democracy::pallet::Event::::ExternalProposed)), - record(Event::Collective(CollectiveEvent::Executed { + record(RuntimeEvent::Collective(CollectiveEvent::Approved { proposal_hash: hash })), + record(RuntimeEvent::Democracy( + mock_democracy::pallet::Event::::ExternalProposed + )), + record(RuntimeEvent::Collective(CollectiveEvent::Executed { proposal_hash: hash, result: Ok(()) })), @@ -1036,44 +1113,52 @@ fn motions_disapproval_works() { let proposal_weight = proposal.get_dispatch_info().weight; let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, false)); - assert_ok!(Collective::close(Origin::signed(2), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, false)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(2), + hash, + 0, + proposal_weight, + proposal_len + )); assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 3 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: false, yes: 1, no: 1 })), - record(Event::Collective(CollectiveEvent::Closed { + record(RuntimeEvent::Collective(CollectiveEvent::Closed { proposal_hash: hash, yes: 1, no: 1 })), - record(Event::Collective(CollectiveEvent::Disapproved { proposal_hash: hash })), + record(RuntimeEvent::Collective(CollectiveEvent::Disapproved { + proposal_hash: hash + })), ] ); }); @@ -1087,45 +1172,51 @@ fn motions_approval_works() { let proposal_weight = proposal.get_dispatch_info().weight; let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, Box::new(proposal.clone()), proposal_len )); - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); - assert_ok!(Collective::close(Origin::signed(2), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(2), + hash, + 0, + proposal_weight, + proposal_len + )); assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 2 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Closed { + record(RuntimeEvent::Collective(CollectiveEvent::Closed { proposal_hash: hash, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Approved { proposal_hash: hash })), - record(Event::Collective(CollectiveEvent::Executed { + record(RuntimeEvent::Collective(CollectiveEvent::Approved { proposal_hash: hash })), + record(RuntimeEvent::Collective(CollectiveEvent::Executed { proposal_hash: hash, result: Err(DispatchError::BadOrigin) })), @@ -1142,14 +1233,14 @@ fn motion_with_no_votes_closes_with_disapproval() { let proposal_weight = proposal.get_dispatch_info().weight; let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, Box::new(proposal.clone()), proposal_len )); assert_eq!( System::events()[0], - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, @@ -1160,7 +1251,7 @@ fn motion_with_no_votes_closes_with_disapproval() { // Closing the motion too early is not possible because it has neither // an approving or disapproving simple majority due to the lack of votes. assert_noop!( - Collective::close(Origin::signed(2), hash, 0, proposal_weight, proposal_len), + Collective::close(RuntimeOrigin::signed(2), hash, 0, proposal_weight, proposal_len), Error::::TooEarly ); @@ -1168,12 +1259,18 @@ fn motion_with_no_votes_closes_with_disapproval() { let closing_block = System::block_number() + MotionDuration::get(); System::set_block_number(closing_block); // we can successfully close the motion. - assert_ok!(Collective::close(Origin::signed(2), hash, 0, proposal_weight, proposal_len)); + assert_ok!(Collective::close( + RuntimeOrigin::signed(2), + hash, + 0, + proposal_weight, + proposal_len + )); // Events show that the close ended in a disapproval. assert_eq!( System::events()[1], - record(Event::Collective(CollectiveEvent::Closed { + record(RuntimeEvent::Collective(CollectiveEvent::Closed { proposal_hash: hash, yes: 0, no: 3 @@ -1181,7 +1278,7 @@ fn motion_with_no_votes_closes_with_disapproval() { ); assert_eq!( System::events()[2], - record(Event::Collective(CollectiveEvent::Disapproved { proposal_hash: hash })) + record(RuntimeEvent::Collective(CollectiveEvent::Disapproved { proposal_hash: hash })) ); }) } @@ -1196,28 +1293,28 @@ fn close_disapprove_does_not_care_about_weight_or_len() { let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, Box::new(proposal.clone()), proposal_len )); // First we make the proposal succeed - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); // It will not close with bad weight/len information assert_noop!( - Collective::close(Origin::signed(2), hash, 0, Weight::zero(), 0), + Collective::close(RuntimeOrigin::signed(2), hash, 0, Weight::zero(), 0), Error::::WrongProposalLength, ); assert_noop!( - Collective::close(Origin::signed(2), hash, 0, Weight::zero(), proposal_len), + Collective::close(RuntimeOrigin::signed(2), hash, 0, Weight::zero(), proposal_len), Error::::WrongProposalWeight, ); // Now we make the proposal fail - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, false)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, false)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, false)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, false)); // It can close even if the weight/len information is bad - assert_ok!(Collective::close(Origin::signed(2), hash, 0, Weight::zero(), 0)); + assert_ok!(Collective::close(RuntimeOrigin::signed(2), hash, 0, Weight::zero(), 0)); }) } @@ -1228,40 +1325,42 @@ fn disapprove_proposal_works() { let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); let hash: H256 = proposal.blake2_256().into(); assert_ok!(Collective::propose( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, Box::new(proposal.clone()), proposal_len )); // Proposal would normally succeed - assert_ok!(Collective::vote(Origin::signed(1), hash, 0, true)); - assert_ok!(Collective::vote(Origin::signed(2), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(1), hash, 0, true)); + assert_ok!(Collective::vote(RuntimeOrigin::signed(2), hash, 0, true)); // But Root can disapprove and remove it anyway - assert_ok!(Collective::disapprove_proposal(Origin::root(), hash)); + assert_ok!(Collective::disapprove_proposal(RuntimeOrigin::root(), hash)); assert_eq!( System::events(), vec![ - record(Event::Collective(CollectiveEvent::Proposed { + record(RuntimeEvent::Collective(CollectiveEvent::Proposed { account: 1, proposal_index: 0, proposal_hash: hash, threshold: 2 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 1, proposal_hash: hash, voted: true, yes: 1, no: 0 })), - record(Event::Collective(CollectiveEvent::Voted { + record(RuntimeEvent::Collective(CollectiveEvent::Voted { account: 2, proposal_hash: hash, voted: true, yes: 2, no: 0 })), - record(Event::Collective(CollectiveEvent::Disapproved { proposal_hash: hash })), + record(RuntimeEvent::Collective(CollectiveEvent::Disapproved { + proposal_hash: hash + })), ] ); }) diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index ac85c469354fe..7483ec8935890 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -20,12 +20,12 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = ] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } log = { version = "0.4", default-features = false } -wasm-instrument = { version = "0.1", default-features = false } +wasm-instrument = { version = "0.3", default-features = false } serde = { version = "1", optional = true, features = ["derive"] } smallvec = { version = "1", default-features = false, features = [ "const_generics", ] } -wasmi-validation = { version = "0.4", default-features = false } +wasmi-validation = { version = "0.5", default-features = false } impl-trait-for-tuples = "0.2" # Only used in benchmarking to generate random contract code @@ -36,8 +36,9 @@ rand_pcg = { version = "0.3", optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = "../benchmarking", optional = true } frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "common" } +pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "primitives" } pallet-contracts-proc-macro = { version = "4.0.0-dev", path = "proc-macro" } +sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } @@ -45,9 +46,9 @@ sp-sandbox = { version = "0.10.0-dev", default-features = false, path = "../../p sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] +array-bytes = "4.1" assert_matches = "1" env_logger = "0.9" -hex-literal = "0.3" pretty_assertions = "1" wat = "1" @@ -69,7 +70,7 @@ std = [ "sp-io/std", "sp-std/std", "sp-sandbox/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "wasm-instrument/std", diff --git a/frame/contracts/fixtures/create_storage_and_call.wat b/frame/contracts/fixtures/create_storage_and_call.wat new file mode 100644 index 0000000000000..2a1e53f7ce08a --- /dev/null +++ b/frame/contracts/fixtures/create_storage_and_call.wat @@ -0,0 +1,55 @@ +;; This calls another contract as passed as its account id. It also creates some storage. +(module + (import "seal0" "seal_input" (func $seal_input (param i32 i32))) + (import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32))) + (import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32))) + (import "env" "memory" (memory 1 1)) + + (func $assert (param i32) + (block $ok + (br_if $ok + (get_local 0) + ) + (unreachable) + ) + ) + + (func (export "deploy")) + + (func (export "call") + ;; store length of input buffer + (i32.store (i32.const 0) (i32.const 512)) + + ;; copy input at address 4 + (call $seal_input (i32.const 4) (i32.const 0)) + + ;; create 4 byte of storage before calling + (call $seal_set_storage + (i32.const 0) ;; Pointer to storage key + (i32.const 0) ;; Pointer to value + (i32.const 4) ;; Size of value + ) + + ;; call passed contract + (call $assert (i32.eqz + (call $seal_call + (i32.const 0) ;; No flags + (i32.const 8) ;; Pointer to "callee" address. + (i64.const 0) ;; How much gas to devote for the execution. 0 = all. + (i32.const 512) ;; Pointer to the buffer with value to transfer + (i32.const 4) ;; Pointer to input data buffer address + (i32.const 4) ;; Length of input data buffer + (i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output + (i32.const 0) ;; Length is ignored in this case + ) + )) + + ;; create 8 byte of storage after calling + ;; item of 12 bytes because we override 4 bytes + (call $seal_set_storage + (i32.const 0) ;; Pointer to storage key + (i32.const 0) ;; Pointer to value + (i32.const 12) ;; Size of value + ) + ) +) diff --git a/frame/contracts/common/Cargo.toml b/frame/contracts/primitives/Cargo.toml similarity index 70% rename from frame/contracts/common/Cargo.toml rename to frame/contracts/primitives/Cargo.toml index 49d7973ab155f..c8b7c4a2f7c37 100644 --- a/frame/contracts/common/Cargo.toml +++ b/frame/contracts/primitives/Cargo.toml @@ -15,23 +15,16 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] bitflags = "1.0" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.0.0", default-features = false, features = ["derive"] } -serde = { version = "1", features = ["derive"], optional = true } # Substrate Dependencies (This crate should not rely on frame) -sp-core = { version = "6.0.0", path = "../../../primitives/core", default-features = false } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } -sp-rpc = { version = "6.0.0", path = "../../../primitives/rpc", optional = true } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-weights = { version = "4.0.0", default-features = false, path = "../../../primitives/weights" } [features] default = ["std"] std = [ "codec/std", - "scale-info/std", - "sp-core/std", "sp-runtime/std", "sp-std/std", - "sp-rpc", - "serde", ] diff --git a/frame/contracts/common/README.md b/frame/contracts/primitives/README.md similarity index 100% rename from frame/contracts/common/README.md rename to frame/contracts/primitives/README.md diff --git a/frame/contracts/common/src/lib.rs b/frame/contracts/primitives/src/lib.rs similarity index 72% rename from frame/contracts/common/src/lib.rs rename to frame/contracts/primitives/src/lib.rs index f810725afcd36..4faea9eb3ee75 100644 --- a/frame/contracts/common/src/lib.rs +++ b/frame/contracts/primitives/src/lib.rs @@ -21,38 +21,23 @@ use bitflags::bitflags; use codec::{Decode, Encode}; -use sp_core::Bytes; use sp_runtime::{ traits::{Saturating, Zero}, DispatchError, RuntimeDebug, }; use sp_std::prelude::*; - -#[cfg(feature = "std")] -use serde::{Deserialize, Serialize}; - -#[cfg(feature = "std")] -use sp_rpc::number::NumberOrHex; +use sp_weights::Weight; /// Result type of a `bare_call` or `bare_instantiate` call. /// /// It contains the execution result together with some auxiliary information. #[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "std", - serde( - rename_all = "camelCase", - bound(serialize = "R: Serialize, Balance: Copy + Into"), - bound(deserialize = "R: Deserialize<'de>, Balance: TryFrom") - ) -)] pub struct ContractResult { - /// How much gas was consumed during execution. - pub gas_consumed: u64, - /// How much gas is required as gas limit in order to execute this call. + /// How much weight was consumed during execution. + pub gas_consumed: Weight, + /// How much weight is required as gas limit in order to execute this call. /// - /// This value should be used to determine the gas limit for on-chain execution. + /// This value should be used to determine the weight limit for on-chain execution. /// /// # Note /// @@ -60,7 +45,7 @@ pub struct ContractResult { /// is used. Currently, only `seal_call_runtime` makes use of pre charging. /// Additionally, any `seal_call` or `seal_instantiate` makes use of pre-charging /// when a non-zero `gas_limit` argument is supplied. - pub gas_required: u64, + pub gas_required: Weight, /// How much balance was deposited and reserved during execution in order to pay for storage. /// /// The storage deposit is never actually charged from the caller in case of [`Self::result`] @@ -80,7 +65,6 @@ pub struct ContractResult { /// /// The debug message is never generated during on-chain execution. It is reserved for /// RPC calls. - #[cfg_attr(feature = "std", serde(with = "as_string"))] pub debug_message: Vec, /// The execution result of the wasm code. pub result: R, @@ -113,8 +97,6 @@ pub enum ContractAccessError { bitflags! { /// Flags used by a contract to customize exit behaviour. #[derive(Encode, Decode)] - #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] - #[cfg_attr(feature = "std", serde(rename_all = "camelCase", transparent))] pub struct ReturnFlags: u32 { /// If this bit is set all changes made by the contract execution are rolled back. const REVERT = 0x0000_0001; @@ -123,13 +105,11 @@ bitflags! { /// Output of a contract call or instantiation which ran to completion. #[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] pub struct ExecReturnValue { /// Flags passed along by `seal_return`. Empty when `seal_return` was never called. pub flags: ReturnFlags, /// Buffer passed along by `seal_return`. Empty when `seal_return` was never called. - pub data: Bytes, + pub data: Vec, } impl ExecReturnValue { @@ -141,8 +121,6 @@ impl ExecReturnValue { /// The result of a successful contract instantiation. #[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] pub struct InstantiateReturnValue { /// The output of the called constructor. pub result: ExecReturnValue, @@ -152,63 +130,40 @@ pub struct InstantiateReturnValue { /// The result of succesfully uploading a contract. #[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "std", - serde( - rename_all = "camelCase", - bound(serialize = "CodeHash: Serialize, Balance: Copy + Into"), - bound(deserialize = "CodeHash: Deserialize<'de>, Balance: TryFrom") - ) -)] pub struct CodeUploadReturnValue { /// The key under which the new code is stored. pub code_hash: CodeHash, /// The deposit that was reserved at the caller. Is zero when the code already existed. - #[cfg_attr(feature = "std", serde(with = "as_hex"))] pub deposit: Balance, } /// Reference to an existing code hash or a new wasm module. #[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] pub enum Code { /// A wasm module as raw bytes. - Upload(Bytes), + Upload(Vec), /// The code hash of an on-chain wasm blob. Existing(Hash), } impl>, Hash> From for Code { fn from(from: T) -> Self { - Code::Upload(Bytes(from.into())) + Code::Upload(from.into()) } } /// The amount of balance that was either charged or refunded in order to pay for storage. #[derive(Eq, PartialEq, Ord, PartialOrd, Encode, Decode, RuntimeDebug, Clone)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "std", - serde( - rename_all = "camelCase", - bound(serialize = "Balance: Copy + Into"), - bound(deserialize = "Balance: TryFrom") - ) -)] pub enum StorageDeposit { /// The transaction reduced storage consumption. /// /// This means that the specified amount of balance was transferred from the involved /// contracts to the call origin. - #[cfg_attr(feature = "std", serde(with = "as_hex"))] Refund(Balance), /// The transaction increased overall storage usage. /// /// This means that the specified amount of balance was transferred from the call origin /// to the contracts involved. - #[cfg_attr(feature = "std", serde(with = "as_hex"))] Charge(Balance), } @@ -295,42 +250,3 @@ where } } } - -#[cfg(feature = "std")] -mod as_string { - use super::*; - use serde::{ser::Error, Deserializer, Serializer}; - - pub fn serialize(bytes: &Vec, serializer: S) -> Result { - std::str::from_utf8(bytes) - .map_err(|e| S::Error::custom(format!("Debug buffer contains invalid UTF8: {}", e)))? - .serialize(serializer) - } - - pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result, D::Error> { - Ok(String::deserialize(deserializer)?.into_bytes()) - } -} - -#[cfg(feature = "std")] -mod as_hex { - use super::*; - use serde::{de::Error as _, Deserializer, Serializer}; - - pub fn serialize(balance: &Balance, serializer: S) -> Result - where - S: Serializer, - Balance: Copy + Into, - { - Into::::into(*balance).serialize(serializer) - } - - pub fn deserialize<'de, D, Balance>(deserializer: D) -> Result - where - D: Deserializer<'de>, - Balance: TryFrom, - { - Balance::try_from(NumberOrHex::deserialize(deserializer)?) - .map_err(|_| D::Error::custom("Cannot decode NumberOrHex to Balance")) - } -} diff --git a/frame/contracts/rpc/Cargo.toml b/frame/contracts/rpc/Cargo.toml deleted file mode 100644 index 7876c7cba40d0..0000000000000 --- a/frame/contracts/rpc/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "pallet-contracts-rpc" -version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" -license = "Apache-2.0" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" -description = "Node-specific RPC methods for interaction with contracts." -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } -serde = { version = "1", features = ["derive"] } - -# Substrate Dependencies -pallet-contracts-primitives = { version = "6.0.0", path = "../common" } -pallet-contracts-rpc-runtime-api = { version = "4.0.0-dev", path = "./runtime-api" } -sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-rpc = { version = "6.0.0", path = "../../../primitives/rpc" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } - -[dev-dependencies] -serde_json = "1" diff --git a/frame/contracts/rpc/README.md b/frame/contracts/rpc/README.md deleted file mode 100644 index be6df237bf60d..0000000000000 --- a/frame/contracts/rpc/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Node-specific RPC methods for interaction with contracts. - -License: Apache-2.0 \ No newline at end of file diff --git a/frame/contracts/rpc/runtime-api/Cargo.toml b/frame/contracts/rpc/runtime-api/Cargo.toml deleted file mode 100644 index bd07d577ec272..0000000000000 --- a/frame/contracts/rpc/runtime-api/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package] -name = "pallet-contracts-rpc-runtime-api" -version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" -license = "Apache-2.0" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" -description = "Runtime API definition required by Contracts RPC extensions." -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } - -# Substrate Dependencies -pallet-contracts-primitives = { version = "6.0.0", default-features = false, path = "../../common" } -sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../../primitives/std" } - -[features] -default = ["std"] -std = [ - "sp-api/std", - "codec/std", - "scale-info/std", - "sp-std/std", - "sp-runtime/std", - "pallet-contracts-primitives/std", -] diff --git a/frame/contracts/rpc/runtime-api/README.md b/frame/contracts/rpc/runtime-api/README.md deleted file mode 100644 index d57f29a93bd1d..0000000000000 --- a/frame/contracts/rpc/runtime-api/README.md +++ /dev/null @@ -1,7 +0,0 @@ -Runtime API definition required by Contracts RPC extensions. - -This API should be imported and implemented by the runtime, -of a node that wants to use the custom RPC extension -adding Contracts access methods. - -License: Apache-2.0 \ No newline at end of file diff --git a/frame/contracts/rpc/runtime-api/src/lib.rs b/frame/contracts/rpc/runtime-api/src/lib.rs deleted file mode 100644 index 9765b37057c7b..0000000000000 --- a/frame/contracts/rpc/runtime-api/src/lib.rs +++ /dev/null @@ -1,85 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Runtime API definition required by Contracts RPC extensions. -//! -//! This API should be imported and implemented by the runtime, -//! of a node that wants to use the custom RPC extension -//! adding Contracts access methods. - -#![cfg_attr(not(feature = "std"), no_std)] - -use codec::Codec; -use pallet_contracts_primitives::{ - Code, CodeUploadResult, ContractExecResult, ContractInstantiateResult, GetStorageResult, -}; -use sp_std::vec::Vec; - -sp_api::decl_runtime_apis! { - /// The API to interact with contracts without using executive. - pub trait ContractsApi where - AccountId: Codec, - Balance: Codec, - BlockNumber: Codec, - Hash: Codec, - { - /// Perform a call from a specified account to a given contract. - /// - /// See `pallet_contracts::Pallet::call`. - fn call( - origin: AccountId, - dest: AccountId, - value: Balance, - gas_limit: u64, - storage_deposit_limit: Option, - input_data: Vec, - ) -> ContractExecResult; - - /// Instantiate a new contract. - /// - /// See `pallet_contracts::Pallet::instantiate`. - fn instantiate( - origin: AccountId, - value: Balance, - gas_limit: u64, - storage_deposit_limit: Option, - code: Code, - data: Vec, - salt: Vec, - ) -> ContractInstantiateResult; - - - /// Upload new code without instantiating a contract from it. - /// - /// See `pallet_contracts::Pallet::upload_code`. - fn upload_code( - origin: AccountId, - code: Vec, - storage_deposit_limit: Option, - ) -> CodeUploadResult; - - /// Query a given storage key in a given contract. - /// - /// Returns `Ok(Some(Vec))` if the storage value exists under the given key in the - /// specified account and `Ok(None)` if it doesn't. If the account specified by the address - /// doesn't exist, or doesn't have a contract then `Err` is returned. - fn get_storage( - address: AccountId, - key: Vec, - ) -> GetStorageResult; - } -} diff --git a/frame/contracts/rpc/src/lib.rs b/frame/contracts/rpc/src/lib.rs deleted file mode 100644 index 1df7a5753f77e..0000000000000 --- a/frame/contracts/rpc/src/lib.rs +++ /dev/null @@ -1,524 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Node-specific RPC methods for interaction with contracts. - -#![warn(unused_crate_dependencies)] - -use std::{marker::PhantomData, sync::Arc}; - -use codec::Codec; -use jsonrpsee::{ - core::{async_trait, Error as JsonRpseeError, RpcResult}, - proc_macros::rpc, - types::error::{CallError, ErrorCode, ErrorObject}, -}; -use pallet_contracts_primitives::{ - Code, CodeUploadResult, ContractExecResult, ContractInstantiateResult, -}; -use serde::{Deserialize, Serialize}; -use sp_api::ProvideRuntimeApi; -use sp_blockchain::HeaderBackend; -use sp_core::Bytes; -use sp_rpc::number::NumberOrHex; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Header as HeaderT}, -}; - -pub use pallet_contracts_rpc_runtime_api::ContractsApi as ContractsRuntimeApi; - -const RUNTIME_ERROR: i32 = 1; -const CONTRACT_DOESNT_EXIST: i32 = 2; -const KEY_DECODING_FAILED: i32 = 3; - -pub type Weight = u64; - -/// A rough estimate of how much gas a decent hardware consumes per second, -/// using native execution. -/// This value is used to set the upper bound for maximal contract calls to -/// prevent blocking the RPC for too long. -/// -/// As 1 gas is equal to 1 weight we base this on the conducted benchmarks which -/// determined runtime weights: -/// -const GAS_PER_SECOND: Weight = 1_000_000_000_000; - -/// The maximum amount of weight that the call and instantiate rpcs are allowed to consume. -/// This puts a ceiling on the weight limit that is supplied to the rpc as an argument. -const GAS_LIMIT: Weight = 5 * GAS_PER_SECOND; - -/// A private newtype for converting `ContractAccessError` into an RPC error. -struct ContractAccessError(pallet_contracts_primitives::ContractAccessError); - -impl From for JsonRpseeError { - fn from(e: ContractAccessError) -> Self { - use pallet_contracts_primitives::ContractAccessError::*; - match e.0 { - DoesntExist => CallError::Custom(ErrorObject::owned( - CONTRACT_DOESNT_EXIST, - "The specified contract doesn't exist.", - None::<()>, - )) - .into(), - KeyDecodingFailed => CallError::Custom(ErrorObject::owned( - KEY_DECODING_FAILED, - "Failed to decode the specified storage key.", - None::<()>, - )) - .into(), - } - } -} - -/// A struct that encodes RPC parameters required for a call to a smart-contract. -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -#[serde(deny_unknown_fields)] -pub struct CallRequest { - origin: AccountId, - dest: AccountId, - value: NumberOrHex, - gas_limit: NumberOrHex, - storage_deposit_limit: Option, - input_data: Bytes, -} - -/// A struct that encodes RPC parameters required to instantiate a new smart-contract. -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -#[serde(deny_unknown_fields)] -pub struct InstantiateRequest { - origin: AccountId, - value: NumberOrHex, - gas_limit: NumberOrHex, - storage_deposit_limit: Option, - code: Code, - data: Bytes, - salt: Bytes, -} - -/// A struct that encodes RPC parameters required for a call to upload a new code. -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -#[serde(deny_unknown_fields)] -pub struct CodeUploadRequest { - origin: AccountId, - code: Bytes, - storage_deposit_limit: Option, -} - -/// Contracts RPC methods. -#[rpc(client, server)] -pub trait ContractsApi -where - Balance: Copy + TryFrom + Into, -{ - /// Executes a call to a contract. - /// - /// This call is performed locally without submitting any transactions. Thus executing this - /// won't change any state. Nonetheless, the calling state-changing contracts is still possible. - /// - /// This method is useful for calling getter-like methods on contracts or to dry-run a - /// a contract call in order to determine the `gas_limit`. - #[method(name = "contracts_call")] - fn call( - &self, - call_request: CallRequest, - at: Option, - ) -> RpcResult>; - - /// Instantiate a new contract. - /// - /// This instantiate is performed locally without submitting any transactions. Thus the contract - /// is not actually created. - /// - /// This method is useful for UIs to dry-run contract instantiations. - #[method(name = "contracts_instantiate")] - fn instantiate( - &self, - instantiate_request: InstantiateRequest, - at: Option, - ) -> RpcResult>; - - /// Upload new code without instantiating a contract from it. - /// - /// This upload is performed locally without submitting any transactions. Thus executing this - /// won't change any state. - /// - /// This method is useful for UIs to dry-run code upload. - #[method(name = "contracts_upload_code")] - fn upload_code( - &self, - upload_request: CodeUploadRequest, - at: Option, - ) -> RpcResult>; - - /// Returns the value under a specified storage `key` in a contract given by `address` param, - /// or `None` if it is not set. - #[method(name = "contracts_getStorage")] - fn get_storage( - &self, - address: AccountId, - key: Bytes, - at: Option, - ) -> RpcResult>; -} - -/// Contracts RPC methods. -pub struct Contracts { - client: Arc, - _marker: PhantomData, -} - -impl Contracts { - /// Create new `Contracts` with the given reference to the client. - pub fn new(client: Arc) -> Self { - Self { client, _marker: Default::default() } - } -} - -#[async_trait] -impl - ContractsApiServer< - ::Hash, - <::Header as HeaderT>::Number, - AccountId, - Balance, - Hash, - > for Contracts -where - Block: BlockT, - Client: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, - Client::Api: ContractsRuntimeApi< - Block, - AccountId, - Balance, - <::Header as HeaderT>::Number, - Hash, - >, - AccountId: Codec, - Balance: Codec + Copy + TryFrom + Into, - Hash: Codec, -{ - fn call( - &self, - call_request: CallRequest, - at: Option<::Hash>, - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = BlockId::hash(at.unwrap_or_else(|| - // If the block hash is not supplied assume the best block. - self.client.info().best_hash)); - - let CallRequest { origin, dest, value, gas_limit, storage_deposit_limit, input_data } = - call_request; - - let value: Balance = decode_hex(value, "balance")?; - let gas_limit: u64 = decode_hex(gas_limit, "weight")?; - let storage_deposit_limit: Option = - storage_deposit_limit.map(|l| decode_hex(l, "balance")).transpose()?; - limit_gas(gas_limit)?; - - api.call(&at, origin, dest, value, gas_limit, storage_deposit_limit, input_data.to_vec()) - .map_err(runtime_error_into_rpc_err) - } - - fn instantiate( - &self, - instantiate_request: InstantiateRequest, - at: Option<::Hash>, - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = BlockId::hash(at.unwrap_or_else(|| - // If the block hash is not supplied assume the best block. - self.client.info().best_hash)); - - let InstantiateRequest { - origin, - value, - gas_limit, - storage_deposit_limit, - code, - data, - salt, - } = instantiate_request; - - let value: Balance = decode_hex(value, "balance")?; - let gas_limit: u64 = decode_hex(gas_limit, "weight")?; - let storage_deposit_limit: Option = - storage_deposit_limit.map(|l| decode_hex(l, "balance")).transpose()?; - limit_gas(gas_limit)?; - - api.instantiate( - &at, - origin, - value, - gas_limit, - storage_deposit_limit, - code, - data.to_vec(), - salt.to_vec(), - ) - .map_err(runtime_error_into_rpc_err) - } - - fn upload_code( - &self, - upload_request: CodeUploadRequest, - at: Option<::Hash>, - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = BlockId::hash(at.unwrap_or_else(|| - // If the block hash is not supplied assume the best block. - self.client.info().best_hash)); - - let CodeUploadRequest { origin, code, storage_deposit_limit } = upload_request; - - let storage_deposit_limit: Option = - storage_deposit_limit.map(|l| decode_hex(l, "balance")).transpose()?; - - api.upload_code(&at, origin, code.to_vec(), storage_deposit_limit) - .map_err(runtime_error_into_rpc_err) - } - - fn get_storage( - &self, - address: AccountId, - key: Bytes, - at: Option<::Hash>, - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); - let result = api - .get_storage(&at, address, key.to_vec()) - .map_err(runtime_error_into_rpc_err)? - .map_err(ContractAccessError)? - .map(Bytes); - - Ok(result) - } -} - -/// Converts a runtime trap into an RPC error. -fn runtime_error_into_rpc_err(err: impl std::fmt::Debug) -> JsonRpseeError { - CallError::Custom(ErrorObject::owned( - RUNTIME_ERROR, - "Runtime error", - Some(format!("{:?}", err)), - )) - .into() -} - -fn decode_hex>(from: H, name: &str) -> RpcResult { - from.try_into().map_err(|_| { - JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( - ErrorCode::InvalidParams.code(), - format!("{:?} does not fit into the {} type", from, name), - None::<()>, - ))) - }) -} - -fn limit_gas(gas_limit: Weight) -> RpcResult<()> { - if gas_limit > GAS_LIMIT { - Err(JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( - ErrorCode::InvalidParams.code(), - format!( - "Requested gas limit is greater than maximum allowed: {} > {}", - gas_limit, GAS_LIMIT - ), - None::<()>, - )))) - } else { - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use pallet_contracts_primitives::{ContractExecResult, ContractInstantiateResult}; - use sp_core::U256; - - fn trim(json: &str) -> String { - json.chars().filter(|c| !c.is_whitespace()).collect() - } - - #[test] - fn call_request_should_serialize_deserialize_properly() { - type Req = CallRequest; - let req: Req = serde_json::from_str( - r#" - { - "origin": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", - "dest": "5DRakbLVnjVrW6niwLfHGW24EeCEvDAFGEXrtaYS5M4ynoom", - "value": "0x112210f4B16c1cb1", - "gasLimit": 1000000000000, - "storageDepositLimit": 5000, - "inputData": "0x8c97db39" - } - "#, - ) - .unwrap(); - assert_eq!(req.gas_limit.into_u256(), U256::from(0xe8d4a51000u64)); - assert_eq!(req.storage_deposit_limit.map(|l| l.into_u256()), Some(5000.into())); - assert_eq!(req.value.into_u256(), U256::from(1234567890987654321u128)); - } - - #[test] - fn instantiate_request_should_serialize_deserialize_properly() { - type Req = InstantiateRequest; - let req: Req = serde_json::from_str( - r#" - { - "origin": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", - "value": "0x88", - "gasLimit": 42, - "code": { "existing": "0x1122" }, - "data": "0x4299", - "salt": "0x9988" - } - "#, - ) - .unwrap(); - - assert_eq!(req.origin, "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL"); - assert_eq!(req.value.into_u256(), 0x88.into()); - assert_eq!(req.gas_limit.into_u256(), 42.into()); - assert_eq!(req.storage_deposit_limit, None); - assert_eq!(&*req.data, [0x42, 0x99].as_ref()); - assert_eq!(&*req.salt, [0x99, 0x88].as_ref()); - let code = match req.code { - Code::Existing(hash) => hash, - _ => panic!("json encoded an existing hash"), - }; - assert_eq!(&code, "0x1122"); - } - - #[test] - fn code_upload_request_should_serialize_deserialize_properly() { - type Req = CodeUploadRequest; - let req: Req = serde_json::from_str( - r#" - { - "origin": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", - "code": "0x8c97db39", - "storageDepositLimit": 5000 - } - "#, - ) - .unwrap(); - assert_eq!(req.origin, "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL"); - assert_eq!(&*req.code, [0x8c, 0x97, 0xdb, 0x39].as_ref()); - assert_eq!(req.storage_deposit_limit.map(|l| l.into_u256()), Some(5000.into())); - } - - #[test] - fn call_result_should_serialize_deserialize_properly() { - fn test(expected: &str) { - let res: ContractExecResult = serde_json::from_str(expected).unwrap(); - let actual = serde_json::to_string(&res).unwrap(); - assert_eq!(actual, trim(expected).as_str()); - } - test( - r#"{ - "gasConsumed": 5000, - "gasRequired": 8000, - "storageDeposit": {"charge": 42000}, - "debugMessage": "HelloWorld", - "result": { - "Ok": { - "flags": 5, - "data": "0x1234" - } - } - }"#, - ); - test( - r#"{ - "gasConsumed": 3400, - "gasRequired": 5200, - "storageDeposit": {"refund": 12000}, - "debugMessage": "HelloWorld", - "result": { - "Err": "BadOrigin" - } - }"#, - ); - } - - #[test] - fn instantiate_result_should_serialize_deserialize_properly() { - fn test(expected: &str) { - let res: ContractInstantiateResult = - serde_json::from_str(expected).unwrap(); - let actual = serde_json::to_string(&res).unwrap(); - assert_eq!(actual, trim(expected).as_str()); - } - test( - r#"{ - "gasConsumed": 5000, - "gasRequired": 8000, - "storageDeposit": {"refund": 12000}, - "debugMessage": "HelloWorld", - "result": { - "Ok": { - "result": { - "flags": 5, - "data": "0x1234" - }, - "accountId": "5CiPP" - } - } - }"#, - ); - test( - r#"{ - "gasConsumed": 3400, - "gasRequired": 5200, - "storageDeposit": {"charge": 0}, - "debugMessage": "HelloWorld", - "result": { - "Err": "BadOrigin" - } - }"#, - ); - } - - #[test] - fn code_upload_result_should_serialize_deserialize_properly() { - fn test(expected: &str) { - let res: CodeUploadResult = serde_json::from_str(expected).unwrap(); - let actual = serde_json::to_string(&res).unwrap(); - assert_eq!(actual, trim(expected).as_str()); - } - test( - r#"{ - "Ok": { - "codeHash": 4711, - "deposit": 99 - } - }"#, - ); - test( - r#"{ - "Err": "BadOrigin" - }"#, - ); - } -} diff --git a/frame/contracts/src/benchmarking/code.rs b/frame/contracts/src/benchmarking/code.rs index 5f9b43d3e3b7a..32ee2dbf93914 100644 --- a/frame/contracts/src/benchmarking/code.rs +++ b/frame/contracts/src/benchmarking/code.rs @@ -195,7 +195,7 @@ where for func in def.imported_functions { let sig = builder::signature() .with_params(func.params) - .with_results(func.return_type.into_iter().collect()) + .with_results(func.return_type) .build_sig(); let sig = contract.push_signature(sig); contract = contract @@ -254,9 +254,9 @@ where code = inject_stack_metering::(code); } - let code = code.to_bytes().unwrap(); + let code = code.into_bytes().unwrap(); let hash = T::Hashing::hash(&code); - Self { code, hash, memory: def.memory } + Self { code: code.into(), hash, memory: def.memory } } } @@ -285,11 +285,11 @@ where .find_map(|e| if let External::Memory(mem) = e.external() { Some(mem) } else { None }) .unwrap() .limits(); - let code = module.to_bytes().unwrap(); + let code = module.into_bytes().unwrap(); let hash = T::Hashing::hash(&code); let memory = ImportedMemory { min_pages: limits.initial(), max_pages: limits.maximum().unwrap() }; - Self { code, hash, memory: Some(memory) } + Self { code: code.into(), hash, memory: Some(memory) } } /// Creates a wasm module with an empty `call` and `deploy` function and nothing else. diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 2f8d101504ffa..186ac6f63503e 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -87,7 +87,7 @@ where module: WasmModule, data: Vec, ) -> Result, &'static str> { - let value = T::Currency::minimum_balance(); + let value = Pallet::::min_balance(); T::Currency::make_free_balance_be(&caller, caller_funding::()); let salt = vec![0xff]; let addr = Contracts::::contract_address(&caller, &module.hash, &salt); @@ -257,7 +257,7 @@ benchmarks! { let instance = Contract::::with_caller( whitelisted_caller(), WasmModule::sized(c, Location::Deploy), vec![], )?; - let value = T::Currency::minimum_balance(); + let value = Pallet::::min_balance(); let origin = RawOrigin::Signed(instance.caller.clone()); let callee = instance.addr; }: call(origin, callee, value, Weight::MAX, None, vec![]) @@ -280,7 +280,7 @@ benchmarks! { let c in 0 .. Perbill::from_percent(49).mul_ceil(T::MaxCodeLen::get()); let s in 0 .. code::max_pages::() * 64 * 1024; let salt = vec![42u8; s as usize]; - let value = T::Currency::minimum_balance(); + let value = Pallet::::min_balance(); let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, caller_funding::()); let WasmModule { code, hash, .. } = WasmModule::::sized(c, Location::Call); @@ -307,7 +307,7 @@ benchmarks! { instantiate { let s in 0 .. code::max_pages::() * 64 * 1024; let salt = vec![42u8; s as usize]; - let value = T::Currency::minimum_balance(); + let value = Pallet::::min_balance(); let caller = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, caller_funding::()); let WasmModule { code, hash, .. } = WasmModule::::dummy(); @@ -338,7 +338,7 @@ benchmarks! { let instance = Contract::::with_caller( whitelisted_caller(), WasmModule::dummy(), vec![], )?; - let value = T::Currency::minimum_balance(); + let value = Pallet::::min_balance(); let origin = RawOrigin::Signed(instance.caller.clone()); let callee = instance.addr.clone(); let before = T::Currency::free_balance(&instance.account_id); @@ -618,11 +618,11 @@ benchmarks! { imported_functions: vec![ImportedFunction { module: "seal0", name: "gas", - params: vec![ValueType::I32], + params: vec![ValueType::I64], return_type: None, }], call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[ - Instruction::I32Const(42), + Instruction::I64Const(42), Instruction::Call(0), ])), .. Default::default() @@ -767,13 +767,13 @@ benchmarks! { let instance = Contract::::new(code, vec![])?; let origin = RawOrigin::Signed(instance.caller.clone()); assert_eq!(T::Currency::total_balance(&beneficiary), 0u32.into()); - assert_eq!(T::Currency::free_balance(&instance.account_id), T::Currency::minimum_balance()); + assert_eq!(T::Currency::free_balance(&instance.account_id), Pallet::::min_balance()); assert_ne!(T::Currency::reserved_balance(&instance.account_id), 0u32.into()); }: call(origin, instance.addr.clone(), 0u32.into(), Weight::MAX, None, vec![]) verify { if r > 0 { assert_eq!(T::Currency::total_balance(&instance.account_id), 0u32.into()); - assert_eq!(T::Currency::total_balance(&beneficiary), T::Currency::minimum_balance()); + assert_eq!(T::Currency::total_balance(&beneficiary), Pallet::::min_balance()); } } @@ -1469,7 +1469,7 @@ benchmarks! { .collect::>(); let account_len = accounts.get(0).map(|i| i.encode().len()).unwrap_or(0); let account_bytes = accounts.iter().flat_map(|x| x.encode()).collect(); - let value = T::Currency::minimum_balance(); + let value = Pallet::::min_balance(); assert!(value > 0u32.into()); let value_bytes = value.encode(); let value_len = value_bytes.len(); @@ -1705,7 +1705,7 @@ benchmarks! { let hash_len = hashes.get(0).map(|x| x.encode().len()).unwrap_or(0); let hashes_bytes = hashes.iter().flat_map(|x| x.encode()).collect::>(); let hashes_len = hashes_bytes.len(); - let value = T::Currency::minimum_balance(); + let value = Pallet::::min_balance(); assert!(value > 0u32.into()); let value_bytes = value.encode(); let value_len = value_bytes.len(); diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index 4ae336a907001..bf35410d0bd4b 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -282,7 +282,7 @@ pub trait Ext: sealing::Sealed { fn append_debug_buffer(&mut self, msg: &str) -> bool; /// Call some dispatchable and return the result. - fn call_runtime(&self, call: ::Call) -> DispatchResultWithPostInfo; + fn call_runtime(&self, call: ::RuntimeCall) -> DispatchResultWithPostInfo; /// Recovers ECDSA compressed public key based on signature and message hash. fn ecdsa_recover(&self, signature: &[u8; 65], message_hash: &[u8; 32]) -> Result<[u8; 33], ()>; @@ -813,6 +813,15 @@ where return Ok(output) } + // Storage limit is enforced as late as possible (when the last frame returns) so that + // the ordering of storage accesses does not matter. + if self.frames.is_empty() { + let frame = &mut self.first_frame; + frame.contract_info.load(&frame.account_id); + let contract = frame.contract_info.as_contract(); + frame.nested_storage.enforce_limit(contract)?; + } + let frame = self.top_frame(); let account_id = &frame.account_id; match (entry_point, delegated_code_hash) { @@ -911,12 +920,7 @@ where // it was invalidated. frame.contract_info.load(account_id); let mut contract = frame.contract_info.into_contract(); - prev.nested_storage.absorb( - frame.nested_storage, - &self.origin, - account_id, - contract.as_mut(), - ); + prev.nested_storage.absorb(frame.nested_storage, account_id, contract.as_mut()); // In case the contract wasn't terminated we need to persist changes made to it. if let Some(contract) = contract { @@ -954,7 +958,6 @@ where let mut contract = self.first_frame.contract_info.as_contract(); self.storage_meter.absorb( mem::take(&mut self.first_frame.nested_storage), - &self.origin, &self.first_frame.account_id, contract.as_deref_mut(), ); @@ -1305,8 +1308,8 @@ where } } - fn call_runtime(&self, call: ::Call) -> DispatchResultWithPostInfo { - let mut origin: T::Origin = RawOrigin::Signed(self.address().clone()).into(); + fn call_runtime(&self, call: ::RuntimeCall) -> DispatchResultWithPostInfo { + let mut origin: T::RuntimeOrigin = RawOrigin::Signed(self.address().clone()).into(); origin.add_filter(T::CallFilter::contains); call.dispatch(origin) } @@ -1370,18 +1373,17 @@ mod tests { storage::Storage, tests::{ test_utils::{get_balance, hash, place_contract, set_balance}, - Call, Event as MetaEvent, ExtBuilder, Test, TestFilter, ALICE, BOB, CHARLIE, GAS_LIMIT, + ExtBuilder, RuntimeCall, RuntimeEvent as MetaEvent, Test, TestFilter, ALICE, BOB, + CHARLIE, GAS_LIMIT, }, Error, }; use assert_matches::assert_matches; use codec::{Decode, Encode}; - use frame_support::{assert_err, assert_ok}; + use frame_support::{assert_err, assert_ok, parameter_types}; use frame_system::{EventRecord, Phase}; - use hex_literal::hex; use pallet_contracts_primitives::ReturnFlags; use pretty_assertions::assert_eq; - use sp_core::Bytes; use sp_runtime::{traits::Hash, DispatchError}; use std::{ cell::RefCell, @@ -1393,8 +1395,8 @@ mod tests { type MockStack<'a> = Stack<'a, Test, MockExecutable>; - thread_local! { - static LOADER: RefCell = RefCell::new(MockLoader::default()); + parameter_types! { + static Loader: MockLoader = MockLoader::default(); } fn events() -> Vec> { @@ -1420,8 +1422,8 @@ mod tests { refcount: u64, } - #[derive(Default)] - struct MockLoader { + #[derive(Default, Clone)] + pub struct MockLoader { map: HashMap, MockExecutable>, counter: u64, } @@ -1431,8 +1433,7 @@ mod tests { func_type: ExportedFunction, f: impl Fn(MockCtx, &MockExecutable) -> ExecResult + 'static, ) -> CodeHash { - LOADER.with(|loader| { - let mut loader = loader.borrow_mut(); + Loader::mutate(|loader| { // Generate code hashes as monotonically increasing values. let hash = ::Hash::from_low_u64_be(loader.counter); loader.counter += 1; @@ -1445,8 +1446,7 @@ mod tests { } fn increment_refcount(code_hash: CodeHash) -> Result<(), DispatchError> { - LOADER.with(|loader| { - let mut loader = loader.borrow_mut(); + Loader::mutate(|loader| { match loader.map.entry(code_hash) { Entry::Vacant(_) => Err(>::CodeNotFound)?, Entry::Occupied(mut entry) => entry.get_mut().refcount += 1, @@ -1457,8 +1457,7 @@ mod tests { fn decrement_refcount(code_hash: CodeHash) { use std::collections::hash_map::Entry::Occupied; - LOADER.with(|loader| { - let mut loader = loader.borrow_mut(); + Loader::mutate(|loader| { let mut entry = match loader.map.entry(code_hash) { Occupied(e) => e, _ => panic!("code_hash does not exist"), @@ -1478,13 +1477,8 @@ mod tests { _schedule: &Schedule, _gas_meter: &mut GasMeter, ) -> Result { - LOADER.with(|loader| { - loader - .borrow_mut() - .map - .get(&code_hash) - .cloned() - .ok_or(Error::::CodeNotFound.into()) + Loader::mutate(|loader| { + loader.map.get(&code_hash).cloned().ok_or(Error::::CodeNotFound.into()) }) } @@ -1522,7 +1516,7 @@ mod tests { } fn exec_success() -> ExecResult { - Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }) + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }) } fn exec_trapped() -> ExecResult { @@ -1531,14 +1525,14 @@ mod tests { #[test] fn it_works() { - thread_local! { - static TEST_DATA: RefCell> = RefCell::new(vec![0]); + parameter_types! { + static TestData: Vec = vec![0]; } let value = Default::default(); let mut gas_meter = GasMeter::::new(GAS_LIMIT); let exec_ch = MockLoader::insert(Call, |_ctx, _executable| { - TEST_DATA.with(|data| data.borrow_mut().push(1)); + TestData::mutate(|data| data.push(1)); exec_success() }); @@ -1562,7 +1556,7 @@ mod tests { ); }); - TEST_DATA.with(|data| assert_eq!(*data.borrow(), vec![0, 1])); + assert_eq!(TestData::get(), vec![0, 1]); } #[test] @@ -1591,7 +1585,7 @@ mod tests { let success_ch = MockLoader::insert(Call, move |ctx, _| { assert_eq!(ctx.ext.value_transferred(), value); - Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }) + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }) }); ExtBuilder::default().build().execute_with(|| { @@ -1626,13 +1620,13 @@ mod tests { let success_ch = MockLoader::insert(Call, move |ctx, _| { assert_eq!(ctx.ext.value_transferred(), value); - Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }) + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }) }); let delegate_ch = MockLoader::insert(Call, move |ctx, _| { assert_eq!(ctx.ext.value_transferred(), value); let _ = ctx.ext.delegate_call(success_ch, Vec::new())?; - Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }) + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }) }); ExtBuilder::default().build().execute_with(|| { @@ -1667,7 +1661,7 @@ mod tests { let dest = BOB; let return_ch = MockLoader::insert(Call, |_, _| { - Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: Bytes(Vec::new()) }) + Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: Vec::new() }) }); ExtBuilder::default().build().execute_with(|| { @@ -1720,7 +1714,7 @@ mod tests { let origin = ALICE; let dest = BOB; let return_ch = MockLoader::insert(Call, |_, _| { - Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(vec![1, 2, 3, 4]) }) + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: vec![1, 2, 3, 4] }) }); ExtBuilder::default().build().execute_with(|| { @@ -1741,7 +1735,7 @@ mod tests { let output = result.unwrap(); assert!(!output.did_revert()); - assert_eq!(output.data, Bytes(vec![1, 2, 3, 4])); + assert_eq!(output.data, vec![1, 2, 3, 4]); }); } @@ -1752,7 +1746,7 @@ mod tests { let origin = ALICE; let dest = BOB; let return_ch = MockLoader::insert(Call, |_, _| { - Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: Bytes(vec![1, 2, 3, 4]) }) + Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: vec![1, 2, 3, 4] }) }); ExtBuilder::default().build().execute_with(|| { @@ -1773,7 +1767,7 @@ mod tests { let output = result.unwrap(); assert!(output.did_revert()); - assert_eq!(output.data, Bytes(vec![1, 2, 3, 4])); + assert_eq!(output.data, vec![1, 2, 3, 4]); }); } @@ -1841,16 +1835,15 @@ mod tests { fn max_depth() { // This test verifies that when we reach the maximal depth creation of an // yet another context fails. - thread_local! { - static REACHED_BOTTOM: RefCell = RefCell::new(false); + parameter_types! { + static ReachedBottom: bool = false; } let value = Default::default(); let recurse_ch = MockLoader::insert(Call, |ctx, _| { // Try to call into yourself. let r = ctx.ext.call(Weight::zero(), BOB, 0, vec![], true); - REACHED_BOTTOM.with(|reached_bottom| { - let mut reached_bottom = reached_bottom.borrow_mut(); + ReachedBottom::mutate(|reached_bottom| { if !*reached_bottom { // We are first time here, it means we just reached bottom. // Verify that we've got proper error and set `reached_bottom`. @@ -1891,15 +1884,14 @@ mod tests { let origin = ALICE; let dest = BOB; - thread_local! { - static WITNESSED_CALLER_BOB: RefCell>> = RefCell::new(None); - static WITNESSED_CALLER_CHARLIE: RefCell>> = RefCell::new(None); + parameter_types! { + static WitnessedCallerBob: Option> = None; + static WitnessedCallerCharlie: Option> = None; } let bob_ch = MockLoader::insert(Call, |ctx, _| { // Record the caller for bob. - WITNESSED_CALLER_BOB - .with(|caller| *caller.borrow_mut() = Some(ctx.ext.caller().clone())); + WitnessedCallerBob::mutate(|caller| *caller = Some(ctx.ext.caller().clone())); // Call into CHARLIE contract. assert_matches!(ctx.ext.call(Weight::zero(), CHARLIE, 0, vec![], true), Ok(_)); @@ -1907,8 +1899,7 @@ mod tests { }); let charlie_ch = MockLoader::insert(Call, |ctx, _| { // Record the caller for charlie. - WITNESSED_CALLER_CHARLIE - .with(|caller| *caller.borrow_mut() = Some(ctx.ext.caller().clone())); + WitnessedCallerCharlie::mutate(|caller| *caller = Some(ctx.ext.caller().clone())); exec_success() }); @@ -1932,8 +1923,8 @@ mod tests { assert_matches!(result, Ok(_)); }); - WITNESSED_CALLER_BOB.with(|caller| assert_eq!(*caller.borrow(), Some(origin))); - WITNESSED_CALLER_CHARLIE.with(|caller| assert_eq!(*caller.borrow(), Some(dest))); + assert_eq!(WitnessedCallerBob::get(), Some(origin)); + assert_eq!(WitnessedCallerCharlie::get(), Some(dest)); } #[test] @@ -2123,7 +2114,7 @@ mod tests { #[test] fn instantiation_work_with_success_output() { let dummy_ch = MockLoader::insert(Constructor, |_, _| { - Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(vec![80, 65, 83, 83]) }) + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: vec![80, 65, 83, 83] }) }); ExtBuilder::default().existential_deposit(15).build().execute_with(|| { @@ -2148,7 +2139,7 @@ mod tests { &[], None, ), - Ok((address, ref output)) if output.data == Bytes(vec![80, 65, 83, 83]) => address + Ok((address, ref output)) if output.data == vec![80, 65, 83, 83] => address ); // Check that the newly created account has the expected code hash and @@ -2167,7 +2158,7 @@ mod tests { #[test] fn instantiation_fails_with_failing_output() { let dummy_ch = MockLoader::insert(Constructor, |_, _| { - Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: Bytes(vec![70, 65, 73, 76]) }) + Ok(ExecReturnValue { flags: ReturnFlags::REVERT, data: vec![70, 65, 73, 76] }) }); ExtBuilder::default().existential_deposit(15).build().execute_with(|| { @@ -2192,7 +2183,7 @@ mod tests { &[], None, ), - Ok((address, ref output)) if output.data == Bytes(vec![70, 65, 73, 76]) => address + Ok((address, ref output)) if output.data == vec![70, 65, 73, 76] => address ); // Check that the account has not been created. @@ -2365,10 +2356,10 @@ mod tests { let code_bob = MockLoader::insert(Call, |ctx, _| { if ctx.input_data[0] == 0 { let info = ctx.ext.contract_info(); - assert_eq!(info.storage_deposit, 0); - info.storage_deposit = 42; + assert_eq!(info.storage_byte_deposit, 0); + info.storage_byte_deposit = 42; assert_eq!(ctx.ext.call(Weight::zero(), CHARLIE, 0, vec![], true), exec_trapped()); - assert_eq!(ctx.ext.contract_info().storage_deposit, 42); + assert_eq!(ctx.ext.contract_info().storage_byte_deposit, 42); } exec_success() }); @@ -2586,7 +2577,7 @@ mod tests { #[test] fn call_runtime_works() { let code_hash = MockLoader::insert(Call, |ctx, _| { - let call = Call::System(frame_system::Call::remark_with_event { + let call = RuntimeCall::System(frame_system::Call::remark_with_event { remark: b"Hello World".to_vec(), }); ctx.ext.call_runtime(call).unwrap(); @@ -2647,10 +2638,11 @@ mod tests { // remark should still be allowed let allowed_call = - Call::System(SysCall::remark_with_event { remark: b"Hello".to_vec() }); + RuntimeCall::System(SysCall::remark_with_event { remark: b"Hello".to_vec() }); // transfers are disallowed by the `TestFiler` (see below) - let forbidden_call = Call::Balances(BalanceCall::transfer { dest: CHARLIE, value: 22 }); + let forbidden_call = + RuntimeCall::Balances(BalanceCall::transfer { dest: CHARLIE, value: 22 }); // simple cases: direct call assert_err!( @@ -2659,7 +2651,7 @@ mod tests { ); // as part of a patch: return is OK (but it interrupted the batch) - assert_ok!(ctx.ext.call_runtime(Call::Utility(UtilCall::batch { + assert_ok!(ctx.ext.call_runtime(RuntimeCall::Utility(UtilCall::batch { calls: vec![allowed_call.clone(), forbidden_call, allowed_call] })),); @@ -2670,7 +2662,7 @@ mod tests { }); TestFilter::set_filter(|call| match call { - Call::Balances(pallet_balances::Call::transfer { .. }) => false, + RuntimeCall::Balances(pallet_balances::Call::transfer { .. }) => false, _ => true, }); @@ -3219,13 +3211,12 @@ mod tests { #[test] fn ecdsa_to_eth_address_returns_proper_value() { let bob_ch = MockLoader::insert(Call, |ctx, _| { - let pubkey_compressed: [u8; 33] = - hex!("028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd91")[..] - .try_into() - .unwrap(); + let pubkey_compressed = array_bytes::hex2array_unchecked( + "028db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd91", + ); assert_eq!( ctx.ext.ecdsa_to_eth_address(&pubkey_compressed).unwrap(), - hex!("09231da7b19A016f9e576d23B16277062F4d46A8")[..] + array_bytes::hex2array_unchecked::<20>("09231da7b19A016f9e576d23B16277062F4d46A8") ); exec_success() }); diff --git a/frame/contracts/src/gas.rs b/frame/contracts/src/gas.rs index ae20e4eeb0def..c0cc2db2aa3eb 100644 --- a/frame/contracts/src/gas.rs +++ b/frame/contracts/src/gas.rs @@ -107,32 +107,45 @@ where /// /// Passing `0` as amount is interpreted as "all remaining gas". pub fn nested(&mut self, amount: Weight) -> Result { - let amount = if amount == Weight::zero() { self.gas_left } else { amount }; - // NOTE that it is ok to allocate all available gas since it still ensured // by `charge` that it doesn't reach zero. - if self.gas_left < amount { - Err(>::OutOfGas.into()) - } else { - self.gas_left -= amount; - Ok(GasMeter::new(amount)) - } + let amount = Weight::from_parts( + if amount.ref_time().is_zero() { + self.gas_left().ref_time() + } else { + amount.ref_time() + }, + if amount.proof_size().is_zero() { + self.gas_left().proof_size() + } else { + amount.proof_size() + }, + ); + self.gas_left = self.gas_left.checked_sub(&amount).ok_or_else(|| >::OutOfGas)?; + Ok(GasMeter::new(amount)) } /// Absorb the remaining gas of a nested meter after we are done using it. pub fn absorb_nested(&mut self, nested: Self) { - if self.gas_left == Weight::zero() { + if self.gas_left.ref_time().is_zero() { // All of the remaining gas was inherited by the nested gas meter. When absorbing // we can therefore safely inherit the lowest gas that the nested gas meter experienced // as long as it is lower than the lowest gas that was experienced by the parent. // We cannot call `self.gas_left_lowest()` here because in the state that this // code is run the parent gas meter has `0` gas left. - self.gas_left_lowest = nested.gas_left_lowest().min(self.gas_left_lowest); + *self.gas_left_lowest.ref_time_mut() = + nested.gas_left_lowest().ref_time().min(self.gas_left_lowest.ref_time()); } else { // The nested gas meter was created with a fixed amount that did not consume all of the // parents (self) gas. The lowest gas that self will experience is when the nested // gas was pre charged with the fixed amount. - self.gas_left_lowest = self.gas_left_lowest(); + *self.gas_left_lowest.ref_time_mut() = self.gas_left_lowest().ref_time(); + } + if self.gas_left.proof_size().is_zero() { + *self.gas_left_lowest.proof_size_mut() = + nested.gas_left_lowest().proof_size().min(self.gas_left_lowest.proof_size()); + } else { + *self.gas_left_lowest.proof_size_mut() = self.gas_left_lowest().proof_size(); } self.gas_left += nested.gas_left; } @@ -155,17 +168,11 @@ where ErasedToken { description: format!("{:?}", token), token: Box::new(token) }; self.tokens.push(erased_tok); } - let amount = token.weight(); - let new_value = self.gas_left.checked_sub(&amount); - - // We always consume the gas even if there is not enough gas. - self.gas_left = new_value.unwrap_or_else(Zero::zero); - - match new_value { - Some(_) => Ok(ChargedAmount(amount)), - None => Err(Error::::OutOfGas.into()), - } + // It is OK to not charge anything on failure because we always charge _before_ we perform + // any action + self.gas_left = self.gas_left.checked_sub(&amount).ok_or_else(|| Error::::OutOfGas)?; + Ok(ChargedAmount(amount)) } /// Adjust a previously charged amount down to its actual amount. @@ -298,20 +305,16 @@ mod tests { assert!(gas_meter.charge(SimpleToken(1)).is_err()); } - // Make sure that if the gas meter is charged by exceeding amount then not only an error - // returned for that charge, but also for all consequent charges. - // - // This is not strictly necessary, because the execution should be interrupted immediately - // if the gas meter runs out of gas. However, this is just a nice property to have. + // Make sure that the gas meter does not charge in case of overcharger #[test] - fn overcharge_is_unrecoverable() { + fn overcharge_does_not_charge() { let mut gas_meter = GasMeter::::new(Weight::from_ref_time(200)); // The first charge is should lead to OOG. assert!(gas_meter.charge(SimpleToken(300)).is_err()); - // The gas meter is emptied at this moment, so this should also fail. - assert!(gas_meter.charge(SimpleToken(1)).is_err()); + // The gas meter should still contain the full 200. + assert!(gas_meter.charge(SimpleToken(200)).is_ok()); } // Charging the exact amount that the user paid for should be diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 3c63ad86016f3..d48a71b85e9fe 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -87,12 +87,12 @@ mod gas; mod benchmarking; mod exec; +mod migration; mod schedule; mod storage; mod wasm; pub mod chain_extension; -pub mod migration; pub mod weights; #[cfg(test)] @@ -105,27 +105,31 @@ use crate::{ wasm::{OwnerInfo, PrefabWasmModule}, weights::WeightInfo, }; -use codec::{Encode, HasCompact}; +use codec::{Codec, Encode, HasCompact}; use frame_support::{ - dispatch::Dispatchable, + dispatch::{Dispatchable, GetDispatchInfo, Pays, PostDispatchInfo}, ensure, - traits::{ConstU32, Contains, Currency, Get, Randomness, ReservableCurrency, Time}, - weights::{DispatchClass, GetDispatchInfo, Pays, PostDispatchInfo, Weight}, - BoundedVec, + traits::{ + tokens::fungible::Inspect, ConstU32, Contains, Currency, Get, Randomness, + ReservableCurrency, Time, + }, + weights::{OldWeight, Weight}, + BoundedVec, WeakBoundedVec, }; -use frame_system::{limits::BlockWeights, Pallet as System}; +use frame_system::Pallet as System; use pallet_contracts_primitives::{ Code, CodeUploadResult, CodeUploadReturnValue, ContractAccessError, ContractExecResult, ContractInstantiateResult, ExecReturnValue, GetStorageResult, InstantiateReturnValue, StorageDeposit, }; use scale_info::TypeInfo; -use sp_core::{crypto::UncheckedFrom, Bytes}; +use sp_core::crypto::UncheckedFrom; use sp_runtime::traits::{Convert, Hash, Saturating, StaticLookup}; use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; pub use crate::{ exec::{Frame, VarSizedKey as StorageKey}, + migration::Migration, pallet::*, schedule::{HostFnWeights, InstructionWeights, Limits, Schedule}, }; @@ -135,7 +139,7 @@ type TrieId = BoundedVec>; type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; type CodeVec = BoundedVec::MaxCodeLen>; -type RelaxedCodeVec = BoundedVec::RelaxedMaxCodeLen>; +type RelaxedCodeVec = WeakBoundedVec::MaxCodeLen>; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; /// Used as a sentinel value when reading and writing contract memory. @@ -195,29 +199,6 @@ where } } -/// A conservative implementation to be used for [`pallet::Config::ContractAccessWeight`]. -/// -/// This derives the weight from the [`BlockWeights`] passed as `B` and the `maxPovSize` passed -/// as `P`. The default value for `P` is the `maxPovSize` used by Polkadot and Kusama. -/// -/// It simply charges from the weight meter pro rata: If loading the contract code would consume -/// 50% of the max storage proof then this charges 50% of the max block weight. -pub struct DefaultContractAccessWeight, const P: u32 = 5_242_880>( - PhantomData, -); - -impl, const P: u32> Get for DefaultContractAccessWeight { - fn get() -> Weight { - let block_weights = B::get(); - block_weights - .per_class - .get(DispatchClass::Normal) - .max_total - .unwrap_or(block_weights.max_block) / - u64::from(P) - } -} - #[frame_support::pallet] pub mod pallet { use super::*; @@ -225,7 +206,7 @@ pub mod pallet { use frame_system::pallet_prelude::*; /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(7); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(8); #[pallet::pallet] #[pallet::storage_version(STORAGE_VERSION)] @@ -236,20 +217,21 @@ pub mod pallet { /// The time implementation used to supply timestamps to contracts through `seal_now`. type Time: Time; - /// The generator used to supply randomness to contracts through `seal_random`. + /// The generator used to supply randomness to contracts through `seal_random` type Randomness: Randomness; /// The currency in which fees are paid and contract balances are held. - type Currency: ReservableCurrency; + type Currency: ReservableCurrency + + Inspect>; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The overarching call type. - type Call: Dispatchable + type RuntimeCall: Dispatchable + GetDispatchInfo + codec::Decode - + IsType<::Call>; + + IsType<::RuntimeCall>; /// Filter that is applied to calls dispatched by contracts. /// @@ -260,7 +242,7 @@ pub mod pallet { /// # Stability /// /// The runtime **must** make sure that all dispatchables that are callable by - /// contracts remain stable. In addition [`Self::Call`] itself must remain stable. + /// contracts remain stable. In addition [`Self::RuntimeCall`] itself must remain stable. /// This means that no existing variants are allowed to switch their positions. /// /// # Note @@ -270,7 +252,7 @@ pub mod pallet { /// Therefore please make sure to be restrictive about which dispatchables are allowed /// in order to not introduce a new DoS vector like memory allocation patterns that can /// be exploited to drive the runtime into a panic. - type CallFilter: Contains<::Call>; + type CallFilter: Contains<::RuntimeCall>; /// Used to answer contracts' queries regarding the current weight price. This is **not** /// used to calculate the actual fee and is only for informational purposes. @@ -329,27 +311,6 @@ pub mod pallet { #[pallet::constant] type DepositPerByte: Get>; - /// The weight per byte of code that is charged when loading a contract from storage. - /// - /// Currently, FRAME only charges fees for computation incurred but not for PoV - /// consumption caused for storage access. This is usually not exploitable because - /// accessing storage carries some substantial weight costs, too. However in case - /// of contract code very much PoV consumption can be caused while consuming very little - /// computation. This could be used to keep the chain busy without paying the - /// proper fee for it. Until this is resolved we charge from the weight meter for - /// contract access. - /// - /// For more information check out: - /// - /// [`DefaultContractAccessWeight`] is a safe default to be used for Polkadot or Kusama - /// parachains. - /// - /// # Note - /// - /// This is only relevant for parachains. Set to zero in case of a standalone chain. - #[pallet::constant] - type ContractAccessWeight: Get; - /// The amount of balance a caller has to pay for each storage item. /// /// # Note @@ -366,15 +327,6 @@ pub mod pallet { /// a wasm binary below this maximum size. type MaxCodeLen: Get; - /// The maximum length of a contract code after reinstrumentation. - /// - /// When uploading a new contract the size defined by [`Self::MaxCodeLen`] is used for both - /// the pristine **and** the instrumented version. When a existing contract needs to be - /// reinstrumented after a runtime upgrade we apply this bound. The reason is that if the - /// new instrumentation increases the size beyond the limit it would make that contract - /// inaccessible until rectified by another runtime upgrade. - type RelaxedMaxCodeLen: Get; - /// The maximum allowable length in bytes for storage keys. type MaxStorageKeyLen: Get; } @@ -417,6 +369,163 @@ pub mod pallet { T::AccountId: AsRef<[u8]>, as HasCompact>::Type: Clone + Eq + PartialEq + Debug + TypeInfo + Encode, { + /// Deprecated version if [`Self::call`] for use in an in-storage `Call`. + #[pallet::weight(T::WeightInfo::call().saturating_add(>::compat_weight(*gas_limit)))] + #[allow(deprecated)] + #[deprecated(note = "1D weight is used in this extrinsic, please migrate to `call`")] + pub fn call_old_weight( + origin: OriginFor, + dest: AccountIdLookupOf, + #[pallet::compact] value: BalanceOf, + #[pallet::compact] gas_limit: OldWeight, + storage_deposit_limit: Option< as codec::HasCompact>::Type>, + data: Vec, + ) -> DispatchResultWithPostInfo { + Self::call( + origin, + dest, + value, + >::compat_weight(gas_limit), + storage_deposit_limit, + data, + ) + } + + /// Deprecated version if [`Self::instantiate_with_code`] for use in an in-storage `Call`. + #[pallet::weight( + T::WeightInfo::instantiate_with_code(code.len() as u32, salt.len() as u32) + .saturating_add(>::compat_weight(*gas_limit)) + )] + #[allow(deprecated)] + #[deprecated( + note = "1D weight is used in this extrinsic, please migrate to `instantiate_with_code`" + )] + pub fn instantiate_with_code_old_weight( + origin: OriginFor, + #[pallet::compact] value: BalanceOf, + #[pallet::compact] gas_limit: OldWeight, + storage_deposit_limit: Option< as codec::HasCompact>::Type>, + code: Vec, + data: Vec, + salt: Vec, + ) -> DispatchResultWithPostInfo { + Self::instantiate_with_code( + origin, + value, + >::compat_weight(gas_limit), + storage_deposit_limit, + code, + data, + salt, + ) + } + + /// Deprecated version if [`Self::instantiate`] for use in an in-storage `Call`. + #[pallet::weight( + T::WeightInfo::instantiate(salt.len() as u32).saturating_add(>::compat_weight(*gas_limit)) + )] + #[allow(deprecated)] + #[deprecated(note = "1D weight is used in this extrinsic, please migrate to `instantiate`")] + pub fn instantiate_old_weight( + origin: OriginFor, + #[pallet::compact] value: BalanceOf, + #[pallet::compact] gas_limit: OldWeight, + storage_deposit_limit: Option< as codec::HasCompact>::Type>, + code_hash: CodeHash, + data: Vec, + salt: Vec, + ) -> DispatchResultWithPostInfo { + Self::instantiate( + origin, + value, + >::compat_weight(gas_limit), + storage_deposit_limit, + code_hash, + data, + salt, + ) + } + + /// Upload new `code` without instantiating a contract from it. + /// + /// If the code does not already exist a deposit is reserved from the caller + /// and unreserved only when [`Self::remove_code`] is called. The size of the reserve + /// depends on the instrumented size of the the supplied `code`. + /// + /// If the code already exists in storage it will still return `Ok` and upgrades + /// the in storage version to the current + /// [`InstructionWeights::version`](InstructionWeights). + /// + /// # Note + /// + /// Anyone can instantiate a contract from any uploaded code and thus prevent its removal. + /// To avoid this situation a constructor could employ access control so that it can + /// only be instantiated by permissioned entities. The same is true when uploading + /// through [`Self::instantiate_with_code`]. + #[pallet::weight(T::WeightInfo::upload_code(code.len() as u32))] + pub fn upload_code( + origin: OriginFor, + code: Vec, + storage_deposit_limit: Option< as codec::HasCompact>::Type>, + ) -> DispatchResult { + let origin = ensure_signed(origin)?; + Self::bare_upload_code(origin, code, storage_deposit_limit.map(Into::into)).map(|_| ()) + } + + /// Remove the code stored under `code_hash` and refund the deposit to its owner. + /// + /// A code can only be removed by its original uploader (its owner) and only if it is + /// not used by any contract. + #[pallet::weight(T::WeightInfo::remove_code())] + pub fn remove_code( + origin: OriginFor, + code_hash: CodeHash, + ) -> DispatchResultWithPostInfo { + let origin = ensure_signed(origin)?; + >::remove(&origin, code_hash)?; + // we waive the fee because removing unused code is beneficial + Ok(Pays::No.into()) + } + + /// Privileged function that changes the code of an existing contract. + /// + /// This takes care of updating refcounts and all other necessary operations. Returns + /// an error if either the `code_hash` or `dest` do not exist. + /// + /// # Note + /// + /// This does **not** change the address of the contract in question. This means + /// that the contract address is no longer derived from its code hash after calling + /// this dispatchable. + #[pallet::weight(T::WeightInfo::set_code())] + pub fn set_code( + origin: OriginFor, + dest: AccountIdLookupOf, + code_hash: CodeHash, + ) -> DispatchResult { + ensure_root(origin)?; + let dest = T::Lookup::lookup(dest)?; + >::try_mutate(&dest, |contract| { + let contract = if let Some(contract) = contract { + contract + } else { + return Err(>::ContractNotFound.into()) + }; + >::add_user(code_hash)?; + >::remove_user(contract.code_hash); + Self::deposit_event( + vec![T::Hashing::hash_of(&dest), code_hash, contract.code_hash], + Event::ContractCodeUpdated { + contract: dest.clone(), + new_code_hash: code_hash, + old_code_hash: contract.code_hash, + }, + ); + contract.code_hash = code_hash; + Ok(()) + }) + } + /// Makes a call to an account, optionally transferring some balance. /// /// # Parameters @@ -438,10 +547,11 @@ pub mod pallet { origin: OriginFor, dest: AccountIdLookupOf, #[pallet::compact] value: BalanceOf, - #[pallet::compact] gas_limit: Weight, + gas_limit: Weight, storage_deposit_limit: Option< as codec::HasCompact>::Type>, data: Vec, ) -> DispatchResultWithPostInfo { + let gas_limit: Weight = gas_limit.into(); let origin = ensure_signed(origin)?; let dest = T::Lookup::lookup(dest)?; let mut output = Self::internal_call( @@ -494,7 +604,7 @@ pub mod pallet { pub fn instantiate_with_code( origin: OriginFor, #[pallet::compact] value: BalanceOf, - #[pallet::compact] gas_limit: Weight, + gas_limit: Weight, storage_deposit_limit: Option< as codec::HasCompact>::Type>, code: Vec, data: Vec, @@ -508,7 +618,7 @@ pub mod pallet { value, gas_limit, storage_deposit_limit.map(Into::into), - Code::Upload(Bytes(code)), + Code::Upload(code), data, salt, None, @@ -535,7 +645,7 @@ pub mod pallet { pub fn instantiate( origin: OriginFor, #[pallet::compact] value: BalanceOf, - #[pallet::compact] gas_limit: Weight, + gas_limit: Weight, storage_deposit_limit: Option< as codec::HasCompact>::Type>, code_hash: CodeHash, data: Vec, @@ -563,86 +673,6 @@ pub mod pallet { T::WeightInfo::instantiate(salt_len), ) } - - /// Upload new `code` without instantiating a contract from it. - /// - /// If the code does not already exist a deposit is reserved from the caller - /// and unreserved only when [`Self::remove_code`] is called. The size of the reserve - /// depends on the instrumented size of the the supplied `code`. - /// - /// If the code already exists in storage it will still return `Ok` and upgrades - /// the in storage version to the current - /// [`InstructionWeights::version`](InstructionWeights). - /// - /// # Note - /// - /// Anyone can instantiate a contract from any uploaded code and thus prevent its removal. - /// To avoid this situation a constructor could employ access control so that it can - /// only be instantiated by permissioned entities. The same is true when uploading - /// through [`Self::instantiate_with_code`]. - #[pallet::weight(T::WeightInfo::upload_code(code.len() as u32))] - pub fn upload_code( - origin: OriginFor, - code: Vec, - storage_deposit_limit: Option< as codec::HasCompact>::Type>, - ) -> DispatchResult { - let origin = ensure_signed(origin)?; - Self::bare_upload_code(origin, code, storage_deposit_limit.map(Into::into)).map(|_| ()) - } - - /// Remove the code stored under `code_hash` and refund the deposit to its owner. - /// - /// A code can only be removed by its original uploader (its owner) and only if it is - /// not used by any contract. - #[pallet::weight(T::WeightInfo::remove_code())] - pub fn remove_code( - origin: OriginFor, - code_hash: CodeHash, - ) -> DispatchResultWithPostInfo { - let origin = ensure_signed(origin)?; - >::remove(&origin, code_hash)?; - // we waive the fee because removing unused code is beneficial - Ok(Pays::No.into()) - } - - /// Privileged function that changes the code of an existing contract. - /// - /// This takes care of updating refcounts and all other necessary operations. Returns - /// an error if either the `code_hash` or `dest` do not exist. - /// - /// # Note - /// - /// This does **not** change the address of the contract in question. This means - /// that the contract address is no longer derived from its code hash after calling - /// this dispatchable. - #[pallet::weight(T::WeightInfo::set_code())] - pub fn set_code( - origin: OriginFor, - dest: AccountIdLookupOf, - code_hash: CodeHash, - ) -> DispatchResult { - ensure_root(origin)?; - let dest = T::Lookup::lookup(dest)?; - >::try_mutate(&dest, |contract| { - let contract = if let Some(contract) = contract { - contract - } else { - return Err(>::ContractNotFound.into()) - }; - >::add_user(code_hash)?; - >::remove_user(contract.code_hash); - Self::deposit_event( - vec![T::Hashing::hash_of(&dest), code_hash, contract.code_hash], - Event::ContractCodeUpdated { - contract: dest.clone(), - new_code_hash: code_hash, - old_code_hash: contract.code_hash, - }, - ); - contract.code_hash = code_hash; - Ok(()) - }) - } } #[pallet::event] @@ -904,8 +934,8 @@ where ); ContractExecResult { result: output.result.map_err(|r| r.error), - gas_consumed: output.gas_meter.gas_consumed().ref_time(), - gas_required: output.gas_meter.gas_required().ref_time(), + gas_consumed: output.gas_meter.gas_consumed(), + gas_required: output.gas_meter.gas_required(), storage_deposit: output.storage_deposit, debug_message: debug_message.unwrap_or_default(), } @@ -949,8 +979,8 @@ where .result .map(|(account_id, result)| InstantiateReturnValue { result, account_id }) .map_err(|e| e.error), - gas_consumed: output.gas_meter.gas_consumed().ref_time(), - gas_required: output.gas_meter.gas_required().ref_time(), + gas_consumed: output.gas_meter.gas_consumed(), + gas_required: output.gas_meter.gas_required(), storage_deposit: output.storage_deposit, debug_message: debug_message.unwrap_or_default(), } @@ -1001,6 +1031,11 @@ where T::AddressGenerator::generate_address(deploying_address, code_hash, salt) } + /// Returns the code hash of the contract specified by `account` ID. + pub fn code_hash(account: &AccountIdOf) -> Option> { + Storage::::code_hash(account) + } + /// Store code for benchmarks which does not check nor instrument the code. #[cfg(feature = "runtime-benchmarks")] fn store_code_raw( @@ -1045,7 +1080,7 @@ where }; let schedule = T::Schedule::get(); let result = ExecStack::>::run_call( - origin, + origin.clone(), dest, &mut gas_meter, &mut storage_meter, @@ -1054,7 +1089,11 @@ where data, debug_message, ); - InternalCallOutput { result, gas_meter, storage_deposit: storage_meter.into_deposit() } + InternalCallOutput { + result, + gas_meter, + storage_deposit: storage_meter.into_deposit(&origin), + } } /// Internal function that does the actual instantiation. @@ -1075,7 +1114,7 @@ where let try_exec = || { let schedule = T::Schedule::get(); let (extra_deposit, executable) = match code { - Code::Upload(Bytes(binary)) => { + Code::Upload(binary) => { let executable = PrefabWasmModule::from_code(binary, &schedule, origin.clone()) .map_err(|(err, msg)| { debug_message.as_mut().map(|buffer| buffer.extend(msg.as_bytes())); @@ -1098,7 +1137,7 @@ where value.saturating_add(extra_deposit), )?; let result = ExecStack::>::run_instantiate( - origin, + origin.clone(), executable, &mut gas_meter, &mut storage_meter, @@ -1109,17 +1148,86 @@ where debug_message, ); storage_deposit = storage_meter - .into_deposit() + .into_deposit(&origin) .saturating_add(&StorageDeposit::Charge(extra_deposit)); result }; InternalInstantiateOutput { result: try_exec(), gas_meter, storage_deposit } } + /// Deposit a pallet contracts event. Handles the conversion to the overarching event type. fn deposit_event(topics: Vec, event: Event) { >::deposit_event_indexed( &topics, - ::Event::from(event).into(), + ::RuntimeEvent::from(event).into(), ) } + + /// Return the existential deposit of [`Config::Currency`]. + fn min_balance() -> BalanceOf { + >>::minimum_balance() + } + + /// Convert a 1D Weight to a 2D weight. + /// + /// Used by backwards compatible extrinsics. We cannot just set the proof to zero + /// or an old `Call` will just fail. + fn compat_weight(gas_limit: OldWeight) -> Weight { + Weight::from(gas_limit).set_proof_size(u64::from(T::MaxCodeLen::get()) * 2) + } +} + +sp_api::decl_runtime_apis! { + /// The API used to dry-run contract interactions. + pub trait ContractsApi where + AccountId: Codec, + Balance: Codec, + BlockNumber: Codec, + Hash: Codec, + { + /// Perform a call from a specified account to a given contract. + /// + /// See [`crate::Pallet::bare_call`]. + fn call( + origin: AccountId, + dest: AccountId, + value: Balance, + gas_limit: Option, + storage_deposit_limit: Option, + input_data: Vec, + ) -> ContractExecResult; + + /// Instantiate a new contract. + /// + /// See `[crate::Pallet::bare_instantiate]`. + fn instantiate( + origin: AccountId, + value: Balance, + gas_limit: Option, + storage_deposit_limit: Option, + code: Code, + data: Vec, + salt: Vec, + ) -> ContractInstantiateResult; + + + /// Upload new code without instantiating a contract from it. + /// + /// See [`crate::Pallet::bare_upload_code`]. + fn upload_code( + origin: AccountId, + code: Vec, + storage_deposit_limit: Option, + ) -> CodeUploadResult; + + /// Query a given storage key in a given contract. + /// + /// Returns `Ok(Some(Vec))` if the storage value exists under the given key in the + /// specified account and `Ok(None)` if it doesn't. If the account specified by the address + /// doesn't exist, or doesn't have a contract then `Err` is returned. + fn get_storage( + address: AccountId, + key: Vec, + ) -> GetStorageResult; + } } diff --git a/frame/contracts/src/migration.rs b/frame/contracts/src/migration.rs index 0db285e81a91f..5ea821aac7682 100644 --- a/frame/contracts/src/migration.rs +++ b/frame/contracts/src/migration.rs @@ -18,37 +18,80 @@ use crate::{BalanceOf, CodeHash, Config, Pallet, TrieId, Weight}; use codec::{Decode, Encode}; use frame_support::{ - codec, pallet_prelude::*, storage::migration, storage_alias, traits::Get, Identity, - Twox64Concat, + codec, + pallet_prelude::*, + storage::migration, + storage_alias, + traits::{Get, OnRuntimeUpgrade}, + Identity, Twox64Concat, }; +use sp_runtime::traits::Saturating; use sp_std::{marker::PhantomData, prelude::*}; -/// Wrapper for all migrations of this pallet, based on `StorageVersion`. -pub fn migrate() -> Weight { - let version = StorageVersion::get::>(); - let mut weight = Weight::zero(); +/// Performs all necessary migrations based on `StorageVersion`. +pub struct Migration(PhantomData); +impl OnRuntimeUpgrade for Migration { + fn on_runtime_upgrade() -> Weight { + let version = StorageVersion::get::>(); + let mut weight = Weight::zero(); - if version < 4 { - weight = weight.saturating_add(v4::migrate::()); - StorageVersion::new(4).put::>(); - } + if version < 4 { + weight = weight.saturating_add(v4::migrate::()); + StorageVersion::new(4).put::>(); + } - if version < 5 { - weight = weight.saturating_add(v5::migrate::()); - StorageVersion::new(5).put::>(); - } + if version < 5 { + weight = weight.saturating_add(v5::migrate::()); + StorageVersion::new(5).put::>(); + } + + if version < 6 { + weight = weight.saturating_add(v6::migrate::()); + StorageVersion::new(6).put::>(); + } + + if version < 7 { + weight = weight.saturating_add(v7::migrate::()); + StorageVersion::new(7).put::>(); + } + + if version < 8 { + weight = weight.saturating_add(v8::migrate::()); + StorageVersion::new(8).put::>(); + } - if version < 6 { - weight = weight.saturating_add(v6::migrate::()); - StorageVersion::new(6).put::>(); + weight } - if version < 7 { - weight = weight.saturating_add(v7::migrate::()); - StorageVersion::new(7).put::>(); + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + let version = StorageVersion::get::>(); + + if version < 7 { + return Ok(vec![]) + } + + if version < 8 { + v8::pre_upgrade::()?; + } + + Ok(vec![]) } - weight + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { + let version = StorageVersion::get::>(); + + if version < 7 { + return Ok(()) + } + + if version < 8 { + v8::post_upgrade::()?; + } + + Ok(()) + } } /// V4: `Schedule` is changed to be a config item rather than an in-storage value. @@ -185,9 +228,9 @@ mod v6 { #[derive(Encode, Decode)] pub struct RawContractInfo { - trie_id: TrieId, - code_hash: CodeHash, - storage_deposit: Balance, + pub trie_id: TrieId, + pub code_hash: CodeHash, + pub storage_deposit: Balance, } #[derive(Encode, Decode)] @@ -199,7 +242,7 @@ mod v6 { refcount: u64, } - type ContractInfo = RawContractInfo, BalanceOf>; + pub type ContractInfo = RawContractInfo, BalanceOf>; #[storage_alias] type ContractInfoOf = StorageMap< @@ -266,3 +309,108 @@ mod v7 { T::DbWeight::get().reads_writes(1, 2) } } + +/// Update `ContractInfo` with new fields that track storage deposits. +mod v8 { + use super::*; + use sp_io::default_child_storage as child; + use v6::ContractInfo as OldContractInfo; + + #[derive(Encode, Decode)] + struct ContractInfo { + trie_id: TrieId, + code_hash: CodeHash, + storage_bytes: u32, + storage_items: u32, + storage_byte_deposit: BalanceOf, + storage_item_deposit: BalanceOf, + storage_base_deposit: BalanceOf, + } + + #[storage_alias] + type ContractInfoOf = + StorageMap, Twox64Concat, ::AccountId, V>; + + pub fn migrate() -> Weight { + let mut weight = Weight::zero(); + + >>::translate_values(|old: OldContractInfo| { + // Count storage items of this contract + let mut storage_bytes = 0u32; + let mut storage_items = 0u32; + let mut key = Vec::new(); + while let Some(next) = child::next_key(&old.trie_id, &key) { + key = next; + let mut val_out = []; + let len = child::read(&old.trie_id, &key, &mut val_out, 0) + .expect("The loop conditions checks for existence of the key; qed"); + storage_bytes.saturating_accrue(len); + storage_items.saturating_accrue(1); + } + + let storage_byte_deposit = + T::DepositPerByte::get().saturating_mul(storage_bytes.into()); + let storage_item_deposit = + T::DepositPerItem::get().saturating_mul(storage_items.into()); + let storage_base_deposit = old + .storage_deposit + .saturating_sub(storage_byte_deposit) + .saturating_sub(storage_item_deposit); + + // Reads: One read for each storage item plus the contract info itself. + // Writes: Only the new contract info. + weight = weight + .saturating_add(T::DbWeight::get().reads_writes(u64::from(storage_items) + 1, 1)); + + Some(ContractInfo { + trie_id: old.trie_id, + code_hash: old.code_hash, + storage_bytes, + storage_items, + storage_byte_deposit, + storage_item_deposit, + storage_base_deposit, + }) + }); + + weight + } + + #[cfg(feature = "try-runtime")] + pub fn pre_upgrade() -> Result<(), &'static str> { + use frame_support::traits::ReservableCurrency; + for (key, value) in ContractInfoOf::>::iter() { + let reserved = T::Currency::reserved_balance(&key); + ensure!(reserved >= value.storage_deposit, "Reserved balance out of sync."); + } + Ok(()) + } + + #[cfg(feature = "try-runtime")] + pub fn post_upgrade() -> Result<(), &'static str> { + use frame_support::traits::ReservableCurrency; + for (key, value) in ContractInfoOf::>::iter() { + let reserved = T::Currency::reserved_balance(&key); + let stored = value + .storage_base_deposit + .saturating_add(value.storage_byte_deposit) + .saturating_add(value.storage_item_deposit); + ensure!(reserved >= stored, "Reserved balance out of sync."); + + let mut storage_bytes = 0u32; + let mut storage_items = 0u32; + let mut key = Vec::new(); + while let Some(next) = child::next_key(&value.trie_id, &key) { + key = next; + let mut val_out = []; + let len = child::read(&value.trie_id, &key, &mut val_out, 0) + .expect("The loop conditions checks for existence of the key; qed"); + storage_bytes.saturating_accrue(len); + storage_items.saturating_accrue(1); + } + ensure!(storage_bytes == value.storage_bytes, "Storage bytes do not match.",); + ensure!(storage_items == value.storage_items, "Storage items do not match.",); + } + Ok(()) + } +} diff --git a/frame/contracts/src/schedule.rs b/frame/contracts/src/schedule.rs index 63867a0cc7448..790b74106860a 100644 --- a/frame/contracts/src/schedule.rs +++ b/frame/contracts/src/schedule.rs @@ -525,7 +525,7 @@ impl Default for InstructionWeights { fn default() -> Self { let max_pages = Limits::default().memory_pages; Self { - version: 2, + version: 3, i64const: cost_instr!(instr_i64const, 1), i64load: cost_instr!(instr_i64load, 2), i64store: cost_instr!(instr_i64store, 2), diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index ec49a6325c125..c7644e696196f 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -34,31 +34,51 @@ use scale_info::TypeInfo; use sp_core::crypto::UncheckedFrom; use sp_io::KillStorageResult; use sp_runtime::{ - traits::{Hash, Zero}, + traits::{Hash, Saturating, Zero}, RuntimeDebug, }; use sp_std::{marker::PhantomData, prelude::*}; -pub type ContractInfo = RawContractInfo, BalanceOf>; - /// Information for managing an account and its sub trie abstraction. /// This is the required info to cache for an account. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct RawContractInfo { +#[scale_info(skip_type_params(T))] +pub struct ContractInfo { /// Unique ID for the subtree encoded as a bytes vector. pub trie_id: TrieId, /// The code associated with a given account. - pub code_hash: CodeHash, - /// The amount of balance that is currently deposited to pay for consumed storage. - pub storage_deposit: Balance, + pub code_hash: CodeHash, + /// How many bytes of storage are accumulated in this contract's child trie. + pub storage_bytes: u32, + /// How many items of storage are accumulated in this contract's child trie. + pub storage_items: u32, + /// This records to how much deposit the accumulated `storage_bytes` amount to. + pub storage_byte_deposit: BalanceOf, + /// This records to how much deposit the accumulated `storage_items` amount to. + pub storage_item_deposit: BalanceOf, + /// This records how much deposit is put down in order to pay for the contract itself. + /// + /// We need to store this information separately so it is not used when calculating any refunds + /// since the base deposit can only ever be refunded on contract termination. + pub storage_base_deposit: BalanceOf, } -impl RawContractInfo { +impl ContractInfo { /// Associated child trie unique id is built from the hash part of the trie id. #[cfg(test)] pub fn child_trie_info(&self) -> ChildInfo { child_trie_info(&self.trie_id[..]) } + + /// The deposit paying for the accumulated storage generated within the contract's child trie. + pub fn extra_deposit(&self) -> BalanceOf { + self.storage_byte_deposit.saturating_add(self.storage_item_deposit) + } + + /// Same as [`Self::extra_deposit`] but including the base deposit. + pub fn total_deposit(&self) -> BalanceOf { + self.extra_deposit().saturating_add(self.storage_base_deposit) + } } /// Associated child trie unique id is built from the hash part of the trie id. @@ -178,7 +198,7 @@ where }, (None, None) => (), } - storage_meter.charge(&diff)?; + storage_meter.charge(&diff); } match &new_value { @@ -200,14 +220,21 @@ where pub fn new_contract( account: &AccountIdOf, trie_id: TrieId, - ch: CodeHash, + code_hash: CodeHash, ) -> Result, DispatchError> { if >::contains_key(account) { return Err(Error::::DuplicateContract.into()) } - let contract = - ContractInfo:: { code_hash: ch, trie_id, storage_deposit: >::zero() }; + let contract = ContractInfo:: { + code_hash, + trie_id, + storage_bytes: 0, + storage_items: 0, + storage_byte_deposit: Zero::zero(), + storage_item_deposit: Zero::zero(), + storage_base_deposit: Zero::zero(), + }; Ok(contract) } @@ -301,7 +328,6 @@ where } /// Returns the code hash of the contract specified by `account` ID. - #[cfg(test)] pub fn code_hash(account: &AccountIdOf) -> Option> { >::get(account).map(|i| i.code_hash) } @@ -313,7 +339,7 @@ where let queue: Vec = (0..T::DeletionQueueDepth::get()) .map(|_| DeletedContract { trie_id: TrieId::default() }) .collect(); - let bounded: BoundedVec<_, _> = queue.try_into().unwrap(); + let bounded: BoundedVec<_, _> = queue.try_into().map_err(|_| ()).unwrap(); >::put(bounded); } } diff --git a/frame/contracts/src/storage/meter.rs b/frame/contracts/src/storage/meter.rs index b06f7ea4aedb5..0a63eb42b86cb 100644 --- a/frame/contracts/src/storage/meter.rs +++ b/frame/contracts/src/storage/meter.rs @@ -17,17 +17,24 @@ //! This module contains functions to meter the storage deposit. -use crate::{storage::ContractInfo, BalanceOf, Config, Error}; +use crate::{storage::ContractInfo, BalanceOf, Config, Error, Inspect, Pallet}; use codec::Encode; use frame_support::{ dispatch::DispatchError, - traits::{tokens::BalanceStatus, Currency, ExistenceRequirement, Get, ReservableCurrency}, - DefaultNoBound, + ensure, + traits::{ + tokens::{BalanceStatus, WithdrawConsequence}, + Currency, ExistenceRequirement, Get, ReservableCurrency, + }, + DefaultNoBound, RuntimeDebugNoBound, }; use pallet_contracts_primitives::StorageDeposit as Deposit; use sp_core::crypto::UncheckedFrom; -use sp_runtime::traits::{Saturating, Zero}; -use sp_std::marker::PhantomData; +use sp_runtime::{ + traits::{Saturating, Zero}, + FixedPointNumber, FixedU128, +}; +use sp_std::{marker::PhantomData, vec::Vec}; /// Deposit that uses the native currency's balance type. pub type DepositOf = Deposit>; @@ -99,22 +106,25 @@ impl State for Root {} impl State for Nested {} /// A type that allows the metering of consumed or freed storage of a single contract call stack. -#[derive(DefaultNoBound)] -pub struct RawMeter, S: State> { +#[derive(DefaultNoBound, RuntimeDebugNoBound)] +pub struct RawMeter { /// The limit of how much balance this meter is allowed to consume. limit: BalanceOf, /// The amount of balance that was used in this meter and all of its already absorbed children. total_deposit: DepositOf, - /// The amount of balance that was used in this meter alone. - own_deposit: DepositOf, - /// Only when a contract was terminated we allow it to drop below the minimum balance. - terminated: bool, + /// The amount of storage changes that were recorded in this meter alone. + own_contribution: Contribution, + /// List of charges that should be applied at the end of a contract stack execution. + /// + /// We only have one charge per contract hence the size of this vector is + /// limited by the maximum call depth. + charges: Vec>, /// Type parameters are only used in impls. _phantom: PhantomData<(E, S)>, } /// This type is used to describe a storage change when charging from the meter. -#[derive(Default)] +#[derive(Default, RuntimeDebugNoBound)] pub struct Diff { /// How many bytes were added to storage. pub bytes_added: u32, @@ -124,43 +134,120 @@ pub struct Diff { pub items_added: u32, /// How many storage items were removed from storage. pub items_removed: u32, - /// If set to true the derived deposit will always a `Charge` larger than the - /// the existential deposit. - pub require_ed: bool, } impl Diff { - /// Calculate how much of a charge or refund results from applying the diff. - pub fn to_deposit(&self) -> DepositOf { - let mut deposit = Deposit::default(); + /// Calculate how much of a charge or refund results from applying the diff and store it + /// in the passed `info` if any. + /// + /// # Note + /// + /// In case `None` is passed for `info` only charges are calculated. This is because refunds + /// are calculated pro rata of the existing storage within a contract and hence need extract + /// this information from the passed `info`. + pub fn update_contract(&self, info: Option<&mut ContractInfo>) -> DepositOf { let per_byte = T::DepositPerByte::get(); let per_item = T::DepositPerItem::get(); + let bytes_added = self.bytes_added.saturating_sub(self.bytes_removed); + let items_added = self.items_added.saturating_sub(self.items_removed); + let mut bytes_deposit = Deposit::Charge(per_byte.saturating_mul((bytes_added).into())); + let mut items_deposit = Deposit::Charge(per_item.saturating_mul((items_added).into())); + + // Without any contract info we can only calculate diffs which add storage + let info = if let Some(info) = info { + info + } else { + debug_assert_eq!(self.bytes_removed, 0); + debug_assert_eq!(self.items_removed, 0); + return bytes_deposit.saturating_add(&items_deposit) + }; - if self.bytes_added > self.bytes_removed { - deposit = deposit.saturating_add(&Deposit::Charge( - per_byte.saturating_mul((self.bytes_added - self.bytes_removed).into()), - )); - } else if self.bytes_removed > self.bytes_added { - deposit = deposit.saturating_add(&Deposit::Refund( - per_byte.saturating_mul((self.bytes_removed - self.bytes_added).into()), - )); + // Refunds are calculated pro rata based on the accumulated storage within the contract + let bytes_removed = self.bytes_removed.saturating_sub(self.bytes_added); + let items_removed = self.items_removed.saturating_sub(self.items_added); + let ratio = FixedU128::checked_from_rational(bytes_removed, info.storage_bytes) + .unwrap_or_default() + .min(FixedU128::from_u32(1)); + bytes_deposit = bytes_deposit + .saturating_add(&Deposit::Refund(ratio.saturating_mul_int(info.storage_byte_deposit))); + let ratio = FixedU128::checked_from_rational(items_removed, info.storage_items) + .unwrap_or_default() + .min(FixedU128::from_u32(1)); + items_deposit = items_deposit + .saturating_add(&Deposit::Refund(ratio.saturating_mul_int(info.storage_item_deposit))); + + // We need to update the contract info structure with the new deposits + info.storage_bytes = + info.storage_bytes.saturating_add(bytes_added).saturating_sub(bytes_removed); + info.storage_items = + info.storage_items.saturating_add(items_added).saturating_sub(items_removed); + match &bytes_deposit { + Deposit::Charge(amount) => + info.storage_byte_deposit = info.storage_byte_deposit.saturating_add(*amount), + Deposit::Refund(amount) => + info.storage_byte_deposit = info.storage_byte_deposit.saturating_sub(*amount), + } + match &items_deposit { + Deposit::Charge(amount) => + info.storage_item_deposit = info.storage_item_deposit.saturating_add(*amount), + Deposit::Refund(amount) => + info.storage_item_deposit = info.storage_item_deposit.saturating_sub(*amount), } - if self.items_added > self.items_removed { - deposit = deposit.saturating_add(&Deposit::Charge( - per_item.saturating_mul((self.items_added - self.items_removed).into()), - )); - } else if self.items_removed > self.items_added { - deposit = deposit.saturating_add(&Deposit::Refund( - per_item.saturating_mul((self.items_removed - self.items_added).into()), - )); + bytes_deposit.saturating_add(&items_deposit) + } +} + +impl Diff { + fn saturating_add(&self, rhs: &Self) -> Self { + Self { + bytes_added: self.bytes_added.saturating_add(rhs.bytes_added), + bytes_removed: self.bytes_removed.saturating_add(rhs.bytes_removed), + items_added: self.items_added.saturating_add(rhs.items_added), + items_removed: self.items_removed.saturating_add(rhs.items_removed), } + } +} + +/// Records information to charge or refund a plain account. +/// +/// All the charges are deferred to the end of a whole call stack. Reason is that by doing +/// this we can do all the refunds before doing any charge. This way a plain account can use +/// more deposit than it has balance as along as it is covered by a refund. This +/// essentially makes the order of storage changes irrelevant with regard to the deposit system. +#[derive(RuntimeDebugNoBound, Clone)] +struct Charge { + contract: T::AccountId, + amount: DepositOf, + terminated: bool, +} - if self.require_ed { - deposit = deposit.max(Deposit::Charge(T::Currency::minimum_balance())) +/// Records the storage changes of a storage meter. +#[derive(RuntimeDebugNoBound)] +enum Contribution { + /// The contract the meter belongs to is alive and accumulates changes using a [`Diff`]. + Alive(Diff), + /// The meter was checked against its limit using [`RawMeter::enforce_limit`] at the end of + /// its execution. In this process the [`Diff`] was converted into a [`Deposit`]. + Checked(DepositOf), + /// The contract was terminated. In this process the [`Diff`] was converted into a [`Deposit`] + /// in order to calculate the refund. + Terminated(DepositOf), +} + +impl Contribution { + /// See [`Diff::update_contract`]. + fn update_contract(&self, info: Option<&mut ContractInfo>) -> DepositOf { + match self { + Self::Alive(diff) => diff.update_contract::(info), + Self::Terminated(deposit) | Self::Checked(deposit) => deposit.clone(), } + } +} - deposit +impl Default for Contribution { + fn default() -> Self { + Self::Alive(Default::default()) } } @@ -178,6 +265,7 @@ where /// usage for this sub call separately. This is necessary because we want to exchange balance /// with the current contract we are interacting with. pub fn nested(&self) -> RawMeter { + debug_assert!(self.is_alive()); RawMeter { limit: self.available(), ..Default::default() } } @@ -192,45 +280,28 @@ where /// /// # Parameters /// - /// `absorbed`: The child storage meter that should be absorbed. - /// `origin`: The origin that spawned the original root meter. - /// `contract`: The contract that this sub call belongs to. - /// `info`: The info of the contract in question. `None` if the contract was terminated. + /// - `absorbed`: The child storage meter that should be absorbed. + /// - `origin`: The origin that spawned the original root meter. + /// - `contract`: The contract that this sub call belongs to. + /// - `info`: The info of the contract in question. `None` if the contract was terminated. pub fn absorb( &mut self, - mut absorbed: RawMeter, - origin: &T::AccountId, + absorbed: RawMeter, contract: &T::AccountId, info: Option<&mut ContractInfo>, ) { - // Absorbing from an existing (non terminated) contract. - if let Some(info) = info { - match &mut absorbed.own_deposit { - Deposit::Charge(amount) => - info.storage_deposit = info.storage_deposit.saturating_add(*amount), - Deposit::Refund(amount) => { - // We need to make sure to never refund more than what was deposited and - // still leave the existential deposit inside the contract's account. - // This case can happen when costs change due to a runtime upgrade where - // increased costs could remove an account due to refunds. - let amount = { - let corrected_amount = (*amount).min( - info.storage_deposit.saturating_sub(T::Currency::minimum_balance()), - ); - let correction = (*amount).saturating_sub(corrected_amount); - absorbed.total_deposit = - absorbed.total_deposit.saturating_sub(&Deposit::Refund(correction)); - *amount = corrected_amount; - corrected_amount - }; - info.storage_deposit = info.storage_deposit.saturating_sub(amount); - }, - } - } - - self.total_deposit = self.total_deposit.saturating_add(&absorbed.total_deposit); - if !absorbed.own_deposit.is_zero() { - E::charge(origin, contract, &absorbed.own_deposit, absorbed.terminated); + let own_deposit = absorbed.own_contribution.update_contract(info); + self.total_deposit = self + .total_deposit + .saturating_add(&absorbed.total_deposit) + .saturating_add(&own_deposit); + if !own_deposit.is_zero() { + self.charges.extend_from_slice(&absorbed.charges); + self.charges.push(Charge { + contract: contract.clone(), + amount: own_deposit, + terminated: absorbed.is_terminated(), + }); } } @@ -238,6 +309,16 @@ where fn available(&self) -> BalanceOf { self.total_deposit.available(&self.limit) } + + /// True if the contract is alive. + fn is_alive(&self) -> bool { + matches!(self.own_contribution, Contribution::Alive(_)) + } + + /// True if the contract is terminated. + fn is_terminated(&self) -> bool { + matches!(self.own_contribution, Contribution::Terminated(_)) + } } /// Functions that only apply to the root state. @@ -260,11 +341,18 @@ where } /// The total amount of deposit that should change hands as result of the execution - /// that this meter was passed into. + /// that this meter was passed into. This will also perform all the charges accumulated + /// in the whole contract stack. /// /// This drops the root meter in order to make sure it is only called when the whole /// execution did finish. - pub fn into_deposit(self) -> DepositOf { + pub fn into_deposit(self, origin: &T::AccountId) -> DepositOf { + for charge in self.charges.iter().filter(|c| matches!(c.amount, Deposit::Refund(_))) { + E::charge(origin, &charge.contract, &charge.amount, charge.terminated); + } + for charge in self.charges.iter().filter(|c| matches!(c.amount, Deposit::Charge(_))) { + E::charge(origin, &charge.contract, &charge.amount, charge.terminated); + } self.total_deposit } } @@ -277,18 +365,12 @@ where E: Ext, { /// Try to charge the `diff` from the meter. Fails if this would exceed the original limit. - pub fn charge(&mut self, diff: &Diff) -> Result, DispatchError> { - debug_assert!(!self.terminated); - let deposit = diff.to_deposit::(); - let total_deposit = self.total_deposit.saturating_add(&deposit); - if let Deposit::Charge(amount) = total_deposit { - if amount > self.limit { - return Err(>::StorageDepositLimitExhausted.into()) - } - } - self.total_deposit = total_deposit; - self.own_deposit = self.own_deposit.saturating_add(&deposit); - Ok(deposit) + pub fn charge(&mut self, diff: &Diff) { + debug_assert!(self.is_alive()); + match &mut self.own_contribution { + Contribution::Alive(own) => *own = own.saturating_add(diff), + _ => panic!("Charge is never called after termination; qed"), + }; } /// Charge from `origin` a storage deposit for contract instantiation. @@ -300,25 +382,22 @@ where contract: &T::AccountId, info: &mut ContractInfo, ) -> Result, DispatchError> { - debug_assert!(!self.terminated); - let deposit = Diff { - bytes_added: info.encoded_size() as u32, - items_added: 1, - require_ed: true, - ..Default::default() - } - .to_deposit::(); - debug_assert!(matches!(deposit, Deposit::Charge(_))); - // We do not increase `own_deposit` because this will be charged later when the contract - // execution does conclude. - let total_deposit = self.total_deposit.saturating_add(&deposit); - if let Deposit::Charge(amount) = &total_deposit { - if amount > &self.limit { - return Err(>::StorageDepositLimitExhausted.into()) - } + debug_assert!(self.is_alive()); + let mut deposit = + Diff { bytes_added: info.encoded_size() as u32, items_added: 1, ..Default::default() } + .update_contract::(None); + + // Instantiate needs to transfer the minimum balance at least in order to pull the + // contract's account into existence. + deposit = deposit.max(Deposit::Charge(Pallet::::min_balance())); + if deposit.charge_or_zero() > self.limit { + return Err(>::StorageDepositLimitExhausted.into()) } - info.storage_deposit = info.storage_deposit.saturating_add(deposit.charge_or_zero()); - self.total_deposit = total_deposit; + + // We do not increase `own_contribution` because this will be charged later when the + // contract execution does conclude and hence would lead to a double charge. + self.total_deposit = deposit.clone(); + info.storage_base_deposit = deposit.charge_or_zero(); if !deposit.is_zero() { // We need to charge immediately so that the account is created before the `value` // is transferred from the caller to the contract. @@ -331,34 +410,55 @@ where /// /// This will manipulate the meter so that all storage deposit accumulated in /// `contract_info` will be refunded to the `origin` of the meter. - pub fn terminate(&mut self, contract_info: &ContractInfo) { - debug_assert!(!self.terminated); - let refund = Deposit::Refund(contract_info.storage_deposit); - - // The deposit for `own_deposit` isn't persisted into the contract info until the current - // frame is dropped. This means that whatever changes were introduced during the - // current frame are dicarded when terminating. - self.total_deposit = - self.total_deposit.saturating_add(&refund).saturating_sub(&self.own_deposit); - self.own_deposit = refund; - self.terminated = true; + pub fn terminate(&mut self, info: &ContractInfo) { + debug_assert!(self.is_alive()); + self.own_contribution = Contribution::Terminated(Deposit::Refund(info.total_deposit())); + } + + /// [`Self::charge`] does not enforce the storage limit since we want to do this check as late + /// as possible to allow later refunds to offset earlier charges. + /// + /// # Note + /// + /// We only need to call this **once** for every call stack and not for every cross contract + /// call. Hence this is only called when the last call frame returns. + pub fn enforce_limit( + &mut self, + info: Option<&mut ContractInfo>, + ) -> Result<(), DispatchError> { + let deposit = self.own_contribution.update_contract(info); + let total_deposit = self.total_deposit.saturating_add(&deposit); + // We don't want to override a `Terminated` with a `Checked`. + if self.is_alive() { + self.own_contribution = Contribution::Checked(deposit); + } + if let Deposit::Charge(amount) = total_deposit { + if amount > self.limit { + return Err(>::StorageDepositLimitExhausted.into()) + } + } + Ok(()) } } -impl Ext for ReservingExt { +impl Ext for ReservingExt +where + T: Config, + T::AccountId: UncheckedFrom + AsRef<[u8]>, +{ fn check_limit( origin: &T::AccountId, limit: Option>, min_leftover: BalanceOf, ) -> Result, DispatchError> { - let max = T::Currency::free_balance(origin) - .saturating_sub(T::Currency::minimum_balance()) - .saturating_sub(min_leftover); - match limit { - Some(limit) if limit <= max => Ok(limit), - None => Ok(max), - _ => Err(>::StorageDepositNotEnoughFunds.into()), - } + let max = T::Currency::reducible_balance(origin, true).saturating_sub(min_leftover); + let limit = limit.unwrap_or(max); + ensure!( + limit <= max && + matches!(T::Currency::can_withdraw(origin, limit), WithdrawConsequence::Success), + >::StorageDepositNotEnoughFunds, + ); + Ok(limit) } fn charge( @@ -393,6 +493,9 @@ impl Ext for ReservingExt { "Failed to transfer storage deposit {:?} from origin {:?} to contract {:?}: {:?}", amount, origin, contract, err, ); + if cfg!(debug_assertions) { + panic!("Unable to collect storage deposit. This is a bug."); + } } }, // For `Refund(_)` no error happen because the initial value transfer from the @@ -411,7 +514,7 @@ impl Ext for ReservingExt { // refund because we consider this unexpected behaviour. *amount.min( &T::Currency::reserved_balance(contract) - .saturating_sub(T::Currency::minimum_balance()), + .saturating_sub(Pallet::::min_balance()), ) }; let result = @@ -422,6 +525,9 @@ impl Ext for ReservingExt { "Failed to repatriate storage deposit {:?} from contract {:?} to origin {:?}: {:?}", amount, contract, origin, result, ); + if cfg!(debug_assertions) { + panic!("Unable to refund storage deposit. This is a bug."); + } } }, }; @@ -441,23 +547,23 @@ mod tests { exec::AccountIdOf, tests::{Test, ALICE, BOB, CHARLIE}, }; + use frame_support::parameter_types; use pretty_assertions::assert_eq; - use std::cell::RefCell; type TestMeter = RawMeter; - thread_local! { - static TEST_EXT: RefCell = RefCell::new(Default::default()); + parameter_types! { + static TestExtTestValue: TestExt = Default::default(); } - #[derive(Debug, PartialEq, Eq)] + #[derive(Debug, PartialEq, Eq, Clone)] struct LimitCheck { origin: AccountIdOf, limit: BalanceOf, min_leftover: BalanceOf, } - #[derive(Debug, PartialEq, Eq)] + #[derive(Debug, PartialEq, Eq, Clone)] struct Charge { origin: AccountIdOf, contract: AccountIdOf, @@ -465,8 +571,8 @@ mod tests { terminated: bool, } - #[derive(Default, Debug, PartialEq, Eq)] - struct TestExt { + #[derive(Default, Debug, PartialEq, Eq, Clone)] + pub struct TestExt { limit_checks: Vec, charges: Vec, } @@ -485,12 +591,9 @@ mod tests { min_leftover: BalanceOf, ) -> Result, DispatchError> { let limit = limit.unwrap_or(42); - TEST_EXT.with(|ext| { - ext.borrow_mut().limit_checks.push(LimitCheck { - origin: origin.clone(), - limit, - min_leftover, - }) + TestExtTestValue::mutate(|ext| { + ext.limit_checks + .push(LimitCheck { origin: origin.clone(), limit, min_leftover }) }); Ok(limit) } @@ -501,8 +604,8 @@ mod tests { amount: &DepositOf, terminated: bool, ) { - TEST_EXT.with(|ext| { - ext.borrow_mut().charges.push(Charge { + TestExtTestValue::mutate(|ext| { + ext.charges.push(Charge { origin: origin.clone(), contract: contract.clone(), amount: amount.clone(), @@ -513,17 +616,29 @@ mod tests { } fn clear_ext() { - TEST_EXT.with(|ext| ext.borrow_mut().clear()) + TestExtTestValue::mutate(|ext| ext.clear()) } - fn new_info(deposit: BalanceOf) -> ContractInfo { + #[derive(Default)] + struct StorageInfo { + bytes: u32, + items: u32, + bytes_deposit: BalanceOf, + items_deposit: BalanceOf, + } + + fn new_info(info: StorageInfo) -> ContractInfo { use crate::storage::Storage; use sp_runtime::traits::Hash; ContractInfo:: { trie_id: >::generate_trie_id(&ALICE, 42), code_hash: ::Hashing::hash(b"42"), - storage_deposit: deposit, + storage_bytes: info.bytes, + storage_items: info.items, + storage_byte_deposit: info.bytes_deposit, + storage_item_deposit: info.items_deposit, + storage_base_deposit: Default::default(), } } @@ -533,15 +648,13 @@ mod tests { TestMeter::new(&ALICE, Some(1_000), 0).unwrap(); - TEST_EXT.with(|ext| { - assert_eq!( - *ext.borrow(), - TestExt { - limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], - ..Default::default() - } - ) - }); + assert_eq!( + TestExtTestValue::get(), + TestExt { + limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], + ..Default::default() + } + ) } #[test] @@ -553,119 +666,83 @@ mod tests { // an empty charge does not create a `Charge` entry let mut nested0 = meter.nested(); - nested0.charge(&Default::default()).unwrap(); - meter.absorb(nested0, &ALICE, &BOB, None); - - TEST_EXT.with(|ext| { - assert_eq!( - *ext.borrow(), - TestExt { - limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], - ..Default::default() - } - ) - }); + nested0.charge(&Default::default()); + meter.absorb(nested0, &BOB, None); + + assert_eq!( + TestExtTestValue::get(), + TestExt { + limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], + ..Default::default() + } + ) } #[test] - fn existential_deposit_works() { + fn charging_works() { clear_ext(); - let mut meter = TestMeter::new(&ALICE, Some(1_000), 0).unwrap(); - assert_eq!(meter.available(), 1_000); + let mut meter = TestMeter::new(&ALICE, Some(100), 0).unwrap(); + assert_eq!(meter.available(), 100); - // a `Refund` will be turned into a `Charge(ed)` which is intended behaviour + let mut nested0_info = + new_info(StorageInfo { bytes: 100, items: 5, bytes_deposit: 100, items_deposit: 10 }); let mut nested0 = meter.nested(); - nested0.charge(&Diff { require_ed: true, ..Default::default() }).unwrap(); - nested0 - .charge(&Diff { bytes_removed: 1, require_ed: true, ..Default::default() }) - .unwrap(); - meter.absorb(nested0, &ALICE, &BOB, None); - - TEST_EXT.with(|ext| { - assert_eq!( - *ext.borrow(), - TestExt { - limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], - charges: vec![Charge { - origin: ALICE, - contract: BOB, - amount: Deposit::Charge(::Currency::minimum_balance() * 2), - terminated: false, - }] - } - ) + nested0.charge(&Diff { + bytes_added: 108, + bytes_removed: 5, + items_added: 1, + items_removed: 2, }); - } + nested0.charge(&Diff { bytes_removed: 99, ..Default::default() }); - #[test] - fn charging_works() { - clear_ext(); + let mut nested1_info = + new_info(StorageInfo { bytes: 100, items: 10, bytes_deposit: 100, items_deposit: 20 }); + let mut nested1 = nested0.nested(); + nested1.charge(&Diff { items_removed: 5, ..Default::default() }); + nested0.absorb(nested1, &CHARLIE, Some(&mut nested1_info)); - let min_balance = ::Currency::minimum_balance(); + let mut nested2_info = + new_info(StorageInfo { bytes: 100, items: 7, bytes_deposit: 100, items_deposit: 20 }); + let mut nested2 = nested0.nested(); + nested2.charge(&Diff { items_removed: 7, ..Default::default() }); + nested0.absorb(nested2, &CHARLIE, Some(&mut nested2_info)); - let mut meter = TestMeter::new(&ALICE, Some(1_000), 0).unwrap(); - assert_eq!(meter.available(), 1_000); + nested0.enforce_limit(Some(&mut nested0_info)).unwrap(); + meter.absorb(nested0, &BOB, Some(&mut nested0_info)); - let mut nested0_info = new_info(100); - let mut nested0 = meter.nested(); - nested0 - .charge(&Diff { - bytes_added: 10, - bytes_removed: 5, - items_added: 1, - items_removed: 2, - ..Default::default() - }) - .unwrap(); - nested0.charge(&Diff { bytes_removed: 1, ..Default::default() }).unwrap(); + meter.into_deposit(&ALICE); - let mut nested1_info = new_info(50); - let mut nested1 = nested0.nested(); - nested1.charge(&Diff { items_removed: 5, ..Default::default() }).unwrap(); - nested0.absorb(nested1, &ALICE, &CHARLIE, Some(&mut nested1_info)); + assert_eq!(nested0_info.extra_deposit(), 112); + assert_eq!(nested1_info.extra_deposit(), 110); + assert_eq!(nested2_info.extra_deposit(), 100); - // Trying to refund more than is available in the contract will cap the charge - // to (deposit_in_contract - ed). - let mut nested2_info = new_info(5); - let mut nested2 = nested0.nested(); - nested2.charge(&Diff { bytes_removed: 7, ..Default::default() }).unwrap(); - nested0.absorb(nested2, &ALICE, &CHARLIE, Some(&mut nested2_info)); - - meter.absorb(nested0, &ALICE, &BOB, Some(&mut nested0_info)); - - assert_eq!(nested0_info.storage_deposit, 102); - assert_eq!(nested1_info.storage_deposit, 40); - assert_eq!(nested2_info.storage_deposit, min_balance); - - TEST_EXT.with(|ext| { - assert_eq!( - *ext.borrow(), - TestExt { - limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], - charges: vec![ - Charge { - origin: ALICE, - contract: CHARLIE, - amount: Deposit::Refund(10), - terminated: false - }, - Charge { - origin: ALICE, - contract: CHARLIE, - amount: Deposit::Refund(4), - terminated: false - }, - Charge { - origin: ALICE, - contract: BOB, - amount: Deposit::Charge(2), - terminated: false - } - ] - } - ) - }); + assert_eq!( + TestExtTestValue::get(), + TestExt { + limit_checks: vec![LimitCheck { origin: ALICE, limit: 100, min_leftover: 0 }], + charges: vec![ + Charge { + origin: ALICE, + contract: CHARLIE, + amount: Deposit::Refund(10), + terminated: false + }, + Charge { + origin: ALICE, + contract: CHARLIE, + amount: Deposit::Refund(20), + terminated: false + }, + Charge { + origin: ALICE, + contract: BOB, + amount: Deposit::Charge(2), + terminated: false + } + ] + } + ) } #[test] @@ -676,48 +753,45 @@ mod tests { assert_eq!(meter.available(), 1_000); let mut nested0 = meter.nested(); - nested0 - .charge(&Diff { - bytes_added: 5, - bytes_removed: 1, - items_added: 3, - items_removed: 1, - ..Default::default() - }) - .unwrap(); - nested0.charge(&Diff { items_added: 2, ..Default::default() }).unwrap(); + nested0.charge(&Diff { + bytes_added: 5, + bytes_removed: 1, + items_added: 3, + items_removed: 1, + }); + nested0.charge(&Diff { items_added: 2, ..Default::default() }); - let nested1_info = new_info(400); + let mut nested1_info = + new_info(StorageInfo { bytes: 100, items: 10, bytes_deposit: 100, items_deposit: 20 }); let mut nested1 = nested0.nested(); - nested1.charge(&Diff { items_removed: 5, ..Default::default() }).unwrap(); - nested1.charge(&Diff { bytes_added: 20, ..Default::default() }).unwrap(); + nested1.charge(&Diff { items_removed: 5, ..Default::default() }); + nested1.charge(&Diff { bytes_added: 20, ..Default::default() }); nested1.terminate(&nested1_info); - nested0.absorb(nested1, &ALICE, &CHARLIE, None); - - meter.absorb(nested0, &ALICE, &BOB, None); - drop(meter); - - TEST_EXT.with(|ext| { - assert_eq!( - *ext.borrow(), - TestExt { - limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], - charges: vec![ - Charge { - origin: ALICE, - contract: CHARLIE, - amount: Deposit::Refund(400), - terminated: true - }, - Charge { - origin: ALICE, - contract: BOB, - amount: Deposit::Charge(12), - terminated: false - } - ] - } - ) - }); + nested0.enforce_limit(Some(&mut nested1_info)).unwrap(); + nested0.absorb(nested1, &CHARLIE, None); + + meter.absorb(nested0, &BOB, None); + meter.into_deposit(&ALICE); + + assert_eq!( + TestExtTestValue::get(), + TestExt { + limit_checks: vec![LimitCheck { origin: ALICE, limit: 1_000, min_leftover: 0 }], + charges: vec![ + Charge { + origin: ALICE, + contract: CHARLIE, + amount: Deposit::Refund(120), + terminated: true + }, + Charge { + origin: ALICE, + contract: BOB, + amount: Deposit::Charge(12), + terminated: false + } + ] + } + ) } } diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index f65f845f7b9fe..6a2144840143a 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -23,27 +23,27 @@ use crate::{ }, exec::{FixSizedKey, Frame}, storage::Storage, + tests::test_utils::{get_contract, get_contract_checked}, wasm::{PrefabWasmModule, ReturnCode as RuntimeReturnCode}, weights::WeightInfo, - BalanceOf, Code, CodeStorage, Config, ContractInfoOf, DefaultAddressGenerator, - DefaultContractAccessWeight, DeletionQueue, Error, Pallet, Schedule, + BalanceOf, Code, CodeStorage, Config, ContractInfoOf, DefaultAddressGenerator, DeletionQueue, + Error, Pallet, Schedule, }; use assert_matches::assert_matches; use codec::Encode; use frame_support::{ assert_err, assert_err_ignore_postinfo, assert_noop, assert_ok, - dispatch::DispatchErrorWithPostInfo, + dispatch::{DispatchClass, DispatchErrorWithPostInfo, PostDispatchInfo}, parameter_types, storage::child, traits::{ - BalanceStatus, ConstU32, ConstU64, Contains, Currency, Get, OnIdle, OnInitialize, - ReservableCurrency, + BalanceStatus, ConstU32, ConstU64, Contains, Currency, Get, LockableCurrency, OnIdle, + OnInitialize, ReservableCurrency, WithdrawReasons, }, - weights::{constants::WEIGHT_PER_SECOND, DispatchClass, PostDispatchInfo, Weight}, + weights::{constants::WEIGHT_PER_SECOND, Weight}, }; use frame_system::{self as system, EventRecord, Phase}; use pretty_assertions::{assert_eq, assert_ne}; -use sp_core::Bytes; use sp_io::hashing::blake2_256; use sp_keystore::{testing::KeyStore, KeystoreExt}; use sp_runtime::{ @@ -51,7 +51,7 @@ use sp_runtime::{ traits::{BlakeTwo256, Convert, Hash, IdentityLookup}, AccountId32, }; -use std::{cell::RefCell, sync::Arc}; +use std::sync::Arc; use crate as pallet_contracts; @@ -76,7 +76,9 @@ frame_support::construct_runtime!( #[macro_use] pub mod test_utils { use super::{Balances, Hash, SysConfig, Test}; - use crate::{exec::AccountIdOf, storage::Storage, CodeHash, Config, ContractInfoOf, Nonce}; + use crate::{ + exec::AccountIdOf, storage::Storage, CodeHash, Config, ContractInfo, ContractInfoOf, Nonce, + }; use codec::Encode; use frame_support::traits::Currency; @@ -97,6 +99,12 @@ pub mod test_utils { pub fn get_balance(who: &AccountIdOf) -> u64 { Balances::free_balance(who) } + pub fn get_contract(addr: &AccountIdOf) -> ContractInfo { + get_contract_checked(addr).unwrap() + } + pub fn get_contract_checked(addr: &AccountIdOf) -> Option> { + ContractInfoOf::::get(addr) + } pub fn hash(s: &S) -> <::Hashing as Hash>::Output { <::Hashing as Hash>::hash_of(s) } @@ -105,6 +113,7 @@ pub mod test_utils { assert_eq!(u32::from_le_bytes($x.data[..].try_into().unwrap()), $y as u32); }}; } + macro_rules! assert_refcount { ( $code_hash:expr , $should:expr $(,)? ) => {{ let is = crate::OwnerInfoOf::::get($code_hash).map(|m| m.refcount()).unwrap(); @@ -113,10 +122,11 @@ pub mod test_utils { } } -thread_local! { - static TEST_EXTENSION: RefCell = Default::default(); +parameter_types! { + static TestExtensionTestValue: TestExtension = Default::default(); } +#[derive(Clone)] pub struct TestExtension { enabled: bool, last_seen_buffer: Vec, @@ -136,15 +146,15 @@ pub struct TempStorageExtension { impl TestExtension { fn disable() { - TEST_EXTENSION.with(|e| e.borrow_mut().enabled = false) + TestExtensionTestValue::mutate(|e| e.enabled = false) } fn last_seen_buffer() -> Vec { - TEST_EXTENSION.with(|e| e.borrow().last_seen_buffer.clone()) + TestExtensionTestValue::get().last_seen_buffer.clone() } fn last_seen_inputs() -> (u32, u32, u32, u32) { - TEST_EXTENSION.with(|e| e.borrow().last_seen_inputs) + TestExtensionTestValue::get().last_seen_inputs } } @@ -163,28 +173,27 @@ impl ChainExtension for TestExtension { let func_id = env.func_id(); let id = env.ext_id() as u32 | func_id as u32; match func_id { - 0x8000 => { + 0 => { let mut env = env.buf_in_buf_out(); let input = env.read(8)?; env.write(&input, false, None)?; - TEST_EXTENSION.with(|e| e.borrow_mut().last_seen_buffer = input); + TestExtensionTestValue::mutate(|e| e.last_seen_buffer = input); Ok(RetVal::Converging(id)) }, - 0x8001 => { + 1 => { let env = env.only_in(); - TEST_EXTENSION.with(|e| { - e.borrow_mut().last_seen_inputs = - (env.val0(), env.val1(), env.val2(), env.val3()) + TestExtensionTestValue::mutate(|e| { + e.last_seen_inputs = (env.val0(), env.val1(), env.val2(), env.val3()) }); Ok(RetVal::Converging(id)) }, - 0x8002 => { + 2 => { let mut env = env.buf_in_buf_out(); let weight = Weight::from_ref_time(env.read(5)?[4].into()); env.charge_weight(weight)?; Ok(RetVal::Converging(id)) }, - 0x8003 => Ok(RetVal::Diverging { flags: ReturnFlags::REVERT, data: vec![42, 99] }), + 3 => Ok(RetVal::Diverging { flags: ReturnFlags::REVERT, data: vec![42, 99] }), _ => { panic!("Passed unknown id to test chain extension: {}", func_id); }, @@ -192,7 +201,7 @@ impl ChainExtension for TestExtension { } fn enabled() -> bool { - TEST_EXTENSION.with(|e| e.borrow().enabled) + TestExtensionTestValue::get().enabled } } @@ -210,7 +219,7 @@ impl ChainExtension for RevertingExtension { } fn enabled() -> bool { - TEST_EXTENSION.with(|e| e.borrow().enabled) + TestExtensionTestValue::get().enabled } } @@ -259,7 +268,7 @@ impl ChainExtension for TempStorageExtension { } fn enabled() -> bool { - TEST_EXTENSION.with(|e| e.borrow().enabled) + TestExtensionTestValue::get().enabled } } @@ -269,7 +278,9 @@ impl RegisteredChainExtension for TempStorageExtension { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(2u64 * WEIGHT_PER_SECOND); + frame_system::limits::BlockWeights::simple_max( + (2u64 * WEIGHT_PER_SECOND).set_proof_size(u64::MAX), + ); pub static ExistentialDeposit: u64 = 1; } impl frame_system::Config for Test { @@ -277,16 +288,16 @@ impl frame_system::Config for Test { type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = AccountId32; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -304,7 +315,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; @@ -318,8 +329,8 @@ impl pallet_timestamp::Config for Test { type WeightInfo = (); } impl pallet_utility::Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; type WeightInfo = (); } @@ -344,19 +355,30 @@ impl Convert> for Test { /// A filter whose filter function can be swapped at runtime. pub struct TestFilter; -thread_local! { - static CALL_FILTER: RefCell bool> = RefCell::new(|_| true); +#[derive(Clone)] +pub struct Filters { + filter: fn(&RuntimeCall) -> bool, +} + +impl Default for Filters { + fn default() -> Self { + Filters { filter: (|_| true) } + } +} + +parameter_types! { + static CallFilter: Filters = Default::default(); } impl TestFilter { - pub fn set_filter(filter: fn(&Call) -> bool) { - CALL_FILTER.with(|fltr| *fltr.borrow_mut() = filter); + pub fn set_filter(filter: fn(&RuntimeCall) -> bool) { + CallFilter::mutate(|fltr| fltr.filter = filter); } } -impl Contains for TestFilter { - fn contains(call: &Call) -> bool { - CALL_FILTER.with(|fltr| fltr.borrow()(call)) +impl Contains for TestFilter { + fn contains(call: &RuntimeCall) -> bool { + (CallFilter::get().filter)(call) } } @@ -368,8 +390,8 @@ impl Config for Test { type Time = Timestamp; type Randomness = Randomness; type Currency = Balances; - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type CallFilter = TestFilter; type CallStack = [Frame; 31]; type WeightPrice = Self; @@ -382,9 +404,7 @@ impl Config for Test { type DepositPerByte = DepositPerByte; type DepositPerItem = DepositPerItem; type AddressGenerator = DefaultAddressGenerator; - type ContractAccessWeight = DefaultContractAccessWeight; type MaxCodeLen = ConstU32<{ 128 * 1024 }>; - type RelaxedMaxCodeLen = ConstU32<{ 256 * 1024 }>; type MaxStorageKeyLen = ConstU32<128>; } @@ -393,7 +413,7 @@ pub const BOB: AccountId32 = AccountId32::new([2u8; 32]); pub const CHARLIE: AccountId32 = AccountId32::new([3u8; 32]); pub const DJANGO: AccountId32 = AccountId32::new([4u8; 32]); -pub const GAS_LIMIT: Weight = Weight::from_ref_time(100_000_000_000); +pub const GAS_LIMIT: Weight = Weight::from_ref_time(100_000_000_000).set_proof_size(256 * 1024); pub struct ExtBuilder { existential_deposit: u64, @@ -479,7 +499,7 @@ fn calling_plain_account_fails() { let base_cost = <::WeightInfo as WeightInfo>::call(); assert_eq!( - Contracts::call(Origin::signed(ALICE), BOB, 0, GAS_LIMIT, None, Vec::new()), + Contracts::call(RuntimeOrigin::signed(ALICE), BOB, 0, GAS_LIMIT, None, Vec::new()), Err(DispatchErrorWithPostInfo { error: Error::::ContractNotFound.into(), post_info: PostDispatchInfo { @@ -502,14 +522,14 @@ fn instantiate_and_call_and_deposit_event() { // We determine the storage deposit limit after uploading because it depends on ALICEs free // balance which is changed by uploading a module. - assert_ok!(Contracts::upload_code(Origin::signed(ALICE), wasm, None)); + assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, None)); // Drop previous events initialize_block(2); // Check at the end to get hash on error easily assert_ok!(Contracts::instantiate( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), value, GAS_LIMIT, None, @@ -525,12 +545,14 @@ fn instantiate_and_call_and_deposit_event() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::NewAccount { account: addr.clone() }), + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: addr.clone() + }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Endowed { + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { account: addr.clone(), free_balance: min_balance, }), @@ -538,7 +560,7 @@ fn instantiate_and_call_and_deposit_event() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: min_balance, @@ -547,7 +569,7 @@ fn instantiate_and_call_and_deposit_event() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: addr.clone(), amount: min_balance, }), @@ -555,7 +577,7 @@ fn instantiate_and_call_and_deposit_event() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: value, @@ -564,7 +586,7 @@ fn instantiate_and_call_and_deposit_event() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::ContractEmitted { + event: RuntimeEvent::Contracts(crate::Event::ContractEmitted { contract: addr.clone(), data: vec![1, 2, 3, 4] }), @@ -572,7 +594,7 @@ fn instantiate_and_call_and_deposit_event() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Instantiated { + event: RuntimeEvent::Contracts(crate::Event::Instantiated { deployer: ALICE, contract: addr.clone() }), @@ -591,7 +613,7 @@ fn deposit_event_max_value_limit() { // Create let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 30_000, GAS_LIMIT, None, @@ -603,10 +625,10 @@ fn deposit_event_max_value_limit() { // Call contract with allowed storage value. assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, - GAS_LIMIT * 2, // we are copying a huge buffer, + GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() * 2), // we are copying a huge buffer, None, ::Schedule::get().limits.payload_len.encode(), )); @@ -614,7 +636,7 @@ fn deposit_event_max_value_limit() { // Call contract with too large a storage value. assert_err_ignore_postinfo!( Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr, 0, GAS_LIMIT, @@ -634,7 +656,7 @@ fn run_out_of_gas() { let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 100 * min_balance, GAS_LIMIT, None, @@ -648,10 +670,10 @@ fn run_out_of_gas() { // loops forever. assert_err_ignore_postinfo!( Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr, // newly created account 0, - Weight::from_ref_time(1_000_000_000_000), + Weight::from_ref_time(1_000_000_000_000).set_proof_size(u64::MAX), None, vec![], ), @@ -668,12 +690,12 @@ fn instantiate_unique_trie_id() { ExtBuilder::default().existential_deposit(500).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); - Contracts::upload_code(Origin::signed(ALICE), wasm, None).unwrap(); + Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, None).unwrap(); let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // Instantiate the contract and store its trie id for later comparison. assert_ok!(Contracts::instantiate( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -681,12 +703,12 @@ fn instantiate_unique_trie_id() { vec![], vec![], )); - let trie_id = ContractInfoOf::::get(&addr).unwrap().trie_id; + let trie_id = get_contract(&addr).trie_id; // Try to instantiate it again without termination should yield an error. assert_err_ignore_postinfo!( Contracts::instantiate( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -699,7 +721,7 @@ fn instantiate_unique_trie_id() { // Terminate the contract. assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -709,7 +731,7 @@ fn instantiate_unique_trie_id() { // Re-Instantiate after termination. assert_ok!(Contracts::instantiate( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -719,7 +741,7 @@ fn instantiate_unique_trie_id() { )); // Trie ids shouldn't match or we might have a collision - assert_ne!(trie_id, ContractInfoOf::::get(&addr).unwrap().trie_id); + assert_ne!(trie_id, get_contract(&addr).trie_id); }); } @@ -731,7 +753,7 @@ fn storage_max_value_limit() { // Create let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 30_000, GAS_LIMIT, None, @@ -740,14 +762,14 @@ fn storage_max_value_limit() { vec![], )); let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); - ContractInfoOf::::get(&addr).unwrap(); + get_contract(&addr); // Call contract with allowed storage value. assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, - GAS_LIMIT * 2, // we are copying a huge buffer + GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() * 2), // we are copying a huge buffer None, ::Schedule::get().limits.payload_len.encode(), )); @@ -755,7 +777,7 @@ fn storage_max_value_limit() { // Call contract with too large a storage value. assert_err_ignore_postinfo!( Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr, 0, GAS_LIMIT, @@ -780,7 +802,7 @@ fn deploy_and_call_other_contract() { // Create let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 100_000, GAS_LIMIT, None, @@ -789,7 +811,7 @@ fn deploy_and_call_other_contract() { vec![], )); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 100_000, GAS_LIMIT, None, @@ -804,7 +826,7 @@ fn deploy_and_call_other_contract() { // Call BOB contract, which attempts to instantiate and call the callee contract and // makes various assertions on the results from those calls. assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), caller_addr.clone(), 0, GAS_LIMIT, @@ -817,14 +839,14 @@ fn deploy_and_call_other_contract() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::NewAccount { + event: RuntimeEvent::System(frame_system::Event::NewAccount { account: callee_addr.clone() }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Endowed { + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { account: callee_addr.clone(), free_balance: min_balance, }), @@ -832,7 +854,7 @@ fn deploy_and_call_other_contract() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: callee_addr.clone(), amount: min_balance, @@ -841,7 +863,7 @@ fn deploy_and_call_other_contract() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: callee_addr.clone(), amount: min_balance, }), @@ -849,7 +871,7 @@ fn deploy_and_call_other_contract() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: caller_addr.clone(), to: callee_addr.clone(), amount: 32768, // hard coded in wasm @@ -858,7 +880,7 @@ fn deploy_and_call_other_contract() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Instantiated { + event: RuntimeEvent::Contracts(crate::Event::Instantiated { deployer: caller_addr.clone(), contract: callee_addr.clone(), }), @@ -866,7 +888,7 @@ fn deploy_and_call_other_contract() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: caller_addr.clone(), to: callee_addr.clone(), amount: 32768, @@ -875,7 +897,7 @@ fn deploy_and_call_other_contract() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: caller_addr.clone(), contract: callee_addr.clone(), }), @@ -883,7 +905,7 @@ fn deploy_and_call_other_contract() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: caller_addr.clone(), }), @@ -905,7 +927,7 @@ fn delegate_call() { // Instantiate the 'caller' assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 300_000, GAS_LIMIT, None, @@ -915,13 +937,13 @@ fn delegate_call() { )); // Only upload 'callee' code assert_ok!(Contracts::upload_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), callee_wasm, Some(codec::Compact(100_000)), )); assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), caller_addr.clone(), 1337, GAS_LIMIT, @@ -939,7 +961,7 @@ fn cannot_self_destruct_through_draning() { // Instantiate the BOB contract. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 1_000, GAS_LIMIT, None, @@ -950,12 +972,12 @@ fn cannot_self_destruct_through_draning() { let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // Check that the BOB contract has been instantiated. - assert_matches!(ContractInfoOf::::get(&addr), Some(_)); + get_contract(&addr); // Call BOB which makes it send all funds to the zero address // The contract code asserts that the transfer was successful assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -980,7 +1002,7 @@ fn cannot_self_destruct_through_storage_refund_after_price_change() { // Instantiate the BOB contract. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -991,25 +1013,26 @@ fn cannot_self_destruct_through_storage_refund_after_price_change() { let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // Check that the BOB contract has been instantiated and has the minimum balance - let info = ContractInfoOf::::get(&addr).unwrap(); - assert_eq!(info.storage_deposit, min_balance); + assert_eq!(get_contract(&addr).total_deposit(), min_balance); + assert_eq!(get_contract(&addr).extra_deposit(), 0); assert_eq!(::Currency::total_balance(&addr), min_balance); - // Create 100 bytes of storage with a price of per byte + // Create 100 bytes of storage with a price of per byte and a single storage item of price 2 assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, 100u32.to_le_bytes().to_vec() )); + assert_eq!(get_contract(&addr).total_deposit(), min_balance + 102); - // Increase the byte price and trigger a refund. This could potentially destroy the account - // because the refund removes the reserved existential deposit. This should not happen. + // Increase the byte price and trigger a refund. This should not have any influence because + // the removal is pro rata and exactly those 100 bytes should have been removed. DEPOSIT_PER_BYTE.with(|c| *c.borrow_mut() = 500); assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -1020,8 +1043,9 @@ fn cannot_self_destruct_through_storage_refund_after_price_change() { // Make sure the account wasn't removed by the refund assert_eq!( ::Currency::total_balance(&addr), - ::Currency::minimum_balance(), + get_contract(&addr).total_deposit(), ); + assert_eq!(get_contract(&addr).extra_deposit(), 2,); }); } @@ -1033,7 +1057,7 @@ fn cannot_self_destruct_by_refund_after_slash() { let min_balance = ::Currency::minimum_balance(); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -1045,7 +1069,7 @@ fn cannot_self_destruct_by_refund_after_slash() { // create 100 more reserved balance assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -1063,7 +1087,7 @@ fn cannot_self_destruct_by_refund_after_slash() { // trigger a refund of 50 which would bring the contract below min when actually refunded assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -1074,15 +1098,12 @@ fn cannot_self_destruct_by_refund_after_slash() { // Make sure the account kept the minimum balance and was not destroyed assert_eq!(::Currency::total_balance(&addr), min_balance); - // even though it was not charged it is still substracted from the storage deposit tracker - assert_eq!(ContractInfoOf::::get(&addr).unwrap().storage_deposit, 550); - assert_eq!( System::events(), vec![ EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Slashed { + event: RuntimeEvent::Balances(pallet_balances::Event::Slashed { who: addr.clone(), amount: 90, }), @@ -1090,7 +1111,7 @@ fn cannot_self_destruct_by_refund_after_slash() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: addr.clone(), }), @@ -1098,7 +1119,7 @@ fn cannot_self_destruct_by_refund_after_slash() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::ReserveRepatriated { + event: RuntimeEvent::Balances(pallet_balances::Event::ReserveRepatriated { from: addr.clone(), to: ALICE, amount: 10, @@ -1119,7 +1140,7 @@ fn cannot_self_destruct_while_live() { // Instantiate the BOB contract. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 100_000, GAS_LIMIT, None, @@ -1130,17 +1151,24 @@ fn cannot_self_destruct_while_live() { let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // Check that the BOB contract has been instantiated. - assert_matches!(ContractInfoOf::::get(&addr), Some(_)); + get_contract(&addr); // Call BOB with input data, forcing it make a recursive call to itself to // self-destruct, resulting in a trap. assert_err_ignore_postinfo!( - Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![0],), + Contracts::call( + RuntimeOrigin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + vec![0], + ), Error::::ContractTrapped, ); // Check that BOB is still there. - assert_matches!(ContractInfoOf::::get(&addr), Some(_)); + get_contract(&addr); }); } @@ -1153,7 +1181,7 @@ fn self_destruct_works() { // Instantiate the BOB contract. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 100_000, GAS_LIMIT, None, @@ -1164,14 +1192,14 @@ fn self_destruct_works() { let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // Check that the BOB contract has been instantiated. - assert_matches!(ContractInfoOf::::get(&addr), Some(_)); + get_contract(&addr); // Drop all previous events initialize_block(2); // Call BOB without input data which triggers termination. assert_matches!( - Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), + Contracts::call(RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), Ok(_) ); @@ -1179,7 +1207,7 @@ fn self_destruct_works() { assert_refcount!(&code_hash, 0); // Check that account is gone - assert!(ContractInfoOf::::get(&addr).is_none()); + assert!(get_contract_checked(&addr).is_none()); assert_eq!(Balances::total_balance(&addr), 0); // check that the beneficiary (django) got remaining balance @@ -1190,7 +1218,7 @@ fn self_destruct_works() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: addr.clone(), to: DJANGO, amount: 100_000, @@ -1199,7 +1227,7 @@ fn self_destruct_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Terminated { + event: RuntimeEvent::Contracts(crate::Event::Terminated { contract: addr.clone(), beneficiary: DJANGO }), @@ -1207,7 +1235,7 @@ fn self_destruct_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: addr.clone(), }), @@ -1215,14 +1243,14 @@ fn self_destruct_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::KilledAccount { + event: RuntimeEvent::System(frame_system::Event::KilledAccount { account: addr.clone() }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::ReserveRepatriated { + event: RuntimeEvent::Balances(pallet_balances::Event::ReserveRepatriated { from: addr.clone(), to: ALICE, amount: 1_000, @@ -1246,7 +1274,7 @@ fn destroy_contract_and_transfer_funds() { // Create let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 200_000, GAS_LIMIT, None, @@ -1258,7 +1286,7 @@ fn destroy_contract_and_transfer_funds() { // This deploys the BOB contract, which in turn deploys the CHARLIE contract during // construction. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 200_000, GAS_LIMIT, None, @@ -1270,11 +1298,11 @@ fn destroy_contract_and_transfer_funds() { let addr_charlie = Contracts::contract_address(&addr_bob, &callee_code_hash, &[0x47, 0x11]); // Check that the CHARLIE contract has been instantiated. - assert_matches!(ContractInfoOf::::get(&addr_charlie), Some(_)); + get_contract(&addr_charlie); // Call BOB, which calls CHARLIE, forcing CHARLIE to self-destruct. assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr_bob, 0, GAS_LIMIT, @@ -1283,7 +1311,7 @@ fn destroy_contract_and_transfer_funds() { )); // Check that CHARLIE has moved on to the great beyond (ie. died). - assert!(ContractInfoOf::::get(&addr_charlie).is_none()); + assert!(get_contract_checked(&addr_charlie).is_none()); }); } @@ -1296,7 +1324,7 @@ fn cannot_self_destruct_in_constructor() { // Fail to instantiate the BOB because the contructor calls seal_terminate. assert_err_ignore_postinfo!( Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 100_000, GAS_LIMIT, None, @@ -1318,7 +1346,7 @@ fn crypto_hashes() { // Instantiate the CRYPTO_HASHES contract. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 100_000, GAS_LIMIT, None, @@ -1367,7 +1395,7 @@ fn transfer_return_code() { let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1406,7 +1434,7 @@ fn call_return_code() { let _ = Balances::deposit_creating(&CHARLIE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1432,7 +1460,7 @@ fn call_return_code() { assert_return_code!(result, RuntimeReturnCode::NotCallable); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(CHARLIE), + RuntimeOrigin::signed(CHARLIE), min_balance * 100, GAS_LIMIT, None, @@ -1533,7 +1561,7 @@ fn instantiate_return_code() { let callee_hash = callee_hash.as_ref().to_vec(); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1543,7 +1571,7 @@ fn instantiate_return_code() { ),); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1633,7 +1661,7 @@ fn disabled_chain_extension_wont_deploy() { TestExtension::disable(); assert_err_ignore_postinfo!( Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 3 * min_balance, GAS_LIMIT, None, @@ -1653,7 +1681,7 @@ fn disabled_chain_extension_errors_on_call() { let min_balance = ::Currency::minimum_balance(); let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1664,7 +1692,7 @@ fn disabled_chain_extension_errors_on_call() { let addr = Contracts::contract_address(&ALICE, &hash, &[]); TestExtension::disable(); assert_err_ignore_postinfo!( - Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), + Contracts::call(RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), Error::::NoChainExtension, ); }); @@ -1677,7 +1705,7 @@ fn chain_extension_works() { let min_balance = ::Currency::minimum_balance(); let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1687,22 +1715,21 @@ fn chain_extension_works() { ),); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - // 0x8000 = read input buffer and pass it through as output - let input: Vec = - ExtensionInput { extension_id: 0, func_id: 0x8000, extra: &[99] }.into(); + // 0 = read input buffer and pass it through as output + let input: Vec = ExtensionInput { extension_id: 0, func_id: 0, extra: &[99] }.into(); let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, input.clone(), false); assert_eq!(TestExtension::last_seen_buffer(), input); - assert_eq!(result.result.unwrap().data, Bytes(input)); + assert_eq!(result.result.unwrap().data, input); - // 0x8001 = treat inputs as integer primitives and store the supplied integers + // 1 = treat inputs as integer primitives and store the supplied integers Contracts::bare_call( ALICE, addr.clone(), 0, GAS_LIMIT, None, - ExtensionInput { extension_id: 0, func_id: 0x8001, extra: &[] }.into(), + ExtensionInput { extension_id: 0, func_id: 1, extra: &[] }.into(), false, ) .result @@ -1710,14 +1737,14 @@ fn chain_extension_works() { // those values passed in the fixture assert_eq!(TestExtension::last_seen_inputs(), (4, 4, 16, 12)); - // 0x8002 = charge some extra weight (amount supplied in the fifth byte) + // 2 = charge some extra weight (amount supplied in the fifth byte) let result = Contracts::bare_call( ALICE, addr.clone(), 0, GAS_LIMIT, None, - ExtensionInput { extension_id: 0, func_id: 0x8002, extra: &[0] }.into(), + ExtensionInput { extension_id: 0, func_id: 2, extra: &[0] }.into(), false, ); assert_ok!(result.result); @@ -1728,37 +1755,37 @@ fn chain_extension_works() { 0, GAS_LIMIT, None, - ExtensionInput { extension_id: 0, func_id: 0x8002, extra: &[42] }.into(), + ExtensionInput { extension_id: 0, func_id: 2, extra: &[42] }.into(), false, ); assert_ok!(result.result); - assert_eq!(result.gas_consumed, gas_consumed + 42); + assert_eq!(result.gas_consumed.ref_time(), gas_consumed.ref_time() + 42); let result = Contracts::bare_call( ALICE, addr.clone(), 0, GAS_LIMIT, None, - ExtensionInput { extension_id: 0, func_id: 0x8002, extra: &[95] }.into(), + ExtensionInput { extension_id: 0, func_id: 2, extra: &[95] }.into(), false, ); assert_ok!(result.result); - assert_eq!(result.gas_consumed, gas_consumed + 95); + assert_eq!(result.gas_consumed.ref_time(), gas_consumed.ref_time() + 95); - // 0x8003 = diverging chain extension call that sets flags to 0x1 and returns a fixed buffer + // 3 = diverging chain extension call that sets flags to 0x1 and returns a fixed buffer let result = Contracts::bare_call( ALICE, addr.clone(), 0, GAS_LIMIT, None, - ExtensionInput { extension_id: 0, func_id: 0x8003, extra: &[] }.into(), + ExtensionInput { extension_id: 0, func_id: 3, extra: &[] }.into(), false, ) .result .unwrap(); assert_eq!(result.flags, ReturnFlags::REVERT); - assert_eq!(result.data, Bytes(vec![42, 99])); + assert_eq!(result.data, vec![42, 99]); // diverging to second chain extension that sets flags to 0x1 and returns a fixed buffer // We set the MSB part to 1 (instead of 0) which routes the request into the second @@ -1775,13 +1802,13 @@ fn chain_extension_works() { .result .unwrap(); assert_eq!(result.flags, ReturnFlags::REVERT); - assert_eq!(result.data, Bytes(vec![0x4B, 0x1D])); + assert_eq!(result.data, vec![0x4B, 0x1D]); // Diverging to third chain extension that is disabled // We set the MSB part to 2 (instead of 0) which routes the request into the third extension assert_err_ignore_postinfo!( Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -1800,7 +1827,7 @@ fn chain_extension_temp_storage_works() { let min_balance = ::Currency::minimum_balance(); let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1834,7 +1861,7 @@ fn lazy_removal_works() { let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1844,7 +1871,7 @@ fn lazy_removal_works() { ),); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - let info = >::get(&addr).unwrap(); + let info = get_contract(&addr); let trie = &info.child_trie_info(); // Put value into the contracts child trie @@ -1852,7 +1879,7 @@ fn lazy_removal_works() { // Terminate the contract assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -1903,7 +1930,7 @@ fn lazy_batch_removal_works() { for i in 0..3u8 { assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1913,7 +1940,7 @@ fn lazy_batch_removal_works() { ),); let addr = Contracts::contract_address(&ALICE, &hash, &[i]); - let info = >::get(&addr).unwrap(); + let info = get_contract(&addr); let trie = &info.child_trie_info(); // Put value into the contracts child trie @@ -1922,7 +1949,7 @@ fn lazy_batch_removal_works() { // Terminate the contract. Contract info should be gone, but value should be still there // as the lazy removal did not run, yet. assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -1965,7 +1992,7 @@ fn lazy_removal_partial_remove_works() { let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -1975,7 +2002,7 @@ fn lazy_removal_partial_remove_works() { ),); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - let info = >::get(&addr).unwrap(); + let info = get_contract(&addr); // Put value into the contracts child trie for val in &vals { @@ -1992,7 +2019,7 @@ fn lazy_removal_partial_remove_works() { // Terminate the contract assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -2077,7 +2104,7 @@ fn lazy_removal_does_no_run_on_low_remaining_weight() { let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2087,7 +2114,7 @@ fn lazy_removal_does_no_run_on_low_remaining_weight() { ),); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - let info = >::get(&addr).unwrap(); + let info = get_contract(&addr); let trie = &info.child_trie_info(); // Put value into the contracts child trie @@ -2095,7 +2122,7 @@ fn lazy_removal_does_no_run_on_low_remaining_weight() { // Terminate the contract assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -2145,7 +2172,7 @@ fn lazy_removal_does_not_use_all_weight() { let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2155,7 +2182,7 @@ fn lazy_removal_does_not_use_all_weight() { ),); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - let info = >::get(&addr).unwrap(); + let info = get_contract(&addr); let (weight_per_key, max_keys) = Storage::::deletion_budget(1, weight_limit); // We create a contract with one less storage item than we can remove within the limit @@ -2178,7 +2205,7 @@ fn lazy_removal_does_not_use_all_weight() { // Terminate the contract assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -2225,7 +2252,7 @@ fn deletion_queue_full() { let _ = Balances::deposit_creating(&ALICE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2241,12 +2268,12 @@ fn deletion_queue_full() { // Terminate the contract should fail assert_err_ignore_postinfo!( - Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), + Contracts::call(RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, vec![],), Error::::DeletionQueueFull, ); // Contract should exist because removal failed - >::get(&addr).unwrap(); + get_contract(&addr); }); } @@ -2259,7 +2286,7 @@ fn refcounter() { // Create two contracts with the same code and check that they do in fact share it. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2268,7 +2295,7 @@ fn refcounter() { vec![0], )); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2280,7 +2307,7 @@ fn refcounter() { // Sharing should also work with the usual instantiate call assert_ok!(Contracts::instantiate( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2296,18 +2323,39 @@ fn refcounter() { let addr2 = Contracts::contract_address(&ALICE, &code_hash, &[2]); // Terminating one contract should decrement the refcount - assert_ok!(Contracts::call(Origin::signed(ALICE), addr0, 0, GAS_LIMIT, None, vec![])); + assert_ok!(Contracts::call( + RuntimeOrigin::signed(ALICE), + addr0, + 0, + GAS_LIMIT, + None, + vec![] + )); assert_refcount!(code_hash, 2); // remove another one - assert_ok!(Contracts::call(Origin::signed(ALICE), addr1, 0, GAS_LIMIT, None, vec![])); + assert_ok!(Contracts::call( + RuntimeOrigin::signed(ALICE), + addr1, + 0, + GAS_LIMIT, + None, + vec![] + )); assert_refcount!(code_hash, 1); // Pristine code should still be there crate::PristineCode::::get(code_hash).unwrap(); // remove the last contract - assert_ok!(Contracts::call(Origin::signed(ALICE), addr2, 0, GAS_LIMIT, None, vec![])); + assert_ok!(Contracts::call( + RuntimeOrigin::signed(ALICE), + addr2, + 0, + GAS_LIMIT, + None, + vec![] + )); assert_refcount!(code_hash, 0); // refcount is `0` but code should still exists because it needs to be removed manually @@ -2326,7 +2374,7 @@ fn reinstrument_does_charge() { let code_len = wasm.len() as u32; assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2360,10 +2408,11 @@ fn reinstrument_does_charge() { let result2 = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, zero.clone(), false); assert!(!result2.result.unwrap().did_revert()); - assert!(result2.gas_consumed > result1.gas_consumed); + assert!(result2.gas_consumed.ref_time() > result1.gas_consumed.ref_time()); assert_eq!( - result2.gas_consumed, - result1.gas_consumed + ::WeightInfo::reinstrument(code_len).ref_time(), + result2.gas_consumed.ref_time(), + result1.gas_consumed.ref_time() + + ::WeightInfo::reinstrument(code_len).ref_time(), ); }); } @@ -2375,7 +2424,7 @@ fn debug_message_works() { ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 30_000, GAS_LIMIT, None, @@ -2398,7 +2447,7 @@ fn debug_message_logging_disabled() { ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 30_000, GAS_LIMIT, None, @@ -2411,7 +2460,7 @@ fn debug_message_logging_disabled() { let result = Contracts::bare_call(ALICE, addr.clone(), 0, GAS_LIMIT, None, vec![], false); assert_matches!(result.result, Ok(_)); // the dispatchables always run without debugging - assert_ok!(Contracts::call(Origin::signed(ALICE), addr, 0, GAS_LIMIT, None, vec![])); + assert_ok!(Contracts::call(RuntimeOrigin::signed(ALICE), addr, 0, GAS_LIMIT, None, vec![])); assert!(result.debug_message.is_empty()); }); } @@ -2423,7 +2472,7 @@ fn debug_message_invalid_utf8() { ExtBuilder::default().existential_deposit(50).build().execute_with(|| { let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 30_000, GAS_LIMIT, None, @@ -2447,7 +2496,7 @@ fn gas_estimation_nested_call_fixed_limit() { let _ = Balances::deposit_creating(&CHARLIE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2458,7 +2507,7 @@ fn gas_estimation_nested_call_fixed_limit() { let addr_caller = Contracts::contract_address(&ALICE, &caller_hash, &[0]); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2487,7 +2536,7 @@ fn gas_estimation_nested_call_fixed_limit() { assert_ok!(&result.result); // We have a subcall with a fixed gas limit. This constitutes precharging. - assert!(result.gas_required > result.gas_consumed); + assert!(result.gas_required.ref_time() > result.gas_consumed.ref_time()); // Make the same call using the estimated gas. Should succeed. assert_ok!( @@ -2495,7 +2544,7 @@ fn gas_estimation_nested_call_fixed_limit() { ALICE, addr_caller, 0, - Weight::from_ref_time(result.gas_required), + result.gas_required, Some(result.storage_deposit.charge_or_zero()), input, false, @@ -2508,6 +2557,7 @@ fn gas_estimation_nested_call_fixed_limit() { #[test] #[cfg(feature = "unstable-interface")] fn gas_estimation_call_runtime() { + use codec::Decode; let (caller_code, caller_hash) = compile_module::("call_runtime").unwrap(); let (callee_code, callee_hash) = compile_module::("dummy").unwrap(); ExtBuilder::default().existential_deposit(50).build().execute_with(|| { @@ -2516,7 +2566,7 @@ fn gas_estimation_call_runtime() { let _ = Balances::deposit_creating(&CHARLIE, 1000 * min_balance); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2527,7 +2577,7 @@ fn gas_estimation_call_runtime() { let addr_caller = Contracts::contract_address(&ALICE, &caller_hash, &[0]); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), min_balance * 100, GAS_LIMIT, None, @@ -2539,10 +2589,10 @@ fn gas_estimation_call_runtime() { // Call something trivial with a huge gas limit so that we can observe the effects // of pre-charging. This should create a difference between consumed and required. - let call = Call::Contracts(crate::Call::call { + let call = RuntimeCall::Contracts(crate::Call::call { dest: addr_callee, value: 0, - gas_limit: GAS_LIMIT / 3, + gas_limit: GAS_LIMIT.set_ref_time(GAS_LIMIT.ref_time() / 3), storage_deposit_limit: None, data: vec![], }); @@ -2555,9 +2605,10 @@ fn gas_estimation_call_runtime() { call.encode(), false, ); - assert_ok!(&result.result); - - assert!(result.gas_required > result.gas_consumed); + // contract encodes the result of the dispatch runtime + let outcome = u32::decode(&mut result.result.unwrap().data.as_ref()).unwrap(); + assert_eq!(outcome, 0); + assert!(result.gas_required.ref_time() > result.gas_consumed.ref_time()); // Make the same call using the required gas. Should succeed. assert_ok!( @@ -2565,7 +2616,7 @@ fn gas_estimation_call_runtime() { ALICE, addr_caller, 0, - Weight::from_ref_time(result.gas_required), + result.gas_required, None, call.encode(), false, @@ -2584,7 +2635,7 @@ fn ecdsa_recover() { // Instantiate the ecdsa_recover contract. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 100_000, GAS_LIMIT, None, @@ -2622,7 +2673,7 @@ fn ecdsa_recover() { .result .unwrap(); assert!(!result.did_revert()); - assert_eq!(result.data.as_ref(), &EXPECTED_COMPRESSED_PUBLIC_KEY); + assert_eq!(result.data, EXPECTED_COMPRESSED_PUBLIC_KEY); }) } @@ -2638,7 +2689,7 @@ fn upload_code_works() { assert!(!>::contains_key(code_hash)); assert_ok!(Contracts::upload_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(1_000)) )); @@ -2649,7 +2700,7 @@ fn upload_code_works() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, amount: 240, }), @@ -2657,7 +2708,7 @@ fn upload_code_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::CodeStored { code_hash }), + event: RuntimeEvent::Contracts(crate::Event::CodeStored { code_hash }), topics: vec![code_hash], }, ] @@ -2676,7 +2727,7 @@ fn upload_code_limit_too_low() { initialize_block(2); assert_noop!( - Contracts::upload_code(Origin::signed(ALICE), wasm, Some(codec::Compact(100))), + Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(100))), >::StorageDepositLimitExhausted, ); @@ -2695,7 +2746,7 @@ fn upload_code_not_enough_balance() { initialize_block(2); assert_noop!( - Contracts::upload_code(Origin::signed(ALICE), wasm, Some(codec::Compact(1_000))), + Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(1_000))), >::StorageDepositNotEnoughFunds, ); @@ -2714,13 +2765,13 @@ fn remove_code_works() { initialize_block(2); assert_ok!(Contracts::upload_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(1_000)) )); assert!(>::contains_key(code_hash)); - assert_ok!(Contracts::remove_code(Origin::signed(ALICE), code_hash)); + assert_ok!(Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash)); assert!(!>::contains_key(code_hash)); assert_eq!( @@ -2728,7 +2779,7 @@ fn remove_code_works() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, amount: 240, }), @@ -2736,12 +2787,12 @@ fn remove_code_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::CodeStored { code_hash }), + event: RuntimeEvent::Contracts(crate::Event::CodeStored { code_hash }), topics: vec![code_hash], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Unreserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Unreserved { who: ALICE, amount: 240, }), @@ -2749,7 +2800,7 @@ fn remove_code_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::CodeRemoved { code_hash }), + event: RuntimeEvent::Contracts(crate::Event::CodeRemoved { code_hash }), topics: vec![code_hash], }, ] @@ -2768,13 +2819,13 @@ fn remove_code_wrong_origin() { initialize_block(2); assert_ok!(Contracts::upload_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), wasm, Some(codec::Compact(1_000)) )); assert_noop!( - Contracts::remove_code(Origin::signed(BOB), code_hash), + Contracts::remove_code(RuntimeOrigin::signed(BOB), code_hash), sp_runtime::traits::BadOrigin, ); @@ -2783,7 +2834,7 @@ fn remove_code_wrong_origin() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, amount: 240, }), @@ -2791,7 +2842,7 @@ fn remove_code_wrong_origin() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::CodeStored { code_hash }), + event: RuntimeEvent::Contracts(crate::Event::CodeStored { code_hash }), topics: vec![code_hash], }, ] @@ -2807,7 +2858,7 @@ fn remove_code_in_use() { let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -2820,7 +2871,7 @@ fn remove_code_in_use() { initialize_block(2); assert_noop!( - Contracts::remove_code(Origin::signed(ALICE), code_hash), + Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash), >::CodeInUse, ); @@ -2839,7 +2890,7 @@ fn remove_code_not_found() { initialize_block(2); assert_noop!( - Contracts::remove_code(Origin::signed(ALICE), code_hash), + Contracts::remove_code(RuntimeOrigin::signed(ALICE), code_hash), >::CodeNotFound, ); @@ -2859,7 +2910,7 @@ fn instantiate_with_zero_balance_works() { // Instantiate the BOB contract. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -2870,7 +2921,7 @@ fn instantiate_with_zero_balance_works() { let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // Check that the BOB contract has been instantiated. - assert_matches!(ContractInfoOf::::get(&addr), Some(_)); + get_contract(&addr); // Make sure the account exists even though no free balance was send assert_eq!(::Currency::free_balance(&addr), 0,); @@ -2884,12 +2935,14 @@ fn instantiate_with_zero_balance_works() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::NewAccount { account: addr.clone() }), + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: addr.clone() + }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Endowed { + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { account: addr.clone(), free_balance: min_balance, }), @@ -2897,7 +2950,7 @@ fn instantiate_with_zero_balance_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: min_balance, @@ -2906,7 +2959,7 @@ fn instantiate_with_zero_balance_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: addr.clone(), amount: min_balance, }), @@ -2914,7 +2967,7 @@ fn instantiate_with_zero_balance_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, amount: 240, }), @@ -2922,12 +2975,12 @@ fn instantiate_with_zero_balance_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::CodeStored { code_hash }), + event: RuntimeEvent::Contracts(crate::Event::CodeStored { code_hash }), topics: vec![code_hash], }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Instantiated { + event: RuntimeEvent::Contracts(crate::Event::Instantiated { deployer: ALICE, contract: addr.clone(), }), @@ -2950,7 +3003,7 @@ fn instantiate_with_below_existential_deposit_works() { // Instantiate the BOB contract. assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 50, GAS_LIMIT, None, @@ -2961,7 +3014,7 @@ fn instantiate_with_below_existential_deposit_works() { let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); // Check that the BOB contract has been instantiated. - assert_matches!(ContractInfoOf::::get(&addr), Some(_)); + get_contract(&addr); // Make sure the account exists even though no free balance was send assert_eq!(::Currency::free_balance(&addr), 50,); @@ -2975,12 +3028,14 @@ fn instantiate_with_below_existential_deposit_works() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::NewAccount { account: addr.clone() }), + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: addr.clone() + }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Endowed { + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { account: addr.clone(), free_balance: min_balance, }), @@ -2988,7 +3043,7 @@ fn instantiate_with_below_existential_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: min_balance, @@ -2997,7 +3052,7 @@ fn instantiate_with_below_existential_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: addr.clone(), amount: min_balance, }), @@ -3005,7 +3060,7 @@ fn instantiate_with_below_existential_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: 50, @@ -3014,7 +3069,7 @@ fn instantiate_with_below_existential_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: ALICE, amount: 240, }), @@ -3022,12 +3077,12 @@ fn instantiate_with_below_existential_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::CodeStored { code_hash }), + event: RuntimeEvent::Contracts(crate::Event::CodeStored { code_hash }), topics: vec![code_hash], }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Instantiated { + event: RuntimeEvent::Contracts(crate::Event::Instantiated { deployer: ALICE, contract: addr.clone(), }), @@ -3046,7 +3101,7 @@ fn storage_deposit_works() { let mut deposit = ::Currency::minimum_balance(); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -3061,7 +3116,7 @@ fn storage_deposit_works() { // Create storage assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 42, GAS_LIMIT, @@ -3071,11 +3126,11 @@ fn storage_deposit_works() { // 4 is for creating 2 storage items let charged0 = 4 + 1_000 + 5_000; deposit += charged0; - assert_eq!(>::get(&addr).unwrap().storage_deposit, deposit); + assert_eq!(get_contract(&addr).total_deposit(), deposit); // Add more storage (but also remove some) assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -3084,27 +3139,28 @@ fn storage_deposit_works() { )); let charged1 = 1_000 - 100; deposit += charged1; - assert_eq!(>::get(&addr).unwrap().storage_deposit, deposit); + assert_eq!(get_contract(&addr).total_deposit(), deposit); // Remove more storage (but also add some) assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, (2_100u32, 900u32).encode(), )); - let refunded0 = 4_000 - 100; + // -1 for numeric instability + let refunded0 = 4_000 - 100 - 1; deposit -= refunded0; - assert_eq!(>::get(&addr).unwrap().storage_deposit, deposit); + assert_eq!(get_contract(&addr).total_deposit(), deposit); assert_eq!( System::events(), vec![ EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: 42, @@ -3113,7 +3169,7 @@ fn storage_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: addr.clone(), }), @@ -3121,7 +3177,7 @@ fn storage_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: charged0, @@ -3130,7 +3186,7 @@ fn storage_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: addr.clone(), amount: charged0, }), @@ -3138,7 +3194,7 @@ fn storage_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: addr.clone(), }), @@ -3146,7 +3202,7 @@ fn storage_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: charged1, @@ -3155,7 +3211,7 @@ fn storage_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Reserved { + event: RuntimeEvent::Balances(pallet_balances::Event::Reserved { who: addr.clone(), amount: charged1, }), @@ -3163,7 +3219,7 @@ fn storage_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: addr.clone(), }), @@ -3171,7 +3227,7 @@ fn storage_deposit_works() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::ReserveRepatriated { + event: RuntimeEvent::Balances(pallet_balances::Event::ReserveRepatriated { from: addr.clone(), to: ALICE, amount: refunded0, @@ -3195,7 +3251,7 @@ fn set_code_extrinsic() { let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -3205,55 +3261,55 @@ fn set_code_extrinsic() { )); let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); - assert_ok!(Contracts::upload_code(Origin::signed(ALICE), new_wasm, None,)); + assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), new_wasm, None,)); // Drop previous events initialize_block(2); - assert_eq!(>::get(&addr).unwrap().code_hash, code_hash); + assert_eq!(get_contract(&addr).code_hash, code_hash); assert_refcount!(&code_hash, 1); assert_refcount!(&new_code_hash, 0); // only root can execute this extrinsic assert_noop!( - Contracts::set_code(Origin::signed(ALICE), addr.clone(), new_code_hash), + Contracts::set_code(RuntimeOrigin::signed(ALICE), addr.clone(), new_code_hash), sp_runtime::traits::BadOrigin, ); - assert_eq!(>::get(&addr).unwrap().code_hash, code_hash); + assert_eq!(get_contract(&addr).code_hash, code_hash); assert_refcount!(&code_hash, 1); assert_refcount!(&new_code_hash, 0); assert_eq!(System::events(), vec![],); // contract must exist assert_noop!( - Contracts::set_code(Origin::root(), BOB, new_code_hash), + Contracts::set_code(RuntimeOrigin::root(), BOB, new_code_hash), >::ContractNotFound, ); - assert_eq!(>::get(&addr).unwrap().code_hash, code_hash); + assert_eq!(get_contract(&addr).code_hash, code_hash); assert_refcount!(&code_hash, 1); assert_refcount!(&new_code_hash, 0); assert_eq!(System::events(), vec![],); // new code hash must exist assert_noop!( - Contracts::set_code(Origin::root(), addr.clone(), Default::default()), + Contracts::set_code(RuntimeOrigin::root(), addr.clone(), Default::default()), >::CodeNotFound, ); - assert_eq!(>::get(&addr).unwrap().code_hash, code_hash); + assert_eq!(get_contract(&addr).code_hash, code_hash); assert_refcount!(&code_hash, 1); assert_refcount!(&new_code_hash, 0); assert_eq!(System::events(), vec![],); // successful call - assert_ok!(Contracts::set_code(Origin::root(), addr.clone(), new_code_hash)); - assert_eq!(>::get(&addr).unwrap().code_hash, new_code_hash); + assert_ok!(Contracts::set_code(RuntimeOrigin::root(), addr.clone(), new_code_hash)); + assert_eq!(get_contract(&addr).code_hash, new_code_hash); assert_refcount!(&code_hash, 0); assert_refcount!(&new_code_hash, 1); assert_eq!( System::events(), vec![EventRecord { phase: Phase::Initialization, - event: Event::Contracts(pallet_contracts::Event::ContractCodeUpdated { + event: RuntimeEvent::Contracts(pallet_contracts::Event::ContractCodeUpdated { contract: addr.clone(), new_code_hash, old_code_hash: code_hash, @@ -3272,7 +3328,7 @@ fn call_after_killed_account_needs_funding() { let min_balance = ::Currency::minimum_balance(); assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 700, GAS_LIMIT, None, @@ -3297,7 +3353,7 @@ fn call_after_killed_account_needs_funding() { // account in order to send balance there. assert_err_ignore_postinfo!( Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), min_balance - 1, GAS_LIMIT, @@ -3309,7 +3365,7 @@ fn call_after_killed_account_needs_funding() { // Sending zero should work as it does not do a transfer assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, @@ -3319,7 +3375,7 @@ fn call_after_killed_account_needs_funding() { // Sending minimum balance should work assert_ok!(Contracts::call( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), addr.clone(), min_balance, GAS_LIMIT, @@ -3332,14 +3388,14 @@ fn call_after_killed_account_needs_funding() { vec![ EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::KilledAccount { + event: RuntimeEvent::System(frame_system::Event::KilledAccount { account: addr.clone() }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Slashed { + event: RuntimeEvent::Balances(pallet_balances::Event::Slashed { who: addr.clone(), amount: min_balance + 700 }), @@ -3347,7 +3403,7 @@ fn call_after_killed_account_needs_funding() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: addr.clone(), }), @@ -3355,12 +3411,14 @@ fn call_after_killed_account_needs_funding() { }, EventRecord { phase: Phase::Initialization, - event: Event::System(frame_system::Event::NewAccount { account: addr.clone() }), + event: RuntimeEvent::System(frame_system::Event::NewAccount { + account: addr.clone() + }), topics: vec![], }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Endowed { + event: RuntimeEvent::Balances(pallet_balances::Event::Endowed { account: addr.clone(), free_balance: min_balance }), @@ -3368,7 +3426,7 @@ fn call_after_killed_account_needs_funding() { }, EventRecord { phase: Phase::Initialization, - event: Event::Balances(pallet_balances::Event::Transfer { + event: RuntimeEvent::Balances(pallet_balances::Event::Transfer { from: ALICE, to: addr.clone(), amount: min_balance @@ -3377,7 +3435,7 @@ fn call_after_killed_account_needs_funding() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: addr.clone(), }), @@ -3399,12 +3457,12 @@ fn contract_reverted() { let input = (flags.bits(), buffer).encode(); // We just upload the code for later use - assert_ok!(Contracts::upload_code(Origin::signed(ALICE), wasm.clone(), None)); + assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm.clone(), None)); // Calling extrinsic: revert leads to an error assert_err_ignore_postinfo!( Contracts::instantiate( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -3418,7 +3476,7 @@ fn contract_reverted() { // Calling extrinsic: revert leads to an error assert_err_ignore_postinfo!( Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 0, GAS_LIMIT, None, @@ -3446,7 +3504,7 @@ fn contract_reverted() { .result .unwrap(); assert_eq!(result.result.flags, flags); - assert_eq!(result.result.data.0, buffer); + assert_eq!(result.result.data, buffer); assert!(!>::contains_key(result.account_id)); // Pass empty flags and therefore successfully instantiate the contract for later use. @@ -3466,7 +3524,14 @@ fn contract_reverted() { // Calling extrinsic: revert leads to an error assert_err_ignore_postinfo!( - Contracts::call(Origin::signed(ALICE), addr.clone(), 0, GAS_LIMIT, None, input.clone()), + Contracts::call( + RuntimeOrigin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + None, + input.clone() + ), >::ContractReverted, ); @@ -3475,7 +3540,7 @@ fn contract_reverted() { .result .unwrap(); assert_eq!(result.flags, flags); - assert_eq!(result.data.0, buffer); + assert_eq!(result.data, buffer); }); } @@ -3486,7 +3551,7 @@ fn code_rejected_error_works() { let _ = Balances::deposit_creating(&ALICE, 1_000_000); assert_noop!( - Contracts::upload_code(Origin::signed(ALICE), wasm.clone(), None), + Contracts::upload_code(RuntimeOrigin::signed(ALICE), wasm.clone(), None), >::CodeRejected, ); @@ -3495,7 +3560,7 @@ fn code_rejected_error_works() { 0, GAS_LIMIT, None, - Code::Upload(Bytes(wasm)), + Code::Upload(wasm), vec![], vec![], true, @@ -3520,7 +3585,7 @@ fn set_code_hash() { // Instantiate the 'caller' assert_ok!(Contracts::instantiate_with_code( - Origin::signed(ALICE), + RuntimeOrigin::signed(ALICE), 300_000, GAS_LIMIT, None, @@ -3529,7 +3594,7 @@ fn set_code_hash() { vec![], )); // upload new code - assert_ok!(Contracts::upload_code(Origin::signed(ALICE), new_wasm.clone(), None)); + assert_ok!(Contracts::upload_code(RuntimeOrigin::signed(ALICE), new_wasm.clone(), None)); System::reset_events(); @@ -3560,7 +3625,7 @@ fn set_code_hash() { &[ EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::ContractCodeUpdated { + event: RuntimeEvent::Contracts(crate::Event::ContractCodeUpdated { contract: contract_addr.clone(), new_code_hash, old_code_hash: code_hash, @@ -3569,7 +3634,7 @@ fn set_code_hash() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: contract_addr.clone(), }), @@ -3577,7 +3642,7 @@ fn set_code_hash() { }, EventRecord { phase: Phase::Initialization, - event: Event::Contracts(crate::Event::Called { + event: RuntimeEvent::Contracts(crate::Event::Called { caller: ALICE, contract: contract_addr.clone(), }), @@ -3587,3 +3652,301 @@ fn set_code_hash() { ); }); } + +#[test] +fn storage_deposit_limit_is_enforced() { + let (wasm, code_hash) = compile_module::("store").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let min_balance = ::Currency::minimum_balance(); + + // Instantiate the BOB contract. + assert_ok!(Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + // Check that the BOB contract has been instantiated and has the minimum balance + assert_eq!(get_contract(&addr).total_deposit(), min_balance); + assert_eq!(::Currency::total_balance(&addr), min_balance); + + // Create 100 bytes of storage with a price of per byte + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(ALICE), + addr.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(1)), + 100u32.to_le_bytes().to_vec() + ), + >::StorageDepositLimitExhausted, + ); + }); +} + +#[test] +fn storage_deposit_limit_is_enforced_late() { + let (wasm_caller, code_hash_caller) = + compile_module::("create_storage_and_call").unwrap(); + let (wasm_callee, code_hash_callee) = compile_module::("store").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + + // Create both contracts: Constructors do nothing. + assert_ok!(Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm_caller, + vec![], + vec![], + )); + let addr_caller = Contracts::contract_address(&ALICE, &code_hash_caller, &[]); + assert_ok!(Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm_callee, + vec![], + vec![], + )); + let addr_callee = Contracts::contract_address(&ALICE, &code_hash_callee, &[]); + + // Create 100 bytes of storage with a price of per byte + // This is 100 Balance + 2 Balance for the item + assert_ok!(Contracts::call( + RuntimeOrigin::signed(ALICE), + addr_callee.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(102)), + 100u32.to_le_bytes().to_vec() + )); + + // We do not remove any storage but require 14 bytes of storage for the new + // storage created in the immediate contract. + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(ALICE), + addr_caller.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(5)), + 100u32 + .to_le_bytes() + .as_ref() + .iter() + .chain(<_ as AsRef<[u8]>>::as_ref(&addr_callee)) + .cloned() + .collect(), + ), + >::StorageDepositLimitExhausted, + ); + + // Allow for the additional 14 bytes but demand an additional byte in the callee contract. + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(ALICE), + addr_caller.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(14)), + 101u32 + .to_le_bytes() + .as_ref() + .iter() + .chain(<_ as AsRef<[u8]>>::as_ref(&addr_callee)) + .cloned() + .collect(), + ), + >::StorageDepositLimitExhausted, + ); + + // Refund in the callee contract but not enough to cover the 14 balance required by the + // caller. + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(ALICE), + addr_caller.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(0)), + 87u32 + .to_le_bytes() + .as_ref() + .iter() + .chain(<_ as AsRef<[u8]>>::as_ref(&addr_callee)) + .cloned() + .collect(), + ), + >::StorageDepositLimitExhausted, + ); + + let _ = Balances::make_free_balance_be(&ALICE, 1_000); + + // Send more than the sender has balance. + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(ALICE), + addr_caller.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(50)), + 1_200u32 + .to_le_bytes() + .as_ref() + .iter() + .chain(<_ as AsRef<[u8]>>::as_ref(&addr_callee)) + .cloned() + .collect(), + ), + >::StorageDepositLimitExhausted, + ); + + // Same as above but allow for the additional balance. + assert_ok!(Contracts::call( + RuntimeOrigin::signed(ALICE), + addr_caller.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(1)), + 87u32 + .to_le_bytes() + .as_ref() + .iter() + .chain(<_ as AsRef<[u8]>>::as_ref(&addr_callee)) + .cloned() + .collect(), + )); + }); +} + +#[test] +fn deposit_limit_honors_liquidity_restrictions() { + let (wasm, code_hash) = compile_module::("store").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let _ = Balances::deposit_creating(&BOB, 1_000); + let min_balance = ::Currency::minimum_balance(); + + // Instantiate the BOB contract. + assert_ok!(Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + // Check that the contract has been instantiated and has the minimum balance + assert_eq!(get_contract(&addr).total_deposit(), min_balance); + assert_eq!(::Currency::total_balance(&addr), min_balance); + + // check that the lock ins honored + Balances::set_lock([0; 8], &BOB, 1_000, WithdrawReasons::TRANSFER); + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(BOB), + addr.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(200)), + 100u32.to_le_bytes().to_vec() + ), + >::StorageDepositNotEnoughFunds, + ); + assert_eq!(Balances::free_balance(&BOB), 1_000); + }); +} + +#[test] +fn deposit_limit_honors_existential_deposit() { + let (wasm, code_hash) = compile_module::("store").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let _ = Balances::deposit_creating(&BOB, 1_000); + let min_balance = ::Currency::minimum_balance(); + + // Instantiate the BOB contract. + assert_ok!(Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + // Check that the contract has been instantiated and has the minimum balance + assert_eq!(get_contract(&addr).total_deposit(), min_balance); + assert_eq!(::Currency::total_balance(&addr), min_balance); + + // check that the deposit can't bring the account below the existential deposit + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(BOB), + addr.clone(), + 0, + GAS_LIMIT, + Some(codec::Compact(900)), + 100u32.to_le_bytes().to_vec() + ), + >::StorageDepositNotEnoughFunds, + ); + assert_eq!(Balances::free_balance(&BOB), 1_000); + }); +} + +#[test] +fn deposit_limit_honors_min_leftover() { + let (wasm, code_hash) = compile_module::("store").unwrap(); + ExtBuilder::default().existential_deposit(200).build().execute_with(|| { + let _ = Balances::deposit_creating(&ALICE, 1_000_000); + let _ = Balances::deposit_creating(&BOB, 1_000); + let min_balance = ::Currency::minimum_balance(); + + // Instantiate the BOB contract. + assert_ok!(Contracts::instantiate_with_code( + RuntimeOrigin::signed(ALICE), + 0, + GAS_LIMIT, + None, + wasm, + vec![], + vec![], + )); + let addr = Contracts::contract_address(&ALICE, &code_hash, &[]); + + // Check that the contract has been instantiated and has the minimum balance + assert_eq!(get_contract(&addr).total_deposit(), min_balance); + assert_eq!(::Currency::total_balance(&addr), min_balance); + + // check that the minumum leftover (value send) is considered + assert_err_ignore_postinfo!( + Contracts::call( + RuntimeOrigin::signed(BOB), + addr.clone(), + 400, + GAS_LIMIT, + Some(codec::Compact(500)), + 100u32.to_le_bytes().to_vec() + ), + >::StorageDepositNotEnoughFunds, + ); + assert_eq!(Balances::free_balance(&BOB), 1_000); + }); +} diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index eb5551e342bca..09e51d981360b 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -39,6 +39,7 @@ use frame_support::{ dispatch::{DispatchError, DispatchResult}, ensure, traits::{Get, ReservableCurrency}, + WeakBoundedVec, }; use sp_core::crypto::UncheckedFrom; use sp_runtime::traits::BadOrigin; @@ -195,10 +196,15 @@ pub fn reinstrument( let original_code = >::get(&prefab_module.code_hash).ok_or(Error::::CodeNotFound)?; let original_code_len = original_code.len(); - prefab_module.code = prepare::reinstrument_contract::(&original_code, schedule) - .map_err(|_| >::CodeRejected)? - .try_into() - .map_err(|_| >::CodeTooLarge)?; + // We need to allow contracts growing too big after re-instrumentation. Otherwise + // the contract can become inaccessible. The user has no influence over this size + // as the contract is already deployed and every change in size would be the result + // of changes in the instrumentation algorithm controlled by the chain authors. + prefab_module.code = WeakBoundedVec::force_from( + prepare::reinstrument_contract::(&original_code, schedule) + .map_err(|_| >::CodeRejected)?, + Some("Contract exceeds limit after re-instrumentation."), + ); prefab_module.instruction_weights_version = schedule.instruction_weights.version; >::insert(&prefab_module.code_hash, &*prefab_module); Ok(original_code_len as u32) @@ -222,16 +228,11 @@ impl Token for CodeToken { // contract code. This is why we subtract `T::*::(0)`. We need to do this at this // point because when charging the general weight for calling the contract we not know the // size of the contract. - let ref_time_weight = match *self { + match *self { Reinstrument(len) => T::WeightInfo::reinstrument(len), - Load(len) => { - let computation = T::WeightInfo::call_with_code_per_byte(len) - .saturating_sub(T::WeightInfo::call_with_code_per_byte(0)); - let bandwidth = T::ContractAccessWeight::get().saturating_mul(len as u64); - computation.max(bandwidth) - }, - }; - - ref_time_weight + Load(len) => T::WeightInfo::call_with_code_per_byte(len) + .saturating_sub(T::WeightInfo::call_with_code_per_byte(0)) + .set_proof_size(len.into()), + } } } diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 6790830b97e02..b341ae3bd155d 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -35,11 +35,7 @@ use crate::{ Schedule, }; use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::{ - dispatch::{DispatchError, DispatchResult}, - ensure, - traits::Get, -}; +use frame_support::dispatch::{DispatchError, DispatchResult}; use sp_core::crypto::UncheckedFrom; use sp_sandbox::{SandboxEnvironmentBuilder, SandboxInstance, SandboxMemory}; use sp_std::prelude::*; @@ -134,12 +130,6 @@ where schedule, owner, )?; - // When instrumenting a new code we apply a stricter limit than enforced by the - // `RelaxedCodeVec` in order to leave some headroom for reinstrumentation. - ensure!( - module.code.len() as u32 <= T::MaxCodeLen::get(), - (>::CodeTooLarge.into(), ""), - ); Ok(module) } @@ -280,15 +270,18 @@ mod tests { }, gas::GasMeter, storage::WriteOutcome, - tests::{Call, Test, ALICE, BOB}, + tests::{RuntimeCall, Test, ALICE, BOB}, BalanceOf, CodeHash, Error, Pallet as Contracts, }; use assert_matches::assert_matches; - use frame_support::{assert_ok, dispatch::DispatchResultWithPostInfo, weights::Weight}; - use hex_literal::hex; + use frame_support::{ + assert_ok, + dispatch::DispatchResultWithPostInfo, + weights::{OldWeight, Weight}, + }; use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; use pretty_assertions::assert_eq; - use sp_core::{Bytes, H256}; + use sp_core::H256; use sp_runtime::DispatchError; use std::{ borrow::BorrowMut, @@ -339,7 +332,7 @@ mod tests { transfers: Vec, // (topics, data) events: Vec<(Vec, Vec)>, - runtime_calls: RefCell>, + runtime_calls: RefCell>, schedule: Schedule, gas_meter: GasMeter, debug_buffer: Vec, @@ -348,8 +341,8 @@ mod tests { } /// The call is mocked and just returns this hardcoded value. - fn call_return_data() -> Bytes { - Bytes(vec![0xDE, 0xAD, 0xBE, 0xEF]) + fn call_return_data() -> Vec { + vec![0xDE, 0xAD, 0xBE, 0xEF] } impl Default for MockExt { @@ -411,7 +404,7 @@ mod tests { }); Ok(( Contracts::::contract_address(&ALICE, &code_hash, salt), - ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }, + ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }, )) } fn set_code_hash(&mut self, hash: CodeHash) -> Result<(), DispatchError> { @@ -532,7 +525,10 @@ mod tests { self.debug_buffer.extend(msg.as_bytes()); true } - fn call_runtime(&self, call: ::Call) -> DispatchResultWithPostInfo { + fn call_runtime( + &self, + call: ::RuntimeCall, + ) -> DispatchResultWithPostInfo { self.runtime_calls.borrow_mut().push(call); Ok(Default::default()) } @@ -808,7 +804,7 @@ mod tests { let mut mock_ext = MockExt::default(); let input = vec![0xff, 0x2a, 0x99, 0x88]; let result = execute(CODE, input.clone(), &mut mock_ext).unwrap(); - assert_eq!(result.data.0, input); + assert_eq!(result.data, input); assert_eq!( &mock_ext.calls, &[CallEntry { to: ALICE, value: 0x2a, data: input, allows_reentry: true }] @@ -911,15 +907,15 @@ mod tests { // value does not exist -> sentinel value returned let result = execute(CODE, [3u8; 32].encode(), &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL); // value did exist -> success let result = execute(CODE, [1u8; 32].encode(), &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 1,); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 1,); // value did exist -> success (zero sized type) let result = execute(CODE, [2u8; 32].encode(), &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0,); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0,); } #[test] @@ -981,13 +977,13 @@ mod tests { let input = (63, [1u8; 64]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); // sentinel returned - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL); // value exists let input = (64, [1u8; 64]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); // true as u32 returned - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 1); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 1); // getter does not remove the value from storage assert_eq!(ext.storage.get(&[1u8; 64].to_vec()).unwrap(), &[42u8]); @@ -995,7 +991,7 @@ mod tests { let input = (19, [2u8; 19]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); // true as u32 returned - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0); // getter does not remove the value from storage assert_eq!(ext.storage.get(&[2u8; 19].to_vec()).unwrap(), &([] as [u8; 0])); } @@ -1238,7 +1234,7 @@ mod tests { let output = execute(CODE_ECDSA_TO_ETH_ADDRESS, vec![], MockExt::default()).unwrap(); assert_eq!( output, - ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes([0x02; 20].to_vec()) } + ExecReturnValue { flags: ReturnFlags::empty(), data: [0x02; 20].to_vec() } ); } @@ -1315,7 +1311,7 @@ mod tests { assert_eq!( output, - ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes([0x22; 32].to_vec()) } + ExecReturnValue { flags: ReturnFlags::empty(), data: [0x22; 32].to_vec() } ); } @@ -1553,10 +1549,11 @@ mod tests { let output = execute(CODE_GAS_LEFT, vec![], &mut ext).unwrap(); - let gas_left = Weight::decode(&mut &*output.data).unwrap(); + let OldWeight(gas_left) = OldWeight::decode(&mut &*output.data).unwrap(); let actual_left = ext.gas_meter.gas_left(); - assert!(gas_left < gas_limit, "gas_left must be less than initial"); - assert!(gas_left > actual_left, "gas_left must be greater than final"); + // TODO: account for proof size weight + assert!(gas_left < gas_limit.ref_time(), "gas_left must be less than initial"); + assert!(gas_left > actual_left.ref_time(), "gas_left must be greater than final"); } const CODE_VALUE_TRANSFERRED: &str = r#" @@ -1633,10 +1630,7 @@ mod tests { fn return_from_start_fn() { let output = execute(CODE_RETURN_FROM_START_FN, vec![], MockExt::default()).unwrap(); - assert_eq!( - output, - ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(vec![1, 2, 3, 4]) } - ); + assert_eq!(output, ExecReturnValue { flags: ReturnFlags::empty(), data: vec![1, 2, 3, 4] }); } const CODE_TIMESTAMP_NOW: &str = r#" @@ -1835,10 +1829,9 @@ mod tests { output, ExecReturnValue { flags: ReturnFlags::empty(), - data: Bytes( - hex!("000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F") - .to_vec() - ), + data: array_bytes::hex_into_unchecked( + "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F" + ) }, ); } @@ -1906,13 +1899,13 @@ mod tests { output, ExecReturnValue { flags: ReturnFlags::empty(), - data: Bytes( - ( - hex!("000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"), - 42u64, - ) - .encode() - ), + data: ( + array_bytes::hex2array_unchecked::<32>( + "000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F" + ), + 42u64, + ) + .encode() }, ); } @@ -1953,7 +1946,7 @@ mod tests { )] ); - assert!(mock_ext.gas_meter.gas_left() > Weight::zero()); + assert!(mock_ext.gas_meter.gas_left().ref_time() > 0); } const CODE_DEPOSIT_EVENT_MAX_TOPICS: &str = r#" @@ -2117,7 +2110,7 @@ mod tests { fn seal_return_with_success_status() { let output = execute( CODE_RETURN_WITH_DATA, - hex!("00000000445566778899").to_vec(), + array_bytes::hex2bytes_unchecked("00000000445566778899"), MockExt::default(), ) .unwrap(); @@ -2126,7 +2119,7 @@ mod tests { output, ExecReturnValue { flags: ReturnFlags::empty(), - data: Bytes(hex!("445566778899").to_vec()), + data: array_bytes::hex2bytes_unchecked("445566778899"), } ); assert!(!output.did_revert()); @@ -2134,15 +2127,18 @@ mod tests { #[test] fn return_with_revert_status() { - let output = - execute(CODE_RETURN_WITH_DATA, hex!("010000005566778899").to_vec(), MockExt::default()) - .unwrap(); + let output = execute( + CODE_RETURN_WITH_DATA, + array_bytes::hex2bytes_unchecked("010000005566778899"), + MockExt::default(), + ) + .unwrap(); assert_eq!( output, ExecReturnValue { flags: ReturnFlags::REVERT, - data: Bytes(hex!("5566778899").to_vec()), + data: array_bytes::hex2bytes_unchecked("5566778899"), } ); assert!(output.did_revert()); @@ -2299,12 +2295,13 @@ mod tests { #[test] #[cfg(feature = "unstable-interface")] fn call_runtime_works() { - let call = Call::System(frame_system::Call::remark { remark: b"Hello World".to_vec() }); + let call = + RuntimeCall::System(frame_system::Call::remark { remark: b"Hello World".to_vec() }); let mut ext = MockExt::default(); let result = execute(CODE_CALL_RUNTIME, call.encode(), &mut ext).unwrap(); assert_eq!(*ext.runtime_calls.borrow(), vec![call]); // 0 = ReturnCode::Success - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0); } #[test] @@ -2369,19 +2366,19 @@ mod tests { // value did not exist before -> sentinel returned let input = ([1u8; 32], [42u8, 48]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL); assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[42u8, 48]); // value do exist -> length of old value returned let input = ([1u8; 32], [0u8; 0]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 2); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 2); assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[0u8; 0]); // value do exist -> length of old value returned (test for zero sized val) let input = ([1u8; 32], [99u8]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0); assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[99u8]); } @@ -2440,19 +2437,19 @@ mod tests { // value did not exist before -> sentinel returned let input = (32, [1u8; 32], [42u8, 48]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL); assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[42u8, 48]); // value do exist -> length of old value returned let input = (32, [1u8; 32], [0u8; 0]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 2); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 2); assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[0u8; 0]); // value do exist -> length of old value returned (test for zero sized val) let input = (32, [1u8; 32], [99u8]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0); assert_eq!(ext.storage.get(&[1u8; 32].to_vec()).unwrap(), &[99u8]); } @@ -2525,7 +2522,7 @@ mod tests { let input = (63, [1u8; 64]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( - u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + u32::from_le_bytes(result.data[0..4].try_into().unwrap()), ReturnCode::KeyNotFound as u32 ); @@ -2533,21 +2530,21 @@ mod tests { let input = (64, [1u8; 64]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( - u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + u32::from_le_bytes(result.data[0..4].try_into().unwrap()), ReturnCode::Success as u32 ); assert_eq!(ext.storage.get(&[1u8; 64].to_vec()).unwrap(), &[42u8]); - assert_eq!(&result.data.0[4..], &[42u8]); + assert_eq!(&result.data[4..], &[42u8]); // value exists (test for 0 sized) let input = (19, [2u8; 19]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( - u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + u32::from_le_bytes(result.data[0..4].try_into().unwrap()), ReturnCode::Success as u32 ); assert_eq!(ext.storage.get(&[2u8; 19].to_vec()), Some(&vec![])); - assert_eq!(&result.data.0[4..], &([] as [u8; 0])); + assert_eq!(&result.data[4..], &([] as [u8; 0])); } #[test] @@ -2609,14 +2606,14 @@ mod tests { let input = (32, [3u8; 32]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); // sentinel returned - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL); assert_eq!(ext.storage.get(&[3u8; 32].to_vec()), None); // value did exist let input = (64, [1u8; 64]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); // length returned - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 1); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 1); // value cleared assert_eq!(ext.storage.get(&[1u8; 64].to_vec()), None); @@ -2624,14 +2621,14 @@ mod tests { let input = (63, [1u8; 64]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); // sentinel returned - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), crate::SENTINEL); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), crate::SENTINEL); assert_eq!(ext.storage.get(&[1u8; 64].to_vec()), None); // value exists let input = (19, [2u8; 19]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); // length returned (test for 0 sized) - assert_eq!(u32::from_le_bytes(result.data.0.try_into().unwrap()), 0); + assert_eq!(u32::from_le_bytes(result.data.try_into().unwrap()), 0); // value cleared assert_eq!(ext.storage.get(&[2u8; 19].to_vec()), None); } @@ -2708,7 +2705,7 @@ mod tests { let input = (63, [1u8; 64]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( - u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + u32::from_le_bytes(result.data[0..4].try_into().unwrap()), ReturnCode::KeyNotFound as u32 ); @@ -2716,21 +2713,21 @@ mod tests { let input = (64, [1u8; 64]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( - u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + u32::from_le_bytes(result.data[0..4].try_into().unwrap()), ReturnCode::Success as u32 ); assert_eq!(ext.storage.get(&[1u8; 64].to_vec()), None); - assert_eq!(&result.data.0[4..], &[42u8]); + assert_eq!(&result.data[4..], &[42u8]); // value did exist -> length returned (test for 0 sized) let input = (19, [2u8; 19]).encode(); let result = execute(CODE, input, &mut ext).unwrap(); assert_eq!( - u32::from_le_bytes(result.data.0[0..4].try_into().unwrap()), + u32::from_le_bytes(result.data[0..4].try_into().unwrap()), ReturnCode::Success as u32 ); assert_eq!(ext.storage.get(&[2u8; 19].to_vec()), None); - assert_eq!(&result.data.0[4..], &[0u8; 0]); + assert_eq!(&result.data[4..], &[0u8; 0]); } #[test] @@ -2767,10 +2764,7 @@ mod tests { let output = execute(CODE_IS_CONTRACT, vec![], MockExt::default()).unwrap(); // The mock ext just always returns 1u32 (`true`). - assert_eq!( - output, - ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(1u32.encode()) }, - ); + assert_eq!(output, ExecReturnValue { flags: ReturnFlags::empty(), data: 1u32.encode() },); } #[test] @@ -2904,10 +2898,7 @@ mod tests { let output = execute(CODE_CALLER_IS_ORIGIN, vec![], MockExt::default()).unwrap(); // The mock ext just always returns 0u32 (`false`) - assert_eq!( - output, - ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(0u32.encode()) }, - ); + assert_eq!(output, ExecReturnValue { flags: ReturnFlags::empty(), data: 0u32.encode() },); } #[test] diff --git a/frame/contracts/src/wasm/prepare.rs b/frame/contracts/src/wasm/prepare.rs index 7b81c1c55b3bd..e8873f604c9c7 100644 --- a/frame/contracts/src/wasm/prepare.rs +++ b/frame/contracts/src/wasm/prepare.rs @@ -54,7 +54,7 @@ impl<'a, T: Config> ContractModule<'a, T> { elements::deserialize_buffer(original_code).map_err(|_| "Can't decode wasm code")?; // Make sure that the module is valid. - validate_module::(&module).map_err(|_| "Module is not valid")?; + validate_module::(&module, ()).map_err(|_| "Module is not valid")?; // Return a `ContractModule` instance with // __valid__ module. @@ -426,7 +426,7 @@ fn do_preparation( .saturating_add(original_code_len) .saturating_add(>::max_encoded_len()) as u32; let deposit = Diff { bytes_added, items_added: 3, ..Default::default() } - .to_deposit::() + .update_contract::(None) .charge_or_zero(); module.owner_info = Some(OwnerInfo { owner, deposit, refcount: 0 }); diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index 334223e3b8432..6d7e6bcf69e5f 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -30,7 +30,7 @@ use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen}; use frame_support::{dispatch::DispatchError, ensure, traits::Get, weights::Weight}; use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; use pallet_contracts_proc_macro::define_env; -use sp_core::{crypto::UncheckedFrom, Bytes}; +use sp_core::crypto::UncheckedFrom; use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256}; use sp_runtime::traits::{Bounded, Zero}; use sp_sandbox::SandboxMemory; @@ -164,7 +164,7 @@ impl> From for TrapReason { pub enum RuntimeCosts { /// Charge the gas meter with the cost of a metering block. The charged costs are /// the supplied cost of the block plus the overhead of the metering itself. - MeteringBlock(u32), + MeteringBlock(u64), /// Weight charged for copying data from the sandbox. CopyFromContract(u32), /// Weight charged for copying data to the sandbox. @@ -261,7 +261,7 @@ impl RuntimeCosts { { use self::RuntimeCosts::*; let weight = match *self { - MeteringBlock(amount) => s.gas.saturating_add(amount.into()), + MeteringBlock(amount) => s.gas.saturating_add(amount), CopyFromContract(len) => s.return_per_byte.saturating_mul(len.into()), CopyToContract(len) => s.input_per_byte.saturating_mul(len.into()), Caller => s.caller, @@ -483,10 +483,10 @@ where TrapReason::Return(ReturnData { flags, data }) => { let flags = ReturnFlags::from_bits(flags).ok_or(Error::::InvalidCallFlags)?; - Ok(ExecReturnValue { flags, data: Bytes(data) }) + Ok(ExecReturnValue { flags, data }) }, TrapReason::Termination => - Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }), + Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }), TrapReason::SupervisorError(error) => return Err(error.into()), } } @@ -494,7 +494,7 @@ where // Check the exact type of the error. match sandbox_result { // No traps were generated. Proceed normally. - Ok(_) => Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }), + Ok(_) => Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }), // `Error::Module` is returned only if instantiation or linking failed (i.e. // wasm binary tried to import a function that is not provided by the host). // This shouldn't happen because validation process ought to reject such binaries. @@ -879,7 +879,7 @@ where if let Ok(return_value) = call_outcome { return Err(TrapReason::Return(ReturnData { flags: return_value.flags.bits(), - data: return_value.data.0, + data: return_value.data, })) } } @@ -957,7 +957,7 @@ pub mod env { /// This call is supposed to be called only by instrumentation injected code. /// /// - amount: How much gas is used. - fn gas(ctx: Runtime, amount: u32) -> Result<(), TrapReason> { + fn gas(ctx: Runtime, amount: u64) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::MeteringBlock(amount))?; Ok(()) } @@ -1737,7 +1737,7 @@ pub mod env { #[prefixed_alias] fn gas_left(ctx: Runtime, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> { ctx.charge_gas(RuntimeCosts::GasLeft)?; - let gas_left = &ctx.ext.gas_meter().gas_left().encode(); + let gas_left = &ctx.ext.gas_meter().gas_left().ref_time().encode(); Ok(ctx.write_sandbox_output(out_ptr, out_len_ptr, gas_left, false, already_charged)?) } @@ -1976,11 +1976,7 @@ pub mod env { data_len: u32, ) -> Result<(), TrapReason> { fn has_duplicates(items: &mut Vec) -> bool { - // # Warning - // - // Unstable sorts are non-deterministic across architectures. The usage here is OK - // because we are rejecting duplicates which removes the non determinism. - items.sort_unstable(); + items.sort(); // Find any two consecutive equal elements. items.windows(2).any(|w| match &w { &[a, b] => a == b, @@ -2314,9 +2310,9 @@ pub mod env { call_ptr: u32, call_len: u32, ) -> Result { - use frame_support::{dispatch::GetDispatchInfo, weights::extract_actual_weight}; + use frame_support::dispatch::{extract_actual_weight, GetDispatchInfo}; ctx.charge_gas(RuntimeCosts::CopyFromContract(call_len))?; - let call: ::Call = + let call: ::RuntimeCall = ctx.read_sandbox_memory_as_unbounded(call_ptr, call_len)?; let dispatch_info = call.get_dispatch_info(); let charged = ctx.charge_gas(RuntimeCosts::CallRuntime(dispatch_info.weight))?; diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index f1f80ba7a43df..4e4a6b6e6a2b7 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,22 +18,22 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-06-22, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-09-08, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_contracts // --extrinsic=* // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 +// --pallet=pallet_contracts +// --chain=dev // --output=./frame/contracts/src/weights.rs // --template=./.maintain/frame-weight-template.hbs @@ -166,25 +166,25 @@ pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - Weight::from_ref_time(1_654_000 as u64) + Weight::from_ref_time(3_089_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - Weight::from_ref_time(8_564_000 as u64) + Weight::from_ref_time(13_917_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(868_000 as u64).saturating_mul(k as u64)) + .saturating_add(Weight::from_ref_time(901_000 as u64).saturating_mul(k as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(k as u64))) } // Storage: Contracts DeletionQueue (r:1 w:0) - /// The range of component `q` is `[0, 1024]`. + /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_944_000 as u64).saturating_mul(q as u64)) + Weight::from_ref_time(14_172_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_301_000 as u64).saturating_mul(q as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -192,9 +192,9 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - Weight::from_ref_time(19_016_000 as u64) + Weight::from_ref_time(21_644_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(49_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(c as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -202,31 +202,33 @@ impl WeightInfo for SubstrateWeight { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) + // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - Weight::from_ref_time(205_194_000 as u64) + Weight::from_ref_time(234_349_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(53_000 as u64).saturating_mul(c as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) + // Storage: System EventTopics (r:3 w:3) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - Weight::from_ref_time(288_487_000 as u64) + Weight::from_ref_time(294_077_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(124_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(110_000 as u64).saturating_mul(c as u64)) // Standard Error: 0 .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(6 as u64)) + .saturating_add(T::DbWeight::get().reads(8 as u64)) + .saturating_add(T::DbWeight::get().writes(9 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) @@ -234,526 +236,560 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) + // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - Weight::from_ref_time(186_136_000 as u64) + Weight::from_ref_time(199_028_000 as u64) // Standard Error: 0 .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(5 as u64)) + .saturating_add(T::DbWeight::get().reads(8 as u64)) + .saturating_add(T::DbWeight::get().writes(7 as u64)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) + // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - Weight::from_ref_time(149_232_000 as u64) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + Weight::from_ref_time(176_247_000 as u64) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) + // Storage: System EventTopics (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - Weight::from_ref_time(51_721_000 as u64) + Weight::from_ref_time(54_917_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(48_000 as u64).saturating_mul(c as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Contracts OwnerInfoOf (r:1 w:1) + // Storage: System EventTopics (r:1 w:1) // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - Weight::from_ref_time(30_016_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + Weight::from_ref_time(37_611_000 as u64) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:2 w:2) + // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - Weight::from_ref_time(27_192_000 as u64) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + Weight::from_ref_time(40_121_000 as u64) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - Weight::from_ref_time(206_405_000 as u64) - // Standard Error: 112_000 - .saturating_add(Weight::from_ref_time(40_987_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(241_129_000 as u64) + // Standard Error: 54_000 + .saturating_add(Weight::from_ref_time(35_413_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - Weight::from_ref_time(106_220_000 as u64) - // Standard Error: 710_000 - .saturating_add(Weight::from_ref_time(307_648_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) + Weight::from_ref_time(189_418_000 as u64) + // Standard Error: 419_000 + .saturating_add(Weight::from_ref_time(207_107_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(104_498_000 as u64) - // Standard Error: 633_000 - .saturating_add(Weight::from_ref_time(368_901_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) + Weight::from_ref_time(203_928_000 as u64) + // Standard Error: 439_000 + .saturating_add(Weight::from_ref_time(268_983_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(208_696_000 as u64) - // Standard Error: 101_000 - .saturating_add(Weight::from_ref_time(44_445_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(243_800_000 as u64) + // Standard Error: 40_000 + .saturating_add(Weight::from_ref_time(38_797_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - Weight::from_ref_time(205_612_000 as u64) - // Standard Error: 68_000 - .saturating_add(Weight::from_ref_time(17_145_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(239_667_000 as u64) + // Standard Error: 27_000 + .saturating_add(Weight::from_ref_time(15_826_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - Weight::from_ref_time(206_947_000 as u64) - // Standard Error: 107_000 - .saturating_add(Weight::from_ref_time(40_789_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(241_116_000 as u64) + // Standard Error: 41_000 + .saturating_add(Weight::from_ref_time(35_402_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - Weight::from_ref_time(208_692_000 as u64) - // Standard Error: 109_000 - .saturating_add(Weight::from_ref_time(40_600_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(240_515_000 as u64) + // Standard Error: 50_000 + .saturating_add(Weight::from_ref_time(35_144_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - Weight::from_ref_time(209_811_000 as u64) - // Standard Error: 208_000 - .saturating_add(Weight::from_ref_time(116_831_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(244_087_000 as u64) + // Standard Error: 87_000 + .saturating_add(Weight::from_ref_time(110_236_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - Weight::from_ref_time(207_406_000 as u64) - // Standard Error: 117_000 - .saturating_add(Weight::from_ref_time(40_702_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(241_774_000 as u64) + // Standard Error: 50_000 + .saturating_add(Weight::from_ref_time(35_216_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - Weight::from_ref_time(209_260_000 as u64) - // Standard Error: 130_000 - .saturating_add(Weight::from_ref_time(40_479_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(241_146_000 as u64) + // Standard Error: 54_000 + .saturating_add(Weight::from_ref_time(35_101_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - Weight::from_ref_time(206_448_000 as u64) - // Standard Error: 95_000 - .saturating_add(Weight::from_ref_time(40_134_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(244_096_000 as u64) + // Standard Error: 55_000 + .saturating_add(Weight::from_ref_time(34_612_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - Weight::from_ref_time(206_969_000 as u64) - // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(40_251_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(242_978_000 as u64) + // Standard Error: 53_000 + .saturating_add(Weight::from_ref_time(34_780_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - Weight::from_ref_time(211_611_000 as u64) - // Standard Error: 175_000 - .saturating_add(Weight::from_ref_time(98_675_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(246_175_000 as u64) + // Standard Error: 86_000 + .saturating_add(Weight::from_ref_time(99_827_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - Weight::from_ref_time(134_484_000 as u64) - // Standard Error: 57_000 - .saturating_add(Weight::from_ref_time(19_329_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(168_655_000 as u64) + // Standard Error: 16_000 + .saturating_add(Weight::from_ref_time(15_635_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - Weight::from_ref_time(208_556_000 as u64) - // Standard Error: 125_000 - .saturating_add(Weight::from_ref_time(40_328_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(239_729_000 as u64) + // Standard Error: 52_000 + .saturating_add(Weight::from_ref_time(33_477_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(268_886_000 as u64) + Weight::from_ref_time(296_718_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(9_627_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(Weight::from_ref_time(9_616_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. - fn seal_return(_r: u32, ) -> Weight { - Weight::from_ref_time(203_591_000 as u64) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + fn seal_return(r: u32, ) -> Weight { + Weight::from_ref_time(237_666_000 as u64) + // Standard Error: 497_000 + .saturating_add(Weight::from_ref_time(2_090_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(204_258_000 as u64) + Weight::from_ref_time(239_842_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(183_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(Weight::from_ref_time(184_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - Weight::from_ref_time(206_625_000 as u64) - // Standard Error: 672_000 - .saturating_add(Weight::from_ref_time(59_377_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((5 as u64).saturating_mul(r as u64))) + Weight::from_ref_time(240_563_000 as u64) + // Standard Error: 519_000 + .saturating_add(Weight::from_ref_time(52_855_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes((6 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - Weight::from_ref_time(208_866_000 as u64) - // Standard Error: 164_000 - .saturating_add(Weight::from_ref_time(133_438_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(248_136_000 as u64) + // Standard Error: 94_000 + .saturating_add(Weight::from_ref_time(137_406_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - Weight::from_ref_time(220_860_000 as u64) - // Standard Error: 209_000 - .saturating_add(Weight::from_ref_time(239_951_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(253_433_000 as u64) + // Standard Error: 105_000 + .saturating_add(Weight::from_ref_time(242_337_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:80 w:80) + // Storage: System EventTopics (r:2 w:2) /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - Weight::from_ref_time(439_782_000 as u64) - // Standard Error: 1_643_000 - .saturating_add(Weight::from_ref_time(264_687_000 as u64).saturating_mul(t as u64)) - // Standard Error: 323_000 - .saturating_add(Weight::from_ref_time(67_636_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) + Weight::from_ref_time(478_106_000 as u64) + // Standard Error: 557_000 + .saturating_add(Weight::from_ref_time(176_325_000 as u64).saturating_mul(t as u64)) + // Standard Error: 153_000 + .saturating_add(Weight::from_ref_time(67_413_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(t as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - Weight::from_ref_time(140_280_000 as u64) - // Standard Error: 82_000 - .saturating_add(Weight::from_ref_time(32_717_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(172_751_000 as u64) + // Standard Error: 37_000 + .saturating_add(Weight::from_ref_time(26_536_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - Weight::from_ref_time(161_247_000 as u64) - // Standard Error: 883_000 - .saturating_add(Weight::from_ref_time(423_997_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) + Weight::from_ref_time(196_276_000 as u64) + // Standard Error: 428_000 + .saturating_add(Weight::from_ref_time(416_783_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - Weight::from_ref_time(529_247_000 as u64) - // Standard Error: 2_745_000 - .saturating_add(Weight::from_ref_time(85_282_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(55 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(53 as u64)) - .saturating_add(T::DbWeight::get().writes((5 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(532_439_000 as u64) + // Standard Error: 1_323_000 + .saturating_add(Weight::from_ref_time(93_843_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(52 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(50 as u64)) + .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - Weight::from_ref_time(529_812_000 as u64) - // Standard Error: 2_513_000 - .saturating_add(Weight::from_ref_time(74_554_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(55 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(53 as u64)) - .saturating_add(T::DbWeight::get().writes((5 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(511_358_000 as u64) + // Standard Error: 1_144_000 + .saturating_add(Weight::from_ref_time(68_754_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(52 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(50 as u64)) + .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - Weight::from_ref_time(184_803_000 as u64) - // Standard Error: 733_000 - .saturating_add(Weight::from_ref_time(404_933_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) + Weight::from_ref_time(204_133_000 as u64) + // Standard Error: 498_000 + .saturating_add(Weight::from_ref_time(406_798_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(500_958_000 as u64) - // Standard Error: 2_980_000 - .saturating_add(Weight::from_ref_time(75_996_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(55 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(52 as u64)) - .saturating_add(T::DbWeight::get().writes((5 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(489_339_000 as u64) + // Standard Error: 1_269_000 + .saturating_add(Weight::from_ref_time(70_700_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(51 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(49 as u64)) + .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - Weight::from_ref_time(177_682_000 as u64) - // Standard Error: 743_000 - .saturating_add(Weight::from_ref_time(338_172_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) + Weight::from_ref_time(211_344_000 as u64) + // Standard Error: 399_000 + .saturating_add(Weight::from_ref_time(330_244_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(465_285_000 as u64) - // Standard Error: 2_599_000 - .saturating_add(Weight::from_ref_time(155_106_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(55 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(449_353_000 as u64) + // Standard Error: 1_027_000 + .saturating_add(Weight::from_ref_time(153_022_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(51 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - Weight::from_ref_time(179_118_000 as u64) - // Standard Error: 572_000 - .saturating_add(Weight::from_ref_time(311_083_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) + Weight::from_ref_time(216_197_000 as u64) + // Standard Error: 341_000 + .saturating_add(Weight::from_ref_time(305_401_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(423_056_000 as u64) - // Standard Error: 2_037_000 - .saturating_add(Weight::from_ref_time(69_665_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(54 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(423_033_000 as u64) + // Standard Error: 878_000 + .saturating_add(Weight::from_ref_time(61_940_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(51 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - Weight::from_ref_time(188_884_000 as u64) - // Standard Error: 761_000 - .saturating_add(Weight::from_ref_time(432_781_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) + Weight::from_ref_time(204_244_000 as u64) + // Standard Error: 448_000 + .saturating_add(Weight::from_ref_time(429_399_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(532_408_000 as u64) - // Standard Error: 3_348_000 - .saturating_add(Weight::from_ref_time(164_943_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(55 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(53 as u64)) - .saturating_add(T::DbWeight::get().writes((5 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(516_945_000 as u64) + // Standard Error: 1_412_000 + .saturating_add(Weight::from_ref_time(162_098_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(52 as u64)) + .saturating_add(T::DbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(T::DbWeight::get().writes(49 as u64)) + .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - Weight::from_ref_time(127_181_000 as u64) - // Standard Error: 1_495_000 - .saturating_add(Weight::from_ref_time(1_500_589_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) + Weight::from_ref_time(170_412_000 as u64) + // Standard Error: 761_000 + .saturating_add(Weight::from_ref_time(1_367_307_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 3_803_000 - .saturating_add(Weight::from_ref_time(14_860_909_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((80 as u64).saturating_mul(r as u64))) + // Standard Error: 9_269_000 + .saturating_add(Weight::from_ref_time(17_505_281_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(7 as u64)) + .saturating_add(T::DbWeight::get().reads((160 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes((160 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 6_045_000 - .saturating_add(Weight::from_ref_time(14_797_140_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads((79 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + // Standard Error: 8_780_000 + .saturating_add(Weight::from_ref_time(17_368_867_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads((158 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes((79 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:81 w:81) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:82 w:82) /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - Weight::from_ref_time(9_196_444_000 as u64) - // Standard Error: 20_486_000 - .saturating_add(Weight::from_ref_time(1_458_153_000 as u64).saturating_mul(t as u64)) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(9_718_000 as u64).saturating_mul(c as u64)) - .saturating_add(T::DbWeight::get().reads(85 as u64)) + Weight::from_ref_time(11_076_579_000 as u64) + // Standard Error: 6_568_000 + .saturating_add(Weight::from_ref_time(1_158_818_000 as u64).saturating_mul(t as u64)) + // Standard Error: 9_000 + .saturating_add(Weight::from_ref_time(9_731_000 as u64).saturating_mul(c as u64)) + .saturating_add(T::DbWeight::get().reads(167 as u64)) .saturating_add(T::DbWeight::get().reads((81 as u64).saturating_mul(t as u64))) - .saturating_add(T::DbWeight::get().writes(81 as u64)) + .saturating_add(T::DbWeight::get().writes(163 as u64)) .saturating_add(T::DbWeight::get().writes((81 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 36_253_000 - .saturating_add(Weight::from_ref_time(21_201_529_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().reads((320 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - .saturating_add(T::DbWeight::get().writes((320 as u64).saturating_mul(r as u64))) + // Standard Error: 24_125_000 + .saturating_add(Weight::from_ref_time(22_830_521_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(8 as u64)) + .saturating_add(T::DbWeight::get().reads((400 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes(5 as u64)) + .saturating_add(T::DbWeight::get().writes((400 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:81 w:81) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -761,457 +797,467 @@ impl WeightInfo for SubstrateWeight { // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) + // Storage: System EventTopics (r:82 w:82) /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - Weight::from_ref_time(12_282_498_000 as u64) - // Standard Error: 48_112_000 - .saturating_add(Weight::from_ref_time(720_795_000 as u64).saturating_mul(t as u64)) - // Standard Error: 22_000 - .saturating_add(Weight::from_ref_time(124_274_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(167 as u64)) + Weight::from_ref_time(13_739_440_000 as u64) + // Standard Error: 79_000 + .saturating_add(Weight::from_ref_time(126_148_000 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(249 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(t as u64))) - .saturating_add(T::DbWeight::get().writes(165 as u64)) + .saturating_add(T::DbWeight::get().writes(247 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - Weight::from_ref_time(203_959_000 as u64) - // Standard Error: 142_000 - .saturating_add(Weight::from_ref_time(61_311_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(241_753_000 as u64) + // Standard Error: 60_000 + .saturating_add(Weight::from_ref_time(55_067_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(349_915_000 as u64) - // Standard Error: 40_000 - .saturating_add(Weight::from_ref_time(320_652_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 95_000 + .saturating_add(Weight::from_ref_time(320_367_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - Weight::from_ref_time(209_219_000 as u64) - // Standard Error: 157_000 - .saturating_add(Weight::from_ref_time(73_728_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(239_849_000 as u64) + // Standard Error: 80_000 + .saturating_add(Weight::from_ref_time(67_626_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(208_860_000 as u64) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(245_718_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 106_000 + .saturating_add(Weight::from_ref_time(247_771_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - Weight::from_ref_time(206_165_000 as u64) - // Standard Error: 138_000 - .saturating_add(Weight::from_ref_time(51_644_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(242_162_000 as u64) + // Standard Error: 58_000 + .saturating_add(Weight::from_ref_time(45_169_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(255_955_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(95_090_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 95_000 + .saturating_add(Weight::from_ref_time(97_479_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - Weight::from_ref_time(208_153_000 as u64) - // Standard Error: 140_000 - .saturating_add(Weight::from_ref_time(51_264_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(240_072_000 as u64) + // Standard Error: 53_000 + .saturating_add(Weight::from_ref_time(44_847_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(278_368_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(95_006_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 95_000 + .saturating_add(Weight::from_ref_time(97_432_000 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - Weight::from_ref_time(331_955_000 as u64) - // Standard Error: 1_155_000 - .saturating_add(Weight::from_ref_time(3_069_955_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(374_614_000 as u64) + // Standard Error: 634_000 + .saturating_add(Weight::from_ref_time(2_968_637_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - Weight::from_ref_time(207_838_000 as u64) - // Standard Error: 783_000 - .saturating_add(Weight::from_ref_time(2_058_503_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(4 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + Weight::from_ref_time(249_022_000 as u64) + // Standard Error: 408_000 + .saturating_add(Weight::from_ref_time(2_062_013_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 1_567_000 - .saturating_add(Weight::from_ref_time(774_380_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads((79 as u64).saturating_mul(r as u64))) - .saturating_add(T::DbWeight::get().writes((79 as u64).saturating_mul(r as u64))) + // Standard Error: 1_536_000 + .saturating_add(Weight::from_ref_time(1_099_219_000 as u64).saturating_mul(r as u64)) + .saturating_add(T::DbWeight::get().reads((158 as u64).saturating_mul(r as u64))) + .saturating_add(T::DbWeight::get().writes((158 as u64).saturating_mul(r as u64))) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - Weight::from_ref_time(73_955_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(612_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_276_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(933_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - Weight::from_ref_time(74_057_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_324_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_309_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(2_977_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - Weight::from_ref_time(74_137_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_427_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_165_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(2_686_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - Weight::from_ref_time(73_844_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_773_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_872_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(2_374_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - Weight::from_ref_time(73_979_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_952_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_891_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(2_629_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - Weight::from_ref_time(73_924_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(941_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_747_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_639_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - Weight::from_ref_time(73_574_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_439_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_262_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(2_142_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - Weight::from_ref_time(73_343_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_603_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(68_808_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(2_342_000 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - Weight::from_ref_time(76_267_000 as u64) + Weight::from_ref_time(73_245_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(e as u64)) + .saturating_add(Weight::from_ref_time(3_000 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - Weight::from_ref_time(74_877_000 as u64) - // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(7_144_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_308_000 as u64) + // Standard Error: 10_000 + .saturating_add(Weight::from_ref_time(7_333_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - Weight::from_ref_time(88_665_000 as u64) - // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(9_142_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(83_967_000 as u64) + // Standard Error: 12_000 + .saturating_add(Weight::from_ref_time(9_205_000 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - Weight::from_ref_time(98_600_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(469_000 as u64).saturating_mul(p as u64)) + Weight::from_ref_time(93_600_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(546_000 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - Weight::from_ref_time(74_555_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(624_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_449_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_052_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - Weight::from_ref_time(74_329_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(688_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_326_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(998_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - Weight::from_ref_time(74_612_000 as u64) + Weight::from_ref_time(70_525_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(909_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_467_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - Weight::from_ref_time(76_906_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_192_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(73_703_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_495_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - Weight::from_ref_time(76_979_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_361_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(73_578_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(1_546_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - Weight::from_ref_time(74_370_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(661_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_379_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(934_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - Weight::from_ref_time(73_584_000 as u64) - // Standard Error: 353_000 - .saturating_add(Weight::from_ref_time(187_114_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_069_000 as u64) + // Standard Error: 114_000 + .saturating_add(Weight::from_ref_time(182_540_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - Weight::from_ref_time(74_206_000 as u64) + Weight::from_ref_time(70_188_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(884_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - Weight::from_ref_time(73_992_000 as u64) + Weight::from_ref_time(69_970_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(893_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_366_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - Weight::from_ref_time(73_985_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(891_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_352_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_356_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - Weight::from_ref_time(74_117_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(901_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_229_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_354_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - Weight::from_ref_time(73_981_000 as u64) + Weight::from_ref_time(70_202_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(866_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_355_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - Weight::from_ref_time(74_104_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(868_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_065_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - Weight::from_ref_time(74_293_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(878_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_252_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_356_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - Weight::from_ref_time(74_055_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_350_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_049_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_823_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - Weight::from_ref_time(73_710_000 as u64) + Weight::from_ref_time(70_519_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_815_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - Weight::from_ref_time(73_917_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_355_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_953_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_834_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - Weight::from_ref_time(74_048_000 as u64) + Weight::from_ref_time(70_299_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_818_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - Weight::from_ref_time(74_029_000 as u64) + Weight::from_ref_time(70_141_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_349_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_825_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - Weight::from_ref_time(74_267_000 as u64) + Weight::from_ref_time(70_209_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_353_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_827_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - Weight::from_ref_time(73_952_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_350_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_980_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_831_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - Weight::from_ref_time(73_851_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_368_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_022_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_829_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - Weight::from_ref_time(74_034_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_348_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_030_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_826_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - Weight::from_ref_time(73_979_000 as u64) + Weight::from_ref_time(70_170_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_353_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_833_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - Weight::from_ref_time(74_000_000 as u64) + Weight::from_ref_time(69_895_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_328_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_826_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - Weight::from_ref_time(73_883_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_331_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_932_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_830_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - Weight::from_ref_time(74_216_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_324_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_091_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_825_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - Weight::from_ref_time(73_989_000 as u64) + Weight::from_ref_time(70_025_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_998_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(2_556_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - Weight::from_ref_time(73_857_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_073_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_910_000 as u64) + // Standard Error: 19_000 + .saturating_add(Weight::from_ref_time(2_290_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - Weight::from_ref_time(73_801_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_027_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_268_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(2_550_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - Weight::from_ref_time(74_130_000 as u64) + Weight::from_ref_time(70_126_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_064_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(2_340_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - Weight::from_ref_time(74_071_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_327_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_381_000 as u64) + // Standard Error: 9_000 + .saturating_add(Weight::from_ref_time(1_844_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - Weight::from_ref_time(74_201_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_330_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_095_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_844_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - Weight::from_ref_time(74_241_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_321_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_471_000 as u64) + // Standard Error: 8_000 + .saturating_add(Weight::from_ref_time(1_836_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - Weight::from_ref_time(74_331_000 as u64) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(1_347_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_302_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_841_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - Weight::from_ref_time(73_674_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_359_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_097_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_850_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - Weight::from_ref_time(73_807_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_166_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_845_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - Weight::from_ref_time(73_725_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_630_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_879_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - Weight::from_ref_time(73_755_000 as u64) + Weight::from_ref_time(70_101_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_861_000 as u64).saturating_mul(r as u64)) } } @@ -1219,25 +1265,25 @@ impl WeightInfo for SubstrateWeight { impl WeightInfo for () { // Storage: Contracts DeletionQueue (r:1 w:0) fn on_process_deletion_queue_batch() -> Weight { - Weight::from_ref_time(1_654_000 as u64) + Weight::from_ref_time(3_089_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `k` is `[0, 1024]`. fn on_initialize_per_trie_key(k: u32, ) -> Weight { - Weight::from_ref_time(8_564_000 as u64) + Weight::from_ref_time(13_917_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(868_000 as u64).saturating_mul(k as u64)) + .saturating_add(Weight::from_ref_time(901_000 as u64).saturating_mul(k as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(k as u64))) } // Storage: Contracts DeletionQueue (r:1 w:0) - /// The range of component `q` is `[0, 1024]`. + /// The range of component `q` is `[0, 128]`. fn on_initialize_per_queue_item(q: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_944_000 as u64).saturating_mul(q as u64)) + Weight::from_ref_time(14_172_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_301_000 as u64).saturating_mul(q as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -1245,9 +1291,9 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn reinstrument(c: u32, ) -> Weight { - Weight::from_ref_time(19_016_000 as u64) + Weight::from_ref_time(21_644_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(49_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(45_000 as u64).saturating_mul(c as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -1255,31 +1301,33 @@ impl WeightInfo for () { // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) + // Storage: System EventTopics (r:2 w:2) /// The range of component `c` is `[0, 131072]`. fn call_with_code_per_byte(c: u32, ) -> Weight { - Weight::from_ref_time(205_194_000 as u64) + Weight::from_ref_time(234_349_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(53_000 as u64).saturating_mul(c as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) + // Storage: System EventTopics (r:3 w:3) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. /// The range of component `s` is `[0, 1048576]`. fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - Weight::from_ref_time(288_487_000 as u64) + Weight::from_ref_time(294_077_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(124_000 as u64).saturating_mul(c as u64)) + .saturating_add(Weight::from_ref_time(110_000 as u64).saturating_mul(c as u64)) // Standard Error: 0 .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) + .saturating_add(RocksDbWeight::get().reads(8 as u64)) + .saturating_add(RocksDbWeight::get().writes(9 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) // Storage: Contracts Nonce (r:1 w:1) @@ -1287,526 +1335,560 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) + // Storage: System EventTopics (r:2 w:2) /// The range of component `s` is `[0, 1048576]`. fn instantiate(s: u32, ) -> Weight { - Weight::from_ref_time(186_136_000 as u64) + Weight::from_ref_time(199_028_000 as u64) // Standard Error: 0 .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(5 as u64)) + .saturating_add(RocksDbWeight::get().reads(8 as u64)) + .saturating_add(RocksDbWeight::get().writes(7 as u64)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) // Storage: System Account (r:1 w:1) + // Storage: System EventTopics (r:2 w:2) fn call() -> Weight { - Weight::from_ref_time(149_232_000 as u64) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + Weight::from_ref_time(176_247_000 as u64) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Contracts CodeStorage (r:1 w:1) + // Storage: System EventTopics (r:1 w:1) // Storage: Contracts PristineCode (r:0 w:1) // Storage: Contracts OwnerInfoOf (r:0 w:1) /// The range of component `c` is `[0, 64226]`. fn upload_code(c: u32, ) -> Weight { - Weight::from_ref_time(51_721_000 as u64) + Weight::from_ref_time(54_917_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(48_000 as u64).saturating_mul(c as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(Weight::from_ref_time(46_000 as u64).saturating_mul(c as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Contracts OwnerInfoOf (r:1 w:1) + // Storage: System EventTopics (r:1 w:1) // Storage: Contracts CodeStorage (r:0 w:1) // Storage: Contracts PristineCode (r:0 w:1) fn remove_code() -> Weight { - Weight::from_ref_time(30_016_000 as u64) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + Weight::from_ref_time(37_611_000 as u64) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:2 w:2) + // Storage: System EventTopics (r:3 w:3) fn set_code() -> Weight { - Weight::from_ref_time(27_192_000 as u64) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + Weight::from_ref_time(40_121_000 as u64) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller(r: u32, ) -> Weight { - Weight::from_ref_time(206_405_000 as u64) - // Standard Error: 112_000 - .saturating_add(Weight::from_ref_time(40_987_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(241_129_000 as u64) + // Standard Error: 54_000 + .saturating_add(Weight::from_ref_time(35_413_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_is_contract(r: u32, ) -> Weight { - Weight::from_ref_time(106_220_000 as u64) - // Standard Error: 710_000 - .saturating_add(Weight::from_ref_time(307_648_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) + Weight::from_ref_time(189_418_000 as u64) + // Standard Error: 419_000 + .saturating_add(Weight::from_ref_time(207_107_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(104_498_000 as u64) - // Standard Error: 633_000 - .saturating_add(Weight::from_ref_time(368_901_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) + Weight::from_ref_time(203_928_000 as u64) + // Standard Error: 439_000 + .saturating_add(Weight::from_ref_time(268_983_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_own_code_hash(r: u32, ) -> Weight { - Weight::from_ref_time(208_696_000 as u64) - // Standard Error: 101_000 - .saturating_add(Weight::from_ref_time(44_445_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(243_800_000 as u64) + // Standard Error: 40_000 + .saturating_add(Weight::from_ref_time(38_797_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_caller_is_origin(r: u32, ) -> Weight { - Weight::from_ref_time(205_612_000 as u64) - // Standard Error: 68_000 - .saturating_add(Weight::from_ref_time(17_145_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(239_667_000 as u64) + // Standard Error: 27_000 + .saturating_add(Weight::from_ref_time(15_826_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_address(r: u32, ) -> Weight { - Weight::from_ref_time(206_947_000 as u64) - // Standard Error: 107_000 - .saturating_add(Weight::from_ref_time(40_789_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(241_116_000 as u64) + // Standard Error: 41_000 + .saturating_add(Weight::from_ref_time(35_402_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas_left(r: u32, ) -> Weight { - Weight::from_ref_time(208_692_000 as u64) - // Standard Error: 109_000 - .saturating_add(Weight::from_ref_time(40_600_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(240_515_000 as u64) + // Standard Error: 50_000 + .saturating_add(Weight::from_ref_time(35_144_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_balance(r: u32, ) -> Weight { - Weight::from_ref_time(209_811_000 as u64) - // Standard Error: 208_000 - .saturating_add(Weight::from_ref_time(116_831_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(244_087_000 as u64) + // Standard Error: 87_000 + .saturating_add(Weight::from_ref_time(110_236_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_value_transferred(r: u32, ) -> Weight { - Weight::from_ref_time(207_406_000 as u64) - // Standard Error: 117_000 - .saturating_add(Weight::from_ref_time(40_702_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(241_774_000 as u64) + // Standard Error: 50_000 + .saturating_add(Weight::from_ref_time(35_216_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_minimum_balance(r: u32, ) -> Weight { - Weight::from_ref_time(209_260_000 as u64) - // Standard Error: 130_000 - .saturating_add(Weight::from_ref_time(40_479_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(241_146_000 as u64) + // Standard Error: 54_000 + .saturating_add(Weight::from_ref_time(35_101_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_block_number(r: u32, ) -> Weight { - Weight::from_ref_time(206_448_000 as u64) - // Standard Error: 95_000 - .saturating_add(Weight::from_ref_time(40_134_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(244_096_000 as u64) + // Standard Error: 55_000 + .saturating_add(Weight::from_ref_time(34_612_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_now(r: u32, ) -> Weight { - Weight::from_ref_time(206_969_000 as u64) - // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(40_251_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(242_978_000 as u64) + // Standard Error: 53_000 + .saturating_add(Weight::from_ref_time(34_780_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: TransactionPayment NextFeeMultiplier (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_weight_to_fee(r: u32, ) -> Weight { - Weight::from_ref_time(211_611_000 as u64) - // Standard Error: 175_000 - .saturating_add(Weight::from_ref_time(98_675_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(246_175_000 as u64) + // Standard Error: 86_000 + .saturating_add(Weight::from_ref_time(99_827_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_gas(r: u32, ) -> Weight { - Weight::from_ref_time(134_484_000 as u64) - // Standard Error: 57_000 - .saturating_add(Weight::from_ref_time(19_329_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(168_655_000 as u64) + // Standard Error: 16_000 + .saturating_add(Weight::from_ref_time(15_635_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_input(r: u32, ) -> Weight { - Weight::from_ref_time(208_556_000 as u64) - // Standard Error: 125_000 - .saturating_add(Weight::from_ref_time(40_328_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(239_729_000 as u64) + // Standard Error: 52_000 + .saturating_add(Weight::from_ref_time(33_477_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_input_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(268_886_000 as u64) + Weight::from_ref_time(296_718_000 as u64) // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(9_627_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(Weight::from_ref_time(9_616_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 1]`. - fn seal_return(_r: u32, ) -> Weight { - Weight::from_ref_time(203_591_000 as u64) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + fn seal_return(r: u32, ) -> Weight { + Weight::from_ref_time(237_666_000 as u64) + // Standard Error: 497_000 + .saturating_add(Weight::from_ref_time(2_090_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_return_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(204_258_000 as u64) + Weight::from_ref_time(239_842_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(183_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(Weight::from_ref_time(184_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: Contracts DeletionQueue (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) /// The range of component `r` is `[0, 1]`. fn seal_terminate(r: u32, ) -> Weight { - Weight::from_ref_time(206_625_000 as u64) - // Standard Error: 672_000 - .saturating_add(Weight::from_ref_time(59_377_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((5 as u64).saturating_mul(r as u64))) + Weight::from_ref_time(240_563_000 as u64) + // Standard Error: 519_000 + .saturating_add(Weight::from_ref_time(52_855_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes((6 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: RandomnessCollectiveFlip RandomMaterial (r:1 w:0) /// The range of component `r` is `[0, 20]`. fn seal_random(r: u32, ) -> Weight { - Weight::from_ref_time(208_866_000 as u64) - // Standard Error: 164_000 - .saturating_add(Weight::from_ref_time(133_438_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(248_136_000 as u64) + // Standard Error: 94_000 + .saturating_add(Weight::from_ref_time(137_406_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_deposit_event(r: u32, ) -> Weight { - Weight::from_ref_time(220_860_000 as u64) - // Standard Error: 209_000 - .saturating_add(Weight::from_ref_time(239_951_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(253_433_000 as u64) + // Standard Error: 105_000 + .saturating_add(Weight::from_ref_time(242_337_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) - // Storage: System EventTopics (r:80 w:80) + // Storage: System EventTopics (r:2 w:2) /// The range of component `t` is `[0, 4]`. /// The range of component `n` is `[0, 16]`. fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - Weight::from_ref_time(439_782_000 as u64) - // Standard Error: 1_643_000 - .saturating_add(Weight::from_ref_time(264_687_000 as u64).saturating_mul(t as u64)) - // Standard Error: 323_000 - .saturating_add(Weight::from_ref_time(67_636_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) + Weight::from_ref_time(478_106_000 as u64) + // Standard Error: 557_000 + .saturating_add(Weight::from_ref_time(176_325_000 as u64).saturating_mul(t as u64)) + // Standard Error: 153_000 + .saturating_add(Weight::from_ref_time(67_413_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(t as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_debug_message(r: u32, ) -> Weight { - Weight::from_ref_time(140_280_000 as u64) - // Standard Error: 82_000 - .saturating_add(Weight::from_ref_time(32_717_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(172_751_000 as u64) + // Standard Error: 37_000 + .saturating_add(Weight::from_ref_time(26_536_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_set_storage(r: u32, ) -> Weight { - Weight::from_ref_time(161_247_000 as u64) - // Standard Error: 883_000 - .saturating_add(Weight::from_ref_time(423_997_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) + Weight::from_ref_time(196_276_000 as u64) + // Standard Error: 428_000 + .saturating_add(Weight::from_ref_time(416_783_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_new_kb(n: u32, ) -> Weight { - Weight::from_ref_time(529_247_000 as u64) - // Standard Error: 2_745_000 - .saturating_add(Weight::from_ref_time(85_282_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(55 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(53 as u64)) - .saturating_add(RocksDbWeight::get().writes((5 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(532_439_000 as u64) + // Standard Error: 1_323_000 + .saturating_add(Weight::from_ref_time(93_843_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(52 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(50 as u64)) + .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_set_storage_per_old_kb(n: u32, ) -> Weight { - Weight::from_ref_time(529_812_000 as u64) - // Standard Error: 2_513_000 - .saturating_add(Weight::from_ref_time(74_554_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(55 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(53 as u64)) - .saturating_add(RocksDbWeight::get().writes((5 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(511_358_000 as u64) + // Standard Error: 1_144_000 + .saturating_add(Weight::from_ref_time(68_754_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(52 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(50 as u64)) + .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_clear_storage(r: u32, ) -> Weight { - Weight::from_ref_time(184_803_000 as u64) - // Standard Error: 733_000 - .saturating_add(Weight::from_ref_time(404_933_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) + Weight::from_ref_time(204_133_000 as u64) + // Standard Error: 498_000 + .saturating_add(Weight::from_ref_time(406_798_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_clear_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(500_958_000 as u64) - // Standard Error: 2_980_000 - .saturating_add(Weight::from_ref_time(75_996_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(55 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(52 as u64)) - .saturating_add(RocksDbWeight::get().writes((5 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(489_339_000 as u64) + // Standard Error: 1_269_000 + .saturating_add(Weight::from_ref_time(70_700_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(51 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(49 as u64)) + .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_get_storage(r: u32, ) -> Weight { - Weight::from_ref_time(177_682_000 as u64) - // Standard Error: 743_000 - .saturating_add(Weight::from_ref_time(338_172_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) + Weight::from_ref_time(211_344_000 as u64) + // Standard Error: 399_000 + .saturating_add(Weight::from_ref_time(330_244_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_get_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(465_285_000 as u64) - // Standard Error: 2_599_000 - .saturating_add(Weight::from_ref_time(155_106_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(55 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(449_353_000 as u64) + // Standard Error: 1_027_000 + .saturating_add(Weight::from_ref_time(153_022_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(51 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_contains_storage(r: u32, ) -> Weight { - Weight::from_ref_time(179_118_000 as u64) - // Standard Error: 572_000 - .saturating_add(Weight::from_ref_time(311_083_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) + Weight::from_ref_time(216_197_000 as u64) + // Standard Error: 341_000 + .saturating_add(Weight::from_ref_time(305_401_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_contains_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(423_056_000 as u64) - // Standard Error: 2_037_000 - .saturating_add(Weight::from_ref_time(69_665_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(54 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(423_033_000 as u64) + // Standard Error: 878_000 + .saturating_add(Weight::from_ref_time(61_940_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(51 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `r` is `[0, 10]`. fn seal_take_storage(r: u32, ) -> Weight { - Weight::from_ref_time(188_884_000 as u64) - // Standard Error: 761_000 - .saturating_add(Weight::from_ref_time(432_781_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) + Weight::from_ref_time(204_244_000 as u64) + // Standard Error: 448_000 + .saturating_add(Weight::from_ref_time(429_399_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: Skipped Metadata (r:0 w:0) /// The range of component `n` is `[0, 8]`. fn seal_take_storage_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(532_408_000 as u64) - // Standard Error: 3_348_000 - .saturating_add(Weight::from_ref_time(164_943_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(55 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(53 as u64)) - .saturating_add(RocksDbWeight::get().writes((5 as u64).saturating_mul(n as u64))) + Weight::from_ref_time(516_945_000 as u64) + // Standard Error: 1_412_000 + .saturating_add(Weight::from_ref_time(162_098_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(52 as u64)) + .saturating_add(RocksDbWeight::get().reads((7 as u64).saturating_mul(n as u64))) + .saturating_add(RocksDbWeight::get().writes(49 as u64)) + .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(n as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_transfer(r: u32, ) -> Weight { - Weight::from_ref_time(127_181_000 as u64) - // Standard Error: 1_495_000 - .saturating_add(Weight::from_ref_time(1_500_589_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) + Weight::from_ref_time(170_412_000 as u64) + // Standard Error: 761_000 + .saturating_add(Weight::from_ref_time(1_367_307_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 3_803_000 - .saturating_add(Weight::from_ref_time(14_860_909_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) - .saturating_add(RocksDbWeight::get().reads((80 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((80 as u64).saturating_mul(r as u64))) + // Standard Error: 9_269_000 + .saturating_add(Weight::from_ref_time(17_505_281_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(7 as u64)) + .saturating_add(RocksDbWeight::get().reads((160 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes((160 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_delegate_call(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 6_045_000 - .saturating_add(Weight::from_ref_time(14_797_140_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads((79 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + // Standard Error: 8_780_000 + .saturating_add(Weight::from_ref_time(17_368_867_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads((158 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes((79 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:81 w:81) // Storage: Contracts CodeStorage (r:2 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:82 w:82) /// The range of component `t` is `[0, 1]`. /// The range of component `c` is `[0, 1024]`. fn seal_call_per_transfer_clone_kb(t: u32, c: u32, ) -> Weight { - Weight::from_ref_time(9_196_444_000 as u64) - // Standard Error: 20_486_000 - .saturating_add(Weight::from_ref_time(1_458_153_000 as u64).saturating_mul(t as u64)) - // Standard Error: 8_000 - .saturating_add(Weight::from_ref_time(9_718_000 as u64).saturating_mul(c as u64)) - .saturating_add(RocksDbWeight::get().reads(85 as u64)) + Weight::from_ref_time(11_076_579_000 as u64) + // Standard Error: 6_568_000 + .saturating_add(Weight::from_ref_time(1_158_818_000 as u64).saturating_mul(t as u64)) + // Standard Error: 9_000 + .saturating_add(Weight::from_ref_time(9_731_000 as u64).saturating_mul(c as u64)) + .saturating_add(RocksDbWeight::get().reads(167 as u64)) .saturating_add(RocksDbWeight::get().reads((81 as u64).saturating_mul(t as u64))) - .saturating_add(RocksDbWeight::get().writes(81 as u64)) + .saturating_add(RocksDbWeight::get().writes(163 as u64)) .saturating_add(RocksDbWeight::get().writes((81 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:80 w:80) /// The range of component `r` is `[0, 20]`. fn seal_instantiate(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 36_253_000 - .saturating_add(Weight::from_ref_time(21_201_529_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().reads((320 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - .saturating_add(RocksDbWeight::get().writes((320 as u64).saturating_mul(r as u64))) + // Standard Error: 24_125_000 + .saturating_add(Weight::from_ref_time(22_830_521_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(8 as u64)) + .saturating_add(RocksDbWeight::get().reads((400 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes(5 as u64)) + .saturating_add(RocksDbWeight::get().writes((400 as u64).saturating_mul(r as u64))) } // Storage: System Account (r:81 w:81) // Storage: Contracts ContractInfoOf (r:81 w:81) @@ -1814,456 +1896,466 @@ impl WeightInfo for () { // Storage: Timestamp Now (r:1 w:0) // Storage: Contracts Nonce (r:1 w:1) // Storage: Contracts OwnerInfoOf (r:1 w:1) + // Storage: System EventTopics (r:82 w:82) /// The range of component `t` is `[0, 1]`. /// The range of component `s` is `[0, 960]`. fn seal_instantiate_per_transfer_salt_kb(t: u32, s: u32, ) -> Weight { - Weight::from_ref_time(12_282_498_000 as u64) - // Standard Error: 48_112_000 - .saturating_add(Weight::from_ref_time(720_795_000 as u64).saturating_mul(t as u64)) - // Standard Error: 22_000 - .saturating_add(Weight::from_ref_time(124_274_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(167 as u64)) + Weight::from_ref_time(13_739_440_000 as u64) + // Standard Error: 79_000 + .saturating_add(Weight::from_ref_time(126_148_000 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(249 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(t as u64))) - .saturating_add(RocksDbWeight::get().writes(165 as u64)) + .saturating_add(RocksDbWeight::get().writes(247 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(t as u64))) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_sha2_256(r: u32, ) -> Weight { - Weight::from_ref_time(203_959_000 as u64) - // Standard Error: 142_000 - .saturating_add(Weight::from_ref_time(61_311_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(241_753_000 as u64) + // Standard Error: 60_000 + .saturating_add(Weight::from_ref_time(55_067_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(349_915_000 as u64) - // Standard Error: 40_000 - .saturating_add(Weight::from_ref_time(320_652_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 95_000 + .saturating_add(Weight::from_ref_time(320_367_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_keccak_256(r: u32, ) -> Weight { - Weight::from_ref_time(209_219_000 as u64) - // Standard Error: 157_000 - .saturating_add(Weight::from_ref_time(73_728_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(239_849_000 as u64) + // Standard Error: 80_000 + .saturating_add(Weight::from_ref_time(67_626_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(208_860_000 as u64) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(245_718_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 106_000 + .saturating_add(Weight::from_ref_time(247_771_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_256(r: u32, ) -> Weight { - Weight::from_ref_time(206_165_000 as u64) - // Standard Error: 138_000 - .saturating_add(Weight::from_ref_time(51_644_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(242_162_000 as u64) + // Standard Error: 58_000 + .saturating_add(Weight::from_ref_time(45_169_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(255_955_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(95_090_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 95_000 + .saturating_add(Weight::from_ref_time(97_479_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_hash_blake2_128(r: u32, ) -> Weight { - Weight::from_ref_time(208_153_000 as u64) - // Standard Error: 140_000 - .saturating_add(Weight::from_ref_time(51_264_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(240_072_000 as u64) + // Standard Error: 53_000 + .saturating_add(Weight::from_ref_time(44_847_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `n` is `[0, 1024]`. fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - Weight::from_ref_time(278_368_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(95_006_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 95_000 + .saturating_add(Weight::from_ref_time(97_432_000 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_recover(r: u32, ) -> Weight { - Weight::from_ref_time(331_955_000 as u64) - // Standard Error: 1_155_000 - .saturating_add(Weight::from_ref_time(3_069_955_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(374_614_000 as u64) + // Standard Error: 634_000 + .saturating_add(Weight::from_ref_time(2_968_637_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) /// The range of component `r` is `[0, 20]`. fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight { - Weight::from_ref_time(207_838_000 as u64) - // Standard Error: 783_000 - .saturating_add(Weight::from_ref_time(2_058_503_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(4 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + Weight::from_ref_time(249_022_000 as u64) + // Standard Error: 408_000 + .saturating_add(Weight::from_ref_time(2_062_013_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: System Account (r:1 w:0) // Storage: Contracts ContractInfoOf (r:1 w:1) // Storage: Contracts CodeStorage (r:1 w:0) // Storage: Timestamp Now (r:1 w:0) + // Storage: System EventTopics (r:2 w:2) // Storage: Contracts OwnerInfoOf (r:16 w:16) /// The range of component `r` is `[0, 20]`. fn seal_set_code_hash(r: u32, ) -> Weight { Weight::from_ref_time(0 as u64) - // Standard Error: 1_567_000 - .saturating_add(Weight::from_ref_time(774_380_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads((79 as u64).saturating_mul(r as u64))) - .saturating_add(RocksDbWeight::get().writes((79 as u64).saturating_mul(r as u64))) + // Standard Error: 1_536_000 + .saturating_add(Weight::from_ref_time(1_099_219_000 as u64).saturating_mul(r as u64)) + .saturating_add(RocksDbWeight::get().reads((158 as u64).saturating_mul(r as u64))) + .saturating_add(RocksDbWeight::get().writes((158 as u64).saturating_mul(r as u64))) } /// The range of component `r` is `[0, 50]`. fn instr_i64const(r: u32, ) -> Weight { - Weight::from_ref_time(73_955_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(612_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_276_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(933_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64load(r: u32, ) -> Weight { - Weight::from_ref_time(74_057_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_324_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_309_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(2_977_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64store(r: u32, ) -> Weight { - Weight::from_ref_time(74_137_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_427_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_165_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(2_686_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_select(r: u32, ) -> Weight { - Weight::from_ref_time(73_844_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_773_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_872_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(2_374_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_if(r: u32, ) -> Weight { - Weight::from_ref_time(73_979_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_952_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_891_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(2_629_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br(r: u32, ) -> Weight { - Weight::from_ref_time(73_924_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(941_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_747_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_639_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_if(r: u32, ) -> Weight { - Weight::from_ref_time(73_574_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_439_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_262_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(2_142_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_br_table(r: u32, ) -> Weight { - Weight::from_ref_time(73_343_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_603_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(68_808_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(2_342_000 as u64).saturating_mul(r as u64)) } /// The range of component `e` is `[1, 256]`. fn instr_br_table_per_entry(e: u32, ) -> Weight { - Weight::from_ref_time(76_267_000 as u64) + Weight::from_ref_time(73_245_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(e as u64)) + .saturating_add(Weight::from_ref_time(3_000 as u64).saturating_mul(e as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call(r: u32, ) -> Weight { - Weight::from_ref_time(74_877_000 as u64) - // Standard Error: 12_000 - .saturating_add(Weight::from_ref_time(7_144_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_308_000 as u64) + // Standard Error: 10_000 + .saturating_add(Weight::from_ref_time(7_333_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_call_indirect(r: u32, ) -> Weight { - Weight::from_ref_time(88_665_000 as u64) - // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(9_142_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(83_967_000 as u64) + // Standard Error: 12_000 + .saturating_add(Weight::from_ref_time(9_205_000 as u64).saturating_mul(r as u64)) } /// The range of component `p` is `[0, 128]`. fn instr_call_indirect_per_param(p: u32, ) -> Weight { - Weight::from_ref_time(98_600_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(469_000 as u64).saturating_mul(p as u64)) + Weight::from_ref_time(93_600_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(546_000 as u64).saturating_mul(p as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_get(r: u32, ) -> Weight { - Weight::from_ref_time(74_555_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(624_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_449_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_052_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_set(r: u32, ) -> Weight { - Weight::from_ref_time(74_329_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(688_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_326_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(998_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_local_tee(r: u32, ) -> Weight { - Weight::from_ref_time(74_612_000 as u64) + Weight::from_ref_time(70_525_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(909_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_467_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_get(r: u32, ) -> Weight { - Weight::from_ref_time(76_906_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_192_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(73_703_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_495_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_global_set(r: u32, ) -> Weight { - Weight::from_ref_time(76_979_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_361_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(73_578_000 as u64) + // Standard Error: 5_000 + .saturating_add(Weight::from_ref_time(1_546_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_memory_current(r: u32, ) -> Weight { - Weight::from_ref_time(74_370_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(661_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_379_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(934_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 1]`. fn instr_memory_grow(r: u32, ) -> Weight { - Weight::from_ref_time(73_584_000 as u64) - // Standard Error: 353_000 - .saturating_add(Weight::from_ref_time(187_114_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_069_000 as u64) + // Standard Error: 114_000 + .saturating_add(Weight::from_ref_time(182_540_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64clz(r: u32, ) -> Weight { - Weight::from_ref_time(74_206_000 as u64) + Weight::from_ref_time(70_188_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(884_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ctz(r: u32, ) -> Weight { - Weight::from_ref_time(73_992_000 as u64) + Weight::from_ref_time(69_970_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(893_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_366_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64popcnt(r: u32, ) -> Weight { - Weight::from_ref_time(73_985_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(891_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_352_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_356_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eqz(r: u32, ) -> Weight { - Weight::from_ref_time(74_117_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(901_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_229_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_354_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendsi32(r: u32, ) -> Weight { - Weight::from_ref_time(73_981_000 as u64) + Weight::from_ref_time(70_202_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(866_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_355_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64extendui32(r: u32, ) -> Weight { - Weight::from_ref_time(74_104_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(868_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_065_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i32wrapi64(r: u32, ) -> Weight { - Weight::from_ref_time(74_293_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(878_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_252_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_356_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64eq(r: u32, ) -> Weight { - Weight::from_ref_time(74_055_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_350_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_049_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_823_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ne(r: u32, ) -> Weight { - Weight::from_ref_time(73_710_000 as u64) + Weight::from_ref_time(70_519_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_815_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64lts(r: u32, ) -> Weight { - Weight::from_ref_time(73_917_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_355_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_953_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_834_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ltu(r: u32, ) -> Weight { - Weight::from_ref_time(74_048_000 as u64) + Weight::from_ref_time(70_299_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_818_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gts(r: u32, ) -> Weight { - Weight::from_ref_time(74_029_000 as u64) + Weight::from_ref_time(70_141_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_349_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_825_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64gtu(r: u32, ) -> Weight { - Weight::from_ref_time(74_267_000 as u64) + Weight::from_ref_time(70_209_000 as u64) // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_353_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_827_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64les(r: u32, ) -> Weight { - Weight::from_ref_time(73_952_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_350_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_980_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_831_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64leu(r: u32, ) -> Weight { - Weight::from_ref_time(73_851_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_368_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_022_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_829_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64ges(r: u32, ) -> Weight { - Weight::from_ref_time(74_034_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_348_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_030_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_826_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64geu(r: u32, ) -> Weight { - Weight::from_ref_time(73_979_000 as u64) + Weight::from_ref_time(70_170_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_353_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_833_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64add(r: u32, ) -> Weight { - Weight::from_ref_time(74_000_000 as u64) + Weight::from_ref_time(69_895_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_328_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_826_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64sub(r: u32, ) -> Weight { - Weight::from_ref_time(73_883_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_331_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_932_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_830_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64mul(r: u32, ) -> Weight { - Weight::from_ref_time(74_216_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(1_324_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_091_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_825_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divs(r: u32, ) -> Weight { - Weight::from_ref_time(73_989_000 as u64) + Weight::from_ref_time(70_025_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_998_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(2_556_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64divu(r: u32, ) -> Weight { - Weight::from_ref_time(73_857_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_073_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(71_910_000 as u64) + // Standard Error: 19_000 + .saturating_add(Weight::from_ref_time(2_290_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rems(r: u32, ) -> Weight { - Weight::from_ref_time(73_801_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_027_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_268_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(2_550_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64remu(r: u32, ) -> Weight { - Weight::from_ref_time(74_130_000 as u64) + Weight::from_ref_time(70_126_000 as u64) // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(2_064_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(2_340_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64and(r: u32, ) -> Weight { - Weight::from_ref_time(74_071_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_327_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_381_000 as u64) + // Standard Error: 9_000 + .saturating_add(Weight::from_ref_time(1_844_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64or(r: u32, ) -> Weight { - Weight::from_ref_time(74_201_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(1_330_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_095_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_844_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64xor(r: u32, ) -> Weight { - Weight::from_ref_time(74_241_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_321_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_471_000 as u64) + // Standard Error: 8_000 + .saturating_add(Weight::from_ref_time(1_836_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shl(r: u32, ) -> Weight { - Weight::from_ref_time(74_331_000 as u64) - // Standard Error: 6_000 - .saturating_add(Weight::from_ref_time(1_347_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_302_000 as u64) + // Standard Error: 2_000 + .saturating_add(Weight::from_ref_time(1_841_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shrs(r: u32, ) -> Weight { - Weight::from_ref_time(73_674_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_359_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_097_000 as u64) + // Standard Error: 3_000 + .saturating_add(Weight::from_ref_time(1_850_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64shru(r: u32, ) -> Weight { - Weight::from_ref_time(73_807_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(70_166_000 as u64) + // Standard Error: 1_000 + .saturating_add(Weight::from_ref_time(1_845_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotl(r: u32, ) -> Weight { - Weight::from_ref_time(73_725_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_358_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(69_630_000 as u64) + // Standard Error: 4_000 + .saturating_add(Weight::from_ref_time(1_879_000 as u64).saturating_mul(r as u64)) } /// The range of component `r` is `[0, 50]`. fn instr_i64rotr(r: u32, ) -> Weight { - Weight::from_ref_time(73_755_000 as u64) + Weight::from_ref_time(70_101_000 as u64) // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(1_360_000 as u64).saturating_mul(r as u64)) + .saturating_add(Weight::from_ref_time(1_861_000 as u64).saturating_mul(r as u64)) } } diff --git a/frame/conviction-voting/Cargo.toml b/frame/conviction-voting/Cargo.toml index ab6d04d199bc6..3c40017ece8e7 100644 --- a/frame/conviction-voting/Cargo.toml +++ b/frame/conviction-voting/Cargo.toml @@ -36,7 +36,7 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "scale-info/std", @@ -46,7 +46,8 @@ std = [ "sp-std/std", ] runtime-benchmarks = [ - "frame-benchmarking", + "frame-support/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/frame/conviction-voting/src/lib.rs b/frame/conviction-voting/src/lib.rs index cd16fccd6661d..b876a9354ee59 100644 --- a/frame/conviction-voting/src/lib.rs +++ b/frame/conviction-voting/src/lib.rs @@ -98,7 +98,8 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + Sized { // System level stuff. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; /// Currency type with which voting happens. @@ -399,7 +400,7 @@ impl, I: 'static> Pallet { Err(i) => { votes .try_insert(i, (poll_index, vote)) - .map_err(|()| Error::::MaxVotesReached)?; + .map_err(|_| Error::::MaxVotesReached)?; }, } // Shouldn't be possible to fail, but we handle it gracefully. diff --git a/frame/conviction-voting/src/tests.rs b/frame/conviction-voting/src/tests.rs index cbd2b0619ac2b..7a3f80442014a 100644 --- a/frame/conviction-voting/src/tests.rs +++ b/frame/conviction-voting/src/tests.rs @@ -50,9 +50,9 @@ frame_support::construct_runtime!( // Test that a fitlered call can be dispatched. pub struct BaseFilter; -impl Contains for BaseFilter { - fn contains(call: &Call) -> bool { - !matches!(call, &Call::Balances(pallet_balances::Call::set_balance { .. })) +impl Contains for BaseFilter { + fn contains(call: &RuntimeCall) -> bool { + !matches!(call, &RuntimeCall::Balances(pallet_balances::Call::set_balance { .. })) } } @@ -65,16 +65,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -92,7 +92,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type MaxLocks = ConstU32<10>; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -187,7 +187,7 @@ impl Polling> for TestPolls { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = pallet_balances::Pallet; type VoteLockingPeriod = ConstU64<3>; type MaxVotes = ConstU32<3>; @@ -269,28 +269,28 @@ fn basic_stuff() { #[test] fn basic_voting_works() { new_test_ext().execute_with(|| { - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(2, 5))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(2, 5))); assert_eq!(tally(3), Tally::from_parts(10, 0, 2)); - assert_ok!(Voting::vote(Origin::signed(1), 3, nay(2, 5))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, nay(2, 5))); assert_eq!(tally(3), Tally::from_parts(0, 10, 0)); assert_eq!(Balances::usable_balance(1), 8); - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(5, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(5, 1))); assert_eq!(tally(3), Tally::from_parts(5, 0, 5)); - assert_ok!(Voting::vote(Origin::signed(1), 3, nay(5, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, nay(5, 1))); assert_eq!(tally(3), Tally::from_parts(0, 5, 0)); assert_eq!(Balances::usable_balance(1), 5); - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(10, 0))); assert_eq!(tally(3), Tally::from_parts(1, 0, 10)); - assert_ok!(Voting::vote(Origin::signed(1), 3, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, nay(10, 0))); assert_eq!(tally(3), Tally::from_parts(0, 1, 0)); assert_eq!(Balances::usable_balance(1), 0); - assert_ok!(Voting::remove_vote(Origin::signed(1), None, 3)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), None, 3)); assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); - assert_ok!(Voting::unlock(Origin::signed(1), class(3), 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), class(3), 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -298,28 +298,28 @@ fn basic_voting_works() { #[test] fn voting_balance_gets_locked() { new_test_ext().execute_with(|| { - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(2, 5))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(2, 5))); assert_eq!(tally(3), Tally::from_parts(10, 0, 2)); - assert_ok!(Voting::vote(Origin::signed(1), 3, nay(2, 5))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, nay(2, 5))); assert_eq!(tally(3), Tally::from_parts(0, 10, 0)); assert_eq!(Balances::usable_balance(1), 8); - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(5, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(5, 1))); assert_eq!(tally(3), Tally::from_parts(5, 0, 5)); - assert_ok!(Voting::vote(Origin::signed(1), 3, nay(5, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, nay(5, 1))); assert_eq!(tally(3), Tally::from_parts(0, 5, 0)); assert_eq!(Balances::usable_balance(1), 5); - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(10, 0))); assert_eq!(tally(3), Tally::from_parts(1, 0, 10)); - assert_ok!(Voting::vote(Origin::signed(1), 3, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, nay(10, 0))); assert_eq!(tally(3), Tally::from_parts(0, 1, 0)); assert_eq!(Balances::usable_balance(1), 0); - assert_ok!(Voting::remove_vote(Origin::signed(1), None, 3)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), None, 3)); assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); - assert_ok!(Voting::unlock(Origin::signed(1), class(3), 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), class(3), 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -327,12 +327,12 @@ fn voting_balance_gets_locked() { #[test] fn successful_but_zero_conviction_vote_balance_can_be_unlocked() { new_test_ext().execute_with(|| { - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(1, 1))); - assert_ok!(Voting::vote(Origin::signed(2), 3, nay(20, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(1, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 3, nay(20, 0))); let c = class(3); Polls::set(vec![(3, Completed(3, false))].into_iter().collect()); - assert_ok!(Voting::remove_vote(Origin::signed(2), Some(c), 3)); - assert_ok!(Voting::unlock(Origin::signed(2), c, 2)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(2), Some(c), 3)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(2), c, 2)); assert_eq!(Balances::usable_balance(2), 20); }); } @@ -340,12 +340,12 @@ fn successful_but_zero_conviction_vote_balance_can_be_unlocked() { #[test] fn unsuccessful_conviction_vote_balance_can_be_unlocked() { new_test_ext().execute_with(|| { - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(1, 1))); - assert_ok!(Voting::vote(Origin::signed(2), 3, nay(20, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(1, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 3, nay(20, 0))); let c = class(3); Polls::set(vec![(3, Completed(3, false))].into_iter().collect()); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(c), 3)); - assert_ok!(Voting::unlock(Origin::signed(1), c, 1)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(c), 3)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), c, 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -354,17 +354,17 @@ fn unsuccessful_conviction_vote_balance_can_be_unlocked() { fn successful_conviction_vote_balance_stays_locked_for_correct_time() { new_test_ext().execute_with(|| { for i in 1..=5 { - assert_ok!(Voting::vote(Origin::signed(i), 3, aye(10, i as u8))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(i), 3, aye(10, i as u8))); } let c = class(3); Polls::set(vec![(3, Completed(3, true))].into_iter().collect()); for i in 1..=5 { - assert_ok!(Voting::remove_vote(Origin::signed(i), Some(c), 3)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(i), Some(c), 3)); } for block in 1..=(3 + 5 * 3) { run_to(block); for i in 1..=5 { - assert_ok!(Voting::unlock(Origin::signed(i), c, i)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(i), c, i)); let expired = block >= (3 << (i - 1)) + 3; assert_eq!(Balances::usable_balance(i), i * 10 - if expired { 0 } else { 10 }); } @@ -385,20 +385,20 @@ fn classwise_delegation_works() { .into_iter() .collect(), ); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 5)); - assert_ok!(Voting::delegate(Origin::signed(1), 1, 3, Conviction::Locked1x, 5)); - assert_ok!(Voting::delegate(Origin::signed(1), 2, 4, Conviction::Locked1x, 5)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 5)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 1, 3, Conviction::Locked1x, 5)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 2, 4, Conviction::Locked1x, 5)); assert_eq!(Balances::usable_balance(1), 5); - assert_ok!(Voting::vote(Origin::signed(2), 0, aye(10, 0))); - assert_ok!(Voting::vote(Origin::signed(2), 1, nay(10, 0))); - assert_ok!(Voting::vote(Origin::signed(2), 2, nay(10, 0))); - assert_ok!(Voting::vote(Origin::signed(3), 0, nay(10, 0))); - assert_ok!(Voting::vote(Origin::signed(3), 1, aye(10, 0))); - assert_ok!(Voting::vote(Origin::signed(3), 2, nay(10, 0))); - assert_ok!(Voting::vote(Origin::signed(4), 0, nay(10, 0))); - assert_ok!(Voting::vote(Origin::signed(4), 1, nay(10, 0))); - assert_ok!(Voting::vote(Origin::signed(4), 2, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 0, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 1, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 2, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(3), 0, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(3), 1, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(3), 2, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(4), 0, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(4), 1, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(4), 2, aye(10, 0))); // 4 hasn't voted yet assert_eq!( @@ -414,7 +414,7 @@ fn classwise_delegation_works() { ); // 4 votes nay to 3. - assert_ok!(Voting::vote(Origin::signed(4), 3, nay(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(4), 3, nay(10, 0))); assert_eq!( Polls::get(), vec![ @@ -428,8 +428,8 @@ fn classwise_delegation_works() { ); // Redelegate for class 2 to account 3. - assert_ok!(Voting::undelegate(Origin::signed(1), 2)); - assert_ok!(Voting::delegate(Origin::signed(1), 2, 3, Conviction::Locked1x, 5)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 2)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 2, 3, Conviction::Locked1x, 5)); assert_eq!( Polls::get(), vec![ @@ -443,12 +443,12 @@ fn classwise_delegation_works() { ); // Redelegating with a lower lock does not forget previous lock and updates correctly. - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); - assert_ok!(Voting::undelegate(Origin::signed(1), 1)); - assert_ok!(Voting::undelegate(Origin::signed(1), 2)); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 3)); - assert_ok!(Voting::delegate(Origin::signed(1), 1, 3, Conviction::Locked1x, 3)); - assert_ok!(Voting::delegate(Origin::signed(1), 2, 4, Conviction::Locked1x, 3)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 1)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 2)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 3)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 1, 3, Conviction::Locked1x, 3)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 2, 4, Conviction::Locked1x, 3)); assert_eq!( Polls::get(), vec![ @@ -462,24 +462,24 @@ fn classwise_delegation_works() { ); assert_eq!(Balances::usable_balance(1), 5); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 2, 1)); // unlock does nothing since the delegation already took place. assert_eq!(Balances::usable_balance(1), 5); // Redelegating with higher amount extends previous lock. - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 6)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 6)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 4); - assert_ok!(Voting::undelegate(Origin::signed(1), 1)); - assert_ok!(Voting::delegate(Origin::signed(1), 1, 3, Conviction::Locked1x, 7)); - assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 1)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 1, 3, Conviction::Locked1x, 7)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 1, 1)); assert_eq!(Balances::usable_balance(1), 3); - assert_ok!(Voting::undelegate(Origin::signed(1), 2)); - assert_ok!(Voting::delegate(Origin::signed(1), 2, 4, Conviction::Locked1x, 8)); - assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 2)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 2, 4, Conviction::Locked1x, 8)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 2, 1)); assert_eq!(Balances::usable_balance(1), 2); assert_eq!( Polls::get(), @@ -499,14 +499,14 @@ fn classwise_delegation_works() { fn redelegation_after_vote_ending_should_keep_lock() { new_test_ext().execute_with(|| { Polls::set(vec![(0, Ongoing(Tally::new(0), 0))].into_iter().collect()); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 5)); - assert_ok!(Voting::vote(Origin::signed(2), 0, aye(10, 1))); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 5)); + assert_ok!(Voting::vote(RuntimeOrigin::signed(2), 0, aye(10, 1))); Polls::set(vec![(0, Completed(1, true))].into_iter().collect()); assert_eq!(Balances::usable_balance(1), 5); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 3, Conviction::Locked1x, 3)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 3, Conviction::Locked1x, 3)); assert_eq!(Balances::usable_balance(1), 5); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 5); }); } @@ -523,9 +523,9 @@ fn lock_amalgamation_valid_with_multiple_removed_votes() { .into_iter() .collect(), ); - assert_ok!(Voting::vote(Origin::signed(1), 0, aye(5, 1))); - assert_ok!(Voting::vote(Origin::signed(1), 1, aye(10, 1))); - assert_ok!(Voting::vote(Origin::signed(1), 2, aye(5, 2))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 0, aye(5, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 1, aye(10, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 2, aye(5, 2))); assert_eq!(Balances::usable_balance(1), 0); Polls::set( @@ -533,28 +533,28 @@ fn lock_amalgamation_valid_with_multiple_removed_votes() { .into_iter() .collect(), ); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 0)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(0), 0)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(0), 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 2)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(0), 2)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); run_to(3); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); run_to(6); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert!(Balances::usable_balance(1) <= 5); run_to(7); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -562,25 +562,25 @@ fn lock_amalgamation_valid_with_multiple_removed_votes() { #[test] fn lock_amalgamation_valid_with_multiple_delegations() { new_test_ext().execute_with(|| { - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 5)); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 10)); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked2x, 5)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 5)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 10)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked2x, 5)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); run_to(3); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); run_to(6); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert!(Balances::usable_balance(1) <= 5); run_to(7); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -589,32 +589,32 @@ fn lock_amalgamation_valid_with_multiple_delegations() { fn lock_amalgamation_valid_with_move_roundtrip_to_delegation() { new_test_ext().execute_with(|| { Polls::set(vec![(0, Ongoing(Tally::new(0), 0))].into_iter().collect()); - assert_ok!(Voting::vote(Origin::signed(1), 0, aye(5, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 0, aye(5, 1))); Polls::set(vec![(0, Completed(1, true))].into_iter().collect()); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 0)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(0), 0)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 5); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 10)); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 10)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); Polls::set(vec![(1, Ongoing(Tally::new(0), 0))].into_iter().collect()); - assert_ok!(Voting::vote(Origin::signed(1), 1, aye(5, 2))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 1, aye(5, 2))); Polls::set(vec![(1, Completed(1, true))].into_iter().collect()); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 1)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(0), 1)); run_to(3); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); run_to(6); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert!(Balances::usable_balance(1) <= 5); run_to(7); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -622,33 +622,33 @@ fn lock_amalgamation_valid_with_move_roundtrip_to_delegation() { #[test] fn lock_amalgamation_valid_with_move_roundtrip_to_casting() { new_test_ext().execute_with(|| { - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 5)); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 5)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 5); Polls::set(vec![(0, Ongoing(Tally::new(0), 0))].into_iter().collect()); - assert_ok!(Voting::vote(Origin::signed(1), 0, aye(10, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 0, aye(10, 1))); Polls::set(vec![(0, Completed(1, true))].into_iter().collect()); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 0)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(0), 0)); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked2x, 10)); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked2x, 10)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); run_to(3); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 0); run_to(6); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert!(Balances::usable_balance(1) <= 5); run_to(7); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -656,30 +656,30 @@ fn lock_amalgamation_valid_with_move_roundtrip_to_casting() { #[test] fn lock_aggregation_over_different_classes_with_delegation_works() { new_test_ext().execute_with(|| { - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::Locked1x, 5)); - assert_ok!(Voting::delegate(Origin::signed(1), 1, 2, Conviction::Locked2x, 5)); - assert_ok!(Voting::delegate(Origin::signed(1), 2, 2, Conviction::Locked1x, 10)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::Locked1x, 5)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 1, 2, Conviction::Locked2x, 5)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 2, 2, Conviction::Locked1x, 10)); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); - assert_ok!(Voting::undelegate(Origin::signed(1), 1)); - assert_ok!(Voting::undelegate(Origin::signed(1), 2)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 1)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 2)); run_to(3); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 2, 1)); assert_eq!(Balances::usable_balance(1), 0); run_to(6); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 2, 1)); assert_eq!(Balances::usable_balance(1), 5); run_to(7); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 2, 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -696,34 +696,34 @@ fn lock_aggregation_over_different_classes_with_casting_works() { .into_iter() .collect(), ); - assert_ok!(Voting::vote(Origin::signed(1), 0, aye(5, 1))); - assert_ok!(Voting::vote(Origin::signed(1), 1, aye(10, 1))); - assert_ok!(Voting::vote(Origin::signed(1), 2, aye(5, 2))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 0, aye(5, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 1, aye(10, 1))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 2, aye(5, 2))); Polls::set( vec![(0, Completed(1, true)), (1, Completed(1, true)), (2, Completed(1, true))] .into_iter() .collect(), ); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(0), 0)); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(1), 1)); - assert_ok!(Voting::remove_vote(Origin::signed(1), Some(2), 2)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(0), 0)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(1), 1)); + assert_ok!(Voting::remove_vote(RuntimeOrigin::signed(1), Some(2), 2)); run_to(3); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 2, 1)); assert_eq!(Balances::usable_balance(1), 0); run_to(6); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 2, 1)); assert_eq!(Balances::usable_balance(1), 5); run_to(7); - assert_ok!(Voting::unlock(Origin::signed(1), 0, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 1, 1)); - assert_ok!(Voting::unlock(Origin::signed(1), 2, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 0, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 1, 1)); + assert_ok!(Voting::unlock(RuntimeOrigin::signed(1), 2, 1)); assert_eq!(Balances::usable_balance(1), 10); }); } @@ -731,21 +731,30 @@ fn lock_aggregation_over_different_classes_with_casting_works() { #[test] fn errors_with_vote_work() { new_test_ext().execute_with(|| { - assert_noop!(Voting::vote(Origin::signed(1), 0, aye(10, 0)), Error::::NotOngoing); - assert_noop!(Voting::vote(Origin::signed(1), 1, aye(10, 0)), Error::::NotOngoing); - assert_noop!(Voting::vote(Origin::signed(1), 2, aye(10, 0)), Error::::NotOngoing); assert_noop!( - Voting::vote(Origin::signed(1), 3, aye(11, 0)), + Voting::vote(RuntimeOrigin::signed(1), 0, aye(10, 0)), + Error::::NotOngoing + ); + assert_noop!( + Voting::vote(RuntimeOrigin::signed(1), 1, aye(10, 0)), + Error::::NotOngoing + ); + assert_noop!( + Voting::vote(RuntimeOrigin::signed(1), 2, aye(10, 0)), + Error::::NotOngoing + ); + assert_noop!( + Voting::vote(RuntimeOrigin::signed(1), 3, aye(11, 0)), Error::::InsufficientFunds ); - assert_ok!(Voting::delegate(Origin::signed(1), 0, 2, Conviction::None, 10)); + assert_ok!(Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::None, 10)); assert_noop!( - Voting::vote(Origin::signed(1), 3, aye(10, 0)), + Voting::vote(RuntimeOrigin::signed(1), 3, aye(10, 0)), Error::::AlreadyDelegating ); - assert_ok!(Voting::undelegate(Origin::signed(1), 0)); + assert_ok!(Voting::undelegate(RuntimeOrigin::signed(1), 0)); Polls::set( vec![ (0, Ongoing(Tally::new(0), 0)), @@ -756,11 +765,11 @@ fn errors_with_vote_work() { .into_iter() .collect(), ); - assert_ok!(Voting::vote(Origin::signed(1), 0, aye(10, 0))); - assert_ok!(Voting::vote(Origin::signed(1), 1, aye(10, 0))); - assert_ok!(Voting::vote(Origin::signed(1), 2, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 0, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 1, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 2, aye(10, 0))); assert_noop!( - Voting::vote(Origin::signed(1), 3, aye(10, 0)), + Voting::vote(RuntimeOrigin::signed(1), 3, aye(10, 0)), Error::::MaxVotesReached ); }); @@ -770,21 +779,21 @@ fn errors_with_vote_work() { fn errors_with_delegating_work() { new_test_ext().execute_with(|| { assert_noop!( - Voting::delegate(Origin::signed(1), 0, 2, Conviction::None, 11), + Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::None, 11), Error::::InsufficientFunds ); assert_noop!( - Voting::delegate(Origin::signed(1), 3, 2, Conviction::None, 10), + Voting::delegate(RuntimeOrigin::signed(1), 3, 2, Conviction::None, 10), Error::::BadClass ); - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(10, 0))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(10, 0))); assert_noop!( - Voting::delegate(Origin::signed(1), 0, 2, Conviction::None, 10), + Voting::delegate(RuntimeOrigin::signed(1), 0, 2, Conviction::None, 10), Error::::AlreadyVoting ); - assert_noop!(Voting::undelegate(Origin::signed(1), 0), Error::::NotDelegating); + assert_noop!(Voting::undelegate(RuntimeOrigin::signed(1), 0), Error::::NotDelegating); }); } @@ -792,31 +801,37 @@ fn errors_with_delegating_work() { fn remove_other_vote_works() { new_test_ext().execute_with(|| { assert_noop!( - Voting::remove_other_vote(Origin::signed(2), 1, 0, 3), + Voting::remove_other_vote(RuntimeOrigin::signed(2), 1, 0, 3), Error::::NotVoter ); - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(10, 2))); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(10, 2))); assert_noop!( - Voting::remove_other_vote(Origin::signed(2), 1, 0, 3), + Voting::remove_other_vote(RuntimeOrigin::signed(2), 1, 0, 3), Error::::NoPermission ); Polls::set(vec![(3, Completed(1, true))].into_iter().collect()); run_to(6); assert_noop!( - Voting::remove_other_vote(Origin::signed(2), 1, 0, 3), + Voting::remove_other_vote(RuntimeOrigin::signed(2), 1, 0, 3), Error::::NoPermissionYet ); run_to(7); - assert_ok!(Voting::remove_other_vote(Origin::signed(2), 1, 0, 3)); + assert_ok!(Voting::remove_other_vote(RuntimeOrigin::signed(2), 1, 0, 3)); }); } #[test] fn errors_with_remove_vote_work() { new_test_ext().execute_with(|| { - assert_noop!(Voting::remove_vote(Origin::signed(1), Some(0), 3), Error::::NotVoter); - assert_ok!(Voting::vote(Origin::signed(1), 3, aye(10, 2))); + assert_noop!( + Voting::remove_vote(RuntimeOrigin::signed(1), Some(0), 3), + Error::::NotVoter + ); + assert_ok!(Voting::vote(RuntimeOrigin::signed(1), 3, aye(10, 2))); Polls::set(vec![(3, Completed(1, true))].into_iter().collect()); - assert_noop!(Voting::remove_vote(Origin::signed(1), None, 3), Error::::ClassNeeded); + assert_noop!( + Voting::remove_vote(RuntimeOrigin::signed(1), None, 3), + Error::::ClassNeeded + ); }); } diff --git a/frame/democracy/Cargo.toml b/frame/democracy/Cargo.toml index e0b85ed7d18df..e50d39ff76902 100644 --- a/frame/democracy/Cargo.toml +++ b/frame/democracy/Cargo.toml @@ -24,17 +24,19 @@ frame-system = { version = "4.0.0-dev", default-features = false, path = "../sys sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +log = { version = "0.4.17", default-features = false } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-scheduler = { version = "4.0.0-dev", path = "../scheduler" } -sp-core = { version = "6.0.0", path = "../../primitives/core" } +pallet-preimage = { version = "4.0.0-dev", path = "../preimage" } [features] default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "scale-info/std", @@ -42,6 +44,7 @@ std = [ "sp-io/std", "sp-runtime/std", "sp-std/std", + "sp-core/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", @@ -49,4 +52,4 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] -try-runtime = ["frame-support/try-runtime"] +try-runtime = ["frame-support/try-runtime",] diff --git a/frame/democracy/src/benchmarking.rs b/frame/democracy/src/benchmarking.rs index d5db82de3840d..424192e2521da 100644 --- a/frame/democracy/src/benchmarking.rs +++ b/frame/democracy/src/benchmarking.rs @@ -22,24 +22,16 @@ use super::*; use frame_benchmarking::{account, benchmarks, whitelist_account}; use frame_support::{ assert_noop, assert_ok, - codec::Decode, - traits::{ - schedule::DispatchTime, Currency, EnsureOrigin, Get, OnInitialize, UnfilteredDispatchable, - }, + traits::{Currency, EnsureOrigin, Get, OnInitialize, UnfilteredDispatchable}, }; -use frame_system::{Pallet as System, RawOrigin}; -use sp_runtime::traits::{BadOrigin, Bounded, One}; +use frame_system::RawOrigin; +use sp_core::H256; +use sp_runtime::{traits::Bounded, BoundedVec}; use crate::Pallet as Democracy; +const REFERENDUM_COUNT_HINT: u32 = 10; const SEED: u32 = 0; -const MAX_REFERENDUMS: u32 = 99; -const MAX_SECONDERS: u32 = 100; -const MAX_BYTES: u32 = 16_384; - -fn assert_last_event(generic_event: ::Event) { - frame_system::Pallet::::assert_last_event(generic_event.into()); -} fn funded_account(name: &'static str, index: u32) -> T::AccountId { let caller: T::AccountId = account(name, index, SEED); @@ -49,37 +41,32 @@ fn funded_account(name: &'static str, index: u32) -> T::AccountId { caller } -fn add_proposal(n: u32) -> Result { +fn make_proposal(n: u32) -> BoundedCallOf { + let call: CallOf = frame_system::Call::remark { remark: n.encode() }.into(); + ::Preimages::bound(call).unwrap() +} + +fn add_proposal(n: u32) -> Result { let other = funded_account::("proposer", n); let value = T::MinimumDeposit::get(); - let proposal_hash: T::Hash = T::Hashing::hash_of(&n); - - Democracy::::propose(RawOrigin::Signed(other).into(), proposal_hash, value)?; - - Ok(proposal_hash) + let proposal = make_proposal::(n); + Democracy::::propose(RawOrigin::Signed(other).into(), proposal.clone(), value)?; + Ok(proposal.hash()) } -fn add_referendum(n: u32) -> Result { - let proposal_hash: T::Hash = T::Hashing::hash_of(&n); +fn add_referendum(n: u32) -> (ReferendumIndex, H256) { let vote_threshold = VoteThreshold::SimpleMajority; - - Democracy::::inject_referendum( - T::LaunchPeriod::get(), - proposal_hash, - vote_threshold, - 0u32.into(), - ); - let referendum_index: ReferendumIndex = ReferendumCount::::get() - 1; - T::Scheduler::schedule_named( - (DEMOCRACY_ID, referendum_index).encode(), - DispatchTime::At(2u32.into()), - None, - 63, - frame_system::RawOrigin::Root.into(), - Call::enact_proposal { proposal_hash, index: referendum_index }.into(), + let proposal = make_proposal::(n); + let hash = proposal.hash(); + ( + Democracy::::inject_referendum( + T::LaunchPeriod::get(), + proposal, + vote_threshold, + 0u32.into(), + ), + hash, ) - .map_err(|_| "failed to schedule named")?; - Ok(referendum_index) } fn account_vote(b: BalanceOf) -> AccountVote> { @@ -97,95 +84,90 @@ benchmarks! { } let caller = funded_account::("caller", 0); - let proposal_hash: T::Hash = T::Hashing::hash_of(&0); + let proposal = make_proposal::(0); let value = T::MinimumDeposit::get(); whitelist_account!(caller); - }: _(RawOrigin::Signed(caller), proposal_hash, value) + }: _(RawOrigin::Signed(caller), proposal, value) verify { assert_eq!(Democracy::::public_props().len(), p as usize, "Proposals not created."); } second { - let s in 0 .. MAX_SECONDERS; - let caller = funded_account::("caller", 0); - let proposal_hash = add_proposal::(s)?; + add_proposal::(0)?; // Create s existing "seconds" - for i in 0 .. s { + // we must reserve one deposit for the `proposal` and one for our benchmarked `second` call. + for i in 0 .. T::MaxDeposits::get() - 2 { let seconder = funded_account::("seconder", i); - Democracy::::second(RawOrigin::Signed(seconder).into(), 0, u32::MAX)?; + Democracy::::second(RawOrigin::Signed(seconder).into(), 0)?; } let deposits = Democracy::::deposit_of(0).ok_or("Proposal not created")?; - assert_eq!(deposits.0.len(), (s + 1) as usize, "Seconds not recorded"); + assert_eq!(deposits.0.len(), (T::MaxDeposits::get() - 1) as usize, "Seconds not recorded"); whitelist_account!(caller); - }: _(RawOrigin::Signed(caller), 0, u32::MAX) + }: _(RawOrigin::Signed(caller), 0) verify { let deposits = Democracy::::deposit_of(0).ok_or("Proposal not created")?; - assert_eq!(deposits.0.len(), (s + 2) as usize, "`second` benchmark did not work"); + assert_eq!(deposits.0.len(), (T::MaxDeposits::get()) as usize, "`second` benchmark did not work"); } vote_new { - let r in 1 .. MAX_REFERENDUMS; - let caller = funded_account::("caller", 0); let account_vote = account_vote::(100u32.into()); // We need to create existing direct votes - for i in 0 .. r { - let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?; + for i in 0 .. T::MaxVotes::get() - 1 { + let ref_index = add_referendum::(i).0; + Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?; } let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, _ => return Err("Votes are not direct".into()), }; - assert_eq!(votes.len(), r as usize, "Votes were not recorded."); + assert_eq!(votes.len(), (T::MaxVotes::get() - 1) as usize, "Votes were not recorded."); - let referendum_index = add_referendum::(r)?; + let ref_index = add_referendum::(T::MaxVotes::get() - 1).0; whitelist_account!(caller); - }: vote(RawOrigin::Signed(caller.clone()), referendum_index, account_vote) + }: vote(RawOrigin::Signed(caller.clone()), ref_index, account_vote) verify { let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, _ => return Err("Votes are not direct".into()), }; - assert_eq!(votes.len(), (r + 1) as usize, "Vote was not recorded."); + assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Vote was not recorded."); } vote_existing { - let r in 1 .. MAX_REFERENDUMS; - let caller = funded_account::("caller", 0); let account_vote = account_vote::(100u32.into()); // We need to create existing direct votes - for i in 0 ..=r { - let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?; + for i in 0..T::MaxVotes::get() { + let ref_index = add_referendum::(i).0; + Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?; } let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, _ => return Err("Votes are not direct".into()), }; - assert_eq!(votes.len(), (r + 1) as usize, "Votes were not recorded."); + assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Votes were not recorded."); // Change vote from aye to nay let nay = Vote { aye: false, conviction: Conviction::Locked1x }; let new_vote = AccountVote::Standard { vote: nay, balance: 1000u32.into() }; - let referendum_index = Democracy::::referendum_count() - 1; + let ref_index = Democracy::::referendum_count() - 1; // This tests when a user changes a vote whitelist_account!(caller); - }: vote(RawOrigin::Signed(caller.clone()), referendum_index, new_vote) + }: vote(RawOrigin::Signed(caller.clone()), ref_index, new_vote) verify { let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, _ => return Err("Votes are not direct".into()), }; - assert_eq!(votes.len(), (r + 1) as usize, "Vote was incorrectly added"); - let referendum_info = Democracy::::referendum_info(referendum_index) + assert_eq!(votes.len(), T::MaxVotes::get() as usize, "Vote was incorrectly added"); + let referendum_info = Democracy::::referendum_info(ref_index) .ok_or("referendum doesn't exist")?; let tally = match referendum_info { ReferendumInfo::Ongoing(r) => r.tally, @@ -196,61 +178,55 @@ benchmarks! { emergency_cancel { let origin = T::CancellationOrigin::successful_origin(); - let referendum_index = add_referendum::(0)?; - assert_ok!(Democracy::::referendum_status(referendum_index)); - }: _(origin, referendum_index) + let ref_index = add_referendum::(0).0; + assert_ok!(Democracy::::referendum_status(ref_index)); + }: _(origin, ref_index) verify { // Referendum has been canceled assert_noop!( - Democracy::::referendum_status(referendum_index), + Democracy::::referendum_status(ref_index), Error::::ReferendumInvalid, ); } blacklist { - let p in 1 .. T::MaxProposals::get(); - // Place our proposal at the end to make sure it's worst case. - for i in 0 .. p - 1 { + for i in 0 .. T::MaxProposals::get() - 1 { add_proposal::(i)?; } // We should really add a lot of seconds here, but we're not doing it elsewhere. + // Add a referendum of our proposal. + let (ref_index, hash) = add_referendum::(0); + assert_ok!(Democracy::::referendum_status(ref_index)); // Place our proposal in the external queue, too. - let hash = T::Hashing::hash_of(&0); assert_ok!( - Democracy::::external_propose(T::ExternalOrigin::successful_origin(), hash) + Democracy::::external_propose(T::ExternalOrigin::successful_origin(), make_proposal::(0)) ); let origin = T::BlacklistOrigin::successful_origin(); - // Add a referendum of our proposal. - let referendum_index = add_referendum::(0)?; - assert_ok!(Democracy::::referendum_status(referendum_index)); - }: _(origin, hash, Some(referendum_index)) + }: _(origin, hash, Some(ref_index)) verify { // Referendum has been canceled assert_noop!( - Democracy::::referendum_status(referendum_index), + Democracy::::referendum_status(ref_index), Error::::ReferendumInvalid ); } // Worst case scenario, we external propose a previously blacklisted proposal external_propose { - let v in 1 .. MAX_VETOERS as u32; - let origin = T::ExternalOrigin::successful_origin(); - let proposal_hash = T::Hashing::hash_of(&0); + let proposal = make_proposal::(0); // Add proposal to blacklist with block number 0 - let addresses = (0..v) + let addresses: BoundedVec<_, _> = (0..(T::MaxBlacklisted::get() - 1)) .into_iter() .map(|i| account::("blacklist", i, SEED)) - .collect::>(); - Blacklist::::insert( - proposal_hash, - (T::BlockNumber::zero(), addresses), - ); - }: _(origin, proposal_hash) + .collect::>() + .try_into() + .unwrap(); + Blacklist::::insert(proposal.hash(), (T::BlockNumber::zero(), addresses)); + }: _(origin, proposal) verify { // External proposal created ensure!(>::exists(), "External proposal didn't work"); @@ -258,8 +234,8 @@ benchmarks! { external_propose_majority { let origin = T::ExternalMajorityOrigin::successful_origin(); - let proposal_hash = T::Hashing::hash_of(&0); - }: _(origin, proposal_hash) + let proposal = make_proposal::(0); + }: _(origin, proposal) verify { // External proposal created ensure!(>::exists(), "External proposal didn't work"); @@ -267,8 +243,8 @@ benchmarks! { external_propose_default { let origin = T::ExternalDefaultOrigin::successful_origin(); - let proposal_hash = T::Hashing::hash_of(&0); - }: _(origin, proposal_hash) + let proposal = make_proposal::(0); + }: _(origin, proposal) verify { // External proposal created ensure!(>::exists(), "External proposal didn't work"); @@ -276,76 +252,60 @@ benchmarks! { fast_track { let origin_propose = T::ExternalDefaultOrigin::successful_origin(); - let proposal_hash: T::Hash = T::Hashing::hash_of(&0); - Democracy::::external_propose_default(origin_propose, proposal_hash)?; + let proposal = make_proposal::(0); + let proposal_hash = proposal.hash(); + Democracy::::external_propose_default(origin_propose, proposal)?; // NOTE: Instant origin may invoke a little bit more logic, but may not always succeed. let origin_fast_track = T::FastTrackOrigin::successful_origin(); let voting_period = T::FastTrackVotingPeriod::get(); let delay = 0u32; - }: _(origin_fast_track, proposal_hash, voting_period, delay.into()) + }: _(origin_fast_track, proposal_hash, voting_period, delay.into()) verify { assert_eq!(Democracy::::referendum_count(), 1, "referendum not created") } veto_external { - // Existing veto-ers - let v in 0 .. MAX_VETOERS as u32; - - let proposal_hash: T::Hash = T::Hashing::hash_of(&v); + let proposal = make_proposal::(0); + let proposal_hash = proposal.hash(); let origin_propose = T::ExternalDefaultOrigin::successful_origin(); - Democracy::::external_propose_default(origin_propose, proposal_hash)?; + Democracy::::external_propose_default(origin_propose, proposal)?; - let mut vetoers: Vec = Vec::new(); - for i in 0 .. v { - vetoers.push(account::("vetoer", i, SEED)); + let mut vetoers: BoundedVec = Default::default(); + for i in 0 .. (T::MaxBlacklisted::get() - 1) { + vetoers.try_push(account::("vetoer", i, SEED)).unwrap(); } vetoers.sort(); Blacklist::::insert(proposal_hash, (T::BlockNumber::zero(), vetoers)); let origin = T::VetoOrigin::successful_origin(); ensure!(NextExternal::::get().is_some(), "no external proposal"); - }: _(origin, proposal_hash) + }: _(origin, proposal_hash) verify { assert!(NextExternal::::get().is_none()); let (_, new_vetoers) = >::get(&proposal_hash).ok_or("no blacklist")?; - assert_eq!(new_vetoers.len(), (v + 1) as usize, "vetoers not added"); + assert_eq!(new_vetoers.len(), T::MaxBlacklisted::get() as usize, "vetoers not added"); } cancel_proposal { - let p in 1 .. T::MaxProposals::get(); - // Place our proposal at the end to make sure it's worst case. - for i in 0 .. p { + for i in 0 .. T::MaxProposals::get() { add_proposal::(i)?; } - let cancel_origin = T::CancelProposalOrigin::successful_origin(); - }: _(cancel_origin, 0) + }: _(cancel_origin, 0) cancel_referendum { - let referendum_index = add_referendum::(0)?; - }: _(RawOrigin::Root, referendum_index) - - cancel_queued { - let r in 1 .. MAX_REFERENDUMS; + let ref_index = add_referendum::(0).0; + }: _(RawOrigin::Root, ref_index) - for i in 0..r { - add_referendum::(i)?; // This add one element in the scheduler - } - - let referendum_index = add_referendum::(r)?; - }: _(RawOrigin::Root, referendum_index) - - // This measures the path of `launch_next` external. Not currently used as we simply - // assume the weight is `MaxBlockWeight` when executing. #[extra] on_initialize_external { - let r in 0 .. MAX_REFERENDUMS; + let r in 0 .. REFERENDUM_COUNT_HINT; for i in 0..r { - add_referendum::(i)?; + add_referendum::(i); } assert_eq!(Democracy::::referendum_count(), r, "referenda not created"); @@ -354,8 +314,8 @@ benchmarks! { LastTabledWasExternal::::put(false); let origin = T::ExternalMajorityOrigin::successful_origin(); - let proposal_hash = T::Hashing::hash_of(&r); - let call = Call::::external_propose_majority { proposal_hash }; + let proposal = make_proposal::(r); + let call = Call::::external_propose_majority { proposal }; call.dispatch_bypass_filter(origin)?; // External proposal created ensure!(>::exists(), "External proposal didn't work"); @@ -379,14 +339,12 @@ benchmarks! { } } - // This measures the path of `launch_next` public. Not currently used as we simply - // assume the weight is `MaxBlockWeight` when executing. #[extra] on_initialize_public { - let r in 1 .. MAX_REFERENDUMS; + let r in 0 .. (T::MaxVotes::get() - 1); for i in 0..r { - add_referendum::(i)?; + add_referendum::(i); } assert_eq!(Democracy::::referendum_count(), r, "referenda not created"); @@ -415,10 +373,10 @@ benchmarks! { // No launch no maturing referenda. on_initialize_base { - let r in 1 .. MAX_REFERENDUMS; + let r in 0 .. (T::MaxVotes::get() - 1); for i in 0..r { - add_referendum::(i)?; + add_referendum::(i); } for (key, mut info) in ReferendumInfoOf::::iter() { @@ -445,10 +403,10 @@ benchmarks! { } on_initialize_base_with_launch_period { - let r in 1 .. MAX_REFERENDUMS; + let r in 0 .. (T::MaxVotes::get() - 1); for i in 0..r { - add_referendum::(i)?; + add_referendum::(i); } for (key, mut info) in ReferendumInfoOf::::iter() { @@ -477,7 +435,7 @@ benchmarks! { } delegate { - let r in 1 .. MAX_REFERENDUMS; + let r in 0 .. (T::MaxVotes::get() - 1); let initial_balance: BalanceOf = 100u32.into(); let delegated_balance: BalanceOf = 1000u32.into(); @@ -504,8 +462,8 @@ benchmarks! { let account_vote = account_vote::(initial_balance); // We need to create existing direct votes for the `new_delegate` for i in 0..r { - let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(new_delegate.clone()).into(), ref_idx, account_vote)?; + let ref_index = add_referendum::(i).0; + Democracy::::vote(RawOrigin::Signed(new_delegate.clone()).into(), ref_index, account_vote)?; } let votes = match VotingOf::::get(&new_delegate) { Voting::Direct { votes, .. } => votes, @@ -529,7 +487,7 @@ benchmarks! { } undelegate { - let r in 1 .. MAX_REFERENDUMS; + let r in 0 .. (T::MaxVotes::get() - 1); let initial_balance: BalanceOf = 100u32.into(); let delegated_balance: BalanceOf = 1000u32.into(); @@ -553,10 +511,10 @@ benchmarks! { // We need to create votes direct votes for the `delegate` let account_vote = account_vote::(initial_balance); for i in 0..r { - let ref_idx = add_referendum::(i)?; + let ref_index = add_referendum::(i).0; Democracy::::vote( RawOrigin::Signed(the_delegate.clone()).into(), - ref_idx, + ref_index, account_vote )?; } @@ -580,71 +538,9 @@ benchmarks! { }: _(RawOrigin::Root) - note_preimage { - // Num of bytes in encoded proposal - let b in 0 .. MAX_BYTES; - - let caller = funded_account::("caller", 0); - let encoded_proposal = vec![1; b as usize]; - whitelist_account!(caller); - }: _(RawOrigin::Signed(caller), encoded_proposal.clone()) - verify { - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - match Preimages::::get(proposal_hash) { - Some(PreimageStatus::Available { .. }) => (), - _ => return Err("preimage not available".into()) - } - } - - note_imminent_preimage { - // Num of bytes in encoded proposal - let b in 0 .. MAX_BYTES; - - // d + 1 to include the one we are testing - let encoded_proposal = vec![1; b as usize]; - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - let block_number = T::BlockNumber::one(); - Preimages::::insert(&proposal_hash, PreimageStatus::Missing(block_number)); - - let caller = funded_account::("caller", 0); - let encoded_proposal = vec![1; b as usize]; - whitelist_account!(caller); - }: _(RawOrigin::Signed(caller), encoded_proposal.clone()) - verify { - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - match Preimages::::get(proposal_hash) { - Some(PreimageStatus::Available { .. }) => (), - _ => return Err("preimage not available".into()) - } - } - - reap_preimage { - // Num of bytes in encoded proposal - let b in 0 .. MAX_BYTES; - - let encoded_proposal = vec![1; b as usize]; - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - - let submitter = funded_account::("submitter", b); - Democracy::::note_preimage(RawOrigin::Signed(submitter).into(), encoded_proposal.clone())?; - - // We need to set this otherwise we get `Early` error. - let block_number = T::VotingPeriod::get() + T::EnactmentPeriod::get() + T::BlockNumber::one(); - System::::set_block_number(block_number); - - assert!(Preimages::::contains_key(proposal_hash)); - - let caller = funded_account::("caller", 0); - whitelist_account!(caller); - }: _(RawOrigin::Signed(caller), proposal_hash, u32::MAX) - verify { - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - assert!(!Preimages::::contains_key(proposal_hash)); - } - // Test when unlock will remove locks unlock_remove { - let r in 1 .. MAX_REFERENDUMS; + let r in 0 .. (T::MaxVotes::get() - 1); let locker = funded_account::("locker", 0); let locker_lookup = T::Lookup::unlookup(locker.clone()); @@ -653,9 +549,9 @@ benchmarks! { let small_vote = account_vote::(base_balance); // Vote and immediately unvote for i in 0 .. r { - let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), ref_idx, small_vote)?; - Democracy::::remove_vote(RawOrigin::Signed(locker.clone()).into(), ref_idx)?; + let ref_index = add_referendum::(i).0; + Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), ref_index, small_vote)?; + Democracy::::remove_vote(RawOrigin::Signed(locker.clone()).into(), ref_index)?; } let caller = funded_account::("caller", 0); @@ -669,7 +565,7 @@ benchmarks! { // Test when unlock will set a new value unlock_set { - let r in 1 .. MAX_REFERENDUMS; + let r in 0 .. (T::MaxVotes::get() - 1); let locker = funded_account::("locker", 0); let locker_lookup = T::Lookup::unlookup(locker.clone()); @@ -677,14 +573,14 @@ benchmarks! { let base_balance: BalanceOf = 100u32.into(); let small_vote = account_vote::(base_balance); for i in 0 .. r { - let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), ref_idx, small_vote)?; + let ref_index = add_referendum::(i).0; + Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), ref_index, small_vote)?; } // Create a big vote so lock increases let big_vote = account_vote::(base_balance * 10u32.into()); - let referendum_index = add_referendum::(r)?; - Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), referendum_index, big_vote)?; + let ref_index = add_referendum::(r).0; + Democracy::::vote(RawOrigin::Signed(locker.clone()).into(), ref_index, big_vote)?; let votes = match VotingOf::::get(&locker) { Voting::Direct { votes, .. } => votes, @@ -695,7 +591,7 @@ benchmarks! { let voting = VotingOf::::get(&locker); assert_eq!(voting.locked_balance(), base_balance * 10u32.into()); - Democracy::::remove_vote(RawOrigin::Signed(locker.clone()).into(), referendum_index)?; + Democracy::::remove_vote(RawOrigin::Signed(locker.clone()).into(), ref_index)?; let caller = funded_account::("caller", 0); whitelist_account!(caller); @@ -709,18 +605,18 @@ benchmarks! { let voting = VotingOf::::get(&locker); // Note that we may want to add a `get_lock` api to actually verify - assert_eq!(voting.locked_balance(), base_balance); + assert_eq!(voting.locked_balance(), if r > 0 { base_balance } else { 0u32.into() }); } remove_vote { - let r in 1 .. MAX_REFERENDUMS; + let r in 1 .. T::MaxVotes::get(); let caller = funded_account::("caller", 0); let account_vote = account_vote::(100u32.into()); for i in 0 .. r { - let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?; + let ref_index = add_referendum::(i).0; + Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?; } let votes = match VotingOf::::get(&caller) { @@ -729,9 +625,9 @@ benchmarks! { }; assert_eq!(votes.len(), r as usize, "Votes not created"); - let referendum_index = r - 1; + let ref_index = r - 1; whitelist_account!(caller); - }: _(RawOrigin::Signed(caller.clone()), referendum_index) + }: _(RawOrigin::Signed(caller.clone()), ref_index) verify { let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, @@ -742,15 +638,15 @@ benchmarks! { // Worst case is when target == caller and referendum is ongoing remove_other_vote { - let r in 1 .. MAX_REFERENDUMS; + let r in 1 .. T::MaxVotes::get(); let caller = funded_account::("caller", r); let caller_lookup = T::Lookup::unlookup(caller.clone()); let account_vote = account_vote::(100u32.into()); for i in 0 .. r { - let ref_idx = add_referendum::(i)?; - Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_idx, account_vote)?; + let ref_index = add_referendum::(i).0; + Democracy::::vote(RawOrigin::Signed(caller.clone()).into(), ref_index, account_vote)?; } let votes = match VotingOf::::get(&caller) { @@ -759,9 +655,9 @@ benchmarks! { }; assert_eq!(votes.len(), r as usize, "Votes not created"); - let referendum_index = r - 1; + let ref_index = r - 1; whitelist_account!(caller); - }: _(RawOrigin::Signed(caller.clone()), caller_lookup, referendum_index) + }: _(RawOrigin::Signed(caller.clone()), caller_lookup, ref_index) verify { let votes = match VotingOf::::get(&caller) { Voting::Direct { votes, .. } => votes, @@ -770,54 +666,6 @@ benchmarks! { assert_eq!(votes.len(), (r - 1) as usize, "Vote was not removed"); } - #[extra] - enact_proposal_execute { - // Num of bytes in encoded proposal - let b in 0 .. MAX_BYTES; - - let proposer = funded_account::("proposer", 0); - let raw_call = Call::note_preimage { encoded_proposal: vec![1; b as usize] }; - let generic_call: T::Proposal = raw_call.into(); - let encoded_proposal = generic_call.encode(); - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - Democracy::::note_preimage(RawOrigin::Signed(proposer).into(), encoded_proposal)?; - - match Preimages::::get(proposal_hash) { - Some(PreimageStatus::Available { .. }) => (), - _ => return Err("preimage not available".into()) - } - }: enact_proposal(RawOrigin::Root, proposal_hash, 0) - verify { - // Fails due to mismatched origin - assert_last_event::(Event::::Executed { ref_index: 0, result: Err(BadOrigin.into()) }.into()); - } - - #[extra] - enact_proposal_slash { - // Num of bytes in encoded proposal - let b in 0 .. MAX_BYTES; - - let proposer = funded_account::("proposer", 0); - // Random invalid bytes - let encoded_proposal = vec![200; b as usize]; - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - Democracy::::note_preimage(RawOrigin::Signed(proposer).into(), encoded_proposal)?; - - match Preimages::::get(proposal_hash) { - Some(PreimageStatus::Available { .. }) => (), - _ => return Err("preimage not available".into()) - } - let origin = RawOrigin::Root.into(); - let call = Call::::enact_proposal { proposal_hash, index: 0 }.encode(); - }: { - assert_eq!( - as Decode>::decode(&mut &*call) - .expect("call is encoded above, encoding must be correct") - .dispatch_bypass_filter(origin), - Err(Error::::PreimageInvalid.into()) - ); - } - impl_benchmark_test_suite!( Democracy, crate::tests::new_test_ext(), diff --git a/frame/democracy/src/conviction.rs b/frame/democracy/src/conviction.rs index 57d631e8c1f4c..a938d8a4e6852 100644 --- a/frame/democracy/src/conviction.rs +++ b/frame/democracy/src/conviction.rs @@ -18,7 +18,7 @@ //! The conviction datatype. use crate::types::Delegations; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::{ traits::{Bounded, CheckedDiv, CheckedMul, Zero}, @@ -27,7 +27,19 @@ use sp_runtime::{ use sp_std::{prelude::*, result::Result}; /// A value denoting the strength of conviction of a vote. -#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug, TypeInfo)] +#[derive( + Encode, + MaxEncodedLen, + Decode, + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + RuntimeDebug, + TypeInfo, +)] pub enum Conviction { /// 0.1x votes, unlocked. None, diff --git a/frame/democracy/src/lib.rs b/frame/democracy/src/lib.rs index bbc5b767e97ff..cf954d4800eee 100644 --- a/frame/democracy/src/lib.rs +++ b/frame/democracy/src/lib.rs @@ -152,21 +152,20 @@ #![recursion_limit = "256"] #![cfg_attr(not(feature = "std"), no_std)] -use codec::{Decode, Encode, Input}; +use codec::{Decode, Encode}; use frame_support::{ ensure, traits::{ defensive_prelude::*, - schedule::{DispatchTime, Named as ScheduleNamed}, - BalanceStatus, Currency, Get, LockIdentifier, LockableCurrency, OnUnbalanced, - ReservableCurrency, WithdrawReasons, + schedule::{v3::Named as ScheduleNamed, DispatchTime}, + Bounded, Currency, Get, LockIdentifier, LockableCurrency, OnUnbalanced, QueryPreimage, + ReservableCurrency, StorePreimage, WithdrawReasons, }, weights::Weight, }; -use scale_info::TypeInfo; use sp_runtime::{ - traits::{Bounded, Dispatchable, Hash, Saturating, StaticLookup, Zero}, - ArithmeticError, DispatchError, DispatchResult, RuntimeDebug, + traits::{Bounded as ArithBounded, One, Saturating, StaticLookup, Zero}, + ArithmeticError, DispatchError, DispatchResult, }; use sp_std::prelude::*; @@ -188,12 +187,9 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] pub mod benchmarking; -const DEMOCRACY_ID: LockIdentifier = *b"democrac"; +pub mod migrations; -/// The maximum number of vetoers on a single proposal used to compute Weight. -/// -/// NOTE: This is not enforced by any logic. -pub const MAX_VETOERS: u32 = 100; +const DEMOCRACY_ID: LockIdentifier = *b"democrac"; /// A proposal index. pub type PropIndex = u32; @@ -206,55 +202,35 @@ type BalanceOf = type NegativeImbalanceOf = <::Currency as Currency< ::AccountId, >>::NegativeImbalance; +pub type CallOf = ::RuntimeCall; +pub type BoundedCallOf = Bounded>; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; -#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum PreimageStatus { - /// The preimage is imminently needed at the argument. - Missing(BlockNumber), - /// The preimage is available. - Available { - data: Vec, - provider: AccountId, - deposit: Balance, - since: BlockNumber, - /// None if it's not imminent. - expiry: Option, - }, -} - -impl PreimageStatus { - fn to_missing_expiry(self) -> Option { - match self { - PreimageStatus::Missing(expiry) => Some(expiry), - _ => None, - } - } -} - -// A value placed in storage that represents the current version of the Democracy storage. -// This value is used by the `on_runtime_upgrade` logic to determine whether we run -// storage migration logic. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo)] -enum Releases { - V1, -} - #[frame_support::pallet] pub mod pallet { use super::{DispatchResult, *}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + use sp_core::H256; + + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] pub trait Config: frame_system::Config + Sized { - type Proposal: Parameter + Dispatchable + From>; - type Event: From> + IsType<::Event>; + type WeightInfo: WeightInfo; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// The Scheduler. + type Scheduler: ScheduleNamed, Self::PalletsOrigin>; + + /// The Preimage provider. + type Preimages: QueryPreimage + StorePreimage; /// Currency type for this pallet. type Currency: ReservableCurrency @@ -287,121 +263,104 @@ pub mod pallet { #[pallet::constant] type MinimumDeposit: Get>; + /// Indicator for whether an emergency origin is even allowed to happen. Some chains may + /// want to set this permanently to `false`, others may want to condition it on things such + /// as an upgrade having happened recently. + #[pallet::constant] + type InstantAllowed: Get; + + /// Minimum voting period allowed for a fast-track referendum. + #[pallet::constant] + type FastTrackVotingPeriod: Get; + + /// Period in blocks where an external proposal may not be re-submitted after being vetoed. + #[pallet::constant] + type CooloffPeriod: Get; + + /// The maximum number of votes for an account. + /// + /// Also used to compute weight, an overly big value can + /// lead to extrinsic with very big weight: see `delegate` for instance. + #[pallet::constant] + type MaxVotes: Get; + + /// The maximum number of public proposals that can exist at any time. + #[pallet::constant] + type MaxProposals: Get; + + /// The maximum number of deposits a public proposal may have at any time. + #[pallet::constant] + type MaxDeposits: Get; + + /// The maximum number of items which can be blacklisted. + #[pallet::constant] + type MaxBlacklisted: Get; + /// Origin from which the next tabled referendum may be forced. This is a normal /// "super-majority-required" referendum. - type ExternalOrigin: EnsureOrigin; + type ExternalOrigin: EnsureOrigin; /// Origin from which the next tabled referendum may be forced; this allows for the tabling /// of a majority-carries referendum. - type ExternalMajorityOrigin: EnsureOrigin; + type ExternalMajorityOrigin: EnsureOrigin; /// Origin from which the next tabled referendum may be forced; this allows for the tabling /// of a negative-turnout-bias (default-carries) referendum. - type ExternalDefaultOrigin: EnsureOrigin; + type ExternalDefaultOrigin: EnsureOrigin; /// Origin from which the next majority-carries (or more permissive) referendum may be /// tabled to vote according to the `FastTrackVotingPeriod` asynchronously in a similar /// manner to the emergency origin. It retains its threshold method. - type FastTrackOrigin: EnsureOrigin; + type FastTrackOrigin: EnsureOrigin; /// Origin from which the next majority-carries (or more permissive) referendum may be /// tabled to vote immediately and asynchronously in a similar manner to the emergency /// origin. It retains its threshold method. - type InstantOrigin: EnsureOrigin; - - /// Indicator for whether an emergency origin is even allowed to happen. Some chains may - /// want to set this permanently to `false`, others may want to condition it on things such - /// as an upgrade having happened recently. - #[pallet::constant] - type InstantAllowed: Get; - - /// Minimum voting period allowed for a fast-track referendum. - #[pallet::constant] - type FastTrackVotingPeriod: Get; + type InstantOrigin: EnsureOrigin; /// Origin from which any referendum may be cancelled in an emergency. - type CancellationOrigin: EnsureOrigin; + type CancellationOrigin: EnsureOrigin; /// Origin from which proposals may be blacklisted. - type BlacklistOrigin: EnsureOrigin; + type BlacklistOrigin: EnsureOrigin; /// Origin from which a proposal may be cancelled and its backers slashed. - type CancelProposalOrigin: EnsureOrigin; + type CancelProposalOrigin: EnsureOrigin; /// Origin for anyone able to veto proposals. - /// - /// # Warning - /// - /// The number of Vetoers for a proposal must be small, extrinsics are weighted according to - /// [MAX_VETOERS](./const.MAX_VETOERS.html) - type VetoOrigin: EnsureOrigin; - - /// Period in blocks where an external proposal may not be re-submitted after being vetoed. - #[pallet::constant] - type CooloffPeriod: Get; - - /// The amount of balance that must be deposited per byte of preimage stored. - #[pallet::constant] - type PreimageByteDeposit: Get>; - - /// An origin that can provide a preimage using operational extrinsics. - type OperationalPreimageOrigin: EnsureOrigin; - - /// Handler for the unbalanced reduction when slashing a preimage deposit. - type Slash: OnUnbalanced>; - - /// The Scheduler. - type Scheduler: ScheduleNamed; + type VetoOrigin: EnsureOrigin; /// Overarching type of all pallets origins. type PalletsOrigin: From>; - /// The maximum number of votes for an account. - /// - /// Also used to compute weight, an overly big value can - /// lead to extrinsic with very big weight: see `delegate` for instance. - #[pallet::constant] - type MaxVotes: Get; - - /// Weight information for extrinsics in this pallet. - type WeightInfo: WeightInfo; - - /// The maximum number of public proposals that can exist at any time. - #[pallet::constant] - type MaxProposals: Get; + /// Handler for the unbalanced reduction when slashing a preimage deposit. + type Slash: OnUnbalanced>; } - // TODO: Refactor public proposal queue into its own pallet. - // https://github.com/paritytech/substrate/issues/5322 /// The number of (public) proposals that have been made so far. #[pallet::storage] #[pallet::getter(fn public_prop_count)] pub type PublicPropCount = StorageValue<_, PropIndex, ValueQuery>; - /// The public proposals. Unsorted. The second item is the proposal's hash. + /// The public proposals. Unsorted. The second item is the proposal. #[pallet::storage] #[pallet::getter(fn public_props)] - pub type PublicProps = - StorageValue<_, Vec<(PropIndex, T::Hash, T::AccountId)>, ValueQuery>; + pub type PublicProps = StorageValue< + _, + BoundedVec<(PropIndex, BoundedCallOf, T::AccountId), T::MaxProposals>, + ValueQuery, + >; /// Those who have locked a deposit. /// /// TWOX-NOTE: Safe, as increasing integer keys are safe. #[pallet::storage] #[pallet::getter(fn deposit_of)] - pub type DepositOf = - StorageMap<_, Twox64Concat, PropIndex, (Vec, BalanceOf)>; - - /// Map of hashes to the proposal preimage, along with who registered it and their deposit. - /// The block number is the block at which it was deposited. - // TODO: Refactor Preimages into its own pallet. - // https://github.com/paritytech/substrate/issues/5322 - #[pallet::storage] - pub type Preimages = StorageMap< + pub type DepositOf = StorageMap< _, - Identity, - T::Hash, - PreimageStatus, T::BlockNumber>, + Twox64Concat, + PropIndex, + (BoundedVec, BalanceOf), >; /// The next free referendum index, aka the number of referenda started so far. @@ -424,7 +383,7 @@ pub mod pallet { _, Twox64Concat, ReferendumIndex, - ReferendumInfo>, + ReferendumInfo, BalanceOf>, >; /// All votes for a particular voter. We store the balance for the number of votes that we @@ -436,14 +395,12 @@ pub mod pallet { _, Twox64Concat, T::AccountId, - Voting, T::AccountId, T::BlockNumber>, + Voting, T::AccountId, T::BlockNumber, T::MaxVotes>, ValueQuery, >; /// True if the last referendum tabled was submitted externally. False if it was a public /// proposal. - // TODO: There should be any number of tabling origins, not just public and "external" - // (council). https://github.com/paritytech/substrate/issues/5322 #[pallet::storage] pub type LastTabledWasExternal = StorageValue<_, bool, ValueQuery>; @@ -452,23 +409,21 @@ pub mod pallet { /// - `LastTabledWasExternal` is `false`; or /// - `PublicProps` is empty. #[pallet::storage] - pub type NextExternal = StorageValue<_, (T::Hash, VoteThreshold)>; + pub type NextExternal = StorageValue<_, (BoundedCallOf, VoteThreshold)>; /// A record of who vetoed what. Maps proposal hash to a possible existent block number /// (until when it may not be resubmitted) and who vetoed it. #[pallet::storage] - pub type Blacklist = - StorageMap<_, Identity, T::Hash, (T::BlockNumber, Vec)>; + pub type Blacklist = StorageMap< + _, + Identity, + H256, + (T::BlockNumber, BoundedVec), + >; /// Record of all proposals that have been subject to emergency cancellation. #[pallet::storage] - pub type Cancellations = StorageMap<_, Identity, T::Hash, bool, ValueQuery>; - - /// Storage version of the pallet. - /// - /// New networks start with last version. - #[pallet::storage] - pub(crate) type StorageVersion = StorageValue<_, Releases>; + pub type Cancellations = StorageMap<_, Identity, H256, bool, ValueQuery>; #[pallet::genesis_config] pub struct GenesisConfig { @@ -488,7 +443,6 @@ pub mod pallet { PublicPropCount::::put(0 as PropIndex); ReferendumCount::::put(0 as ReferendumIndex); LowestUnbaked::::put(0 as ReferendumIndex); - StorageVersion::::put(Releases::V1); } } @@ -498,7 +452,7 @@ pub mod pallet { /// A motion has been proposed by a public account. Proposed { proposal_index: PropIndex, deposit: BalanceOf }, /// A public proposal has been tabled for referendum vote. - Tabled { proposal_index: PropIndex, deposit: BalanceOf, depositors: Vec }, + Tabled { proposal_index: PropIndex, deposit: BalanceOf }, /// An external proposal has been tabled. ExternalTabled, /// A referendum has begun. @@ -509,31 +463,14 @@ pub mod pallet { NotPassed { ref_index: ReferendumIndex }, /// A referendum has been cancelled. Cancelled { ref_index: ReferendumIndex }, - /// A proposal has been enacted. - Executed { ref_index: ReferendumIndex, result: DispatchResult }, /// An account has delegated their vote to another account. Delegated { who: T::AccountId, target: T::AccountId }, /// An account has cancelled a previous delegation operation. Undelegated { account: T::AccountId }, /// An external proposal has been vetoed. - Vetoed { who: T::AccountId, proposal_hash: T::Hash, until: T::BlockNumber }, - /// A proposal's preimage was noted, and the deposit taken. - PreimageNoted { proposal_hash: T::Hash, who: T::AccountId, deposit: BalanceOf }, - /// A proposal preimage was removed and used (the deposit was returned). - PreimageUsed { proposal_hash: T::Hash, provider: T::AccountId, deposit: BalanceOf }, - /// A proposal could not be executed because its preimage was invalid. - PreimageInvalid { proposal_hash: T::Hash, ref_index: ReferendumIndex }, - /// A proposal could not be executed because its preimage was missing. - PreimageMissing { proposal_hash: T::Hash, ref_index: ReferendumIndex }, - /// A registered preimage was removed and the deposit collected by the reaper. - PreimageReaped { - proposal_hash: T::Hash, - provider: T::AccountId, - deposit: BalanceOf, - reaper: T::AccountId, - }, + Vetoed { who: T::AccountId, proposal_hash: H256, until: T::BlockNumber }, /// A proposal_hash has been blacklisted permanently. - Blacklisted { proposal_hash: T::Hash }, + Blacklisted { proposal_hash: H256 }, /// An account has voted in a referendum Voted { voter: T::AccountId, ref_index: ReferendumIndex, vote: AccountVote> }, /// An account has secconded a proposal @@ -562,20 +499,8 @@ pub mod pallet { NoProposal, /// Identity may not veto a proposal twice AlreadyVetoed, - /// Preimage already noted - DuplicatePreimage, - /// Not imminent - NotImminent, - /// Too early - TooEarly, - /// Imminent - Imminent, - /// Preimage not found - PreimageMissing, /// Vote given for invalid referendum ReferendumInvalid, - /// Invalid preimage - PreimageInvalid, /// No proposals waiting NoneWaiting, /// The given account did not vote on the referendum. @@ -599,8 +524,8 @@ pub mod pallet { WrongUpperBound, /// Maximum number of votes reached. MaxVotesReached, - /// Maximum number of proposals reached. - TooManyProposals, + /// Maximum number of items reached. + TooMany, /// Voting period too low VotingPeriodLow, } @@ -624,12 +549,10 @@ pub mod pallet { /// - `value`: The amount of deposit (must be at least `MinimumDeposit`). /// /// Emits `Proposed`. - /// - /// Weight: `O(p)` #[pallet::weight(T::WeightInfo::propose())] pub fn propose( origin: OriginFor, - proposal_hash: T::Hash, + proposal: BoundedCallOf, #[pallet::compact] value: BalanceOf, ) -> DispatchResult { let who = ensure_signed(origin)?; @@ -638,7 +561,8 @@ pub mod pallet { let index = Self::public_prop_count(); let real_prop_count = PublicProps::::decode_len().unwrap_or(0) as u32; let max_proposals = T::MaxProposals::get(); - ensure!(real_prop_count < max_proposals, Error::::TooManyProposals); + ensure!(real_prop_count < max_proposals, Error::::TooMany); + let proposal_hash = proposal.hash(); if let Some((until, _)) = >::get(proposal_hash) { ensure!( @@ -648,10 +572,14 @@ pub mod pallet { } T::Currency::reserve(&who, value)?; + + let depositors = BoundedVec::<_, T::MaxDeposits>::truncate_from(vec![who.clone()]); + DepositOf::::insert(index, (depositors, value)); + PublicPropCount::::put(index + 1); - >::insert(index, (&[&who][..], value)); - >::append((index, proposal_hash, who)); + PublicProps::::try_append((index, proposal, who)) + .map_err(|_| Error::::TooMany)?; Self::deposit_event(Event::::Proposed { proposal_index: index, deposit: value }); Ok(()) @@ -663,23 +591,19 @@ pub mod pallet { /// must have funds to cover the deposit, equal to the original deposit. /// /// - `proposal`: The index of the proposal to second. - /// - `seconds_upper_bound`: an upper bound on the current number of seconds on this - /// proposal. Extrinsic is weighted according to this value with no refund. - /// - /// Weight: `O(S)` where S is the number of seconds a proposal already has. - #[pallet::weight(T::WeightInfo::second(*seconds_upper_bound))] + #[pallet::weight(T::WeightInfo::second())] pub fn second( origin: OriginFor, #[pallet::compact] proposal: PropIndex, - #[pallet::compact] seconds_upper_bound: u32, ) -> DispatchResult { let who = ensure_signed(origin)?; let seconds = Self::len_of_deposit_of(proposal).ok_or(Error::::ProposalMissing)?; - ensure!(seconds <= seconds_upper_bound, Error::::WrongUpperBound); + ensure!(seconds < T::MaxDeposits::get(), Error::::TooMany); let mut deposit = Self::deposit_of(proposal).ok_or(Error::::ProposalMissing)?; T::Currency::reserve(&who, deposit.1)?; - deposit.0.push(who.clone()); + let ok = deposit.0.try_push(who.clone()).is_ok(); + debug_assert!(ok, "`seconds` is below static limit; `try_insert` should succeed; qed"); >::insert(proposal, deposit); Self::deposit_event(Event::::Seconded { seconder: who, prop_index: proposal }); Ok(()) @@ -692,12 +616,7 @@ pub mod pallet { /// /// - `ref_index`: The index of the referendum to vote for. /// - `vote`: The vote configuration. - /// - /// Weight: `O(R)` where R is the number of referendums the voter has voted on. - #[pallet::weight( - T::WeightInfo::vote_new(T::MaxVotes::get()) - .max(T::WeightInfo::vote_existing(T::MaxVotes::get())) - )] + #[pallet::weight(T::WeightInfo::vote_new().max(T::WeightInfo::vote_existing()))] pub fn vote( origin: OriginFor, #[pallet::compact] ref_index: ReferendumIndex, @@ -723,7 +642,7 @@ pub mod pallet { T::CancellationOrigin::ensure_origin(origin)?; let status = Self::referendum_status(ref_index)?; - let h = status.proposal_hash; + let h = status.proposal.hash(); ensure!(!>::contains_key(h), Error::::AlreadyCanceled); >::insert(h, true); @@ -737,20 +656,20 @@ pub mod pallet { /// The dispatch origin of this call must be `ExternalOrigin`. /// /// - `proposal_hash`: The preimage hash of the proposal. - /// - /// Weight: `O(V)` with V number of vetoers in the blacklist of proposal. - /// Decoding vec of length V. Charged as maximum - #[pallet::weight(T::WeightInfo::external_propose(MAX_VETOERS))] - pub fn external_propose(origin: OriginFor, proposal_hash: T::Hash) -> DispatchResult { + #[pallet::weight(T::WeightInfo::external_propose())] + pub fn external_propose( + origin: OriginFor, + proposal: BoundedCallOf, + ) -> DispatchResult { T::ExternalOrigin::ensure_origin(origin)?; ensure!(!>::exists(), Error::::DuplicateProposal); - if let Some((until, _)) = >::get(proposal_hash) { + if let Some((until, _)) = >::get(proposal.hash()) { ensure!( >::block_number() >= until, Error::::ProposalBlacklisted, ); } - >::put((proposal_hash, VoteThreshold::SuperMajorityApprove)); + >::put((proposal, VoteThreshold::SuperMajorityApprove)); Ok(()) } @@ -768,10 +687,10 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::external_propose_majority())] pub fn external_propose_majority( origin: OriginFor, - proposal_hash: T::Hash, + proposal: BoundedCallOf, ) -> DispatchResult { T::ExternalMajorityOrigin::ensure_origin(origin)?; - >::put((proposal_hash, VoteThreshold::SimpleMajority)); + >::put((proposal, VoteThreshold::SimpleMajority)); Ok(()) } @@ -789,10 +708,10 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::external_propose_default())] pub fn external_propose_default( origin: OriginFor, - proposal_hash: T::Hash, + proposal: BoundedCallOf, ) -> DispatchResult { T::ExternalDefaultOrigin::ensure_origin(origin)?; - >::put((proposal_hash, VoteThreshold::SuperMajorityAgainst)); + >::put((proposal, VoteThreshold::SuperMajorityAgainst)); Ok(()) } @@ -803,7 +722,7 @@ pub mod pallet { /// The dispatch of this call must be `FastTrackOrigin`. /// /// - `proposal_hash`: The hash of the current external proposal. - /// - `voting_period`: The period that is allowed for voting on this proposal. + /// - `voting_period`: The period that is allowed for voting on this proposal. Increased to /// Must be always greater than zero. /// For `FastTrackOrigin` must be equal or greater than `FastTrackVotingPeriod`. /// - `delay`: The number of block after voting has ended in approval and this should be @@ -815,7 +734,7 @@ pub mod pallet { #[pallet::weight(T::WeightInfo::fast_track())] pub fn fast_track( origin: OriginFor, - proposal_hash: T::Hash, + proposal_hash: H256, voting_period: T::BlockNumber, delay: T::BlockNumber, ) -> DispatchResult { @@ -834,20 +753,21 @@ pub mod pallet { T::InstantOrigin::ensure_origin(ensure_instant)?; ensure!(T::InstantAllowed::get(), Error::::InstantNotAllowed); } + ensure!(voting_period > T::BlockNumber::zero(), Error::::VotingPeriodLow); - let (e_proposal_hash, threshold) = + let (ext_proposal, threshold) = >::get().ok_or(Error::::ProposalMissing)?; ensure!( threshold != VoteThreshold::SuperMajorityApprove, Error::::NotSimpleMajority, ); - ensure!(proposal_hash == e_proposal_hash, Error::::InvalidHash); + ensure!(proposal_hash == ext_proposal.hash(), Error::::InvalidHash); >::kill(); let now = >::block_number(); Self::inject_referendum( now.saturating_add(voting_period), - proposal_hash, + ext_proposal, threshold, delay, ); @@ -863,22 +783,24 @@ pub mod pallet { /// Emits `Vetoed`. /// /// Weight: `O(V + log(V))` where V is number of `existing vetoers` - #[pallet::weight(T::WeightInfo::veto_external(MAX_VETOERS))] - pub fn veto_external(origin: OriginFor, proposal_hash: T::Hash) -> DispatchResult { + #[pallet::weight(T::WeightInfo::veto_external())] + pub fn veto_external(origin: OriginFor, proposal_hash: H256) -> DispatchResult { let who = T::VetoOrigin::ensure_origin(origin)?; - if let Some((e_proposal_hash, _)) = >::get() { - ensure!(proposal_hash == e_proposal_hash, Error::::ProposalMissing); + if let Some((ext_proposal, _)) = NextExternal::::get() { + ensure!(proposal_hash == ext_proposal.hash(), Error::::ProposalMissing); } else { return Err(Error::::NoProposal.into()) } let mut existing_vetoers = - >::get(&proposal_hash).map(|pair| pair.1).unwrap_or_else(Vec::new); + >::get(&proposal_hash).map(|pair| pair.1).unwrap_or_default(); let insert_position = existing_vetoers.binary_search(&who).err().ok_or(Error::::AlreadyVetoed)?; + existing_vetoers + .try_insert(insert_position, who.clone()) + .map_err(|_| Error::::TooMany)?; - existing_vetoers.insert(insert_position, who.clone()); let until = >::block_number().saturating_add(T::CooloffPeriod::get()); >::insert(&proposal_hash, (until, existing_vetoers)); @@ -905,21 +827,6 @@ pub mod pallet { Ok(()) } - /// Cancel a proposal queued for enactment. - /// - /// The dispatch origin of this call must be _Root_. - /// - /// - `which`: The index of the referendum to cancel. - /// - /// Weight: `O(D)` where `D` is the items in the dispatch queue. Weighted as `D = 10`. - #[pallet::weight((T::WeightInfo::cancel_queued(10), DispatchClass::Operational))] - pub fn cancel_queued(origin: OriginFor, which: ReferendumIndex) -> DispatchResult { - ensure_root(origin)?; - T::Scheduler::cancel_named((DEMOCRACY_ID, which).encode()) - .map_err(|_| Error::::ProposalMissing)?; - Ok(()) - } - /// Delegate the voting power (with some given conviction) of the sending account. /// /// The balance delegated is locked for as long as it's delegated, and thereafter for the @@ -989,135 +896,6 @@ pub mod pallet { Ok(()) } - /// Register the preimage for an upcoming proposal. This doesn't require the proposal to be - /// in the dispatch queue but does require a deposit, returned once enacted. - /// - /// The dispatch origin of this call must be _Signed_. - /// - /// - `encoded_proposal`: The preimage of a proposal. - /// - /// Emits `PreimageNoted`. - /// - /// Weight: `O(E)` with E size of `encoded_proposal` (protected by a required deposit). - #[pallet::weight(T::WeightInfo::note_preimage(encoded_proposal.len() as u32))] - pub fn note_preimage(origin: OriginFor, encoded_proposal: Vec) -> DispatchResult { - Self::note_preimage_inner(ensure_signed(origin)?, encoded_proposal)?; - Ok(()) - } - - /// Same as `note_preimage` but origin is `OperationalPreimageOrigin`. - #[pallet::weight(( - T::WeightInfo::note_preimage(encoded_proposal.len() as u32), - DispatchClass::Operational, - ))] - pub fn note_preimage_operational( - origin: OriginFor, - encoded_proposal: Vec, - ) -> DispatchResult { - let who = T::OperationalPreimageOrigin::ensure_origin(origin)?; - Self::note_preimage_inner(who, encoded_proposal)?; - Ok(()) - } - - /// Register the preimage for an upcoming proposal. This requires the proposal to be - /// in the dispatch queue. No deposit is needed. When this call is successful, i.e. - /// the preimage has not been uploaded before and matches some imminent proposal, - /// no fee is paid. - /// - /// The dispatch origin of this call must be _Signed_. - /// - /// - `encoded_proposal`: The preimage of a proposal. - /// - /// Emits `PreimageNoted`. - /// - /// Weight: `O(E)` with E size of `encoded_proposal` (protected by a required deposit). - #[pallet::weight(T::WeightInfo::note_imminent_preimage(encoded_proposal.len() as u32))] - pub fn note_imminent_preimage( - origin: OriginFor, - encoded_proposal: Vec, - ) -> DispatchResultWithPostInfo { - Self::note_imminent_preimage_inner(ensure_signed(origin)?, encoded_proposal)?; - // We check that this preimage was not uploaded before in - // `note_imminent_preimage_inner`, thus this call can only be successful once. If - // successful, user does not pay a fee. - Ok(Pays::No.into()) - } - - /// Same as `note_imminent_preimage` but origin is `OperationalPreimageOrigin`. - #[pallet::weight(( - T::WeightInfo::note_imminent_preimage(encoded_proposal.len() as u32), - DispatchClass::Operational, - ))] - pub fn note_imminent_preimage_operational( - origin: OriginFor, - encoded_proposal: Vec, - ) -> DispatchResultWithPostInfo { - let who = T::OperationalPreimageOrigin::ensure_origin(origin)?; - Self::note_imminent_preimage_inner(who, encoded_proposal)?; - // We check that this preimage was not uploaded before in - // `note_imminent_preimage_inner`, thus this call can only be successful once. If - // successful, user does not pay a fee. - Ok(Pays::No.into()) - } - - /// Remove an expired proposal preimage and collect the deposit. - /// - /// The dispatch origin of this call must be _Signed_. - /// - /// - `proposal_hash`: The preimage hash of a proposal. - /// - `proposal_length_upper_bound`: an upper bound on length of the proposal. Extrinsic is - /// weighted according to this value with no refund. - /// - /// This will only work after `VotingPeriod` blocks from the time that the preimage was - /// noted, if it's the same account doing it. If it's a different account, then it'll only - /// work an additional `EnactmentPeriod` later. - /// - /// Emits `PreimageReaped`. - /// - /// Weight: `O(D)` where D is length of proposal. - #[pallet::weight(T::WeightInfo::reap_preimage(*proposal_len_upper_bound))] - pub fn reap_preimage( - origin: OriginFor, - proposal_hash: T::Hash, - #[pallet::compact] proposal_len_upper_bound: u32, - ) -> DispatchResult { - let who = ensure_signed(origin)?; - - ensure!( - Self::pre_image_data_len(proposal_hash)? <= proposal_len_upper_bound, - Error::::WrongUpperBound, - ); - - let (provider, deposit, since, expiry) = >::get(&proposal_hash) - .and_then(|m| match m { - PreimageStatus::Available { provider, deposit, since, expiry, .. } => - Some((provider, deposit, since, expiry)), - _ => None, - }) - .ok_or(Error::::PreimageMissing)?; - - let now = >::block_number(); - let (voting, enactment) = (T::VotingPeriod::get(), T::EnactmentPeriod::get()); - let additional = if who == provider { Zero::zero() } else { enactment }; - ensure!( - now >= since.saturating_add(voting).saturating_add(additional), - Error::::TooEarly - ); - ensure!(expiry.map_or(true, |e| now > e), Error::::Imminent); - - let res = - T::Currency::repatriate_reserved(&provider, &who, deposit, BalanceStatus::Free); - debug_assert!(res.is_ok()); - >::remove(&proposal_hash); - Self::deposit_event(Event::::PreimageReaped { - proposal_hash, - provider, - deposit, - reaper: who, - }); - Ok(()) - } - /// Unlock tokens that have an expired lock. /// /// The dispatch origin of this call must be _Signed_. @@ -1125,10 +903,7 @@ pub mod pallet { /// - `target`: The account to remove the lock on. /// /// Weight: `O(R)` with R number of vote of target. - #[pallet::weight( - T::WeightInfo::unlock_set(T::MaxVotes::get()) - .max(T::WeightInfo::unlock_remove(T::MaxVotes::get())) - )] + #[pallet::weight(T::WeightInfo::unlock_set(T::MaxVotes::get()).max(T::WeightInfo::unlock_remove(T::MaxVotes::get())))] pub fn unlock(origin: OriginFor, target: AccountIdLookupOf) -> DispatchResult { ensure_signed(origin)?; let target = T::Lookup::lookup(target)?; @@ -1197,17 +972,6 @@ pub mod pallet { Ok(()) } - /// Enact a proposal from a referendum. For now we just make the weight be the maximum. - #[pallet::weight(T::BlockWeights::get().max_block)] - pub fn enact_proposal( - origin: OriginFor, - proposal_hash: T::Hash, - index: ReferendumIndex, - ) -> DispatchResult { - ensure_root(origin)?; - Self::do_enact_proposal(proposal_hash, index) - } - /// Permanently place a proposal into the blacklist. This prevents it from ever being /// proposed again. /// @@ -1223,21 +987,21 @@ pub mod pallet { /// /// Weight: `O(p)` (though as this is an high-privilege dispatch, we assume it has a /// reasonable value). - #[pallet::weight((T::WeightInfo::blacklist(T::MaxProposals::get()), DispatchClass::Operational))] + #[pallet::weight((T::WeightInfo::blacklist(), DispatchClass::Operational))] pub fn blacklist( origin: OriginFor, - proposal_hash: T::Hash, + proposal_hash: H256, maybe_ref_index: Option, ) -> DispatchResult { T::BlacklistOrigin::ensure_origin(origin)?; // Insert the proposal into the blacklist. - let permanent = (T::BlockNumber::max_value(), Vec::::new()); + let permanent = (T::BlockNumber::max_value(), BoundedVec::::default()); Blacklist::::insert(&proposal_hash, permanent); // Remove the queued proposal, if it's there. PublicProps::::mutate(|props| { - if let Some(index) = props.iter().position(|p| p.1 == proposal_hash) { + if let Some(index) = props.iter().position(|p| p.1.hash() == proposal_hash) { let (prop_index, ..) = props.remove(index); if let Some((whos, amount)) = DepositOf::::take(prop_index) { for who in whos.into_iter() { @@ -1248,14 +1012,14 @@ pub mod pallet { }); // Remove the external queued referendum, if it's there. - if matches!(NextExternal::::get(), Some((h, ..)) if h == proposal_hash) { + if matches!(NextExternal::::get(), Some((p, ..)) if p.hash() == proposal_hash) { NextExternal::::kill(); } // Remove the referendum, if it's there. if let Some(ref_index) = maybe_ref_index { if let Ok(status) = Self::referendum_status(ref_index) { - if status.proposal_hash == proposal_hash { + if status.proposal.hash() == proposal_hash { Self::internal_cancel_referendum(ref_index); } } @@ -1272,7 +1036,7 @@ pub mod pallet { /// - `prop_index`: The index of the proposal to cancel. /// /// Weight: `O(p)` where `p = PublicProps::::decode_len()` - #[pallet::weight(T::WeightInfo::cancel_proposal(T::MaxProposals::get()))] + #[pallet::weight(T::WeightInfo::cancel_proposal())] pub fn cancel_proposal( origin: OriginFor, #[pallet::compact] prop_index: PropIndex, @@ -1292,6 +1056,25 @@ pub mod pallet { } } +pub trait EncodeInto: Encode { + fn encode_into + Default>(&self) -> T { + let mut t = T::default(); + self.using_encoded(|data| { + if data.len() <= t.as_mut().len() { + t.as_mut()[0..data.len()].copy_from_slice(data); + } else { + // encoded self is too big to fit into a T. hash it and use the first bytes of that + // instead. + let hash = sp_io::hashing::blake2_256(data); + let l = t.as_mut().len().min(hash.len()); + t.as_mut()[0..l].copy_from_slice(&hash[0..l]); + } + }); + t + } +} +impl EncodeInto for T {} + impl Pallet { // exposed immutables. @@ -1304,7 +1087,7 @@ impl Pallet { /// Get all referenda ready for tally at block `n`. pub fn maturing_referenda_at( n: T::BlockNumber, - ) -> Vec<(ReferendumIndex, ReferendumStatus>)> { + ) -> Vec<(ReferendumIndex, ReferendumStatus, BalanceOf>)> { let next = Self::lowest_unbaked(); let last = Self::referendum_count(); Self::maturing_referenda_at_inner(n, next..last) @@ -1313,7 +1096,7 @@ impl Pallet { fn maturing_referenda_at_inner( n: T::BlockNumber, range: core::ops::Range, - ) -> Vec<(ReferendumIndex, ReferendumStatus>)> { + ) -> Vec<(ReferendumIndex, ReferendumStatus, BalanceOf>)> { range .into_iter() .map(|i| (i, Self::referendum_info(i))) @@ -1329,13 +1112,13 @@ impl Pallet { /// Start a referendum. pub fn internal_start_referendum( - proposal_hash: T::Hash, + proposal: BoundedCallOf, threshold: VoteThreshold, delay: T::BlockNumber, ) -> ReferendumIndex { >::inject_referendum( >::block_number().saturating_add(T::VotingPeriod::get()), - proposal_hash, + proposal, threshold, delay, ) @@ -1351,8 +1134,8 @@ impl Pallet { /// Ok if the given referendum is active, Err otherwise fn ensure_ongoing( - r: ReferendumInfo>, - ) -> Result>, DispatchError> { + r: ReferendumInfo, BalanceOf>, + ) -> Result, BalanceOf>, DispatchError> { match r { ReferendumInfo::Ongoing(s) => Ok(s), _ => Err(Error::::ReferendumInvalid.into()), @@ -1361,7 +1144,7 @@ impl Pallet { fn referendum_status( ref_index: ReferendumIndex, - ) -> Result>, DispatchError> { + ) -> Result, BalanceOf>, DispatchError> { let info = ReferendumInfoOf::::get(ref_index).ok_or(Error::::ReferendumInvalid)?; Self::ensure_ongoing(info) } @@ -1386,11 +1169,9 @@ impl Pallet { votes[i].1 = vote; }, Err(i) => { - ensure!( - votes.len() as u32 <= T::MaxVotes::get(), - Error::::MaxVotesReached - ); - votes.insert(i, (ref_index, vote)); + votes + .try_insert(i, (ref_index, vote)) + .map_err(|_| Error::::MaxVotesReached)?; }, } Self::deposit_event(Event::::Voted { voter: who.clone(), ref_index, vote }); @@ -1604,14 +1385,14 @@ impl Pallet { /// Start a referendum fn inject_referendum( end: T::BlockNumber, - proposal_hash: T::Hash, + proposal: BoundedCallOf, threshold: VoteThreshold, delay: T::BlockNumber, ) -> ReferendumIndex { let ref_index = Self::referendum_count(); ReferendumCount::::put(ref_index + 1); let status = - ReferendumStatus { end, proposal_hash, threshold, delay, tally: Default::default() }; + ReferendumStatus { end, proposal, threshold, delay, tally: Default::default() }; let item = ReferendumInfo::Ongoing(status); >::insert(ref_index, item); Self::deposit_event(Event::::Started { ref_index, threshold }); @@ -1657,14 +1438,10 @@ impl Pallet { if let Some((depositors, deposit)) = >::take(prop_index) { // refund depositors - for d in &depositors { + for d in depositors.iter() { T::Currency::unreserve(d, deposit); } - Self::deposit_event(Event::::Tabled { - proposal_index: prop_index, - deposit, - depositors, - }); + Self::deposit_event(Event::::Tabled { proposal_index: prop_index, deposit }); Self::inject_referendum( now.saturating_add(T::VotingPeriod::get()), proposal, @@ -1678,71 +1455,35 @@ impl Pallet { } } - fn do_enact_proposal(proposal_hash: T::Hash, index: ReferendumIndex) -> DispatchResult { - let preimage = >::take(&proposal_hash); - if let Some(PreimageStatus::Available { data, provider, deposit, .. }) = preimage { - if let Ok(proposal) = T::Proposal::decode(&mut &data[..]) { - let err_amount = T::Currency::unreserve(&provider, deposit); - debug_assert!(err_amount.is_zero()); - Self::deposit_event(Event::::PreimageUsed { proposal_hash, provider, deposit }); - - let res = proposal - .dispatch(frame_system::RawOrigin::Root.into()) - .map(|_| ()) - .map_err(|e| e.error); - Self::deposit_event(Event::::Executed { ref_index: index, result: res }); - - Ok(()) - } else { - T::Slash::on_unbalanced(T::Currency::slash_reserved(&provider, deposit).0); - Self::deposit_event(Event::::PreimageInvalid { - proposal_hash, - ref_index: index, - }); - Err(Error::::PreimageInvalid.into()) - } - } else { - Self::deposit_event(Event::::PreimageMissing { proposal_hash, ref_index: index }); - Err(Error::::PreimageMissing.into()) - } - } - fn bake_referendum( now: T::BlockNumber, index: ReferendumIndex, - status: ReferendumStatus>, + status: ReferendumStatus, BalanceOf>, ) -> bool { let total_issuance = T::Currency::total_issuance(); let approved = status.threshold.approved(status.tally, total_issuance); if approved { Self::deposit_event(Event::::Passed { ref_index: index }); - if status.delay.is_zero() { - let _ = Self::do_enact_proposal(status.proposal_hash, index); - } else { - let when = now.saturating_add(status.delay); - // Note that we need the preimage now. - Preimages::::mutate_exists( - &status.proposal_hash, - |maybe_pre| match *maybe_pre { - Some(PreimageStatus::Available { ref mut expiry, .. }) => - *expiry = Some(when), - ref mut a => *a = Some(PreimageStatus::Missing(when)), - }, - ); - - if T::Scheduler::schedule_named( - (DEMOCRACY_ID, index).encode(), - DispatchTime::At(when), - None, - 63, - frame_system::RawOrigin::Root.into(), - Call::enact_proposal { proposal_hash: status.proposal_hash, index }.into(), - ) - .is_err() - { - frame_support::print("LOGIC ERROR: bake_referendum/schedule_named failed"); - } + // Actually `hold` the proposal now since we didn't hold it when it came in via the + // submit extrinsic and we now know that it will be needed. This will be reversed by + // Scheduler pallet once it is executed which assumes that we will already have placed + // a `hold` on it. + T::Preimages::hold(&status.proposal); + + // Earliest it can be scheduled for is next block. + let when = now.saturating_add(status.delay.max(One::one())); + if T::Scheduler::schedule_named( + (DEMOCRACY_ID, index).encode_into(), + DispatchTime::At(when), + None, + 63, + frame_system::RawOrigin::Root.into(), + status.proposal, + ) + .is_err() + { + frame_support::print("LOGIC ERROR: bake_referendum/schedule_named failed"); } } else { Self::deposit_event(Event::::NotPassed { ref_index: index }); @@ -1778,11 +1519,10 @@ impl Pallet { if Self::launch_next(now).is_ok() { weight = max_block_weight; } else { - weight = - weight.saturating_add(T::WeightInfo::on_initialize_base_with_launch_period(r)); + weight.saturating_accrue(T::WeightInfo::on_initialize_base_with_launch_period(r)); } } else { - weight = weight.saturating_add(T::WeightInfo::on_initialize_base(r)); + weight.saturating_accrue(T::WeightInfo::on_initialize_base(r)); } // tally up votes for any expiring referenda. @@ -1793,8 +1533,8 @@ impl Pallet { } // Notes: - // * We don't consider the lowest unbaked to be the last maturing in case some refendum have - // longer voting period than others. + // * We don't consider the lowest unbaked to be the last maturing in case some referenda + // have a longer voting period than others. // * The iteration here shouldn't trigger any storage read that are not in cache, due to // `maturing_referenda_at_inner` having already read them. // * We shouldn't iterate more than `LaunchPeriod/VotingPeriod + 1` times because the number @@ -1820,116 +1560,6 @@ impl Pallet { // `Compact`. decode_compact_u32_at(&>::hashed_key_for(proposal)) } - - /// Check that pre image exists and its value is variant `PreimageStatus::Missing`. - /// - /// This check is done without getting the complete value in the runtime to avoid copying a big - /// value in the runtime. - fn check_pre_image_is_missing(proposal_hash: T::Hash) -> DispatchResult { - // To decode the enum variant we only need the first byte. - let mut buf = [0u8; 1]; - let key = >::hashed_key_for(proposal_hash); - let bytes = sp_io::storage::read(&key, &mut buf, 0).ok_or(Error::::NotImminent)?; - // The value may be smaller that 1 byte. - let mut input = &buf[0..buf.len().min(bytes as usize)]; - - match input.read_byte() { - Ok(0) => Ok(()), // PreimageStatus::Missing is variant 0 - Ok(1) => Err(Error::::DuplicatePreimage.into()), - _ => { - sp_runtime::print("Failed to decode `PreimageStatus` variant"); - Err(Error::::NotImminent.into()) - }, - } - } - - /// Check that pre image exists, its value is variant `PreimageStatus::Available` and decode - /// the length of `data: Vec` fields. - /// - /// This check is done without getting the complete value in the runtime to avoid copying a big - /// value in the runtime. - /// - /// If the pre image is missing variant or doesn't exist then the error `PreimageMissing` is - /// returned. - fn pre_image_data_len(proposal_hash: T::Hash) -> Result { - // To decode the `data` field of Available variant we need: - // * one byte for the variant - // * at most 5 bytes to decode a `Compact` - let mut buf = [0u8; 6]; - let key = >::hashed_key_for(proposal_hash); - let bytes = sp_io::storage::read(&key, &mut buf, 0).ok_or(Error::::PreimageMissing)?; - // The value may be smaller that 6 bytes. - let mut input = &buf[0..buf.len().min(bytes as usize)]; - - match input.read_byte() { - Ok(1) => (), // Check that input exists and is second variant. - Ok(0) => return Err(Error::::PreimageMissing.into()), - _ => { - sp_runtime::print("Failed to decode `PreimageStatus` variant"); - return Err(Error::::PreimageMissing.into()) - }, - } - - // Decode the length of the vector. - let len = codec::Compact::::decode(&mut input) - .map_err(|_| { - sp_runtime::print("Failed to decode `PreimageStatus` variant"); - DispatchError::from(Error::::PreimageMissing) - })? - .0; - - Ok(len) - } - - // See `note_preimage` - fn note_preimage_inner(who: T::AccountId, encoded_proposal: Vec) -> DispatchResult { - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - ensure!(!>::contains_key(&proposal_hash), Error::::DuplicatePreimage); - - let deposit = >::from(encoded_proposal.len() as u32) - .saturating_mul(T::PreimageByteDeposit::get()); - T::Currency::reserve(&who, deposit)?; - - let now = >::block_number(); - let a = PreimageStatus::Available { - data: encoded_proposal, - provider: who.clone(), - deposit, - since: now, - expiry: None, - }; - >::insert(proposal_hash, a); - - Self::deposit_event(Event::::PreimageNoted { proposal_hash, who, deposit }); - - Ok(()) - } - - // See `note_imminent_preimage` - fn note_imminent_preimage_inner( - who: T::AccountId, - encoded_proposal: Vec, - ) -> DispatchResult { - let proposal_hash = T::Hashing::hash(&encoded_proposal[..]); - Self::check_pre_image_is_missing(proposal_hash)?; - let status = Preimages::::get(&proposal_hash).ok_or(Error::::NotImminent)?; - let expiry = status.to_missing_expiry().ok_or(Error::::DuplicatePreimage)?; - - let now = >::block_number(); - let free = >::zero(); - let a = PreimageStatus::Available { - data: encoded_proposal, - provider: who.clone(), - deposit: Zero::zero(), - since: now, - expiry: Some(expiry), - }; - >::insert(proposal_hash, a); - - Self::deposit_event(Event::::PreimageNoted { proposal_hash, who, deposit: free }); - - Ok(()) - } } /// Decode `Compact` from the trie at given key. diff --git a/frame/democracy/src/migrations.rs b/frame/democracy/src/migrations.rs new file mode 100644 index 0000000000000..3ec249c1d981c --- /dev/null +++ b/frame/democracy/src/migrations.rs @@ -0,0 +1,236 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Storage migrations for the preimage pallet. + +use super::*; +use frame_support::{pallet_prelude::*, storage_alias, traits::OnRuntimeUpgrade, BoundedVec}; +use sp_core::H256; + +/// The log target. +const TARGET: &'static str = "runtime::democracy::migration::v1"; + +/// The original data layout of the democracy pallet without a specific version number. +mod v0 { + use super::*; + + #[storage_alias] + pub type PublicProps = StorageValue< + Pallet, + Vec<(PropIndex, ::Hash, ::AccountId)>, + ValueQuery, + >; + + #[storage_alias] + pub type NextExternal = + StorageValue, (::Hash, VoteThreshold)>; + + #[cfg(feature = "try-runtime")] + #[storage_alias] + pub type ReferendumInfoOf = StorageMap< + Pallet, + frame_support::Twox64Concat, + ReferendumIndex, + ReferendumInfo< + ::BlockNumber, + ::Hash, + BalanceOf, + >, + >; +} + +pub mod v1 { + use super::*; + + /// Migration for translating bare `Hash`es into `Bounded`s. + pub struct Migration(sp_std::marker::PhantomData); + + impl> OnRuntimeUpgrade for Migration { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + assert_eq!(StorageVersion::get::>(), 0, "can only upgrade from version 0"); + + let props_count = v0::PublicProps::::get().len(); + log::info!(target: TARGET, "{} public proposals will be migrated.", props_count,); + ensure!(props_count <= T::MaxProposals::get() as usize, "too many proposals"); + + let referenda_count = v0::ReferendumInfoOf::::iter().count(); + log::info!(target: TARGET, "{} referenda will be migrated.", referenda_count); + + Ok((props_count as u32, referenda_count as u32).encode()) + } + + #[allow(deprecated)] + fn on_runtime_upgrade() -> Weight { + let mut weight = T::DbWeight::get().reads(1); + if StorageVersion::get::>() != 0 { + log::warn!( + target: TARGET, + "skipping on_runtime_upgrade: executed on wrong storage version.\ + Expected version 0" + ); + return weight + } + + ReferendumInfoOf::::translate( + |index, old: ReferendumInfo>| { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + log::info!(target: TARGET, "migrating referendum #{:?}", &index); + Some(match old { + ReferendumInfo::Ongoing(status) => + ReferendumInfo::Ongoing(ReferendumStatus { + end: status.end, + proposal: Bounded::from_legacy_hash(status.proposal), + threshold: status.threshold, + delay: status.delay, + tally: status.tally, + }), + ReferendumInfo::Finished { approved, end } => + ReferendumInfo::Finished { approved, end }, + }) + }, + ); + + let props = v0::PublicProps::::take() + .into_iter() + .map(|(i, hash, a)| (i, Bounded::from_legacy_hash(hash), a)) + .collect::>(); + let bounded = BoundedVec::<_, T::MaxProposals>::truncate_from(props.clone()); + PublicProps::::put(bounded); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + + if props.len() as u32 > T::MaxProposals::get() { + log::error!( + target: TARGET, + "truncated {} public proposals to {}; continuing", + props.len(), + T::MaxProposals::get() + ); + } + + if let Some((hash, threshold)) = v0::NextExternal::::take() { + log::info!(target: TARGET, "migrating next external proposal"); + NextExternal::::put((Bounded::from_legacy_hash(hash), threshold)); + } + + StorageVersion::new(1).put::>(); + + weight.saturating_add(T::DbWeight::get().reads_writes(1, 2)) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + assert_eq!(StorageVersion::get::>(), 1, "must upgrade"); + + let (old_props_count, old_ref_count): (u32, u32) = + Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed"); + let new_props_count = crate::PublicProps::::get().len() as u32; + assert_eq!(new_props_count, old_props_count, "must migrate all public proposals"); + let new_ref_count = crate::ReferendumInfoOf::::iter().count() as u32; + assert_eq!(new_ref_count, old_ref_count, "must migrate all referenda"); + + log::info!( + target: TARGET, + "{} public proposals migrated, {} referenda migrated", + new_props_count, + new_ref_count, + ); + Ok(()) + } + } +} + +#[cfg(test)] +#[cfg(feature = "try-runtime")] +mod test { + use super::*; + use crate::{ + tests::{Test as T, *}, + types::*, + }; + use frame_support::bounded_vec; + + #[allow(deprecated)] + #[test] + fn migration_works() { + new_test_ext().execute_with(|| { + assert_eq!(StorageVersion::get::>(), 0); + // Insert some values into the v0 storage: + + // Case 1: Ongoing referendum + let hash = H256::repeat_byte(1); + let status = ReferendumStatus { + end: 1u32.into(), + proposal: hash.clone(), + threshold: VoteThreshold::SuperMajorityApprove, + delay: 1u32.into(), + tally: Tally { ayes: 1u32.into(), nays: 1u32.into(), turnout: 1u32.into() }, + }; + v0::ReferendumInfoOf::::insert(1u32, ReferendumInfo::Ongoing(status)); + + // Case 2: Finished referendum + v0::ReferendumInfoOf::::insert( + 2u32, + ReferendumInfo::Finished { approved: true, end: 123u32.into() }, + ); + + // Case 3: Public proposals + let hash2 = H256::repeat_byte(2); + v0::PublicProps::::put(vec![ + (3u32, hash.clone(), 123u64), + (4u32, hash2.clone(), 123u64), + ]); + + // Case 4: Next external + v0::NextExternal::::put((hash.clone(), VoteThreshold::SuperMajorityApprove)); + + // Migrate. + let state = v1::Migration::::pre_upgrade().unwrap(); + let _weight = v1::Migration::::on_runtime_upgrade(); + v1::Migration::::post_upgrade(state).unwrap(); + // Check that all values got migrated. + + // Case 1: Ongoing referendum + assert_eq!( + ReferendumInfoOf::::get(1u32), + Some(ReferendumInfo::Ongoing(ReferendumStatus { + end: 1u32.into(), + proposal: Bounded::from_legacy_hash(hash), + threshold: VoteThreshold::SuperMajorityApprove, + delay: 1u32.into(), + tally: Tally { ayes: 1u32.into(), nays: 1u32.into(), turnout: 1u32.into() }, + })) + ); + // Case 2: Finished referendum + assert_eq!( + ReferendumInfoOf::::get(2u32), + Some(ReferendumInfo::Finished { approved: true, end: 123u32.into() }) + ); + // Case 3: Public proposals + let props: BoundedVec<_, ::MaxProposals> = bounded_vec![ + (3u32, Bounded::from_legacy_hash(hash), 123u64), + (4u32, Bounded::from_legacy_hash(hash2), 123u64) + ]; + assert_eq!(PublicProps::::get(), props); + // Case 4: Next external + assert_eq!( + NextExternal::::get(), + Some((Bounded::from_legacy_hash(hash), VoteThreshold::SuperMajorityApprove)) + ); + }); + } +} diff --git a/frame/democracy/src/tests.rs b/frame/democracy/src/tests.rs index def8f84067909..eceb1a3400bba 100644 --- a/frame/democracy/src/tests.rs +++ b/frame/democracy/src/tests.rs @@ -19,11 +19,11 @@ use super::*; use crate as pallet_democracy; -use codec::Encode; use frame_support::{ assert_noop, assert_ok, ord_parameter_types, parameter_types, traits::{ - ConstU32, ConstU64, Contains, EqualPrivilegeOnly, GenesisBuild, OnInitialize, SortedMembers, + ConstU32, ConstU64, Contains, EqualPrivilegeOnly, GenesisBuild, OnInitialize, + SortedMembers, StorePreimage, }, weights::Weight, }; @@ -35,14 +35,12 @@ use sp_runtime::{ traits::{BadOrigin, BlakeTwo256, IdentityLookup}, Perbill, }; - mod cancellation; mod decoders; mod delegation; mod external_proposing; mod fast_tracking; mod lock_voting; -mod preimage; mod public_proposals; mod scheduling; mod voting; @@ -63,6 +61,7 @@ frame_support::construct_runtime!( { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + Preimage: pallet_preimage, Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event}, Democracy: pallet_democracy::{Pallet, Call, Storage, Config, Event}, } @@ -70,31 +69,31 @@ frame_support::construct_runtime!( // Test that a fitlered call can be dispatched. pub struct BaseFilter; -impl Contains for BaseFilter { - fn contains(call: &Call) -> bool { - !matches!(call, &Call::Balances(pallet_balances::Call::set_balance { .. })) +impl Contains for BaseFilter { + fn contains(call: &RuntimeCall) -> bool { + !matches!(call, &RuntimeCall::Balances(pallet_balances::Call::set_balance { .. })) } } parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(Weight::from_ref_time(1_000_000)); + frame_system::limits::BlockWeights::simple_max(frame_support::weights::constants::WEIGHT_PER_SECOND.set_proof_size(u64::MAX)); } impl frame_system::Config for Test { type BaseCallFilter = BaseFilter; - type BlockWeights = (); + type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -109,18 +108,27 @@ impl frame_system::Config for Test { parameter_types! { pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; } + +impl pallet_preimage::Config for Test { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type BaseDeposit = ConstU64<0>; + type ByteDeposit = ConstU64<0>; +} + impl pallet_scheduler::Config for Test { - type Event = Event; - type Origin = Origin; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; type PalletsOrigin = OriginCaller; - type Call = Call; + type RuntimeCall = RuntimeCall; type MaximumWeight = MaximumSchedulerWeight; type ScheduleOrigin = EnsureRoot; - type MaxScheduledPerBlock = (); + type MaxScheduledPerBlock = ConstU32<100>; type WeightInfo = (); type OriginPrivilegeCmp = EqualPrivilegeOnly; - type PreimageProvider = (); - type NoPreimagePostponement = (); + type Preimages = (); } impl pallet_balances::Config for Test { @@ -128,7 +136,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type MaxLocks = ConstU32<10>; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -156,8 +164,7 @@ impl SortedMembers for OneToFive { } impl Config for Test { - type Proposal = Call; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = pallet_balances::Pallet; type EnactmentPeriod = ConstU64<2>; type LaunchPeriod = ConstU64<2>; @@ -165,6 +172,8 @@ impl Config for Test { type VoteLockingPeriod = ConstU64<3>; type FastTrackVotingPeriod = ConstU64<2>; type MinimumDeposit = ConstU64<1>; + type MaxDeposits = ConstU32<1000>; + type MaxBlacklisted = ConstU32<5>; type ExternalOrigin = EnsureSignedBy; type ExternalMajorityOrigin = EnsureSignedBy; type ExternalDefaultOrigin = EnsureSignedBy; @@ -174,16 +183,15 @@ impl Config for Test { type CancelProposalOrigin = EnsureRoot; type VetoOrigin = EnsureSignedBy; type CooloffPeriod = ConstU64<2>; - type PreimageByteDeposit = PreimageByteDeposit; type Slash = (); type InstantOrigin = EnsureSignedBy; type InstantAllowed = InstantAllowed; type Scheduler = Scheduler; type MaxVotes = ConstU32<100>; - type OperationalPreimageOrigin = EnsureSignedBy; type PalletsOrigin = OriginCaller; type WeightInfo = (); type MaxProposals = ConstU32<100>; + type Preimages = Preimage; } pub fn new_test_ext() -> sp_io::TestExternalities { @@ -201,12 +209,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities { ext } -/// Execute the function two times, with `true` and with `false`. -pub fn new_test_ext_execute_with_cond(execute: impl FnOnce(bool) -> () + Clone) { - new_test_ext().execute_with(|| (execute.clone())(false)); - new_test_ext().execute_with(|| execute(true)); -} - #[test] fn params_should_work() { new_test_ext().execute_with(|| { @@ -216,40 +218,22 @@ fn params_should_work() { }); } -fn set_balance_proposal(value: u64) -> Vec { - Call::Balances(pallet_balances::Call::set_balance { who: 42, new_free: value, new_reserved: 0 }) - .encode() +fn set_balance_proposal(value: u64) -> BoundedCallOf { + let inner = pallet_balances::Call::set_balance { who: 42, new_free: value, new_reserved: 0 }; + let outer = RuntimeCall::Balances(inner); + Preimage::bound(outer).unwrap() } #[test] fn set_balance_proposal_is_correctly_filtered_out() { for i in 0..10 { - let call = Call::decode(&mut &set_balance_proposal(i)[..]).unwrap(); + let call = Preimage::realize(&set_balance_proposal(i)).unwrap().0; assert!(!::BaseCallFilter::contains(&call)); } } -fn set_balance_proposal_hash(value: u64) -> H256 { - BlakeTwo256::hash(&set_balance_proposal(value)[..]) -} - -fn set_balance_proposal_hash_and_note(value: u64) -> H256 { - let p = set_balance_proposal(value); - let h = BlakeTwo256::hash(&p[..]); - match Democracy::note_preimage(Origin::signed(6), p) { - Ok(_) => (), - Err(x) if x == Error::::DuplicatePreimage.into() => (), - Err(x) => panic!("{:?}", x), - } - h -} - fn propose_set_balance(who: u64, value: u64, delay: u64) -> DispatchResult { - Democracy::propose(Origin::signed(who), set_balance_proposal_hash(value), delay) -} - -fn propose_set_balance_and_note(who: u64, value: u64, delay: u64) -> DispatchResult { - Democracy::propose(Origin::signed(who), set_balance_proposal_hash_and_note(value), delay) + Democracy::propose(RuntimeOrigin::signed(who), set_balance_proposal(value), delay) } fn next_block() { @@ -266,7 +250,7 @@ fn fast_forward_to(n: u64) { fn begin_referendum() -> ReferendumIndex { System::set_block_number(0); - assert_ok!(propose_set_balance_and_note(1, 2, 1)); + assert_ok!(propose_set_balance(1, 2, 1)); fast_forward_to(2); 0 } diff --git a/frame/democracy/src/tests/cancellation.rs b/frame/democracy/src/tests/cancellation.rs index 9035e17c5c80b..ff046d612c026 100644 --- a/frame/democracy/src/tests/cancellation.rs +++ b/frame/democracy/src/tests/cancellation.rs @@ -24,12 +24,12 @@ fn cancel_referendum_should_work() { new_test_ext().execute_with(|| { let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); - assert_ok!(Democracy::cancel_referendum(Origin::root(), r.into())); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); + assert_ok!(Democracy::cancel_referendum(RuntimeOrigin::root(), r.into())); assert_eq!(Democracy::lowest_unbaked(), 0); next_block(); @@ -42,54 +42,33 @@ fn cancel_referendum_should_work() { }); } -#[test] -fn cancel_queued_should_work() { - new_test_ext().execute_with(|| { - System::set_block_number(0); - assert_ok!(propose_set_balance_and_note(1, 2, 1)); - - // start of 2 => next referendum scheduled. - fast_forward_to(2); - - assert_ok!(Democracy::vote(Origin::signed(1), 0, aye(1))); - - fast_forward_to(4); - - assert!(pallet_scheduler::Agenda::::get(6)[0].is_some()); - - assert_noop!(Democracy::cancel_queued(Origin::root(), 1), Error::::ProposalMissing); - assert_ok!(Democracy::cancel_queued(Origin::root(), 0)); - assert!(pallet_scheduler::Agenda::::get(6)[0].is_none()); - }); -} - #[test] fn emergency_cancel_should_work() { new_test_ext().execute_with(|| { System::set_block_number(0); let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 2, ); assert!(Democracy::referendum_status(r).is_ok()); - assert_noop!(Democracy::emergency_cancel(Origin::signed(3), r), BadOrigin); - assert_ok!(Democracy::emergency_cancel(Origin::signed(4), r)); + assert_noop!(Democracy::emergency_cancel(RuntimeOrigin::signed(3), r), BadOrigin); + assert_ok!(Democracy::emergency_cancel(RuntimeOrigin::signed(4), r)); assert!(Democracy::referendum_info(r).is_none()); // some time later... let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 2, ); assert!(Democracy::referendum_status(r).is_ok()); assert_noop!( - Democracy::emergency_cancel(Origin::signed(4), r), + Democracy::emergency_cancel(RuntimeOrigin::signed(4), r), Error::::AlreadyCanceled, ); }); diff --git a/frame/democracy/src/tests/decoders.rs b/frame/democracy/src/tests/decoders.rs index 1fbb88060549b..1c8b9c3d980f9 100644 --- a/frame/democracy/src/tests/decoders.rs +++ b/frame/democracy/src/tests/decoders.rs @@ -18,7 +18,10 @@ //! The for various partial storage decoders use super::*; -use frame_support::storage::{migration, unhashed}; +use frame_support::{ + storage::{migration, unhashed}, + BoundedVec, +}; #[test] fn test_decode_compact_u32_at() { @@ -42,7 +45,8 @@ fn test_decode_compact_u32_at() { fn len_of_deposit_of() { new_test_ext().execute_with(|| { for l in vec![0, 1, 200, 1000] { - let value: (Vec, u64) = ((0..l).map(|_| Default::default()).collect(), 3u64); + let value: (BoundedVec, u64) = + ((0..l).map(|_| Default::default()).collect::>().try_into().unwrap(), 3u64); DepositOf::::insert(2, value); assert_eq!(Democracy::len_of_deposit_of(2), Some(l)); } @@ -51,35 +55,3 @@ fn len_of_deposit_of() { assert_eq!(Democracy::len_of_deposit_of(2), None); }) } - -#[test] -fn pre_image() { - new_test_ext().execute_with(|| { - let key = Default::default(); - let missing = PreimageStatus::Missing(0); - Preimages::::insert(key, missing); - assert_noop!(Democracy::pre_image_data_len(key), Error::::PreimageMissing); - assert_eq!(Democracy::check_pre_image_is_missing(key), Ok(())); - - Preimages::::remove(key); - assert_noop!(Democracy::pre_image_data_len(key), Error::::PreimageMissing); - assert_noop!(Democracy::check_pre_image_is_missing(key), Error::::NotImminent); - - for l in vec![0, 10, 100, 1000u32] { - let available = PreimageStatus::Available { - data: (0..l).map(|i| i as u8).collect(), - provider: 0, - deposit: 0, - since: 0, - expiry: None, - }; - - Preimages::::insert(key, available); - assert_eq!(Democracy::pre_image_data_len(key), Ok(l)); - assert_noop!( - Democracy::check_pre_image_is_missing(key), - Error::::DuplicatePreimage - ); - } - }) -} diff --git a/frame/democracy/src/tests/delegation.rs b/frame/democracy/src/tests/delegation.rs index 3551ca8f91123..bca7cb9524112 100644 --- a/frame/democracy/src/tests/delegation.rs +++ b/frame/democracy/src/tests/delegation.rs @@ -24,38 +24,38 @@ fn single_proposal_should_work_with_delegation() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(propose_set_balance_and_note(1, 2, 1)); + assert_ok!(propose_set_balance(1, 2, 1)); fast_forward_to(2); // Delegate first vote. - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::None, 20)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20)); let r = 0; - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); assert_eq!(tally(r), Tally { ayes: 3, nays: 0, turnout: 30 }); // Delegate a second vote. - assert_ok!(Democracy::delegate(Origin::signed(3), 1, Conviction::None, 30)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(3), 1, Conviction::None, 30)); assert_eq!(tally(r), Tally { ayes: 6, nays: 0, turnout: 60 }); // Reduce first vote. - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::None, 10)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 10)); assert_eq!(tally(r), Tally { ayes: 5, nays: 0, turnout: 50 }); // Second vote delegates to first; we don't do tiered delegation, so it doesn't get used. - assert_ok!(Democracy::delegate(Origin::signed(3), 2, Conviction::None, 30)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(3), 2, Conviction::None, 30)); assert_eq!(tally(r), Tally { ayes: 2, nays: 0, turnout: 20 }); // Main voter cancels their vote - assert_ok!(Democracy::remove_vote(Origin::signed(1), r)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(1), r)); assert_eq!(tally(r), Tally { ayes: 0, nays: 0, turnout: 0 }); // First delegator delegates half funds with conviction; nothing changes yet. - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::Locked1x, 10)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::Locked1x, 10)); assert_eq!(tally(r), Tally { ayes: 0, nays: 0, turnout: 0 }); // Main voter reinstates their vote - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); assert_eq!(tally(r), Tally { ayes: 11, nays: 0, turnout: 20 }); }); } @@ -64,7 +64,7 @@ fn single_proposal_should_work_with_delegation() { fn self_delegation_not_allowed() { new_test_ext().execute_with(|| { assert_noop!( - Democracy::delegate(Origin::signed(1), 1, Conviction::None, 10), + Democracy::delegate(RuntimeOrigin::signed(1), 1, Conviction::None, 10), Error::::Nonsense, ); }); @@ -75,19 +75,19 @@ fn cyclic_delegation_should_unwind() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(propose_set_balance_and_note(1, 2, 1)); + assert_ok!(propose_set_balance(1, 2, 1)); fast_forward_to(2); // Check behavior with cycle. - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::None, 20)); - assert_ok!(Democracy::delegate(Origin::signed(3), 2, Conviction::None, 30)); - assert_ok!(Democracy::delegate(Origin::signed(1), 3, Conviction::None, 10)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(3), 2, Conviction::None, 30)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(1), 3, Conviction::None, 10)); let r = 0; - assert_ok!(Democracy::undelegate(Origin::signed(3))); - assert_ok!(Democracy::vote(Origin::signed(3), r, aye(3))); - assert_ok!(Democracy::undelegate(Origin::signed(1))); - assert_ok!(Democracy::vote(Origin::signed(1), r, nay(1))); + assert_ok!(Democracy::undelegate(RuntimeOrigin::signed(3))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(3), r, aye(3))); + assert_ok!(Democracy::undelegate(RuntimeOrigin::signed(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, nay(1))); // Delegated vote is counted. assert_eq!(tally(r), Tally { ayes: 3, nays: 3, turnout: 60 }); @@ -100,18 +100,18 @@ fn single_proposal_should_work_with_vote_and_delegation() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(propose_set_balance_and_note(1, 2, 1)); + assert_ok!(propose_set_balance(1, 2, 1)); fast_forward_to(2); let r = 0; - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); - assert_ok!(Democracy::vote(Origin::signed(2), r, nay(2))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, nay(2))); assert_eq!(tally(r), Tally { ayes: 1, nays: 2, turnout: 30 }); // Delegate vote. - assert_ok!(Democracy::remove_vote(Origin::signed(2), r)); - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::None, 20)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(2), r)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20)); // Delegated vote replaces the explicit vote. assert_eq!(tally(r), Tally { ayes: 3, nays: 0, turnout: 30 }); }); @@ -122,15 +122,15 @@ fn single_proposal_should_work_with_undelegation() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(propose_set_balance_and_note(1, 2, 1)); + assert_ok!(propose_set_balance(1, 2, 1)); // Delegate and undelegate vote. - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::None, 20)); - assert_ok!(Democracy::undelegate(Origin::signed(2))); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20)); + assert_ok!(Democracy::undelegate(RuntimeOrigin::signed(2))); fast_forward_to(2); let r = 0; - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); // Delegated vote is not counted. assert_eq!(tally(r), Tally { ayes: 1, nays: 0, turnout: 10 }); @@ -143,11 +143,11 @@ fn single_proposal_should_work_with_delegation_and_vote() { new_test_ext().execute_with(|| { let r = begin_referendum(); // Delegate, undelegate and vote. - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::None, 20)); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::None, 20)); assert_eq!(tally(r), Tally { ayes: 3, nays: 0, turnout: 30 }); - assert_ok!(Democracy::undelegate(Origin::signed(2))); - assert_ok!(Democracy::vote(Origin::signed(2), r, aye(2))); + assert_ok!(Democracy::undelegate(RuntimeOrigin::signed(2))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, aye(2))); // Delegated vote is not counted. assert_eq!(tally(r), Tally { ayes: 3, nays: 0, turnout: 30 }); }); @@ -159,8 +159,8 @@ fn conviction_should_be_honored_in_delegation() { new_test_ext().execute_with(|| { let r = begin_referendum(); // Delegate and vote. - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::Locked6x, 20)); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::Locked6x, 20)); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); // Delegated vote is huge. assert_eq!(tally(r), Tally { ayes: 121, nays: 0, turnout: 30 }); }); @@ -171,8 +171,12 @@ fn split_vote_delegation_should_be_ignored() { // If transactor voted, delegated vote is overwritten. new_test_ext().execute_with(|| { let r = begin_referendum(); - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::Locked6x, 20)); - assert_ok!(Democracy::vote(Origin::signed(1), r, AccountVote::Split { aye: 10, nay: 0 })); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::Locked6x, 20)); + assert_ok!(Democracy::vote( + RuntimeOrigin::signed(1), + r, + AccountVote::Split { aye: 10, nay: 0 } + )); // Delegated vote is huge. assert_eq!(tally(r), Tally { ayes: 1, nays: 0, turnout: 10 }); }); @@ -184,8 +188,8 @@ fn redelegation_keeps_lock() { new_test_ext().execute_with(|| { let r = begin_referendum(); // Delegate and vote. - assert_ok!(Democracy::delegate(Origin::signed(2), 1, Conviction::Locked6x, 20)); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 1, Conviction::Locked6x, 20)); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); // Delegated vote is huge. assert_eq!(tally(r), Tally { ayes: 121, nays: 0, turnout: 30 }); @@ -196,14 +200,14 @@ fn redelegation_keeps_lock() { assert_eq!(VotingOf::::get(2).prior(), &prior_lock); // Delegate someone else at a lower conviction and amount - assert_ok!(Democracy::delegate(Origin::signed(2), 3, Conviction::None, 10)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(2), 3, Conviction::None, 10)); // 6x prior should appear w/ locked balance. prior_lock.accumulate(98, 20); assert_eq!(VotingOf::::get(2).prior(), &prior_lock); assert_eq!(VotingOf::::get(2).locked_balance(), 20); // Unlock shouldn't work - assert_ok!(Democracy::unlock(Origin::signed(2), 2)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(2), 2)); assert_eq!(VotingOf::::get(2).prior(), &prior_lock); assert_eq!(VotingOf::::get(2).locked_balance(), 20); @@ -211,7 +215,7 @@ fn redelegation_keeps_lock() { // Now unlock can remove the prior lock and reduce the locked amount. assert_eq!(VotingOf::::get(2).prior(), &prior_lock); - assert_ok!(Democracy::unlock(Origin::signed(2), 2)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(2), 2)); assert_eq!(VotingOf::::get(2).prior(), &vote::PriorLock::default()); assert_eq!(VotingOf::::get(2).locked_balance(), 10); }); diff --git a/frame/democracy/src/tests/external_proposing.rs b/frame/democracy/src/tests/external_proposing.rs index 6ac34a38723ce..4cfdd2aa74a3d 100644 --- a/frame/democracy/src/tests/external_proposing.rs +++ b/frame/democracy/src/tests/external_proposing.rs @@ -23,56 +23,50 @@ use super::*; fn veto_external_works() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(Democracy::external_propose( - Origin::signed(2), - set_balance_proposal_hash_and_note(2), - )); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); assert!(>::exists()); - let h = set_balance_proposal_hash_and_note(2); - assert_ok!(Democracy::veto_external(Origin::signed(3), h)); + let h = set_balance_proposal(2).hash(); + assert_ok!(Democracy::veto_external(RuntimeOrigin::signed(3), h)); // cancelled. assert!(!>::exists()); // fails - same proposal can't be resubmitted. assert_noop!( - Democracy::external_propose(Origin::signed(2), set_balance_proposal_hash(2),), + Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),), Error::::ProposalBlacklisted ); fast_forward_to(1); // fails as we're still in cooloff period. assert_noop!( - Democracy::external_propose(Origin::signed(2), set_balance_proposal_hash(2),), + Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),), Error::::ProposalBlacklisted ); fast_forward_to(2); // works; as we're out of the cooloff period. - assert_ok!(Democracy::external_propose( - Origin::signed(2), - set_balance_proposal_hash_and_note(2), - )); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); assert!(>::exists()); // 3 can't veto the same thing twice. - assert_noop!(Democracy::veto_external(Origin::signed(3), h), Error::::AlreadyVetoed); + assert_noop!( + Democracy::veto_external(RuntimeOrigin::signed(3), h), + Error::::AlreadyVetoed + ); // 4 vetoes. - assert_ok!(Democracy::veto_external(Origin::signed(4), h)); + assert_ok!(Democracy::veto_external(RuntimeOrigin::signed(4), h)); // cancelled again. assert!(!>::exists()); fast_forward_to(3); // same proposal fails as we're still in cooloff assert_noop!( - Democracy::external_propose(Origin::signed(2), set_balance_proposal_hash(2),), + Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2)), Error::::ProposalBlacklisted ); // different proposal works fine. - assert_ok!(Democracy::external_propose( - Origin::signed(2), - set_balance_proposal_hash_and_note(3), - )); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(3),)); }); } @@ -81,19 +75,16 @@ fn external_blacklisting_should_work() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(Democracy::external_propose( - Origin::signed(2), - set_balance_proposal_hash_and_note(2), - )); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); - let hash = set_balance_proposal_hash(2); - assert_ok!(Democracy::blacklist(Origin::root(), hash, None)); + let hash = set_balance_proposal(2).hash(); + assert_ok!(Democracy::blacklist(RuntimeOrigin::root(), hash, None)); fast_forward_to(2); assert_noop!(Democracy::referendum_status(0), Error::::ReferendumInvalid); assert_noop!( - Democracy::external_propose(Origin::signed(2), set_balance_proposal_hash_and_note(2),), + Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2)), Error::::ProposalBlacklisted, ); }); @@ -104,15 +95,12 @@ fn external_referendum_works() { new_test_ext().execute_with(|| { System::set_block_number(0); assert_noop!( - Democracy::external_propose(Origin::signed(1), set_balance_proposal_hash(2),), + Democracy::external_propose(RuntimeOrigin::signed(1), set_balance_proposal(2),), BadOrigin, ); - assert_ok!(Democracy::external_propose( - Origin::signed(2), - set_balance_proposal_hash_and_note(2), - )); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2),)); assert_noop!( - Democracy::external_propose(Origin::signed(2), set_balance_proposal_hash(1),), + Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(1),), Error::::DuplicateProposal ); fast_forward_to(2); @@ -120,7 +108,7 @@ fn external_referendum_works() { Democracy::referendum_status(0), Ok(ReferendumStatus { end: 4, - proposal_hash: set_balance_proposal_hash(2), + proposal: set_balance_proposal(2), threshold: VoteThreshold::SuperMajorityApprove, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, @@ -134,19 +122,19 @@ fn external_majority_referendum_works() { new_test_ext().execute_with(|| { System::set_block_number(0); assert_noop!( - Democracy::external_propose_majority(Origin::signed(1), set_balance_proposal_hash(2)), + Democracy::external_propose_majority(RuntimeOrigin::signed(1), set_balance_proposal(2)), BadOrigin, ); assert_ok!(Democracy::external_propose_majority( - Origin::signed(3), - set_balance_proposal_hash_and_note(2) + RuntimeOrigin::signed(3), + set_balance_proposal(2) )); fast_forward_to(2); assert_eq!( Democracy::referendum_status(0), Ok(ReferendumStatus { end: 4, - proposal_hash: set_balance_proposal_hash(2), + proposal: set_balance_proposal(2), threshold: VoteThreshold::SimpleMajority, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, @@ -160,19 +148,19 @@ fn external_default_referendum_works() { new_test_ext().execute_with(|| { System::set_block_number(0); assert_noop!( - Democracy::external_propose_default(Origin::signed(3), set_balance_proposal_hash(2)), + Democracy::external_propose_default(RuntimeOrigin::signed(3), set_balance_proposal(2)), BadOrigin, ); assert_ok!(Democracy::external_propose_default( - Origin::signed(1), - set_balance_proposal_hash_and_note(2) + RuntimeOrigin::signed(1), + set_balance_proposal(2) )); fast_forward_to(2); assert_eq!( Democracy::referendum_status(0), Ok(ReferendumStatus { end: 4, - proposal_hash: set_balance_proposal_hash(2), + proposal: set_balance_proposal(2), threshold: VoteThreshold::SuperMajorityAgainst, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, @@ -185,11 +173,8 @@ fn external_default_referendum_works() { fn external_and_public_interleaving_works() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(Democracy::external_propose( - Origin::signed(2), - set_balance_proposal_hash_and_note(1), - )); - assert_ok!(propose_set_balance_and_note(6, 2, 2)); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(1),)); + assert_ok!(propose_set_balance(6, 2, 2)); fast_forward_to(2); @@ -198,17 +183,14 @@ fn external_and_public_interleaving_works() { Democracy::referendum_status(0), Ok(ReferendumStatus { end: 4, - proposal_hash: set_balance_proposal_hash_and_note(1), + proposal: set_balance_proposal(1), threshold: VoteThreshold::SuperMajorityApprove, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, }) ); // replenish external - assert_ok!(Democracy::external_propose( - Origin::signed(2), - set_balance_proposal_hash_and_note(3), - )); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(3),)); fast_forward_to(4); @@ -217,7 +199,7 @@ fn external_and_public_interleaving_works() { Democracy::referendum_status(1), Ok(ReferendumStatus { end: 6, - proposal_hash: set_balance_proposal_hash_and_note(2), + proposal: set_balance_proposal(2), threshold: VoteThreshold::SuperMajorityApprove, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, @@ -232,17 +214,14 @@ fn external_and_public_interleaving_works() { Democracy::referendum_status(2), Ok(ReferendumStatus { end: 8, - proposal_hash: set_balance_proposal_hash_and_note(3), + proposal: set_balance_proposal(3), threshold: VoteThreshold::SuperMajorityApprove, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, }) ); // replenish external - assert_ok!(Democracy::external_propose( - Origin::signed(2), - set_balance_proposal_hash_and_note(5), - )); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(5),)); fast_forward_to(8); @@ -251,18 +230,15 @@ fn external_and_public_interleaving_works() { Democracy::referendum_status(3), Ok(ReferendumStatus { end: 10, - proposal_hash: set_balance_proposal_hash_and_note(5), + proposal: set_balance_proposal(5), threshold: VoteThreshold::SuperMajorityApprove, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, }) ); // replenish both - assert_ok!(Democracy::external_propose( - Origin::signed(2), - set_balance_proposal_hash_and_note(7), - )); - assert_ok!(propose_set_balance_and_note(6, 4, 2)); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(7),)); + assert_ok!(propose_set_balance(6, 4, 2)); fast_forward_to(10); @@ -271,17 +247,17 @@ fn external_and_public_interleaving_works() { Democracy::referendum_status(4), Ok(ReferendumStatus { end: 12, - proposal_hash: set_balance_proposal_hash_and_note(4), + proposal: set_balance_proposal(4), threshold: VoteThreshold::SuperMajorityApprove, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, }) ); // replenish public again - assert_ok!(propose_set_balance_and_note(6, 6, 2)); + assert_ok!(propose_set_balance(6, 6, 2)); // cancel external - let h = set_balance_proposal_hash_and_note(7); - assert_ok!(Democracy::veto_external(Origin::signed(3), h)); + let h = set_balance_proposal(7).hash(); + assert_ok!(Democracy::veto_external(RuntimeOrigin::signed(3), h)); fast_forward_to(12); @@ -290,7 +266,7 @@ fn external_and_public_interleaving_works() { Democracy::referendum_status(5), Ok(ReferendumStatus { end: 14, - proposal_hash: set_balance_proposal_hash_and_note(6), + proposal: set_balance_proposal(6), threshold: VoteThreshold::SuperMajorityApprove, delay: 2, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, diff --git a/frame/democracy/src/tests/fast_tracking.rs b/frame/democracy/src/tests/fast_tracking.rs index caf83c6d46120..97bb7a63908ab 100644 --- a/frame/democracy/src/tests/fast_tracking.rs +++ b/frame/democracy/src/tests/fast_tracking.rs @@ -23,22 +23,22 @@ use super::*; fn fast_track_referendum_works() { new_test_ext().execute_with(|| { System::set_block_number(0); - let h = set_balance_proposal_hash_and_note(2); + let h = set_balance_proposal(2).hash(); assert_noop!( - Democracy::fast_track(Origin::signed(5), h, 3, 2), + Democracy::fast_track(RuntimeOrigin::signed(5), h, 3, 2), Error::::ProposalMissing ); assert_ok!(Democracy::external_propose_majority( - Origin::signed(3), - set_balance_proposal_hash_and_note(2) + RuntimeOrigin::signed(3), + set_balance_proposal(2) )); - assert_noop!(Democracy::fast_track(Origin::signed(1), h, 3, 2), BadOrigin); - assert_ok!(Democracy::fast_track(Origin::signed(5), h, 2, 0)); + assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(1), h, 3, 2), BadOrigin); + assert_ok!(Democracy::fast_track(RuntimeOrigin::signed(5), h, 2, 0)); assert_eq!( Democracy::referendum_status(0), Ok(ReferendumStatus { end: 2, - proposal_hash: set_balance_proposal_hash_and_note(2), + proposal: set_balance_proposal(2), threshold: VoteThreshold::SimpleMajority, delay: 0, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, @@ -51,32 +51,32 @@ fn fast_track_referendum_works() { fn instant_referendum_works() { new_test_ext().execute_with(|| { System::set_block_number(0); - let h = set_balance_proposal_hash_and_note(2); + let h = set_balance_proposal(2).hash(); assert_noop!( - Democracy::fast_track(Origin::signed(5), h, 3, 2), + Democracy::fast_track(RuntimeOrigin::signed(5), h, 3, 2), Error::::ProposalMissing ); assert_ok!(Democracy::external_propose_majority( - Origin::signed(3), - set_balance_proposal_hash_and_note(2) + RuntimeOrigin::signed(3), + set_balance_proposal(2) )); - assert_noop!(Democracy::fast_track(Origin::signed(1), h, 3, 2), BadOrigin); - assert_noop!(Democracy::fast_track(Origin::signed(5), h, 1, 0), BadOrigin); + assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(1), h, 3, 2), BadOrigin); + assert_noop!(Democracy::fast_track(RuntimeOrigin::signed(5), h, 1, 0), BadOrigin); assert_noop!( - Democracy::fast_track(Origin::signed(6), h, 1, 0), + Democracy::fast_track(RuntimeOrigin::signed(6), h, 1, 0), Error::::InstantNotAllowed ); INSTANT_ALLOWED.with(|v| *v.borrow_mut() = true); assert_noop!( - Democracy::fast_track(Origin::signed(6), h, 0, 0), + Democracy::fast_track(RuntimeOrigin::signed(6), h, 0, 0), Error::::VotingPeriodLow ); - assert_ok!(Democracy::fast_track(Origin::signed(6), h, 1, 0)); + assert_ok!(Democracy::fast_track(RuntimeOrigin::signed(6), h, 1, 0)); assert_eq!( Democracy::referendum_status(0), Ok(ReferendumStatus { end: 1, - proposal_hash: set_balance_proposal_hash_and_note(2), + proposal: set_balance_proposal(2), threshold: VoteThreshold::SimpleMajority, delay: 0, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, @@ -93,7 +93,7 @@ fn instant_next_block_referendum_backed() { let majority_origin_id = 3; let instant_origin_id = 6; let voting_period = 1; - let proposal_hash = set_balance_proposal_hash_and_note(2); + let proposal = set_balance_proposal(2); let delay = 2; // has no effect on test // init @@ -102,14 +102,14 @@ fn instant_next_block_referendum_backed() { // propose with majority origin assert_ok!(Democracy::external_propose_majority( - Origin::signed(majority_origin_id), - proposal_hash + RuntimeOrigin::signed(majority_origin_id), + proposal.clone() )); // fast track with instant origin and voting period pointing to the next block assert_ok!(Democracy::fast_track( - Origin::signed(instant_origin_id), - proposal_hash, + RuntimeOrigin::signed(instant_origin_id), + proposal.hash(), voting_period, delay )); @@ -119,7 +119,7 @@ fn instant_next_block_referendum_backed() { Democracy::referendum_status(0), Ok(ReferendumStatus { end: start_block_number + voting_period, - proposal_hash, + proposal, threshold: VoteThreshold::SimpleMajority, delay, tally: Tally { ayes: 0, nays: 0, turnout: 0 }, @@ -143,13 +143,10 @@ fn instant_next_block_referendum_backed() { fn fast_track_referendum_fails_when_no_simple_majority() { new_test_ext().execute_with(|| { System::set_block_number(0); - let h = set_balance_proposal_hash_and_note(2); - assert_ok!(Democracy::external_propose( - Origin::signed(2), - set_balance_proposal_hash_and_note(2) - )); + let h = set_balance_proposal(2).hash(); + assert_ok!(Democracy::external_propose(RuntimeOrigin::signed(2), set_balance_proposal(2))); assert_noop!( - Democracy::fast_track(Origin::signed(5), h, 3, 2), + Democracy::fast_track(RuntimeOrigin::signed(5), h, 3, 2), Error::::NotSimpleMajority ); }); diff --git a/frame/democracy/src/tests/lock_voting.rs b/frame/democracy/src/tests/lock_voting.rs index 0718734367314..540198ecf33a1 100644 --- a/frame/democracy/src/tests/lock_voting.rs +++ b/frame/democracy/src/tests/lock_voting.rs @@ -43,15 +43,15 @@ fn lock_voting_should_work() { System::set_block_number(0); let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, nay(5, 10))); - assert_ok!(Democracy::vote(Origin::signed(2), r, aye(4, 20))); - assert_ok!(Democracy::vote(Origin::signed(3), r, aye(3, 30))); - assert_ok!(Democracy::vote(Origin::signed(4), r, aye(2, 40))); - assert_ok!(Democracy::vote(Origin::signed(5), r, nay(1, 50))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, nay(5, 10))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, aye(4, 20))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(3), r, aye(3, 30))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(4), r, aye(2, 40))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, nay(1, 50))); assert_eq!(tally(r), Tally { ayes: 250, nays: 100, turnout: 150 }); // All balances are currently locked. @@ -59,23 +59,23 @@ fn lock_voting_should_work() { assert_eq!(Balances::locks(i), vec![the_lock(i * 10)]); } - fast_forward_to(2); + fast_forward_to(3); // Referendum passed; 1 and 5 didn't get their way and can now reap and unlock. - assert_ok!(Democracy::remove_vote(Origin::signed(1), r)); - assert_ok!(Democracy::unlock(Origin::signed(1), 1)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(1), r)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(1), 1)); // Anyone can reap and unlock anyone else's in this context. - assert_ok!(Democracy::remove_other_vote(Origin::signed(2), 5, r)); - assert_ok!(Democracy::unlock(Origin::signed(2), 5)); + assert_ok!(Democracy::remove_other_vote(RuntimeOrigin::signed(2), 5, r)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(2), 5)); // 2, 3, 4 got their way with the vote, so they cannot be reaped by others. assert_noop!( - Democracy::remove_other_vote(Origin::signed(1), 2, r), + Democracy::remove_other_vote(RuntimeOrigin::signed(1), 2, r), Error::::NoPermission ); // However, they can be unvoted by the owner, though it will make no difference to the lock. - assert_ok!(Democracy::remove_vote(Origin::signed(2), r)); - assert_ok!(Democracy::unlock(Origin::signed(2), 2)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(2), r)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(2), 2)); assert_eq!(Balances::locks(1), vec![]); assert_eq!(Balances::locks(2), vec![the_lock(20)]); @@ -87,35 +87,35 @@ fn lock_voting_should_work() { fast_forward_to(7); // No change yet... assert_noop!( - Democracy::remove_other_vote(Origin::signed(1), 4, r), + Democracy::remove_other_vote(RuntimeOrigin::signed(1), 4, r), Error::::NoPermission ); - assert_ok!(Democracy::unlock(Origin::signed(1), 4)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(1), 4)); assert_eq!(Balances::locks(4), vec![the_lock(40)]); fast_forward_to(8); // 4 should now be able to reap and unlock - assert_ok!(Democracy::remove_other_vote(Origin::signed(1), 4, r)); - assert_ok!(Democracy::unlock(Origin::signed(1), 4)); + assert_ok!(Democracy::remove_other_vote(RuntimeOrigin::signed(1), 4, r)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(1), 4)); assert_eq!(Balances::locks(4), vec![]); fast_forward_to(13); assert_noop!( - Democracy::remove_other_vote(Origin::signed(1), 3, r), + Democracy::remove_other_vote(RuntimeOrigin::signed(1), 3, r), Error::::NoPermission ); - assert_ok!(Democracy::unlock(Origin::signed(1), 3)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(1), 3)); assert_eq!(Balances::locks(3), vec![the_lock(30)]); fast_forward_to(14); - assert_ok!(Democracy::remove_other_vote(Origin::signed(1), 3, r)); - assert_ok!(Democracy::unlock(Origin::signed(1), 3)); + assert_ok!(Democracy::remove_other_vote(RuntimeOrigin::signed(1), 3, r)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(1), 3)); assert_eq!(Balances::locks(3), vec![]); // 2 doesn't need to reap_vote here because it was already done before. fast_forward_to(25); - assert_ok!(Democracy::unlock(Origin::signed(1), 2)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(1), 2)); assert_eq!(Balances::locks(2), vec![the_lock(20)]); fast_forward_to(26); - assert_ok!(Democracy::unlock(Origin::signed(1), 2)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(1), 2)); assert_eq!(Balances::locks(2), vec![]); }); } @@ -126,17 +126,17 @@ fn no_locks_without_conviction_should_work() { System::set_block_number(0); let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(0, 10))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(0, 10))); - fast_forward_to(2); + fast_forward_to(3); assert_eq!(Balances::free_balance(42), 2); - assert_ok!(Democracy::remove_other_vote(Origin::signed(2), 1, r)); - assert_ok!(Democracy::unlock(Origin::signed(2), 1)); + assert_ok!(Democracy::remove_other_vote(RuntimeOrigin::signed(2), 1, r)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(2), 1)); assert_eq!(Balances::locks(1), vec![]); }); } @@ -146,15 +146,15 @@ fn lock_voting_should_work_with_delegation() { new_test_ext().execute_with(|| { let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, nay(5, 10))); - assert_ok!(Democracy::vote(Origin::signed(2), r, aye(4, 20))); - assert_ok!(Democracy::vote(Origin::signed(3), r, aye(3, 30))); - assert_ok!(Democracy::delegate(Origin::signed(4), 2, Conviction::Locked2x, 40)); - assert_ok!(Democracy::vote(Origin::signed(5), r, nay(1, 50))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, nay(5, 10))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, aye(4, 20))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(3), r, aye(3, 30))); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(4), 2, Conviction::Locked2x, 40)); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, nay(1, 50))); assert_eq!(tally(r), Tally { ayes: 250, nays: 100, turnout: 150 }); @@ -167,29 +167,17 @@ fn lock_voting_should_work_with_delegation() { fn setup_three_referenda() -> (u32, u32, u32) { System::set_block_number(0); - let r1 = Democracy::inject_referendum( - 2, - set_balance_proposal_hash_and_note(2), - VoteThreshold::SimpleMajority, - 0, - ); - assert_ok!(Democracy::vote(Origin::signed(5), r1, aye(4, 10))); - - let r2 = Democracy::inject_referendum( - 2, - set_balance_proposal_hash_and_note(2), - VoteThreshold::SimpleMajority, - 0, - ); - assert_ok!(Democracy::vote(Origin::signed(5), r2, aye(3, 20))); - - let r3 = Democracy::inject_referendum( - 2, - set_balance_proposal_hash_and_note(2), - VoteThreshold::SimpleMajority, - 0, - ); - assert_ok!(Democracy::vote(Origin::signed(5), r3, aye(2, 50))); + let r1 = + Democracy::inject_referendum(2, set_balance_proposal(2), VoteThreshold::SimpleMajority, 0); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r1, aye(4, 10))); + + let r2 = + Democracy::inject_referendum(2, set_balance_proposal(2), VoteThreshold::SimpleMajority, 0); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r2, aye(3, 20))); + + let r3 = + Democracy::inject_referendum(2, set_balance_proposal(2), VoteThreshold::SimpleMajority, 0); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r3, aye(2, 50))); fast_forward_to(2); @@ -206,36 +194,36 @@ fn prior_lockvotes_should_be_enforced() { fast_forward_to(7); assert_noop!( - Democracy::remove_other_vote(Origin::signed(1), 5, r.2), + Democracy::remove_other_vote(RuntimeOrigin::signed(1), 5, r.2), Error::::NoPermission ); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(50)]); fast_forward_to(8); - assert_ok!(Democracy::remove_other_vote(Origin::signed(1), 5, r.2)); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::remove_other_vote(RuntimeOrigin::signed(1), 5, r.2)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(20)]); fast_forward_to(13); assert_noop!( - Democracy::remove_other_vote(Origin::signed(1), 5, r.1), + Democracy::remove_other_vote(RuntimeOrigin::signed(1), 5, r.1), Error::::NoPermission ); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(20)]); fast_forward_to(14); - assert_ok!(Democracy::remove_other_vote(Origin::signed(1), 5, r.1)); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::remove_other_vote(RuntimeOrigin::signed(1), 5, r.1)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(10)]); fast_forward_to(25); assert_noop!( - Democracy::remove_other_vote(Origin::signed(1), 5, r.0), + Democracy::remove_other_vote(RuntimeOrigin::signed(1), 5, r.0), Error::::NoPermission ); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(10)]); fast_forward_to(26); - assert_ok!(Democracy::remove_other_vote(Origin::signed(1), 5, r.0)); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::remove_other_vote(RuntimeOrigin::signed(1), 5, r.0)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![]); }); } @@ -249,27 +237,27 @@ fn single_consolidation_of_lockvotes_should_work_as_before() { // r.2 locked 50 until 2 + 2 * 3 = #8 fast_forward_to(7); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.2)); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.2)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(50)]); fast_forward_to(8); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(20)]); fast_forward_to(13); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.1)); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.1)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(20)]); fast_forward_to(14); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(10)]); fast_forward_to(25); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.0)); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.0)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![the_lock(10)]); fast_forward_to(26); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![]); }); } @@ -282,20 +270,20 @@ fn multi_consolidation_of_lockvotes_should_be_conservative() { // r.1 locked 20 until 2 + 4 * 3 = #14 // r.2 locked 50 until 2 + 2 * 3 = #8 - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.2)); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.1)); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.0)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.2)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.1)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.0)); fast_forward_to(8); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 20); fast_forward_to(14); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 10); fast_forward_to(26); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![]); }); } @@ -306,36 +294,36 @@ fn locks_should_persist_from_voting_to_delegation() { System::set_block_number(0); let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SimpleMajority, 0, ); - assert_ok!(Democracy::vote(Origin::signed(5), r, aye(4, 10))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, aye(4, 10))); fast_forward_to(2); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r)); // locked 10 until #26. - assert_ok!(Democracy::delegate(Origin::signed(5), 1, Conviction::Locked3x, 20)); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(5), 1, Conviction::Locked3x, 20)); // locked 20. assert!(Balances::locks(5)[0].amount == 20); - assert_ok!(Democracy::undelegate(Origin::signed(5))); + assert_ok!(Democracy::undelegate(RuntimeOrigin::signed(5))); // locked 20 until #14 fast_forward_to(13); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert!(Balances::locks(5)[0].amount == 20); fast_forward_to(14); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 10); fast_forward_to(25); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 10); fast_forward_to(26); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![]); }); } @@ -344,8 +332,8 @@ fn locks_should_persist_from_voting_to_delegation() { fn locks_should_persist_from_delegation_to_voting() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(Democracy::delegate(Origin::signed(5), 1, Conviction::Locked5x, 5)); - assert_ok!(Democracy::undelegate(Origin::signed(5))); + assert_ok!(Democracy::delegate(RuntimeOrigin::signed(5), 1, Conviction::Locked5x, 5)); + assert_ok!(Democracy::undelegate(RuntimeOrigin::signed(5))); // locked 5 until 16 * 3 = #48 let r = setup_three_referenda(); @@ -353,24 +341,24 @@ fn locks_should_persist_from_delegation_to_voting() { // r.1 locked 20 until 2 + 4 * 3 = #14 // r.2 locked 50 until 2 + 2 * 3 = #8 - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.2)); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.1)); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r.0)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.2)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.1)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r.0)); fast_forward_to(8); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 20); fast_forward_to(14); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 10); fast_forward_to(26); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert!(Balances::locks(5)[0].amount >= 5); fast_forward_to(48); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![]); }); } diff --git a/frame/democracy/src/tests/preimage.rs b/frame/democracy/src/tests/preimage.rs deleted file mode 100644 index 21303c8eddae3..0000000000000 --- a/frame/democracy/src/tests/preimage.rs +++ /dev/null @@ -1,219 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! The preimage tests. - -use super::*; - -#[test] -fn missing_preimage_should_fail() { - new_test_ext().execute_with(|| { - let r = Democracy::inject_referendum( - 2, - set_balance_proposal_hash(2), - VoteThreshold::SuperMajorityApprove, - 0, - ); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); - - next_block(); - next_block(); - - assert_eq!(Balances::free_balance(42), 0); - }); -} - -#[test] -fn preimage_deposit_should_be_required_and_returned() { - new_test_ext_execute_with_cond(|operational| { - // fee of 100 is too much. - PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 100); - assert_noop!( - if operational { - Democracy::note_preimage_operational(Origin::signed(6), vec![0; 500]) - } else { - Democracy::note_preimage(Origin::signed(6), vec![0; 500]) - }, - BalancesError::::InsufficientBalance, - ); - // fee of 1 is reasonable. - PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1); - let r = Democracy::inject_referendum( - 2, - set_balance_proposal_hash_and_note(2), - VoteThreshold::SuperMajorityApprove, - 0, - ); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); - - assert_eq!(Balances::reserved_balance(6), 12); - - next_block(); - next_block(); - - assert_eq!(Balances::reserved_balance(6), 0); - assert_eq!(Balances::free_balance(6), 60); - assert_eq!(Balances::free_balance(42), 2); - }); -} - -#[test] -fn preimage_deposit_should_be_reapable_earlier_by_owner() { - new_test_ext_execute_with_cond(|operational| { - PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1); - assert_ok!(if operational { - Democracy::note_preimage_operational(Origin::signed(6), set_balance_proposal(2)) - } else { - Democracy::note_preimage(Origin::signed(6), set_balance_proposal(2)) - }); - - assert_eq!(Balances::reserved_balance(6), 12); - - next_block(); - assert_noop!( - Democracy::reap_preimage(Origin::signed(6), set_balance_proposal_hash(2), u32::MAX), - Error::::TooEarly - ); - next_block(); - assert_ok!(Democracy::reap_preimage( - Origin::signed(6), - set_balance_proposal_hash(2), - u32::MAX - )); - - assert_eq!(Balances::free_balance(6), 60); - assert_eq!(Balances::reserved_balance(6), 0); - }); -} - -#[test] -fn preimage_deposit_should_be_reapable() { - new_test_ext_execute_with_cond(|operational| { - assert_noop!( - Democracy::reap_preimage(Origin::signed(5), set_balance_proposal_hash(2), u32::MAX), - Error::::PreimageMissing - ); - - PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1); - assert_ok!(if operational { - Democracy::note_preimage_operational(Origin::signed(6), set_balance_proposal(2)) - } else { - Democracy::note_preimage(Origin::signed(6), set_balance_proposal(2)) - }); - assert_eq!(Balances::reserved_balance(6), 12); - - next_block(); - next_block(); - next_block(); - assert_noop!( - Democracy::reap_preimage(Origin::signed(5), set_balance_proposal_hash(2), u32::MAX), - Error::::TooEarly - ); - - next_block(); - assert_ok!(Democracy::reap_preimage( - Origin::signed(5), - set_balance_proposal_hash(2), - u32::MAX - )); - assert_eq!(Balances::reserved_balance(6), 0); - assert_eq!(Balances::free_balance(6), 48); - assert_eq!(Balances::free_balance(5), 62); - }); -} - -#[test] -fn noting_imminent_preimage_for_free_should_work() { - new_test_ext_execute_with_cond(|operational| { - PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1); - - let r = Democracy::inject_referendum( - 2, - set_balance_proposal_hash(2), - VoteThreshold::SuperMajorityApprove, - 1, - ); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); - - assert_noop!( - if operational { - Democracy::note_imminent_preimage_operational( - Origin::signed(6), - set_balance_proposal(2), - ) - } else { - Democracy::note_imminent_preimage(Origin::signed(6), set_balance_proposal(2)) - }, - Error::::NotImminent - ); - - next_block(); - - // Now we're in the dispatch queue it's all good. - assert_ok!(Democracy::note_imminent_preimage(Origin::signed(6), set_balance_proposal(2))); - - next_block(); - - assert_eq!(Balances::free_balance(42), 2); - }); -} - -#[test] -fn reaping_imminent_preimage_should_fail() { - new_test_ext().execute_with(|| { - let h = set_balance_proposal_hash_and_note(2); - let r = Democracy::inject_referendum(3, h, VoteThreshold::SuperMajorityApprove, 1); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); - next_block(); - next_block(); - assert_noop!( - Democracy::reap_preimage(Origin::signed(6), h, u32::MAX), - Error::::Imminent - ); - }); -} - -#[test] -fn note_imminent_preimage_can_only_be_successful_once() { - new_test_ext().execute_with(|| { - PREIMAGE_BYTE_DEPOSIT.with(|v| *v.borrow_mut() = 1); - - let r = Democracy::inject_referendum( - 2, - set_balance_proposal_hash(2), - VoteThreshold::SuperMajorityApprove, - 1, - ); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); - next_block(); - - // First time works - assert_ok!(Democracy::note_imminent_preimage(Origin::signed(6), set_balance_proposal(2))); - - // Second time fails - assert_noop!( - Democracy::note_imminent_preimage(Origin::signed(6), set_balance_proposal(2)), - Error::::DuplicatePreimage - ); - - // Fails from any user - assert_noop!( - Democracy::note_imminent_preimage(Origin::signed(5), set_balance_proposal(2)), - Error::::DuplicatePreimage - ); - }); -} diff --git a/frame/democracy/src/tests/public_proposals.rs b/frame/democracy/src/tests/public_proposals.rs index 65e5466857dc1..f48824dc95c5d 100644 --- a/frame/democracy/src/tests/public_proposals.rs +++ b/frame/democracy/src/tests/public_proposals.rs @@ -22,9 +22,9 @@ use super::*; #[test] fn backing_for_should_work() { new_test_ext().execute_with(|| { - assert_ok!(propose_set_balance_and_note(1, 2, 2)); - assert_ok!(propose_set_balance_and_note(1, 4, 4)); - assert_ok!(propose_set_balance_and_note(1, 3, 3)); + assert_ok!(propose_set_balance(1, 2, 2)); + assert_ok!(propose_set_balance(1, 4, 4)); + assert_ok!(propose_set_balance(1, 3, 3)); assert_eq!(Democracy::backing_for(0), Some(2)); assert_eq!(Democracy::backing_for(1), Some(4)); assert_eq!(Democracy::backing_for(2), Some(3)); @@ -34,11 +34,11 @@ fn backing_for_should_work() { #[test] fn deposit_for_proposals_should_be_taken() { new_test_ext().execute_with(|| { - assert_ok!(propose_set_balance_and_note(1, 2, 5)); - assert_ok!(Democracy::second(Origin::signed(2), 0, u32::MAX)); - assert_ok!(Democracy::second(Origin::signed(5), 0, u32::MAX)); - assert_ok!(Democracy::second(Origin::signed(5), 0, u32::MAX)); - assert_ok!(Democracy::second(Origin::signed(5), 0, u32::MAX)); + assert_ok!(propose_set_balance(1, 2, 5)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(2), 0)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0)); assert_eq!(Balances::free_balance(1), 5); assert_eq!(Balances::free_balance(2), 15); assert_eq!(Balances::free_balance(5), 35); @@ -48,11 +48,11 @@ fn deposit_for_proposals_should_be_taken() { #[test] fn deposit_for_proposals_should_be_returned() { new_test_ext().execute_with(|| { - assert_ok!(propose_set_balance_and_note(1, 2, 5)); - assert_ok!(Democracy::second(Origin::signed(2), 0, u32::MAX)); - assert_ok!(Democracy::second(Origin::signed(5), 0, u32::MAX)); - assert_ok!(Democracy::second(Origin::signed(5), 0, u32::MAX)); - assert_ok!(Democracy::second(Origin::signed(5), 0, u32::MAX)); + assert_ok!(propose_set_balance(1, 2, 5)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(2), 0)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0)); + assert_ok!(Democracy::second(RuntimeOrigin::signed(5), 0)); fast_forward_to(3); assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 20); @@ -77,29 +77,21 @@ fn poor_proposer_should_not_work() { #[test] fn poor_seconder_should_not_work() { new_test_ext().execute_with(|| { - assert_ok!(propose_set_balance_and_note(2, 2, 11)); + assert_ok!(propose_set_balance(2, 2, 11)); assert_noop!( - Democracy::second(Origin::signed(1), 0, u32::MAX), + Democracy::second(RuntimeOrigin::signed(1), 0), BalancesError::::InsufficientBalance ); }); } -#[test] -fn invalid_seconds_upper_bound_should_not_work() { - new_test_ext().execute_with(|| { - assert_ok!(propose_set_balance_and_note(1, 2, 5)); - assert_noop!(Democracy::second(Origin::signed(2), 0, 0), Error::::WrongUpperBound); - }); -} - #[test] fn cancel_proposal_should_work() { new_test_ext().execute_with(|| { - assert_ok!(propose_set_balance_and_note(1, 2, 2)); - assert_ok!(propose_set_balance_and_note(1, 4, 4)); - assert_noop!(Democracy::cancel_proposal(Origin::signed(1), 0), BadOrigin); - assert_ok!(Democracy::cancel_proposal(Origin::root(), 0)); + assert_ok!(propose_set_balance(1, 2, 2)); + assert_ok!(propose_set_balance(1, 4, 4)); + assert_noop!(Democracy::cancel_proposal(RuntimeOrigin::signed(1), 0), BadOrigin); + assert_ok!(Democracy::cancel_proposal(RuntimeOrigin::root(), 0)); System::assert_last_event(crate::Event::ProposalCanceled { prop_index: 0 }.into()); assert_eq!(Democracy::backing_for(0), None); assert_eq!(Democracy::backing_for(1), Some(4)); @@ -110,24 +102,24 @@ fn cancel_proposal_should_work() { fn blacklisting_should_work() { new_test_ext().execute_with(|| { System::set_block_number(0); - let hash = set_balance_proposal_hash(2); + let hash = set_balance_proposal(2).hash(); - assert_ok!(propose_set_balance_and_note(1, 2, 2)); - assert_ok!(propose_set_balance_and_note(1, 4, 4)); + assert_ok!(propose_set_balance(1, 2, 2)); + assert_ok!(propose_set_balance(1, 4, 4)); - assert_noop!(Democracy::blacklist(Origin::signed(1), hash, None), BadOrigin); - assert_ok!(Democracy::blacklist(Origin::root(), hash, None)); + assert_noop!(Democracy::blacklist(RuntimeOrigin::signed(1), hash, None), BadOrigin); + assert_ok!(Democracy::blacklist(RuntimeOrigin::root(), hash, None)); assert_eq!(Democracy::backing_for(0), None); assert_eq!(Democracy::backing_for(1), Some(4)); - assert_noop!(propose_set_balance_and_note(1, 2, 2), Error::::ProposalBlacklisted); + assert_noop!(propose_set_balance(1, 2, 2), Error::::ProposalBlacklisted); fast_forward_to(2); - let hash = set_balance_proposal_hash(4); + let hash = set_balance_proposal(4).hash(); assert_ok!(Democracy::referendum_status(0)); - assert_ok!(Democracy::blacklist(Origin::root(), hash, Some(0))); + assert_ok!(Democracy::blacklist(RuntimeOrigin::root(), hash, Some(0))); assert_noop!(Democracy::referendum_status(0), Error::::ReferendumInvalid); }); } @@ -136,14 +128,14 @@ fn blacklisting_should_work() { fn runners_up_should_come_after() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(propose_set_balance_and_note(1, 2, 2)); - assert_ok!(propose_set_balance_and_note(1, 4, 4)); - assert_ok!(propose_set_balance_and_note(1, 3, 3)); + assert_ok!(propose_set_balance(1, 2, 2)); + assert_ok!(propose_set_balance(1, 4, 4)); + assert_ok!(propose_set_balance(1, 3, 3)); fast_forward_to(2); - assert_ok!(Democracy::vote(Origin::signed(1), 0, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), 0, aye(1))); fast_forward_to(4); - assert_ok!(Democracy::vote(Origin::signed(1), 1, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), 1, aye(1))); fast_forward_to(6); - assert_ok!(Democracy::vote(Origin::signed(1), 2, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), 2, aye(1))); }); } diff --git a/frame/democracy/src/tests/scheduling.rs b/frame/democracy/src/tests/scheduling.rs index d28f24d76bb5b..5e133f38945d6 100644 --- a/frame/democracy/src/tests/scheduling.rs +++ b/frame/democracy/src/tests/scheduling.rs @@ -24,11 +24,11 @@ fn simple_passing_should_work() { new_test_ext().execute_with(|| { let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); assert_eq!(tally(r), Tally { ayes: 1, nays: 0, turnout: 10 }); assert_eq!(Democracy::lowest_unbaked(), 0); next_block(); @@ -43,11 +43,11 @@ fn simple_failing_should_work() { new_test_ext().execute_with(|| { let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, nay(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, nay(1))); assert_eq!(tally(r), Tally { ayes: 0, nays: 1, turnout: 10 }); next_block(); @@ -62,26 +62,28 @@ fn ooo_inject_referendums_should_work() { new_test_ext().execute_with(|| { let r1 = Democracy::inject_referendum( 3, - set_balance_proposal_hash_and_note(3), + set_balance_proposal(3), VoteThreshold::SuperMajorityApprove, 0, ); let r2 = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r2, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r2, aye(1))); assert_eq!(tally(r2), Tally { ayes: 1, nays: 0, turnout: 10 }); next_block(); - assert_eq!(Balances::free_balance(42), 2); - assert_ok!(Democracy::vote(Origin::signed(1), r1, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r1, aye(1))); assert_eq!(tally(r1), Tally { ayes: 1, nays: 0, turnout: 10 }); + next_block(); + assert_eq!(Balances::free_balance(42), 2); + next_block(); assert_eq!(Balances::free_balance(42), 3); }); @@ -92,16 +94,16 @@ fn delayed_enactment_should_work() { new_test_ext().execute_with(|| { let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 1, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); - assert_ok!(Democracy::vote(Origin::signed(2), r, aye(2))); - assert_ok!(Democracy::vote(Origin::signed(3), r, aye(3))); - assert_ok!(Democracy::vote(Origin::signed(4), r, aye(4))); - assert_ok!(Democracy::vote(Origin::signed(5), r, aye(5))); - assert_ok!(Democracy::vote(Origin::signed(6), r, aye(6))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, aye(2))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(3), r, aye(3))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(4), r, aye(4))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, aye(5))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(6), r, aye(6))); assert_eq!(tally(r), Tally { ayes: 21, nays: 0, turnout: 210 }); @@ -118,39 +120,42 @@ fn lowest_unbaked_should_be_sensible() { new_test_ext().execute_with(|| { let r1 = Democracy::inject_referendum( 3, - set_balance_proposal_hash_and_note(1), + set_balance_proposal(1), VoteThreshold::SuperMajorityApprove, 0, ); let r2 = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); let r3 = Democracy::inject_referendum( 10, - set_balance_proposal_hash_and_note(3), + set_balance_proposal(3), VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r1, aye(1))); - assert_ok!(Democracy::vote(Origin::signed(1), r2, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r1, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r2, aye(1))); // r3 is canceled - assert_ok!(Democracy::cancel_referendum(Origin::root(), r3.into())); + assert_ok!(Democracy::cancel_referendum(RuntimeOrigin::root(), r3.into())); assert_eq!(Democracy::lowest_unbaked(), 0); next_block(); - - // r2 is approved - assert_eq!(Balances::free_balance(42), 2); + // r2 ends with approval assert_eq!(Democracy::lowest_unbaked(), 0); next_block(); - - // r1 is approved - assert_eq!(Balances::free_balance(42), 1); + // r1 ends with approval assert_eq!(Democracy::lowest_unbaked(), 3); assert_eq!(Democracy::lowest_unbaked(), Democracy::referendum_count()); + + // r2 is executed + assert_eq!(Balances::free_balance(42), 2); + + next_block(); + // r1 is executed + assert_eq!(Balances::free_balance(42), 1); }); } diff --git a/frame/democracy/src/tests/voting.rs b/frame/democracy/src/tests/voting.rs index d4fceaf0ee489..482cd430e0e7f 100644 --- a/frame/democracy/src/tests/voting.rs +++ b/frame/democracy/src/tests/voting.rs @@ -24,7 +24,7 @@ fn overvoting_should_fail() { new_test_ext().execute_with(|| { let r = begin_referendum(); assert_noop!( - Democracy::vote(Origin::signed(1), r, aye(2)), + Democracy::vote(RuntimeOrigin::signed(1), r, aye(2)), Error::::InsufficientFunds ); }); @@ -35,9 +35,12 @@ fn split_voting_should_work() { new_test_ext().execute_with(|| { let r = begin_referendum(); let v = AccountVote::Split { aye: 40, nay: 20 }; - assert_noop!(Democracy::vote(Origin::signed(5), r, v), Error::::InsufficientFunds); + assert_noop!( + Democracy::vote(RuntimeOrigin::signed(5), r, v), + Error::::InsufficientFunds + ); let v = AccountVote::Split { aye: 30, nay: 20 }; - assert_ok!(Democracy::vote(Origin::signed(5), r, v)); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, v)); assert_eq!(tally(r), Tally { ayes: 3, nays: 2, turnout: 50 }); }); @@ -48,10 +51,10 @@ fn split_vote_cancellation_should_work() { new_test_ext().execute_with(|| { let r = begin_referendum(); let v = AccountVote::Split { aye: 30, nay: 20 }; - assert_ok!(Democracy::vote(Origin::signed(5), r, v)); - assert_ok!(Democracy::remove_vote(Origin::signed(5), r)); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, v)); + assert_ok!(Democracy::remove_vote(RuntimeOrigin::signed(5), r)); assert_eq!(tally(r), Tally { ayes: 0, nays: 0, turnout: 0 }); - assert_ok!(Democracy::unlock(Origin::signed(5), 5)); + assert_ok!(Democracy::unlock(RuntimeOrigin::signed(5), 5)); assert_eq!(Balances::locks(5), vec![]); }); } @@ -60,20 +63,20 @@ fn split_vote_cancellation_should_work() { fn single_proposal_should_work() { new_test_ext().execute_with(|| { System::set_block_number(0); - assert_ok!(propose_set_balance_and_note(1, 2, 1)); + assert_ok!(propose_set_balance(1, 2, 1)); let r = 0; assert!(Democracy::referendum_info(r).is_none()); // start of 2 => next referendum scheduled. fast_forward_to(2); - assert_ok!(Democracy::vote(Origin::signed(1), r, aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, aye(1))); assert_eq!(Democracy::referendum_count(), 1); assert_eq!( Democracy::referendum_status(0), Ok(ReferendumStatus { end: 4, - proposal_hash: set_balance_proposal_hash_and_note(2), + proposal: set_balance_proposal(2), threshold: VoteThreshold::SuperMajorityApprove, delay: 2, tally: Tally { ayes: 1, nays: 0, turnout: 10 }, @@ -103,17 +106,17 @@ fn controversial_voting_should_work() { new_test_ext().execute_with(|| { let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(1), r, big_aye(1))); - assert_ok!(Democracy::vote(Origin::signed(2), r, big_nay(2))); - assert_ok!(Democracy::vote(Origin::signed(3), r, big_nay(3))); - assert_ok!(Democracy::vote(Origin::signed(4), r, big_aye(4))); - assert_ok!(Democracy::vote(Origin::signed(5), r, big_nay(5))); - assert_ok!(Democracy::vote(Origin::signed(6), r, big_aye(6))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(1), r, big_aye(1))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(2), r, big_nay(2))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(3), r, big_nay(3))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(4), r, big_aye(4))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, big_nay(5))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(6), r, big_aye(6))); assert_eq!(tally(r), Tally { ayes: 110, nays: 100, turnout: 210 }); @@ -129,12 +132,12 @@ fn controversial_low_turnout_voting_should_work() { new_test_ext().execute_with(|| { let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(5), r, big_nay(5))); - assert_ok!(Democracy::vote(Origin::signed(6), r, big_aye(6))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, big_nay(5))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(6), r, big_aye(6))); assert_eq!(tally(r), Tally { ayes: 60, nays: 50, turnout: 110 }); @@ -153,13 +156,13 @@ fn passing_low_turnout_voting_should_work() { let r = Democracy::inject_referendum( 2, - set_balance_proposal_hash_and_note(2), + set_balance_proposal(2), VoteThreshold::SuperMajorityApprove, 0, ); - assert_ok!(Democracy::vote(Origin::signed(4), r, big_aye(4))); - assert_ok!(Democracy::vote(Origin::signed(5), r, big_nay(5))); - assert_ok!(Democracy::vote(Origin::signed(6), r, big_aye(6))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(4), r, big_aye(4))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(5), r, big_nay(5))); + assert_ok!(Democracy::vote(RuntimeOrigin::signed(6), r, big_aye(6))); assert_eq!(tally(r), Tally { ayes: 100, nays: 50, turnout: 150 }); next_block(); diff --git a/frame/democracy/src/types.rs b/frame/democracy/src/types.rs index 52ab8a40eb3e3..4b7f1a0fac45c 100644 --- a/frame/democracy/src/types.rs +++ b/frame/democracy/src/types.rs @@ -18,7 +18,7 @@ //! Miscellaneous additional datatypes. use crate::{AccountVote, Conviction, Vote, VoteThreshold}; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::{ traits::{Bounded, CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, Saturating, Zero}, @@ -26,7 +26,7 @@ use sp_runtime::{ }; /// Info regarding an ongoing referendum. -#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive(Encode, MaxEncodedLen, Decode, Default, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] pub struct Tally { /// The number of aye votes, expressed in terms of post-conviction lock-vote. pub ayes: Balance, @@ -37,7 +37,9 @@ pub struct Tally { } /// Amount of votes and capital placed in delegation for an account. -#[derive(Encode, Decode, Default, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +#[derive( + Encode, MaxEncodedLen, Decode, Default, Copy, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, +)] pub struct Delegations { /// The number of votes (this is post-conviction). pub votes: Balance, @@ -160,12 +162,12 @@ impl< } /// Info regarding an ongoing referendum. -#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] -pub struct ReferendumStatus { +#[derive(Encode, MaxEncodedLen, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +pub struct ReferendumStatus { /// When voting on this referendum will end. pub end: BlockNumber, - /// The hash of the proposal being voted on. - pub proposal_hash: Hash, + /// The proposal being voted on. + pub proposal: Proposal, /// The thresholding mechanism to determine whether it passed. pub threshold: VoteThreshold, /// The delay (in blocks) to wait after a successful referendum before deploying. @@ -175,23 +177,23 @@ pub struct ReferendumStatus { } /// Info regarding a referendum, present or past. -#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] -pub enum ReferendumInfo { +#[derive(Encode, MaxEncodedLen, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +pub enum ReferendumInfo { /// Referendum is happening, the arg is the block number at which it will end. - Ongoing(ReferendumStatus), + Ongoing(ReferendumStatus), /// Referendum finished at `end`, and has been `approved` or rejected. Finished { approved: bool, end: BlockNumber }, } -impl ReferendumInfo { +impl ReferendumInfo { /// Create a new instance. pub fn new( end: BlockNumber, - proposal_hash: Hash, + proposal: Proposal, threshold: VoteThreshold, delay: BlockNumber, ) -> Self { - let s = ReferendumStatus { end, proposal_hash, threshold, delay, tally: Tally::default() }; + let s = ReferendumStatus { end, proposal, threshold, delay, tally: Tally::default() }; ReferendumInfo::Ongoing(s) } } diff --git a/frame/democracy/src/vote.rs b/frame/democracy/src/vote.rs index c74623d4dfeb8..122f54febd8cf 100644 --- a/frame/democracy/src/vote.rs +++ b/frame/democracy/src/vote.rs @@ -18,11 +18,12 @@ //! The vote datatype. use crate::{Conviction, Delegations, ReferendumIndex}; -use codec::{Decode, Encode, EncodeLike, Input, Output}; +use codec::{Decode, Encode, EncodeLike, Input, MaxEncodedLen, Output}; +use frame_support::traits::Get; use scale_info::TypeInfo; use sp_runtime::{ traits::{Saturating, Zero}, - RuntimeDebug, + BoundedVec, RuntimeDebug, }; use sp_std::prelude::*; @@ -39,6 +40,12 @@ impl Encode for Vote { } } +impl MaxEncodedLen for Vote { + fn max_encoded_len() -> usize { + 1 + } +} + impl EncodeLike for Vote {} impl Decode for Vote { @@ -66,7 +73,7 @@ impl TypeInfo for Vote { } /// A vote for a referendum of a particular account. -#[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] +#[derive(Encode, MaxEncodedLen, Decode, Copy, Clone, Eq, PartialEq, RuntimeDebug, TypeInfo)] pub enum AccountVote { /// A standard vote, one-way (approve or reject) with a given amount of conviction. Standard { vote: Vote, balance: Balance }, @@ -107,7 +114,18 @@ impl AccountVote { /// A "prior" lock, i.e. a lock for some now-forgotten reason. #[derive( - Encode, Decode, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, RuntimeDebug, TypeInfo, + Encode, + MaxEncodedLen, + Decode, + Default, + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + RuntimeDebug, + TypeInfo, )] pub struct PriorLock(BlockNumber, Balance); @@ -131,13 +149,15 @@ impl PriorLock { +#[derive(Clone, Encode, Decode, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] +#[codec(mel_bound(skip_type_params(MaxVotes)))] +#[scale_info(skip_type_params(MaxVotes))] +pub enum Voting> { /// The account is voting directly. `delegations` is the total amount of post-conviction voting /// weight that it controls from those that have delegated to it. Direct { /// The current votes of the account. - votes: Vec<(ReferendumIndex, AccountVote)>, + votes: BoundedVec<(ReferendumIndex, AccountVote), MaxVotes>, /// The total amount of delegations that this account has received. delegations: Delegations, /// Any pre-existing locks from past voting/delegating activity. @@ -155,20 +175,24 @@ pub enum Voting { }, } -impl Default - for Voting +impl> Default + for Voting { fn default() -> Self { Voting::Direct { - votes: Vec::new(), + votes: Default::default(), delegations: Default::default(), prior: PriorLock(Zero::zero(), Default::default()), } } } -impl - Voting +impl< + Balance: Saturating + Ord + Zero + Copy, + BlockNumber: Ord + Copy + Zero, + AccountId, + MaxVotes: Get, + > Voting { pub fn rejig(&mut self, now: BlockNumber) { match self { diff --git a/frame/democracy/src/vote_threshold.rs b/frame/democracy/src/vote_threshold.rs index 443d6b1166198..e8ef91def9820 100644 --- a/frame/democracy/src/vote_threshold.rs +++ b/frame/democracy/src/vote_threshold.rs @@ -18,7 +18,7 @@ //! Voting thresholds. use crate::Tally; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; @@ -26,7 +26,9 @@ use sp_runtime::traits::{IntegerSquareRoot, Zero}; use sp_std::ops::{Add, Div, Mul, Rem}; /// A means of determining if a vote is past pass threshold. -#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, sp_runtime::RuntimeDebug, TypeInfo)] +#[derive( + Clone, Copy, PartialEq, Eq, Encode, MaxEncodedLen, Decode, sp_runtime::RuntimeDebug, TypeInfo, +)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum VoteThreshold { /// A supermajority of approvals is needed to pass this vote. diff --git a/frame/democracy/src/weights.rs b/frame/democracy/src/weights.rs index 272921ed3a15d..0a3b717938022 100644 --- a/frame/democracy/src/weights.rs +++ b/frame/democracy/src/weights.rs @@ -18,22 +18,24 @@ //! Autogenerated weights for pallet_democracy //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-10-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_democracy // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --pallet=pallet_democracy +// --chain=dev // --output=./frame/democracy/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -45,27 +47,23 @@ use sp_std::marker::PhantomData; /// Weight functions needed for pallet_democracy. pub trait WeightInfo { fn propose() -> Weight; - fn second(s: u32, ) -> Weight; - fn vote_new(r: u32, ) -> Weight; - fn vote_existing(r: u32, ) -> Weight; + fn second() -> Weight; + fn vote_new() -> Weight; + fn vote_existing() -> Weight; fn emergency_cancel() -> Weight; - fn blacklist(p: u32, ) -> Weight; - fn external_propose(v: u32, ) -> Weight; + fn blacklist() -> Weight; + fn external_propose() -> Weight; fn external_propose_majority() -> Weight; fn external_propose_default() -> Weight; fn fast_track() -> Weight; - fn veto_external(v: u32, ) -> Weight; - fn cancel_proposal(p: u32, ) -> Weight; + fn veto_external() -> Weight; + fn cancel_proposal() -> Weight; fn cancel_referendum() -> Weight; - fn cancel_queued(r: u32, ) -> Weight; fn on_initialize_base(r: u32, ) -> Weight; fn on_initialize_base_with_launch_period(r: u32, ) -> Weight; fn delegate(r: u32, ) -> Weight; fn undelegate(r: u32, ) -> Weight; fn clear_public_proposals() -> Weight; - fn note_preimage(b: u32, ) -> Weight; - fn note_imminent_preimage(b: u32, ) -> Weight; - fn reap_preimage(b: u32, ) -> Weight; fn unlock_remove(r: u32, ) -> Weight; fn unlock_set(r: u32, ) -> Weight; fn remove_vote(r: u32, ) -> Weight; @@ -80,125 +78,103 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - Weight::from_ref_time(48_328_000 as u64) + Weight::from_ref_time(57_410_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy DepositOf (r:1 w:1) - fn second(s: u32, ) -> Weight { - Weight::from_ref_time(30_923_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(s as u64)) + fn second() -> Weight { + Weight::from_ref_time(49_224_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - fn vote_new(r: u32, ) -> Weight { - Weight::from_ref_time(40_345_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(140_000 as u64).saturating_mul(r as u64)) + fn vote_new() -> Weight { + Weight::from_ref_time(60_933_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - fn vote_existing(r: u32, ) -> Weight { - Weight::from_ref_time(39_853_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(150_000 as u64).saturating_mul(r as u64)) + fn vote_existing() -> Weight { + Weight::from_ref_time(60_393_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - Weight::from_ref_time(19_364_000 as u64) + Weight::from_ref_time(24_588_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Democracy PublicProps (r:1 w:1) + // Storage: Democracy DepositOf (r:1 w:1) + // Storage: System Account (r:1 w:1) // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Blacklist (r:0 w:1) - // Storage: Democracy DepositOf (r:1 w:1) - // Storage: System Account (r:1 w:1) - fn blacklist(p: u32, ) -> Weight { - Weight::from_ref_time(57_708_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64)) + fn blacklist() -> Weight { + Weight::from_ref_time(91_226_000 as u64) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) - fn external_propose(v: u32, ) -> Weight { - Weight::from_ref_time(10_714_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(33_000 as u64).saturating_mul(v as u64)) + fn external_propose() -> Weight { + Weight::from_ref_time(18_898_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - Weight::from_ref_time(3_697_000 as u64) + Weight::from_ref_time(5_136_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - Weight::from_ref_time(3_831_000 as u64) + Weight::from_ref_time(5_243_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - Weight::from_ref_time(20_271_000 as u64) + Weight::from_ref_time(24_275_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) - fn veto_external(v: u32, ) -> Weight { - Weight::from_ref_time(21_319_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(v as u64)) + fn veto_external() -> Weight { + Weight::from_ref_time(30_988_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Democracy PublicProps (r:1 w:1) // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) - fn cancel_proposal(p: u32, ) -> Weight { - Weight::from_ref_time(43_960_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(184_000 as u64).saturating_mul(p as u64)) + fn cancel_proposal() -> Weight { + Weight::from_ref_time(78_515_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - Weight::from_ref_time(13_475_000 as u64) + Weight::from_ref_time(16_155_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } - // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Scheduler Agenda (r:1 w:1) - fn cancel_queued(r: u32, ) -> Weight { - Weight::from_ref_time(24_320_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(560_000 as u64).saturating_mul(r as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - } // Storage: Democracy LowestUnbaked (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:0) - // Storage: Democracy ReferendumInfoOf (r:1 w:0) + // Storage: Democracy ReferendumInfoOf (r:2 w:0) + /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { - Weight::from_ref_time(3_428_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_171_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(7_007_000 as u64) + // Standard Error: 2_686 + .saturating_add(Weight::from_ref_time(2_288_781 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) @@ -208,33 +184,36 @@ impl WeightInfo for SubstrateWeight { // Storage: Democracy LastTabledWasExternal (r:1 w:0) // Storage: Democracy NextExternal (r:1 w:0) // Storage: Democracy PublicProps (r:1 w:0) - // Storage: Democracy ReferendumInfoOf (r:1 w:0) + // Storage: Democracy ReferendumInfoOf (r:2 w:0) + /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - Weight::from_ref_time(7_867_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_177_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(9_528_000 as u64) + // Standard Error: 2_521 + .saturating_add(Weight::from_ref_time(2_291_780 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(5 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy VotingOf (r:3 w:3) - // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + // Storage: Democracy ReferendumInfoOf (r:2 w:2) + /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { - Weight::from_ref_time(37_902_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(4_335_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(46_787_000 as u64) + // Standard Error: 2_943 + .saturating_add(Weight::from_ref_time(3_460_194 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(4 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(r as u64))) } // Storage: Democracy VotingOf (r:2 w:2) - // Storage: Democracy ReferendumInfoOf (r:1 w:1) + // Storage: Democracy ReferendumInfoOf (r:2 w:2) + /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { - Weight::from_ref_time(21_272_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(4_351_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(29_789_000 as u64) + // Standard Error: 2_324 + .saturating_add(Weight::from_ref_time(3_360_918 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(T::DbWeight::get().writes(2 as u64)) @@ -242,69 +221,48 @@ impl WeightInfo for SubstrateWeight { } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - Weight::from_ref_time(4_913_000 as u64) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: Democracy Preimages (r:1 w:1) - fn note_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(27_986_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: Democracy Preimages (r:1 w:1) - fn note_imminent_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(20_058_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: Democracy Preimages (r:1 w:1) - // Storage: System Account (r:1 w:0) - fn reap_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(28_619_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) + Weight::from_ref_time(6_519_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { - Weight::from_ref_time(26_619_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(28_884_000 as u64) + // Standard Error: 2_631 + .saturating_add(Weight::from_ref_time(163_516 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { - Weight::from_ref_time(25_373_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(33_498_000 as u64) + // Standard Error: 622 + .saturating_add(Weight::from_ref_time(133_421 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) + /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { - Weight::from_ref_time(15_961_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(18_201_000 as u64) + // Standard Error: 1_007 + .saturating_add(Weight::from_ref_time(152_699 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) + /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { - Weight::from_ref_time(15_992_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(113_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(18_455_000 as u64) + // Standard Error: 951 + .saturating_add(Weight::from_ref_time(150_907 as u64).saturating_mul(r as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -317,125 +275,103 @@ impl WeightInfo for () { // Storage: Democracy Blacklist (r:1 w:0) // Storage: Democracy DepositOf (r:0 w:1) fn propose() -> Weight { - Weight::from_ref_time(48_328_000 as u64) + Weight::from_ref_time(57_410_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy DepositOf (r:1 w:1) - fn second(s: u32, ) -> Weight { - Weight::from_ref_time(30_923_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(s as u64)) + fn second() -> Weight { + Weight::from_ref_time(49_224_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - fn vote_new(r: u32, ) -> Weight { - Weight::from_ref_time(40_345_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(140_000 as u64).saturating_mul(r as u64)) + fn vote_new() -> Weight { + Weight::from_ref_time(60_933_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - fn vote_existing(r: u32, ) -> Weight { - Weight::from_ref_time(39_853_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(150_000 as u64).saturating_mul(r as u64)) + fn vote_existing() -> Weight { + Weight::from_ref_time(60_393_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Cancellations (r:1 w:1) fn emergency_cancel() -> Weight { - Weight::from_ref_time(19_364_000 as u64) + Weight::from_ref_time(24_588_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Democracy PublicProps (r:1 w:1) + // Storage: Democracy DepositOf (r:1 w:1) + // Storage: System Account (r:1 w:1) // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy Blacklist (r:0 w:1) - // Storage: Democracy DepositOf (r:1 w:1) - // Storage: System Account (r:1 w:1) - fn blacklist(p: u32, ) -> Weight { - Weight::from_ref_time(57_708_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(192_000 as u64).saturating_mul(p as u64)) + fn blacklist() -> Weight { + Weight::from_ref_time(91_226_000 as u64) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:0) - fn external_propose(v: u32, ) -> Weight { - Weight::from_ref_time(10_714_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(33_000 as u64).saturating_mul(v as u64)) + fn external_propose() -> Weight { + Weight::from_ref_time(18_898_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_majority() -> Weight { - Weight::from_ref_time(3_697_000 as u64) + Weight::from_ref_time(5_136_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:0 w:1) fn external_propose_default() -> Weight { - Weight::from_ref_time(3_831_000 as u64) + Weight::from_ref_time(5_243_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:1) // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn fast_track() -> Weight { - Weight::from_ref_time(20_271_000 as u64) + Weight::from_ref_time(24_275_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy NextExternal (r:1 w:1) // Storage: Democracy Blacklist (r:1 w:1) - fn veto_external(v: u32, ) -> Weight { - Weight::from_ref_time(21_319_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(52_000 as u64).saturating_mul(v as u64)) + fn veto_external() -> Weight { + Weight::from_ref_time(30_988_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Democracy PublicProps (r:1 w:1) // Storage: Democracy DepositOf (r:1 w:1) // Storage: System Account (r:1 w:1) - fn cancel_proposal(p: u32, ) -> Weight { - Weight::from_ref_time(43_960_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(184_000 as u64).saturating_mul(p as u64)) + fn cancel_proposal() -> Weight { + Weight::from_ref_time(78_515_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:0 w:1) fn cancel_referendum() -> Weight { - Weight::from_ref_time(13_475_000 as u64) + Weight::from_ref_time(16_155_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } - // Storage: Scheduler Lookup (r:1 w:1) - // Storage: Scheduler Agenda (r:1 w:1) - fn cancel_queued(r: u32, ) -> Weight { - Weight::from_ref_time(24_320_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(560_000 as u64).saturating_mul(r as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - } // Storage: Democracy LowestUnbaked (r:1 w:1) // Storage: Democracy ReferendumCount (r:1 w:0) - // Storage: Democracy ReferendumInfoOf (r:1 w:0) + // Storage: Democracy ReferendumInfoOf (r:2 w:0) + /// The range of component `r` is `[0, 99]`. fn on_initialize_base(r: u32, ) -> Weight { - Weight::from_ref_time(3_428_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_171_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(7_007_000 as u64) + // Standard Error: 2_686 + .saturating_add(Weight::from_ref_time(2_288_781 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(1 as u64)) @@ -445,33 +381,36 @@ impl WeightInfo for () { // Storage: Democracy LastTabledWasExternal (r:1 w:0) // Storage: Democracy NextExternal (r:1 w:0) // Storage: Democracy PublicProps (r:1 w:0) - // Storage: Democracy ReferendumInfoOf (r:1 w:0) + // Storage: Democracy ReferendumInfoOf (r:2 w:0) + /// The range of component `r` is `[0, 99]`. fn on_initialize_base_with_launch_period(r: u32, ) -> Weight { - Weight::from_ref_time(7_867_000 as u64) - // Standard Error: 2_000 - .saturating_add(Weight::from_ref_time(3_177_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(9_528_000 as u64) + // Standard Error: 2_521 + .saturating_add(Weight::from_ref_time(2_291_780 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(5 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy VotingOf (r:3 w:3) - // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) + // Storage: Democracy ReferendumInfoOf (r:2 w:2) + /// The range of component `r` is `[0, 99]`. fn delegate(r: u32, ) -> Weight { - Weight::from_ref_time(37_902_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(4_335_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(46_787_000 as u64) + // Standard Error: 2_943 + .saturating_add(Weight::from_ref_time(3_460_194 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(4 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(r as u64))) } // Storage: Democracy VotingOf (r:2 w:2) - // Storage: Democracy ReferendumInfoOf (r:1 w:1) + // Storage: Democracy ReferendumInfoOf (r:2 w:2) + /// The range of component `r` is `[0, 99]`. fn undelegate(r: u32, ) -> Weight { - Weight::from_ref_time(21_272_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(4_351_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(29_789_000 as u64) + // Standard Error: 2_324 + .saturating_add(Weight::from_ref_time(3_360_918 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(r as u64))) .saturating_add(RocksDbWeight::get().writes(2 as u64)) @@ -479,69 +418,48 @@ impl WeightInfo for () { } // Storage: Democracy PublicProps (r:0 w:1) fn clear_public_proposals() -> Weight { - Weight::from_ref_time(4_913_000 as u64) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: Democracy Preimages (r:1 w:1) - fn note_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(27_986_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: Democracy Preimages (r:1 w:1) - fn note_imminent_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(20_058_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(b as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: Democracy Preimages (r:1 w:1) - // Storage: System Account (r:1 w:0) - fn reap_preimage(b: u32, ) -> Weight { - Weight::from_ref_time(28_619_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(b as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) + Weight::from_ref_time(6_519_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `r` is `[0, 99]`. fn unlock_remove(r: u32, ) -> Weight { - Weight::from_ref_time(26_619_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(56_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(28_884_000 as u64) + // Standard Error: 2_631 + .saturating_add(Weight::from_ref_time(163_516 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy VotingOf (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `r` is `[0, 99]`. fn unlock_set(r: u32, ) -> Weight { - Weight::from_ref_time(25_373_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(142_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(33_498_000 as u64) + // Standard Error: 622 + .saturating_add(Weight::from_ref_time(133_421 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) + /// The range of component `r` is `[1, 100]`. fn remove_vote(r: u32, ) -> Weight { - Weight::from_ref_time(15_961_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(115_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(18_201_000 as u64) + // Standard Error: 1_007 + .saturating_add(Weight::from_ref_time(152_699 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Democracy ReferendumInfoOf (r:1 w:1) // Storage: Democracy VotingOf (r:1 w:1) + /// The range of component `r` is `[1, 100]`. fn remove_other_vote(r: u32, ) -> Weight { - Weight::from_ref_time(15_992_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(113_000 as u64).saturating_mul(r as u64)) + Weight::from_ref_time(18_455_000 as u64) + // Standard Error: 951 + .saturating_add(Weight::from_ref_time(150_907 as u64).saturating_mul(r as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } diff --git a/frame/election-provider-multi-phase/Cargo.toml b/frame/election-provider-multi-phase/Cargo.toml index aea3b5cd6d2b0..ca94fef6a4356 100644 --- a/frame/election-provider-multi-phase/Cargo.toml +++ b/frame/election-provider-multi-phase/Cargo.toml @@ -52,6 +52,7 @@ frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } [features] default = ["std"] std = [ + "pallet-election-provider-support-benchmarking?/std", "codec/std", "scale-info/std", "log/std", @@ -68,7 +69,7 @@ std = [ "frame-election-provider-support/std", "log/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "rand/std", "strum/std", ] diff --git a/frame/election-provider-multi-phase/src/lib.rs b/frame/election-provider-multi-phase/src/lib.rs index 84949080aa58c..3dc6161bb202a 100644 --- a/frame/election-provider-multi-phase/src/lib.rs +++ b/frame/election-provider-multi-phase/src/lib.rs @@ -231,12 +231,14 @@ use codec::{Decode, Encode}; use frame_election_provider_support::{ - ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolution, + ElectionDataProvider, ElectionProvider, ElectionProviderBase, InstantElectionProvider, + NposSolution, }; use frame_support::{ + dispatch::DispatchClass, ensure, traits::{Currency, Get, OnUnbalanced, ReservableCurrency}, - weights::{DispatchClass, Weight}, + weights::Weight, }; use frame_system::{ensure_none, offchain::SendTransactionTypes}; use scale_info::TypeInfo; @@ -288,7 +290,7 @@ pub type SolutionTargetIndexOf = as NposSolution>::TargetIndex pub type SolutionAccuracyOf = ::MinerConfig> as NposSolution>::Accuracy; /// The fallback election type. -pub type FallbackErrorOf = <::Fallback as ElectionProvider>::Error; +pub type FallbackErrorOf = <::Fallback as ElectionProviderBase>::Error; /// Configuration for the benchmarks of the pallet. pub trait BenchmarkingConfig { @@ -311,12 +313,18 @@ pub trait BenchmarkingConfig { /// A fallback implementation that transitions the pallet to the emergency phase. pub struct NoFallback(sp_std::marker::PhantomData); -impl ElectionProvider for NoFallback { +impl ElectionProviderBase for NoFallback { type AccountId = T::AccountId; type BlockNumber = T::BlockNumber; type DataProvider = T::DataProvider; type Error = &'static str; + fn ongoing() -> bool { + false + } +} + +impl ElectionProvider for NoFallback { fn elect() -> Result, Self::Error> { // Do nothing, this will enable the emergency phase. Err("NoFallback.") @@ -570,8 +578,8 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + SendTransactionTypes> { - type Event: From> - + IsType<::Event> + type RuntimeEvent: From> + + IsType<::RuntimeEvent> + TryInto>; /// Currency type. @@ -699,7 +707,7 @@ pub mod pallet { /// Origin that can control this pallet. Note that any action taken by this origin (such) /// as providing an emergency solution is not checked. Thus, it must be a trusted origin. - type ForceOrigin: EnsureOrigin; + type ForceOrigin: EnsureOrigin; /// The configuration of benchmarking. type BenchmarkingConfig: BenchmarkingConfig; @@ -708,6 +716,25 @@ pub mod pallet { type WeightInfo: WeightInfo; } + // Expose miner configs over the metadata such that they can be re-implemented. + #[pallet::extra_constants] + impl Pallet { + #[pallet::constant_name(MinerMaxLength)] + fn max_length() -> u32 { + ::MaxLength::get() + } + + #[pallet::constant_name(MinerMaxWeight)] + fn max_weight() -> Weight { + ::MaxWeight::get() + } + + #[pallet::constant_name(MinerMaxVotesPerVoter)] + fn max_votes_per_voter() -> u32 { + ::MaxVotesPerVoter::get() + } + } + #[pallet::hooks] impl Hooks> for Pallet { fn on_initialize(now: T::BlockNumber) -> Weight { @@ -985,7 +1012,7 @@ pub mod pallet { let size = Self::snapshot_metadata().ok_or(Error::::MissingSnapshotMetadata)?; ensure!( - Self::solution_weight_of(&raw_solution, size) < T::SignedMaxWeight::get(), + Self::solution_weight_of(&raw_solution, size).all_lt(T::SignedMaxWeight::get()), Error::::SignedTooMuchWeight, ); @@ -1537,7 +1564,7 @@ impl Pallet { >::take() .ok_or(ElectionError::::NothingQueued) .or_else(|_| { - T::Fallback::elect() + ::elect() .map(|supports| ReadySolution { supports, score: Default::default(), @@ -1572,12 +1599,21 @@ impl Pallet { } } -impl ElectionProvider for Pallet { +impl ElectionProviderBase for Pallet { type AccountId = T::AccountId; type BlockNumber = T::BlockNumber; type Error = ElectionError; type DataProvider = T::DataProvider; + fn ongoing() -> bool { + match Self::current_phase() { + Phase::Off => false, + _ => true, + } + } +} + +impl ElectionProvider for Pallet { fn elect() -> Result, Self::Error> { match Self::do_elect() { Ok(supports) => { @@ -1594,7 +1630,6 @@ impl ElectionProvider for Pallet { } } } - /// convert a DispatchError to a custom InvalidTransaction with the inner code being the error /// number. pub fn dispatch_error_to_invalid(error: DispatchError) -> InvalidTransaction { @@ -1807,9 +1842,9 @@ mod tests { use super::*; use crate::{ mock::{ - multi_phase_events, raw_solution, roll_to, AccountId, ExtBuilder, MockWeightInfo, - MockedWeightInfo, MultiPhase, Origin, Runtime, SignedMaxSubmissions, System, - TargetIndex, Targets, + multi_phase_events, raw_solution, roll_to, roll_to_signed, roll_to_unsigned, AccountId, + ExtBuilder, MockWeightInfo, MockedWeightInfo, MultiPhase, Runtime, RuntimeOrigin, + SignedMaxSubmissions, System, TargetIndex, Targets, }, Phase, }; @@ -1833,7 +1868,7 @@ mod tests { assert!(MultiPhase::snapshot().is_none()); assert_eq!(MultiPhase::round(), 1); - roll_to(15); + roll_to_signed(); assert_eq!(MultiPhase::current_phase(), Phase::Signed); assert_eq!(multi_phase_events(), vec![Event::SignedPhaseStarted { round: 1 }]); assert!(MultiPhase::snapshot().is_some()); @@ -1844,7 +1879,7 @@ mod tests { assert!(MultiPhase::snapshot().is_some()); assert_eq!(MultiPhase::round(), 1); - roll_to(25); + roll_to_unsigned(); assert_eq!(MultiPhase::current_phase(), Phase::Unsigned((true, 25))); assert_eq!( multi_phase_events(), @@ -1877,11 +1912,29 @@ mod tests { roll_to(44); assert!(MultiPhase::current_phase().is_off()); - roll_to(45); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); roll_to(55); assert!(MultiPhase::current_phase().is_unsigned_open_at(55)); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::UnsignedPhaseStarted { round: 1 }, + Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { + minimal_stake: 0, + sum_stake: 0, + sum_stake_squared: 0 + } + }, + Event::SignedPhaseStarted { round: 2 }, + Event::UnsignedPhaseStarted { round: 2 } + ] + ); }) } @@ -1905,6 +1958,21 @@ mod tests { assert!(MultiPhase::current_phase().is_off()); assert!(MultiPhase::snapshot().is_none()); + + assert_eq!( + multi_phase_events(), + vec![ + Event::UnsignedPhaseStarted { round: 1 }, + Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { + minimal_stake: 0, + sum_stake: 0, + sum_stake_squared: 0 + } + } + ] + ); }); } @@ -1917,7 +1985,7 @@ mod tests { roll_to(19); assert!(MultiPhase::current_phase().is_off()); - roll_to(20); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); assert!(MultiPhase::snapshot().is_some()); @@ -1928,6 +1996,21 @@ mod tests { assert!(MultiPhase::current_phase().is_off()); assert!(MultiPhase::snapshot().is_none()); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { + minimal_stake: 0, + sum_stake: 0, + sum_stake_squared: 0 + } + } + ] + ) }); } @@ -1950,6 +2033,14 @@ mod tests { assert_ok!(MultiPhase::elect()); assert!(MultiPhase::current_phase().is_off()); + + assert_eq!( + multi_phase_events(), + vec![Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { minimal_stake: 0, sum_stake: 0, sum_stake_squared: 0 } + }] + ); }); } @@ -1958,16 +2049,13 @@ mod tests { // An early termination in the signed phase, with no queued solution. ExtBuilder::default().build_and_execute(|| { // Signed phase started at block 15 and will end at 25. - roll_to(14); - assert_eq!(MultiPhase::current_phase(), Phase::Off); - roll_to(15); + roll_to_signed(); assert_eq!(multi_phase_events(), vec![Event::SignedPhaseStarted { round: 1 }]); assert_eq!(MultiPhase::current_phase(), Phase::Signed); assert_eq!(MultiPhase::round(), 1); // An unexpected call to elect. - roll_to(20); assert_ok!(MultiPhase::elect()); // We surely can't have any feasible solutions. This will cause an on-chain election. @@ -1996,10 +2084,8 @@ mod tests { // an early termination in the signed phase, with no queued solution. ExtBuilder::default().build_and_execute(|| { // signed phase started at block 15 and will end at 25. - roll_to(14); - assert_eq!(MultiPhase::current_phase(), Phase::Off); - roll_to(15); + roll_to_signed(); assert_eq!(multi_phase_events(), vec![Event::SignedPhaseStarted { round: 1 }]); assert_eq!(MultiPhase::current_phase(), Phase::Signed); assert_eq!(MultiPhase::round(), 1); @@ -2010,11 +2096,13 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(crate::mock::Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit( + crate::mock::RuntimeOrigin::signed(99), + Box::new(solution) + )); } // an unexpected call to elect. - roll_to(20); assert_ok!(MultiPhase::elect()); // all storage items must be cleared. @@ -2024,20 +2112,45 @@ mod tests { assert!(MultiPhase::desired_targets().is_none()); assert!(MultiPhase::queued_solution().is_none()); assert!(MultiPhase::signed_submissions().is_empty()); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::Slashed { account: 99, value: 5 }, + Event::Slashed { account: 99, value: 5 }, + Event::Slashed { account: 99, value: 5 }, + Event::Slashed { account: 99, value: 5 }, + Event::Slashed { account: 99, value: 5 }, + Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { + minimal_stake: 0, + sum_stake: 0, + sum_stake_squared: 0 + } + } + ] + ); }) } #[test] fn check_events_with_compute_signed() { ExtBuilder::default().build_and_execute(|| { - roll_to(14); - assert_eq!(MultiPhase::current_phase(), Phase::Off); - - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let solution = raw_solution(); - assert_ok!(MultiPhase::submit(crate::mock::Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit( + crate::mock::RuntimeOrigin::signed(99), + Box::new(solution) + )); roll_to(30); assert_ok!(MultiPhase::elect()); @@ -2065,7 +2178,7 @@ mod tests { #[test] fn check_events_with_compute_unsigned() { ExtBuilder::default().build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); // ensure we have snapshots in place. @@ -2078,13 +2191,12 @@ mod tests { // ensure this solution is valid. assert!(MultiPhase::queued_solution().is_none()); assert_ok!(MultiPhase::submit_unsigned( - crate::mock::Origin::none(), + crate::mock::RuntimeOrigin::none(), Box::new(solution), witness )); assert!(MultiPhase::queued_solution().is_some()); - roll_to(30); assert_ok!(MultiPhase::elect()); assert_eq!( @@ -2112,7 +2224,7 @@ mod tests { #[test] fn fallback_strategy_works() { ExtBuilder::default().onchain_fallback(true).build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert_eq!(MultiPhase::current_phase(), Phase::Unsigned((true, 25))); // Zilch solutions thus far, but we get a result. @@ -2125,11 +2237,27 @@ mod tests { (30, Support { total: 40, voters: vec![(2, 5), (4, 5), (30, 30)] }), (40, Support { total: 60, voters: vec![(2, 5), (3, 10), (4, 5), (40, 40)] }) ] - ) + ); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::UnsignedPhaseStarted { round: 1 }, + Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { + minimal_stake: 0, + sum_stake: 0, + sum_stake_squared: 0 + } + } + ] + ); }); ExtBuilder::default().onchain_fallback(false).build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert_eq!(MultiPhase::current_phase(), Phase::Unsigned((true, 25))); // Zilch solutions thus far. @@ -2137,13 +2265,22 @@ mod tests { assert_eq!(MultiPhase::elect().unwrap_err(), ElectionError::Fallback("NoFallback.")); // phase is now emergency. assert_eq!(MultiPhase::current_phase(), Phase::Emergency); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::UnsignedPhaseStarted { round: 1 }, + Event::ElectionFailed + ] + ); }) } #[test] fn governance_fallback_works() { ExtBuilder::default().onchain_fallback(false).build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert_eq!(MultiPhase::current_phase(), Phase::Unsigned((true, 25))); // Zilch solutions thus far. @@ -2156,12 +2293,12 @@ mod tests { // no single account can trigger this assert_noop!( - MultiPhase::governance_fallback(Origin::signed(99), None, None), + MultiPhase::governance_fallback(RuntimeOrigin::signed(99), None, None), DispatchError::BadOrigin ); // only root can - assert_ok!(MultiPhase::governance_fallback(Origin::root(), None, None)); + assert_ok!(MultiPhase::governance_fallback(RuntimeOrigin::root(), None, None)); // something is queued now assert!(MultiPhase::queued_solution().is_some()); // next election call with fix everything.; @@ -2202,9 +2339,16 @@ mod tests { assert_eq!(MultiPhase::current_phase(), Phase::Off); // On-chain backup works though. - roll_to(29); let supports = MultiPhase::elect().unwrap(); assert!(supports.len() > 0); + + assert_eq!( + multi_phase_events(), + vec![Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { minimal_stake: 0, sum_stake: 0, sum_stake_squared: 0 } + }] + ); }); } @@ -2228,6 +2372,8 @@ mod tests { let err = MultiPhase::elect().unwrap_err(); assert_eq!(err, ElectionError::Fallback("NoFallback.")); assert_eq!(MultiPhase::current_phase(), Phase::Emergency); + + assert_eq!(multi_phase_events(), vec![Event::ElectionFailed]); }); } @@ -2241,7 +2387,7 @@ mod tests { crate::mock::MaxElectingVoters::set(2); // Signed phase opens just fine. - roll_to(15); + roll_to_signed(); assert_eq!(MultiPhase::current_phase(), Phase::Signed); assert_eq!( @@ -2254,7 +2400,7 @@ mod tests { #[test] fn untrusted_score_verification_is_respected() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert_eq!(MultiPhase::current_phase(), Phase::Signed); // set the solution balancing to get the desired score. @@ -2299,8 +2445,8 @@ mod tests { }; let mut active = 1; - while weight_with(active) <= - ::BlockWeights::get().max_block || + while weight_with(active) + .all_lte(::BlockWeights::get().max_block) || active == all_voters { active += 1; diff --git a/frame/election-provider-multi-phase/src/mock.rs b/frame/election-provider-multi-phase/src/mock.rs index 48b76bbb98a8f..e04e0bf474caf 100644 --- a/frame/election-provider-multi-phase/src/mock.rs +++ b/frame/election-provider-multi-phase/src/mock.rs @@ -26,7 +26,7 @@ pub use frame_support::{assert_noop, assert_ok, pallet_prelude::GetDefault}; use frame_support::{ bounded_vec, parameter_types, traits::{ConstU32, Hooks}, - weights::Weight, + weights::{constants, Weight}, BoundedVec, }; use multi_phase::unsigned::{IndexAssignmentOf, VoterOf}; @@ -50,7 +50,8 @@ use sp_runtime::{ use std::sync::Arc; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = + sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Runtime where @@ -85,7 +86,7 @@ pub(crate) fn multi_phase_events() -> Vec> { System::events() .into_iter() .map(|r| r.event) - .filter_map(|e| if let Event::MultiPhase(inner) = e { Some(inner) } else { None }) + .filter_map(|e| if let RuntimeEvent::MultiPhase(inner) = e { Some(inner) } else { None }) .collect::>() } @@ -98,6 +99,17 @@ pub fn roll_to(n: BlockNumber) { } } +pub fn roll_to_unsigned() { + while !matches!(MultiPhase::current_phase(), Phase::Unsigned(_)) { + roll_to(System::block_number() + 1); + } +} +pub fn roll_to_signed() { + while !matches!(MultiPhase::current_phase(), Phase::Signed) { + roll_to(System::block_number() + 1); + } +} + pub fn roll_to_with_ocw(n: BlockNumber) { let now = System::block_number(); for i in now + 1..=n { @@ -143,7 +155,7 @@ pub fn trim_helpers() -> TrimHelpers { seq_phragmen(desired_targets as usize, targets.clone(), voters.clone(), None).unwrap(); // sort by decreasing order of stake - assignments.sort_unstable_by_key(|assignment| { + assignments.sort_by_key(|assignment| { std::cmp::Reverse(stakes.get(&assignment.who).cloned().unwrap_or_default()) }); @@ -198,16 +210,16 @@ pub fn witness() -> SolutionOrSnapshotSize { impl frame_system::Config for Runtime { type SS58Prefix = (); type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type DbWeight = (); type BlockLength = (); @@ -226,12 +238,15 @@ const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); parameter_types! { pub const ExistentialDeposit: u64 = 1; pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights - ::with_sensible_defaults(2u64 * frame_support::weights::constants::WEIGHT_PER_SECOND, NORMAL_DISPATCH_RATIO); + ::with_sensible_defaults( + Weight::from_parts(2u64 * constants::WEIGHT_PER_SECOND.ref_time(), u64::MAX), + NORMAL_DISPATCH_RATIO, + ); } impl pallet_balances::Config for Runtime { type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; @@ -241,8 +256,9 @@ impl pallet_balances::Config for Runtime { type WeightInfo = (); } -#[derive(Eq, PartialEq, Debug, Clone, Copy)] +#[derive(Default, Eq, PartialEq, Debug, Clone, Copy)] pub enum MockedWeightInfo { + #[default] Basic, Complex, Real, @@ -295,12 +311,17 @@ impl onchain::Config for OnChainSeqPhragmen { } pub struct MockFallback; -impl ElectionProvider for MockFallback { +impl ElectionProviderBase for MockFallback { type AccountId = AccountId; type BlockNumber = u64; type Error = &'static str; type DataProvider = StakingMock; + fn ongoing() -> bool { + false + } +} +impl ElectionProvider for MockFallback { fn elect() -> Result, Self::Error> { Self::elect_with_bounds(Bounded::max_value(), Bounded::max_value()) } @@ -361,7 +382,7 @@ impl MinerConfig for Runtime { } impl crate::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type EstimateCallFee = frame_support::traits::ConstU32<8>; type SignedPhase = SignedPhase; @@ -393,13 +414,13 @@ impl crate::Config for Runtime { impl frame_system::offchain::SendTransactionTypes for Runtime where - Call: From, + RuntimeCall: From, { - type OverarchingCall = Call; + type OverarchingCall = RuntimeCall; type Extrinsic = Extrinsic; } -pub type Extrinsic = sp_runtime::testing::TestXt; +pub type Extrinsic = sp_runtime::testing::TestXt; parameter_types! { pub MaxNominations: u32 = ::LIMIT as u32; diff --git a/frame/election-provider-multi-phase/src/signed.rs b/frame/election-provider-multi-phase/src/signed.rs index b9abfdfba14fb..175c92757f35e 100644 --- a/frame/election-provider-multi-phase/src/signed.rs +++ b/frame/election-provider-multi-phase/src/signed.rs @@ -528,10 +528,11 @@ mod tests { use super::*; use crate::{ mock::{ - balances, raw_solution, roll_to, Balances, ExtBuilder, MockedWeightInfo, MultiPhase, - Origin, Runtime, SignedMaxRefunds, SignedMaxSubmissions, SignedMaxWeight, + balances, multi_phase_events, raw_solution, roll_to, roll_to_signed, Balances, + ExtBuilder, MockedWeightInfo, MultiPhase, Runtime, RuntimeOrigin, SignedMaxRefunds, + SignedMaxSubmissions, SignedMaxWeight, }, - Error, Perbill, Phase, + Error, Event, Perbill, Phase, }; use frame_support::{assert_noop, assert_ok, assert_storage_noop}; @@ -546,7 +547,7 @@ mod tests { let solution = raw_solution(); assert_noop!( - MultiPhase::submit(Origin::signed(10), Box::new(solution)), + MultiPhase::submit(RuntimeOrigin::signed(10), Box::new(solution)), Error::::PreDispatchEarlySubmission, ); }) @@ -555,40 +556,57 @@ mod tests { #[test] fn should_pay_deposit() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let solution = raw_solution(); assert_eq!(balances(&99), (100, 0)); - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); assert_eq!(balances(&99), (95, 5)); assert_eq!(MultiPhase::signed_submissions().iter().next().unwrap().deposit, 5); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false } + ] + ); }) } #[test] fn good_solution_is_rewarded() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let solution = raw_solution(); assert_eq!(balances(&99), (100, 0)); - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); assert_eq!(balances(&99), (95, 5)); assert!(MultiPhase::finalize_signed_phase()); assert_eq!(balances(&99), (100 + 7 + 8, 0)); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::Rewarded { account: 99, value: 7 } + ] + ); }) } #[test] fn bad_solution_is_slashed() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let mut solution = raw_solution(); @@ -597,20 +615,29 @@ mod tests { // make the solution invalid. solution.score.minimal_stake += 1; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); assert_eq!(balances(&99), (95, 5)); // no good solution was stored. assert!(!MultiPhase::finalize_signed_phase()); // and the bond is gone. assert_eq!(balances(&99), (95, 0)); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::Slashed { account: 99, value: 5 } + ] + ); }) } #[test] fn suppressed_solution_gets_bond_back() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let mut solution = raw_solution(); @@ -618,11 +645,11 @@ mod tests { assert_eq!(balances(&999), (100, 0)); // submit as correct. - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution.clone()))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution.clone()))); // make the solution invalid and weaker. solution.score.minimal_stake -= 1; - assert_ok!(MultiPhase::submit(Origin::signed(999), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(999), Box::new(solution))); assert_eq!(balances(&99), (95, 5)); assert_eq!(balances(&999), (95, 5)); @@ -633,13 +660,22 @@ mod tests { assert_eq!(balances(&99), (100 + 7 + 8, 0)); // 999 gets everything back, including the call fee. assert_eq!(balances(&999), (100 + 8, 0)); + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::Rewarded { account: 99, value: 7 } + ] + ); }) } #[test] fn cannot_submit_worse_with_full_queue() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); for s in 0..SignedMaxSubmissions::get() { @@ -648,7 +684,7 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); } // weaker. @@ -658,7 +694,7 @@ mod tests { }; assert_noop!( - MultiPhase::submit(Origin::signed(99), Box::new(solution)), + MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution)), Error::::SignedQueueFull, ); }) @@ -667,7 +703,7 @@ mod tests { #[test] fn call_fee_refund_is_limited_by_signed_max_refunds() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); assert_eq!(SignedMaxRefunds::get(), 1); assert!(SignedMaxSubmissions::get() > 2); @@ -679,11 +715,11 @@ mod tests { let mut solution = raw_solution(); solution.score.minimal_stake -= s as u128; - assert_ok!(MultiPhase::submit(Origin::signed(account), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(account), Box::new(solution))); assert_eq!(balances(&account), (95, 5)); } - assert!(MultiPhase::finalize_signed_phase()); + assert_ok!(MultiPhase::do_elect()); for s in 0..SignedMaxSubmissions::get() { let account = 99 + s as u64; @@ -699,6 +735,26 @@ mod tests { assert_eq!(balances(&account), (100, 0)); } } + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::Rewarded { account: 99, value: 7 }, + Event::ElectionFinalized { + compute: ElectionCompute::Signed, + score: ElectionScore { + minimal_stake: 40, + sum_stake: 100, + sum_stake_squared: 5200 + } + } + ] + ); }); } @@ -708,7 +764,7 @@ mod tests { .signed_max_submission(1) .better_signed_threshold(Perbill::from_percent(20)) .build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let mut solution = RawSolution { @@ -719,7 +775,7 @@ mod tests { }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); // This is 10% better, so does not meet the 20% threshold and is therefore rejected. solution = RawSolution { @@ -732,7 +788,7 @@ mod tests { }; assert_noop!( - MultiPhase::submit(Origin::signed(99), Box::new(solution)), + MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution)), Error::::SignedQueueFull, ); @@ -746,14 +802,28 @@ mod tests { ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + prev_ejected: false + }, + Event::SolutionStored { + compute: ElectionCompute::Signed, + prev_ejected: true + } + ] + ); }) } #[test] fn weakest_is_removed_if_better_provided() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); for s in 0..SignedMaxSubmissions::get() { @@ -764,7 +834,7 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(account), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(account), Box::new(solution))); assert_eq!(balances(&account), (95, 5)); } @@ -781,7 +851,7 @@ mod tests { score: ElectionScore { minimal_stake: 20, ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(999), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(999), Box::new(solution))); // the one with score 5 was rejected, the new one inserted. assert_eq!( @@ -800,7 +870,7 @@ mod tests { #[test] fn replace_weakest_works() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); for s in 1..SignedMaxSubmissions::get() { @@ -809,14 +879,14 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); } let solution = RawSolution { score: ElectionScore { minimal_stake: 4, ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); assert_eq!( MultiPhase::signed_submissions() @@ -831,7 +901,7 @@ mod tests { score: ElectionScore { minimal_stake: 5, ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); // the one with score 5 was rejected, the new one inserted. assert_eq!( @@ -847,7 +917,7 @@ mod tests { #[test] fn early_ejected_solution_gets_bond_back() { ExtBuilder::default().signed_deposit(2, 0, 0).build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); for s in 0..SignedMaxSubmissions::get() { @@ -856,7 +926,7 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); } assert_eq!(balances(&99).1, 2 * 5); @@ -867,7 +937,7 @@ mod tests { score: ElectionScore { minimal_stake: 20, ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(999), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(999), Box::new(solution))); // got one bond back. assert_eq!(balances(&99).1, 2 * 4); @@ -878,7 +948,7 @@ mod tests { #[test] fn equally_good_solution_is_not_accepted() { ExtBuilder::default().signed_max_submission(3).build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); for i in 0..SignedMaxSubmissions::get() { @@ -886,7 +956,7 @@ mod tests { score: ElectionScore { minimal_stake: (5 + i).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); } assert_eq!( MultiPhase::signed_submissions() @@ -902,7 +972,7 @@ mod tests { ..Default::default() }; assert_noop!( - MultiPhase::submit(Origin::signed(99), Box::new(solution)), + MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution)), Error::::SignedQueueFull, ); }) @@ -915,7 +985,7 @@ mod tests { // - bad_solution_is_slashed // - suppressed_solution_gets_bond_back ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); assert_eq!(balances(&99), (100, 0)); @@ -924,18 +994,18 @@ mod tests { let solution = raw_solution(); // submit a correct one. - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution.clone()))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution.clone()))); // make the solution invalidly better and submit. This ought to be slashed. let mut solution_999 = solution.clone(); solution_999.score.minimal_stake += 1; - assert_ok!(MultiPhase::submit(Origin::signed(999), Box::new(solution_999))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(999), Box::new(solution_999))); // make the solution invalidly worse and submit. This ought to be suppressed and // returned. let mut solution_9999 = solution.clone(); solution_9999.score.minimal_stake -= 1; - assert_ok!(MultiPhase::submit(Origin::signed(9999), Box::new(solution_9999))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(9999), Box::new(solution_9999))); assert_eq!( MultiPhase::signed_submissions().iter().map(|x| x.who).collect::>(), @@ -951,16 +1021,27 @@ mod tests { assert_eq!(balances(&999), (95, 0)); // 9999 gets everything back, including the call fee. assert_eq!(balances(&9999), (100 + 8, 0)); + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::Slashed { account: 999, value: 5 }, + Event::Rewarded { account: 99, value: 7 } + ] + ); }) } #[test] fn cannot_consume_too_much_future_weight() { ExtBuilder::default() - .signed_weight(Weight::from_ref_time(40)) + .signed_weight(Weight::from_ref_time(40).set_proof_size(u64::MAX)) .mock_weight_info(MockedWeightInfo::Basic) .build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let (raw, witness) = MultiPhase::mine_solution().unwrap(); @@ -973,16 +1054,19 @@ mod tests { // default solution will have 5 edges (5 * 5 + 10) assert_eq!(solution_weight, Weight::from_ref_time(35)); assert_eq!(raw.solution.voter_count(), 5); - assert_eq!(::SignedMaxWeight::get(), Weight::from_ref_time(40)); + assert_eq!( + ::SignedMaxWeight::get(), + Weight::from_ref_time(40).set_proof_size(u64::MAX) + ); - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(raw.clone()))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(raw.clone()))); - ::set(Weight::from_ref_time(30)); + ::set(Weight::from_ref_time(30).set_proof_size(u64::MAX)); // note: resubmitting the same solution is technically okay as long as the queue has // space. assert_noop!( - MultiPhase::submit(Origin::signed(99), Box::new(raw)), + MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(raw)), Error::::SignedTooMuchWeight, ); }) @@ -991,14 +1075,14 @@ mod tests { #[test] fn insufficient_deposit_does_not_store_submission() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let solution = raw_solution(); assert_eq!(balances(&123), (0, 0)); assert_noop!( - MultiPhase::submit(Origin::signed(123), Box::new(solution)), + MultiPhase::submit(RuntimeOrigin::signed(123), Box::new(solution)), Error::::SignedCannotPayDeposit, ); @@ -1011,7 +1095,7 @@ mod tests { #[test] fn insufficient_deposit_with_full_queue_works_properly() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); for s in 0..SignedMaxSubmissions::get() { @@ -1020,7 +1104,7 @@ mod tests { score: ElectionScore { minimal_stake: (5 + s).into(), ..Default::default() }, ..Default::default() }; - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); } // this solution has a higher score than any in the queue @@ -1034,7 +1118,7 @@ mod tests { assert_eq!(balances(&123), (0, 0)); assert_noop!( - MultiPhase::submit(Origin::signed(123), Box::new(solution)), + MultiPhase::submit(RuntimeOrigin::signed(123), Box::new(solution)), Error::::SignedCannotPayDeposit, ); @@ -1057,19 +1141,28 @@ mod tests { #[test] fn finalize_signed_phase_is_idempotent_given_submissions() { ExtBuilder::default().build_and_execute(|| { - roll_to(15); + roll_to_signed(); assert!(MultiPhase::current_phase().is_signed()); let solution = raw_solution(); // submit a correct one. - assert_ok!(MultiPhase::submit(Origin::signed(99), Box::new(solution))); + assert_ok!(MultiPhase::submit(RuntimeOrigin::signed(99), Box::new(solution))); // _some_ good solution was stored. assert!(MultiPhase::finalize_signed_phase()); // calling it again doesn't change anything assert_storage_noop!(MultiPhase::finalize_signed_phase()); + + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::SolutionStored { compute: ElectionCompute::Signed, prev_ejected: false }, + Event::Rewarded { account: 99, value: 7 } + ] + ); }) } } diff --git a/frame/election-provider-multi-phase/src/unsigned.rs b/frame/election-provider-multi-phase/src/unsigned.rs index 8ef7d87473159..7340605dfe621 100644 --- a/frame/election-provider-multi-phase/src/unsigned.rs +++ b/frame/election-provider-multi-phase/src/unsigned.rs @@ -34,7 +34,7 @@ use sp_runtime::{ offchain::storage::{MutateStorageError, StorageValueRef}, DispatchError, SaturatedConversion, }; -use sp_std::{cmp::Ordering, prelude::*}; +use sp_std::prelude::*; /// Storage key used to store the last block number at which offchain worker ran. pub(crate) const OFFCHAIN_LAST_BLOCK: &[u8] = b"parity/multi-phase-unsigned-election"; @@ -638,16 +638,17 @@ impl Miner { }; let next_voters = |current_weight: Weight, voters: u32, step: u32| -> Result { - match current_weight.cmp(&max_weight) { - Ordering::Less => { - let next_voters = voters.checked_add(step); - match next_voters { - Some(voters) if voters < max_voters => Ok(voters), - _ => Err(()), - } - }, - Ordering::Greater => voters.checked_sub(step).ok_or(()), - Ordering::Equal => Ok(voters), + if current_weight.all_lt(max_weight) { + let next_voters = voters.checked_add(step); + match next_voters { + Some(voters) if voters < max_voters => Ok(voters), + _ => Err(()), + } + } else if current_weight.any_gt(max_weight) { + voters.checked_sub(step).ok_or(()) + } else { + // If any of the constituent weights is equal to the max weight, we're at max + Ok(voters) } }; @@ -672,16 +673,16 @@ impl Miner { // Time to finish. We might have reduced less than expected due to rounding error. Increase // one last time if we have any room left, the reduce until we are sure we are below limit. - while voters < max_voters && weight_with(voters + 1) < max_weight { + while voters < max_voters && weight_with(voters + 1).all_lt(max_weight) { voters += 1; } - while voters.checked_sub(1).is_some() && weight_with(voters) > max_weight { + while voters.checked_sub(1).is_some() && weight_with(voters).any_gt(max_weight) { voters -= 1; } let final_decision = voters.min(size.voters); debug_assert!( - weight_with(final_decision) <= max_weight, + weight_with(final_decision).all_lte(max_weight), "weight_with({}) <= {}", final_decision, max_weight, @@ -699,151 +700,346 @@ mod max_weight { fn find_max_voter_binary_search_works() { let w = SolutionOrSnapshotSize { voters: 10, targets: 0 }; MockWeightInfo::set(crate::mock::MockedWeightInfo::Complex); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::zero()), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1)), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(999)), 0); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::zero().set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1).set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(999).set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1000).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1001)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1001).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1990)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1990).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1999)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1999).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2000).set_proof_size(u64::MAX) + ), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2001)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2001).set_proof_size(u64::MAX) + ), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2010)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2010).set_proof_size(u64::MAX) + ), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2990)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2990).set_proof_size(u64::MAX) + ), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2999)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2999).set_proof_size(u64::MAX) + ), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(3000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(3000).set_proof_size(u64::MAX) + ), 3 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(3333)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(3333).set_proof_size(u64::MAX) + ), 3 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(5500)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(5500).set_proof_size(u64::MAX) + ), 5 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(7777)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(7777).set_proof_size(u64::MAX) + ), 7 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(9999)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(9999).set_proof_size(u64::MAX) + ), 9 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(10_000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(10_000).set_proof_size(u64::MAX) + ), 10 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(10_999)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(10_999).set_proof_size(u64::MAX) + ), 10 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(11_000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(11_000).set_proof_size(u64::MAX) + ), 10 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(22_000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(22_000).set_proof_size(u64::MAX) + ), 10 ); let w = SolutionOrSnapshotSize { voters: 1, targets: 0 }; - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(0)), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1)), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(999)), 0); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(0).set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1).set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(999).set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1000).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1001)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1001).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1990)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1990).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1999)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1999).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2000).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2001)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2001).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2010)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2010).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(3333)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(3333).set_proof_size(u64::MAX) + ), 1 ); let w = SolutionOrSnapshotSize { voters: 2, targets: 0 }; - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(0)), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1)), 0); - assert_eq!(Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(999)), 0); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(0).set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1).set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(999).set_proof_size(u64::MAX) + ), + 0 + ); + assert_eq!( + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1000).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1001)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1001).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(1999)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(1999).set_proof_size(u64::MAX) + ), 1 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2000)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2000).set_proof_size(u64::MAX) + ), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2001)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2001).set_proof_size(u64::MAX) + ), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(2010)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(2010).set_proof_size(u64::MAX) + ), 2 ); assert_eq!( - Miner::::maximum_voter_for_weight(0, w, Weight::from_ref_time(3333)), + Miner::::maximum_voter_for_weight( + 0, + w, + Weight::from_ref_time(3333).set_proof_size(u64::MAX) + ), 2 ); } @@ -854,11 +1050,12 @@ mod tests { use super::*; use crate::{ mock::{ - roll_to, roll_to_with_ocw, trim_helpers, witness, BlockNumber, Call as OuterCall, - ExtBuilder, Extrinsic, MinerMaxWeight, MultiPhase, Origin, Runtime, System, - TestNposSolution, TrimHelpers, UnsignedPhase, + multi_phase_events, roll_to, roll_to_signed, roll_to_unsigned, roll_to_with_ocw, + trim_helpers, witness, BlockNumber, ExtBuilder, Extrinsic, MinerMaxWeight, MultiPhase, + Runtime, RuntimeCall, RuntimeOrigin, System, TestNposSolution, TrimHelpers, + UnsignedPhase, }, - CurrentPhase, InvalidTransaction, Phase, QueuedSolution, TransactionSource, + CurrentPhase, Event, InvalidTransaction, Phase, QueuedSolution, TransactionSource, TransactionValidityError, }; use codec::Decode; @@ -904,7 +1101,7 @@ mod tests { )); // signed - roll_to(15); + roll_to_signed(); assert_eq!(MultiPhase::current_phase(), Phase::Signed); assert!(matches!( ::validate_unsigned( @@ -920,7 +1117,7 @@ mod tests { )); // unsigned - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); assert!(::validate_unsigned( @@ -951,7 +1148,7 @@ mod tests { #[test] fn validate_unsigned_retracts_low_score() { ExtBuilder::default().desired_targets(0).build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); let solution = RawSolution:: { @@ -997,7 +1194,7 @@ mod tests { #[test] fn validate_unsigned_retracts_incorrect_winner_count() { ExtBuilder::default().desired_targets(1).build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); let raw = RawSolution:: { @@ -1026,7 +1223,7 @@ mod tests { .miner_tx_priority(20) .desired_targets(0) .build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); let solution = RawSolution:: { @@ -1057,7 +1254,7 @@ mod tests { Some(\"PreDispatchWrongWinnerCount\") })")] fn unfeasible_solution_panics() { ExtBuilder::default().build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); // This is in itself an invalid BS solution. @@ -1069,8 +1266,8 @@ mod tests { raw_solution: Box::new(solution.clone()), witness: witness(), }; - let outer_call: OuterCall = call.into(); - let _ = outer_call.dispatch(Origin::none()); + let runtime_call: RuntimeCall = call.into(); + let _ = runtime_call.dispatch(RuntimeOrigin::none()); }) } @@ -1079,7 +1276,7 @@ mod tests { deprive validator from their authoring reward.")] fn wrong_witness_panics() { ExtBuilder::default().build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); // This solution is unfeasible as well, but we won't even get there. @@ -1095,15 +1292,15 @@ mod tests { raw_solution: Box::new(solution.clone()), witness: correct_witness, }; - let outer_call: OuterCall = call.into(); - let _ = outer_call.dispatch(Origin::none()); + let runtime_call: RuntimeCall = call.into(); + let _ = runtime_call.dispatch(RuntimeOrigin::none()); }) } #[test] fn miner_works() { ExtBuilder::default().build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); // ensure we have snapshots in place. @@ -1115,18 +1312,33 @@ mod tests { // ensure this solution is valid. assert!(MultiPhase::queued_solution().is_none()); - assert_ok!(MultiPhase::submit_unsigned(Origin::none(), Box::new(solution), witness)); + assert_ok!(MultiPhase::submit_unsigned( + RuntimeOrigin::none(), + Box::new(solution), + witness + )); assert!(MultiPhase::queued_solution().is_some()); + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::UnsignedPhaseStarted { round: 1 }, + Event::SolutionStored { + compute: ElectionCompute::Unsigned, + prev_ejected: false + } + ] + ); }) } #[test] fn miner_trims_weight() { ExtBuilder::default() - .miner_weight(Weight::from_ref_time(100)) + .miner_weight(Weight::from_ref_time(100).set_proof_size(u64::MAX)) .mock_weight_info(crate::mock::MockedWeightInfo::Basic) .build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); let (raw, witness) = MultiPhase::mine_solution().unwrap(); @@ -1141,7 +1353,7 @@ mod tests { assert_eq!(raw.solution.voter_count(), 5); // now reduce the max weight - ::set(Weight::from_ref_time(25)); + ::set(Weight::from_ref_time(25).set_proof_size(u64::MAX)); let (raw, witness) = MultiPhase::mine_solution().unwrap(); let solution_weight = ::solution_weight( @@ -1160,7 +1372,7 @@ mod tests { fn miner_will_not_submit_if_not_enough_winners() { let (mut ext, _) = ExtBuilder::default().desired_targets(8).build_offchainify(0); ext.execute_with(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); // Force the number of winners to be bigger to fail @@ -1186,7 +1398,7 @@ mod tests { .add_voter(8, 5, bounded_vec![10]) .better_unsigned_threshold(Perbill::from_percent(50)) .build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); assert_eq!(MultiPhase::desired_targets().unwrap(), 1); @@ -1214,7 +1426,7 @@ mod tests { let solution = RawSolution { solution: raw, score, round: MultiPhase::round() }; assert_ok!(MultiPhase::unsigned_pre_dispatch_checks(&solution)); assert_ok!(MultiPhase::submit_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(solution), witness )); @@ -1275,7 +1487,7 @@ mod tests { // and it is fine assert_ok!(MultiPhase::unsigned_pre_dispatch_checks(&solution)); assert_ok!(MultiPhase::submit_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(solution), witness )); @@ -1288,7 +1500,7 @@ mod tests { ext.execute_with(|| { let offchain_repeat = ::OffchainRepeat::get(); - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); // first execution -- okay. @@ -1329,7 +1541,7 @@ mod tests { let guard = StorageValueRef::persistent(&OFFCHAIN_LOCK); let last_block = StorageValueRef::persistent(OFFCHAIN_LAST_BLOCK); - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); // initially, the lock is not set. @@ -1350,7 +1562,7 @@ mod tests { // ensure that if the guard is in hold, a new execution is not allowed. let (mut ext, pool) = ExtBuilder::default().build_offchainify(0); ext.execute_with(|| { - roll_to(25); + roll_to_unsigned(); assert!(MultiPhase::current_phase().is_unsigned()); // artificially set the value, as if another thread is mid-way. @@ -1378,7 +1590,7 @@ mod tests { fn ocw_only_runs_when_unsigned_open_now() { let (mut ext, pool) = ExtBuilder::default().build_offchainify(0); ext.execute_with(|| { - roll_to(25); + roll_to_unsigned(); assert_eq!(MultiPhase::current_phase(), Phase::Unsigned((true, 25))); // we must clear the offchain storage to ensure the offchain execution check doesn't get @@ -1458,6 +1670,21 @@ mod tests { // the submitted solution changes because the cache was cleared. assert_eq!(tx_cache_1, tx_cache_3); + assert_eq!( + multi_phase_events(), + vec![ + Event::SignedPhaseStarted { round: 1 }, + Event::UnsignedPhaseStarted { round: 1 }, + Event::ElectionFinalized { + compute: ElectionCompute::Fallback, + score: ElectionScore { + minimal_stake: 0, + sum_stake: 0, + sum_stake_squared: 0 + } + } + ] + ); }) } @@ -1555,7 +1782,7 @@ mod tests { let encoded = pool.read().transactions[0].clone(); let extrinsic: Extrinsic = codec::Decode::decode(&mut &*encoded).unwrap(); let call = extrinsic.call; - assert!(matches!(call, OuterCall::MultiPhase(Call::submit_unsigned { .. }))); + assert!(matches!(call, RuntimeCall::MultiPhase(Call::submit_unsigned { .. }))); }) } @@ -1572,7 +1799,7 @@ mod tests { let encoded = pool.read().transactions[0].clone(); let extrinsic = Extrinsic::decode(&mut &*encoded).unwrap(); let call = match extrinsic.call { - OuterCall::MultiPhase(call @ Call::submit_unsigned { .. }) => call, + RuntimeCall::MultiPhase(call @ Call::submit_unsigned { .. }) => call, _ => panic!("bad call: unexpected submission"), }; @@ -1597,7 +1824,7 @@ mod tests { #[test] fn trim_assignments_length_does_not_modify_when_short_enough() { ExtBuilder::default().build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); // given let TrimHelpers { mut assignments, encoded_size_of, .. } = trim_helpers(); @@ -1622,7 +1849,7 @@ mod tests { #[test] fn trim_assignments_length_modifies_when_too_long() { ExtBuilder::default().build().execute_with(|| { - roll_to(25); + roll_to_unsigned(); // given let TrimHelpers { mut assignments, encoded_size_of, .. } = trim_helpers(); @@ -1648,7 +1875,7 @@ mod tests { #[test] fn trim_assignments_length_trims_lowest_stake() { ExtBuilder::default().build().execute_with(|| { - roll_to(25); + roll_to_unsigned(); // given let TrimHelpers { voters, mut assignments, encoded_size_of, voter_index } = @@ -1711,7 +1938,7 @@ mod tests { // or when we trim it to zero. ExtBuilder::default().build_and_execute(|| { // we need snapshot for `trim_helpers` to work. - roll_to(25); + roll_to_unsigned(); let TrimHelpers { mut assignments, encoded_size_of, .. } = trim_helpers(); assert!(assignments.len() > 0); @@ -1733,7 +1960,7 @@ mod tests { #[test] fn mine_solution_solutions_always_within_acceptable_length() { ExtBuilder::default().build_and_execute(|| { - roll_to(25); + roll_to_unsigned(); // how long would the default solution be? let solution = MultiPhase::mine_solution().unwrap(); diff --git a/frame/election-provider-support/Cargo.toml b/frame/election-provider-support/Cargo.toml index 67e1ea63cb655..5d064c770f8d9 100644 --- a/frame/election-provider-support/Cargo.toml +++ b/frame/election-provider-support/Cargo.toml @@ -31,6 +31,7 @@ sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elect [features] default = ["std"] +fuzz = ["default"] std = [ "codec/std", "frame-support/std", diff --git a/frame/election-provider-support/benchmarking/Cargo.toml b/frame/election-provider-support/benchmarking/Cargo.toml index 00037d460db17..0f296d9a70ee0 100644 --- a/frame/election-provider-support/benchmarking/Cargo.toml +++ b/frame/election-provider-support/benchmarking/Cargo.toml @@ -25,7 +25,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../../pri default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-election-provider-support/std", "frame-system/std", "sp-npos-elections/std", diff --git a/frame/election-provider-support/solution-type/fuzzer/Cargo.toml b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml index 10f82cd316851..2cc620452586d 100644 --- a/frame/election-provider-support/solution-type/fuzzer/Cargo.toml +++ b/frame/election-provider-support/solution-type/fuzzer/Cargo.toml @@ -13,7 +13,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } diff --git a/frame/election-provider-support/src/lib.rs b/frame/election-provider-support/src/lib.rs index 21a01ce1904ec..5ee65e102bd06 100644 --- a/frame/election-provider-support/src/lib.rs +++ b/frame/election-provider-support/src/lib.rs @@ -20,10 +20,11 @@ //! This crate provides two traits that could interact to enable extensible election functionality //! within FRAME pallets. //! -//! Something that will provide the functionality of election will implement [`ElectionProvider`], -//! whilst needing an associated [`ElectionProvider::DataProvider`], which needs to be fulfilled by -//! an entity implementing [`ElectionDataProvider`]. Most often, *the data provider is* the receiver -//! of the election, resulting in a diagram as below: +//! Something that will provide the functionality of election will implement +//! [`ElectionProvider`] and its parent-trait [`ElectionProviderBase`], whilst needing an +//! associated [`ElectionProviderBase::DataProvider`], which needs to be +//! fulfilled by an entity implementing [`ElectionDataProvider`]. Most often, *the data provider is* +//! the receiver of the election, resulting in a diagram as below: //! //! ```ignore //! ElectionDataProvider @@ -131,12 +132,16 @@ //! type DataProvider: ElectionDataProvider; //! } //! -//! impl ElectionProvider for GenericElectionProvider { +//! impl ElectionProviderBase for GenericElectionProvider { //! type AccountId = AccountId; //! type BlockNumber = BlockNumber; //! type Error = &'static str; //! type DataProvider = T::DataProvider; +//! fn ongoing() -> bool { false } +//! +//! } //! +//! impl ElectionProvider for GenericElectionProvider { //! fn elect() -> Result, Self::Error> { //! Self::DataProvider::electable_targets(None) //! .map_err(|_| "failed to elect") @@ -177,8 +182,8 @@ pub use frame_support::{traits::Get, weights::Weight, BoundedVec, RuntimeDebug}; /// Re-export some type as they are used in the interface. pub use sp_arithmetic::PerThing; pub use sp_npos_elections::{ - Assignment, BalancingConfig, ElectionResult, Error, ExtendedBalance, IdentifierT, PerThing128, - Support, Supports, VoteWeight, + Assignment, BalancingConfig, BoundedSupports, ElectionResult, Error, ExtendedBalance, + IdentifierT, PerThing128, Support, Supports, VoteWeight, }; pub use traits::NposSolution; @@ -349,12 +354,12 @@ pub trait ElectionDataProvider { fn clear() {} } -/// Something that can compute the result of an election and pass it back to the caller. +/// Base trait for [`ElectionProvider`] and [`BoundedElectionProvider`]. It is +/// meant to be used only with an extension trait that adds an election +/// functionality. /// -/// This trait only provides an interface to _request_ an election, i.e. -/// [`ElectionProvider::elect`]. That data required for the election need to be passed to the -/// implemented of this trait through [`ElectionProvider::DataProvider`]. -pub trait ElectionProvider { +/// Data can be bounded or unbounded and is fetched from [`Self::DataProvider`]. +pub trait ElectionProviderBase { /// The account identifier type. type AccountId; @@ -370,23 +375,41 @@ pub trait ElectionProvider { BlockNumber = Self::BlockNumber, >; - /// Elect a new set of winners, without specifying any bounds on the amount of data fetched from - /// [`Self::DataProvider`]. An implementation could nonetheless impose its own custom limits. - /// - /// The result is returned in a target major format, namely as *vector of supports*. - /// - /// This should be implemented as a self-weighing function. The implementor should register its - /// appropriate weight at the end of execution with the system pallet directly. + /// Indicate if this election provider is currently ongoing an asynchronous election or not. + fn ongoing() -> bool; +} + +/// Elect a new set of winners, bounded by `MaxWinners`. +/// +/// Returns a result in bounded, target major format, namely as +/// *BoundedVec<(AccountId, Vec), MaxWinners>*. +pub trait BoundedElectionProvider: ElectionProviderBase { + /// The upper bound on election winners. + type MaxWinners: Get; + /// Performs the election. This should be implemented as a self-weighing function. The + /// implementor should register its appropriate weight at the end of execution with the + /// system pallet directly. + fn elect() -> Result, Self::Error>; +} + +/// Same a [`BoundedElectionProvider`], but no bounds are imposed on the number +/// of winners. +/// +/// The result is returned in a target major format, namely as +///*Vec<(AccountId, Vec)>*. +pub trait ElectionProvider: ElectionProviderBase { + /// Performs the election. This should be implemented as a self-weighing + /// function, similar to [`BoundedElectionProvider::elect()`]. fn elect() -> Result, Self::Error>; } -/// A sub-trait of the [`ElectionProvider`] for cases where we need to be sure an election needs to -/// happen instantly, not asynchronously. +/// A sub-trait of the [`ElectionProvider`] for cases where we need to be sure +/// an election needs to happen instantly, not asynchronously. /// /// The same `DataProvider` is assumed to be used. /// -/// Consequently, allows for control over the amount of data that is being fetched from the -/// [`ElectionProvider::DataProvider`]. +/// Consequently, allows for control over the amount of data that is being +/// fetched from the [`ElectionProviderBase::DataProvider`]. pub trait InstantElectionProvider: ElectionProvider { /// Elect a new set of winners, but unlike [`ElectionProvider::elect`] which cannot enforce /// bounds, this trait method can enforce bounds on the amount of data provided by the @@ -407,7 +430,7 @@ pub trait InstantElectionProvider: ElectionProvider { pub struct NoElection(sp_std::marker::PhantomData); #[cfg(feature = "std")] -impl ElectionProvider +impl ElectionProviderBase for NoElection<(AccountId, BlockNumber, DataProvider)> where DataProvider: ElectionDataProvider, @@ -417,6 +440,17 @@ where type Error = &'static str; type DataProvider = DataProvider; + fn ongoing() -> bool { + false + } +} + +#[cfg(feature = "std")] +impl ElectionProvider + for NoElection<(AccountId, BlockNumber, DataProvider)> +where + DataProvider: ElectionDataProvider, +{ fn elect() -> Result, Self::Error> { Err(" cannot do anything.") } @@ -519,9 +553,7 @@ pub trait SortedListProvider { /// If `who` changes by the returned amount they are guaranteed to have a worst case change /// in their list position. #[cfg(feature = "runtime-benchmarks")] - fn score_update_worst_case(_who: &AccountId, _is_increase: bool) -> Self::Score { - Self::Score::max_value() - } + fn score_update_worst_case(_who: &AccountId, _is_increase: bool) -> Self::Score; } /// Something that can provide the `Score` of an account. Similar to [`ElectionProvider`] and @@ -533,8 +565,8 @@ pub trait ScoreProvider { /// Get the current `Score` of `who`. fn score(who: &AccountId) -> Self::Score; - /// For tests and benchmarks, set the `score`. - #[cfg(any(feature = "runtime-benchmarks", test))] + /// For tests, benchmarks and fuzzing, set the `score`. + #[cfg(any(feature = "runtime-benchmarks", feature = "fuzz", test))] fn set_score_of(_: &AccountId, _: Self::Score) {} } diff --git a/frame/election-provider-support/src/onchain.rs b/frame/election-provider-support/src/onchain.rs index 62e76c3888822..88aa6ca7267a0 100644 --- a/frame/election-provider-support/src/onchain.rs +++ b/frame/election-provider-support/src/onchain.rs @@ -20,9 +20,10 @@ //! careful when using it onchain. use crate::{ - Debug, ElectionDataProvider, ElectionProvider, InstantElectionProvider, NposSolver, WeightInfo, + Debug, ElectionDataProvider, ElectionProvider, ElectionProviderBase, InstantElectionProvider, + NposSolver, WeightInfo, }; -use frame_support::{traits::Get, weights::DispatchClass}; +use frame_support::{dispatch::DispatchClass, traits::Get}; use sp_npos_elections::*; use sp_std::{collections::btree_map::BTreeMap, marker::PhantomData, prelude::*}; @@ -133,11 +134,6 @@ fn elect_with( } impl ElectionProvider for UnboundedExecution { - type AccountId = ::AccountId; - type BlockNumber = ::BlockNumber; - type Error = Error; - type DataProvider = T::DataProvider; - fn elect() -> Result, Self::Error> { // This should not be called if not in `std` mode (and therefore neither in genesis nor in // testing) @@ -152,6 +148,17 @@ impl ElectionProvider for UnboundedExecution { } } +impl ElectionProviderBase for UnboundedExecution { + type AccountId = ::AccountId; + type BlockNumber = ::BlockNumber; + type Error = Error; + type DataProvider = T::DataProvider; + + fn ongoing() -> bool { + false + } +} + impl InstantElectionProvider for UnboundedExecution { fn elect_with_bounds( max_voters: usize, @@ -161,12 +168,18 @@ impl InstantElectionProvider for UnboundedExecution { } } -impl ElectionProvider for BoundedExecution { +impl ElectionProviderBase for BoundedExecution { type AccountId = ::AccountId; type BlockNumber = ::BlockNumber; type Error = Error; type DataProvider = T::DataProvider; + fn ongoing() -> bool { + false + } +} + +impl ElectionProvider for BoundedExecution { fn elect() -> Result, Self::Error> { elect_with::(Some(T::VotersBound::get() as usize), Some(T::TargetsBound::get() as usize)) } @@ -211,16 +224,16 @@ mod tests { impl frame_system::Config for Runtime { type SS58Prefix = (); type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = AccountId; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_core::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = sp_runtime::traits::IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = (); + type RuntimeEvent = (); type BlockHashCount = (); type DbWeight = (); type BlockLength = (); diff --git a/frame/elections-phragmen/Cargo.toml b/frame/elections-phragmen/Cargo.toml index a58aeabd36a31..eb47c3bcb0601 100644 --- a/frame/elections-phragmen/Cargo.toml +++ b/frame/elections-phragmen/Cargo.toml @@ -36,6 +36,7 @@ substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/elections-phragmen/src/benchmarking.rs b/frame/elections-phragmen/src/benchmarking.rs index 22d00a912a4f7..06ac8d7c60162 100644 --- a/frame/elections-phragmen/src/benchmarking.rs +++ b/frame/elections-phragmen/src/benchmarking.rs @@ -362,7 +362,7 @@ benchmarks! { // total number of voters. let v in (T::MaxVoters::get() / 2) .. T::MaxVoters::get(); // those that are defunct and need removal. - let d in 1 .. (T::MaxVoters::get() / 2); + let d in 0 .. (T::MaxVoters::get() / 2); // remove any previous stuff. clean::(); diff --git a/frame/elections-phragmen/src/lib.rs b/frame/elections-phragmen/src/lib.rs index 0a10cbd4a6fe7..dfaf6d47f00fd 100644 --- a/frame/elections-phragmen/src/lib.rs +++ b/frame/elections-phragmen/src/lib.rs @@ -195,7 +195,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Identifier for the elections-phragmen pallet's lock #[pallet::constant] @@ -1178,7 +1178,9 @@ mod tests { parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); + frame_system::limits::BlockWeights::simple_max( + frame_support::weights::Weight::from_ref_time(1024).set_proof_size(u64::MAX), + ); } impl frame_system::Config for Test { @@ -1186,16 +1188,16 @@ mod tests { type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -1210,7 +1212,7 @@ mod tests { impl pallet_balances::Config for Test { type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = frame_system::Pallet; @@ -1283,7 +1285,7 @@ mod tests { impl Config for Test { type PalletId = ElectionsPhragmenPalletId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type ChangeMembers = TestChangeMembers; @@ -1302,7 +1304,8 @@ mod tests { } pub type Block = sp_runtime::generic::Block; - pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; + pub type UncheckedExtrinsic = + sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Test where @@ -1489,11 +1492,11 @@ mod tests { ensure_members_has_approval_stake(); } - fn submit_candidacy(origin: Origin) -> sp_runtime::DispatchResult { + fn submit_candidacy(origin: RuntimeOrigin) -> sp_runtime::DispatchResult { Elections::submit_candidacy(origin, Elections::candidates().len() as u32) } - fn vote(origin: Origin, votes: Vec, stake: u64) -> DispatchResultWithPostInfo { + fn vote(origin: RuntimeOrigin, votes: Vec, stake: u64) -> DispatchResultWithPostInfo { // historical note: helper function was created in a period of time in which the API of vote // call was changing. Currently it is a wrapper for the original call and does not do much. // Nonetheless, totally harmless. @@ -1575,8 +1578,8 @@ mod tests { Voter { stake: 20u64, votes: vec![2], deposit: 0 } ); - assert_ok!(Elections::remove_voter(Origin::signed(1))); - assert_ok!(Elections::remove_voter(Origin::signed(2))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(1))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(2))); assert_eq!(Elections::voting(1), Default::default()); assert_eq!(Elections::voting(2), Default::default()); @@ -1669,7 +1672,7 @@ mod tests { assert!(Elections::is_candidate(&2).is_err()); assert_eq!(balances(&1), (10, 0)); - assert_ok!(submit_candidacy(Origin::signed(1))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(1))); assert_eq!(balances(&1), (7, 3)); assert_eq!(candidate_ids(), vec![1]); @@ -1678,7 +1681,7 @@ mod tests { assert!(Elections::is_candidate(&2).is_err()); assert_eq!(balances(&2), (20, 0)); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); assert_eq!(balances(&2), (17, 3)); assert_eq!(candidate_ids(), vec![1, 2]); @@ -1695,15 +1698,15 @@ mod tests { #[test] fn updating_candidacy_bond_works() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); assert_eq!(Elections::candidates(), vec![(5, 3)]); // a runtime upgrade changes the bond. CANDIDACY_BOND.with(|v| *v.borrow_mut() = 4); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); assert_eq!(Elections::candidates(), vec![(4, 4), (5, 3)]); // once elected, they each hold their candidacy bond, no more. @@ -1727,13 +1730,13 @@ mod tests { ExtBuilder::default().build_and_execute(|| { assert_eq!(candidate_ids(), Vec::::new()); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); assert_eq!(candidate_ids(), vec![3]); - assert_ok!(submit_candidacy(Origin::signed(1))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(1))); assert_eq!(candidate_ids(), vec![1, 3]); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); assert_eq!(candidate_ids(), vec![1, 2, 3]); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); assert_eq!(candidate_ids(), vec![1, 2, 3, 4]); }); } @@ -1742,9 +1745,12 @@ mod tests { fn dupe_candidate_submission_should_not_work() { ExtBuilder::default().build_and_execute(|| { assert_eq!(candidate_ids(), Vec::::new()); - assert_ok!(submit_candidacy(Origin::signed(1))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(1))); assert_eq!(candidate_ids(), vec![1]); - assert_noop!(submit_candidacy(Origin::signed(1)), Error::::DuplicatedCandidate); + assert_noop!( + submit_candidacy(RuntimeOrigin::signed(1)), + Error::::DuplicatedCandidate + ); }); } @@ -1752,8 +1758,8 @@ mod tests { fn member_candidacy_submission_should_not_work() { // critically important to make sure that outgoing candidates and losers are not mixed up. ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(vote(Origin::signed(2), vec![5], 20)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -1762,19 +1768,19 @@ mod tests { assert!(Elections::runners_up().is_empty()); assert!(candidate_ids().is_empty()); - assert_noop!(submit_candidacy(Origin::signed(5)), Error::::MemberSubmit); + assert_noop!(submit_candidacy(RuntimeOrigin::signed(5)), Error::::MemberSubmit); }); } #[test] fn runner_candidate_submission_should_not_work() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(2), vec![5, 4], 20)); - assert_ok!(vote(Origin::signed(1), vec![3], 10)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5, 4], 20)); + assert_ok!(vote(RuntimeOrigin::signed(1), vec![3], 10)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -1782,7 +1788,7 @@ mod tests { assert_eq!(members_ids(), vec![4, 5]); assert_eq!(runners_up_ids(), vec![3]); - assert_noop!(submit_candidacy(Origin::signed(3)), Error::::RunnerUpSubmit); + assert_noop!(submit_candidacy(RuntimeOrigin::signed(3)), Error::::RunnerUpSubmit); }); } @@ -1791,7 +1797,7 @@ mod tests { ExtBuilder::default().build_and_execute(|| { assert_eq!(candidate_ids(), Vec::::new()); assert_noop!( - submit_candidacy(Origin::signed(7)), + submit_candidacy(RuntimeOrigin::signed(7)), Error::::InsufficientCandidateFunds, ); }); @@ -1803,8 +1809,8 @@ mod tests { assert_eq!(candidate_ids(), Vec::::new()); assert_eq!(balances(&2), (20, 0)); - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(vote(Origin::signed(2), vec![5], 20)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 20)); assert_eq!(balances(&2), (18, 2)); assert_eq!(has_lock(&2), 18); @@ -1817,8 +1823,8 @@ mod tests { assert_eq!(candidate_ids(), Vec::::new()); assert_eq!(balances(&2), (20, 0)); - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(vote(Origin::signed(2), vec![5], 12)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 12)); assert_eq!(balances(&2), (18, 2)); assert_eq!(has_lock(&2), 12); @@ -1830,9 +1836,9 @@ mod tests { ExtBuilder::default().build_and_execute(|| { assert_eq!(balances(&2), (20, 0)); - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(vote(Origin::signed(2), vec![5], 20)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 20)); // User only locks up to their free balance. assert_eq!(balances(&2), (18, 2)); @@ -1840,7 +1846,7 @@ mod tests { assert_eq!(locked_stake_of(&2), 18); // can update; different stake; different lock and reserve. - assert_ok!(vote(Origin::signed(2), vec![5, 4], 15)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5, 4], 15)); assert_eq!(balances(&2), (18, 2)); assert_eq!(has_lock(&2), 15); assert_eq!(locked_stake_of(&2), 15); @@ -1850,10 +1856,10 @@ mod tests { #[test] fn updated_voting_bond_works() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); assert_eq!(balances(&2), (20, 0)); - assert_ok!(vote(Origin::signed(2), vec![5], 5)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 5)); assert_eq!(balances(&2), (18, 2)); assert_eq!(voter_deposit(&2), 2); @@ -1863,11 +1869,11 @@ mod tests { // proof that bond changed. assert_eq!(balances(&1), (10, 0)); - assert_ok!(vote(Origin::signed(1), vec![5], 5)); + assert_ok!(vote(RuntimeOrigin::signed(1), vec![5], 5)); assert_eq!(balances(&1), (9, 1)); assert_eq!(voter_deposit(&1), 1); - assert_ok!(Elections::remove_voter(Origin::signed(2))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(2))); assert_eq!(balances(&2), (20, 0)); }) } @@ -1877,11 +1883,11 @@ mod tests { ExtBuilder::default().voter_bond_factor(1).build_and_execute(|| { assert_eq!(balances(&2), (20, 0)); - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); // initial vote. - assert_ok!(vote(Origin::signed(2), vec![5], 10)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 10)); // 2 + 1 assert_eq!(balances(&2), (17, 3)); @@ -1890,7 +1896,7 @@ mod tests { assert_eq!(locked_stake_of(&2), 10); // can update; different stake; different lock and reserve. - assert_ok!(vote(Origin::signed(2), vec![5, 4], 15)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5, 4], 15)); // 2 + 2 assert_eq!(balances(&2), (16, 4)); assert_eq!(Elections::voting(&2).deposit, 4); @@ -1898,7 +1904,7 @@ mod tests { assert_eq!(locked_stake_of(&2), 15); // stay at two votes with different stake. - assert_ok!(vote(Origin::signed(2), vec![5, 3], 18)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5, 3], 18)); // 2 + 2 assert_eq!(balances(&2), (16, 4)); assert_eq!(Elections::voting(&2).deposit, 4); @@ -1906,7 +1912,7 @@ mod tests { assert_eq!(locked_stake_of(&2), 16); // back to 1 vote. - assert_ok!(vote(Origin::signed(2), vec![4], 12)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![4], 12)); // 2 + 1 assert_eq!(balances(&2), (17, 3)); assert_eq!(Elections::voting(&2).deposit, 3); @@ -1918,17 +1924,17 @@ mod tests { #[test] fn cannot_vote_for_no_candidate() { ExtBuilder::default().build_and_execute(|| { - assert_noop!(vote(Origin::signed(2), vec![], 20), Error::::NoVotes); + assert_noop!(vote(RuntimeOrigin::signed(2), vec![], 20), Error::::NoVotes); }); } #[test] fn can_vote_for_old_members_even_when_no_new_candidates() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); - assert_ok!(vote(Origin::signed(2), vec![4, 5], 20)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![4, 5], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -1936,22 +1942,22 @@ mod tests { assert_eq!(members_ids(), vec![4, 5]); assert!(candidate_ids().is_empty()); - assert_ok!(vote(Origin::signed(3), vec![4, 5], 10)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![4, 5], 10)); }); } #[test] fn prime_works() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); - assert_ok!(vote(Origin::signed(1), vec![4, 3], 10)); - assert_ok!(vote(Origin::signed(2), vec![4], 20)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(1), vec![4, 3], 10)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![4], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -1959,7 +1965,7 @@ mod tests { assert_eq!(members_ids(), vec![4, 5]); assert!(candidate_ids().is_empty()); - assert_ok!(vote(Origin::signed(3), vec![4, 5], 10)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![4, 5], 10)); assert_eq!(PRIME.with(|p| *p.borrow()), Some(4)); }); } @@ -1967,17 +1973,20 @@ mod tests { #[test] fn prime_votes_for_exiting_members_are_removed() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); - assert_ok!(vote(Origin::signed(1), vec![4, 3], 10)); - assert_ok!(vote(Origin::signed(2), vec![4], 20)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(1), vec![4, 3], 10)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![4], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); - assert_ok!(Elections::renounce_candidacy(Origin::signed(4), Renouncing::Candidate(3))); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(4), + Renouncing::Candidate(3) + )); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -1992,18 +2001,18 @@ mod tests { #[test] fn prime_is_kept_if_other_members_leave() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); assert_eq!(members_ids(), vec![4, 5]); assert_eq!(PRIME.with(|p| *p.borrow()), Some(5)); - assert_ok!(Elections::renounce_candidacy(Origin::signed(4), Renouncing::Member)); + assert_ok!(Elections::renounce_candidacy(RuntimeOrigin::signed(4), Renouncing::Member)); assert_eq!(members_ids(), vec![5]); assert_eq!(PRIME.with(|p| *p.borrow()), Some(5)); @@ -2013,18 +2022,18 @@ mod tests { #[test] fn prime_is_gone_if_renouncing() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); assert_eq!(members_ids(), vec![4, 5]); assert_eq!(PRIME.with(|p| *p.borrow()), Some(5)); - assert_ok!(Elections::renounce_candidacy(Origin::signed(5), Renouncing::Member)); + assert_ok!(Elections::renounce_candidacy(RuntimeOrigin::signed(5), Renouncing::Member)); assert_eq!(members_ids(), vec![4]); assert_eq!(PRIME.with(|p| *p.borrow()), None); @@ -2038,29 +2047,29 @@ mod tests { .balance_factor(10) .build_and_execute(|| { // when we have only candidates - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); assert_noop!( // content of the vote is irrelevant. - vote(Origin::signed(1), vec![9, 99, 999, 9999], 5), + vote(RuntimeOrigin::signed(1), vec![9, 99, 999, 9999], 5), Error::::TooManyVotes, ); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); // now we have 2 members, 1 runner-up, and 1 new candidate - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(1), vec![9, 99, 999, 9999], 5)); + assert_ok!(vote(RuntimeOrigin::signed(1), vec![9, 99, 999, 9999], 5)); assert_noop!( - vote(Origin::signed(1), vec![9, 99, 999, 9_999, 99_999], 5), + vote(RuntimeOrigin::signed(1), vec![9, 99, 999, 9_999, 99_999], 5), Error::::TooManyVotes, ); }); @@ -2069,23 +2078,23 @@ mod tests { #[test] fn cannot_vote_for_less_than_ed() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); - assert_noop!(vote(Origin::signed(2), vec![4], 1), Error::::LowBalance); + assert_noop!(vote(RuntimeOrigin::signed(2), vec![4], 1), Error::::LowBalance); }) } #[test] fn can_vote_for_more_than_free_balance_but_moot() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); // User has 100 free and 50 reserved. - assert_ok!(Balances::set_balance(Origin::root(), 2, 100, 50)); + assert_ok!(Balances::set_balance(RuntimeOrigin::root(), 2, 100, 50)); // User tries to vote with 150 tokens. - assert_ok!(vote(Origin::signed(2), vec![4, 5], 150)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![4, 5], 150)); // We truncate to only their free balance, after reserving additional for voting. assert_eq!(locked_stake_of(&2), 98); assert_eq!(has_lock(&2), 98); @@ -2095,10 +2104,10 @@ mod tests { #[test] fn remove_voter_should_work() { ExtBuilder::default().voter_bond(8).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); - assert_ok!(vote(Origin::signed(2), vec![5], 20)); - assert_ok!(vote(Origin::signed(3), vec![5], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![5], 30)); assert_eq_uvec!(all_voters(), vec![2, 3]); assert_eq!(balances(&2), (12, 8)); @@ -2108,7 +2117,7 @@ mod tests { assert_eq!(votes_of(&2), vec![5]); assert_eq!(votes_of(&3), vec![5]); - assert_ok!(Elections::remove_voter(Origin::signed(2))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(2))); assert_eq_uvec!(all_voters(), vec![3]); assert!(votes_of(&2).is_empty()); @@ -2122,35 +2131,41 @@ mod tests { #[test] fn non_voter_remove_should_not_work() { ExtBuilder::default().build_and_execute(|| { - assert_noop!(Elections::remove_voter(Origin::signed(3)), Error::::MustBeVoter); + assert_noop!( + Elections::remove_voter(RuntimeOrigin::signed(3)), + Error::::MustBeVoter + ); }); } #[test] fn dupe_remove_should_fail() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(vote(Origin::signed(2), vec![5], 20)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 20)); - assert_ok!(Elections::remove_voter(Origin::signed(2))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(2))); assert!(all_voters().is_empty()); - assert_noop!(Elections::remove_voter(Origin::signed(2)), Error::::MustBeVoter); + assert_noop!( + Elections::remove_voter(RuntimeOrigin::signed(2)), + Error::::MustBeVoter + ); }); } #[test] fn removed_voter_should_not_be_counted() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); - assert_ok!(Elections::remove_voter(Origin::signed(4))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(4))); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2162,13 +2177,13 @@ mod tests { #[test] fn simple_voting_rounds_should_work() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(2), vec![5], 20)); - assert_ok!(vote(Origin::signed(4), vec![4], 15)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 15)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); assert_eq_uvec!(all_voters(), vec![2, 3, 4]); @@ -2205,36 +2220,36 @@ mod tests { System::set_block_number(5); Elections::on_initialize(System::block_number()); - System::assert_last_event(Event::Elections(super::Event::EmptyTerm)); + System::assert_last_event(RuntimeEvent::Elections(super::Event::EmptyTerm)); }) } #[test] fn all_outgoing() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); System::set_block_number(5); Elections::on_initialize(System::block_number()); - System::assert_last_event(Event::Elections(super::Event::NewTerm { + System::assert_last_event(RuntimeEvent::Elections(super::Event::NewTerm { new_members: vec![(4, 35), (5, 45)], })); assert_eq!(members_and_stake(), vec![(4, 35), (5, 45)]); assert_eq!(runners_up_and_stake(), vec![]); - assert_ok!(Elections::remove_voter(Origin::signed(5))); - assert_ok!(Elections::remove_voter(Origin::signed(4))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(5))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(4))); System::set_block_number(10); Elections::on_initialize(System::block_number()); - System::assert_last_event(Event::Elections(super::Event::NewTerm { + System::assert_last_event(RuntimeEvent::Elections(super::Event::NewTerm { new_members: vec![], })); @@ -2247,11 +2262,11 @@ mod tests { #[test] fn defunct_voter_will_be_counted() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); // This guy's vote is pointless for this round. - assert_ok!(vote(Origin::signed(3), vec![4], 30)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![4], 30)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2260,7 +2275,7 @@ mod tests { assert_eq!(Elections::election_rounds(), 1); // but now it has a valid target. - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); System::set_block_number(10); Elections::on_initialize(System::block_number()); @@ -2275,15 +2290,15 @@ mod tests { #[test] fn only_desired_seats_are_chosen() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2296,8 +2311,8 @@ mod tests { #[test] fn phragmen_should_not_self_vote() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2306,7 +2321,7 @@ mod tests { assert_eq!(Elections::election_rounds(), 1); assert!(members_ids().is_empty()); - System::assert_last_event(Event::Elections(super::Event::NewTerm { + System::assert_last_event(RuntimeEvent::Elections(super::Event::NewTerm { new_members: vec![], })); }); @@ -2315,15 +2330,15 @@ mod tests { #[test] fn runners_up_should_be_kept() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![3], 20)); - assert_ok!(vote(Origin::signed(3), vec![2], 30)); - assert_ok!(vote(Origin::signed(4), vec![5], 40)); - assert_ok!(vote(Origin::signed(5), vec![4], 50)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![3], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![2], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![5], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![4], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2342,22 +2357,22 @@ mod tests { #[test] fn runners_up_should_be_next_candidates() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); assert_eq!(members_and_stake(), vec![(4, 35), (5, 45)]); assert_eq!(runners_up_and_stake(), vec![(2, 15), (3, 25)]); - assert_ok!(vote(Origin::signed(5), vec![5], 10)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 10)); System::set_block_number(10); Elections::on_initialize(System::block_number()); @@ -2370,13 +2385,13 @@ mod tests { #[test] fn runners_up_lose_bond_once_outgoing() { ExtBuilder::default().desired_runners_up(1).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2384,8 +2399,8 @@ mod tests { assert_eq!(runners_up_ids(), vec![2]); assert_eq!(balances(&2), (15, 5)); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); System::set_block_number(10); Elections::on_initialize(System::block_number()); @@ -2400,17 +2415,17 @@ mod tests { ExtBuilder::default().build_and_execute(|| { assert_eq!(balances(&5), (50, 0)); - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); assert_eq!(balances(&5), (47, 3)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); assert_eq!(balances(&5), (45, 5)); System::set_block_number(5); Elections::on_initialize(System::block_number()); assert_eq!(members_ids(), vec![5]); - assert_ok!(Elections::remove_voter(Origin::signed(5))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(5))); assert_eq!(balances(&5), (47, 3)); System::set_block_number(10); @@ -2424,10 +2439,10 @@ mod tests { #[test] fn candidates_lose_the_bond_when_outgoing() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(4), vec![5], 40)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![5], 40)); assert_eq!(balances(&5), (47, 3)); assert_eq!(balances(&3), (27, 3)); @@ -2447,11 +2462,11 @@ mod tests { #[test] fn current_members_are_always_next_candidate() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2459,13 +2474,13 @@ mod tests { assert_eq!(members_ids(), vec![4, 5]); assert_eq!(Elections::election_rounds(), 1); - assert_ok!(submit_candidacy(Origin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); - assert_ok!(Elections::remove_voter(Origin::signed(4))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(4))); // 5 will persist as candidates despite not being in the list. assert_eq!(candidate_ids(), vec![2, 3]); @@ -2483,15 +2498,15 @@ mod tests { // what I mean by uninterrupted: // given no input or stimulants the same members are re-elected. ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); let check_at_block = |b: u32| { System::set_block_number(b.into()); @@ -2516,11 +2531,11 @@ mod tests { #[test] fn remove_members_triggers_election() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2528,10 +2543,10 @@ mod tests { assert_eq!(Elections::election_rounds(), 1); // a new candidate - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); - assert_ok!(Elections::remove_member(Origin::root(), 4, true, true)); + assert_ok!(Elections::remove_member(RuntimeOrigin::root(), 4, true, true)); assert_eq!(balances(&4), (35, 2)); // slashed assert_eq!(Elections::election_rounds(), 2); // new election round @@ -2542,14 +2557,14 @@ mod tests { #[test] fn seats_should_be_released_when_no_vote() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(2), vec![3], 20)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![3], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); assert_eq!(>::decode_len().unwrap(), 3); @@ -2560,10 +2575,10 @@ mod tests { assert_eq!(members_ids(), vec![3, 5]); assert_eq!(Elections::election_rounds(), 1); - assert_ok!(Elections::remove_voter(Origin::signed(2))); - assert_ok!(Elections::remove_voter(Origin::signed(3))); - assert_ok!(Elections::remove_voter(Origin::signed(4))); - assert_ok!(Elections::remove_voter(Origin::signed(5))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(2))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(3))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(4))); + assert_ok!(Elections::remove_voter(RuntimeOrigin::signed(5))); // meanwhile, no one cares to become a candidate again. System::set_block_number(10); @@ -2576,29 +2591,29 @@ mod tests { #[test] fn incoming_outgoing_are_reported() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); assert_eq!(members_ids(), vec![4, 5]); - assert_ok!(submit_candidacy(Origin::signed(1))); - assert_ok!(submit_candidacy(Origin::signed(2))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(1))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); // 5 will change their vote and becomes an `outgoing` - assert_ok!(vote(Origin::signed(5), vec![4], 8)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![4], 8)); // 4 will stay in the set - assert_ok!(vote(Origin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); // 3 will become a winner - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); // these two are losers. - assert_ok!(vote(Origin::signed(2), vec![2], 20)); - assert_ok!(vote(Origin::signed(1), vec![1], 10)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(1), vec![1], 10)); System::set_block_number(10); Elections::on_initialize(System::block_number()); @@ -2614,7 +2629,7 @@ mod tests { // 5 is an outgoing loser. will also get slashed. assert_eq!(balances(&5), (45, 2)); - System::assert_has_event(Event::Elections(super::Event::NewTerm { + System::assert_has_event(RuntimeEvent::Elections(super::Event::NewTerm { new_members: vec![(4, 35), (5, 45)], })); }) @@ -2623,12 +2638,12 @@ mod tests { #[test] fn invalid_votes_are_moot() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![10], 50)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![10], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2641,15 +2656,15 @@ mod tests { #[test] fn members_are_sorted_based_on_id_runners_on_merit() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![3], 20)); - assert_ok!(vote(Origin::signed(3), vec![2], 30)); - assert_ok!(vote(Origin::signed(4), vec![5], 40)); - assert_ok!(vote(Origin::signed(5), vec![4], 50)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![3], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![2], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![5], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![4], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2663,19 +2678,19 @@ mod tests { #[test] fn runner_up_replacement_maintains_members_order() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![5], 20)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![2], 50)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![2], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); assert_eq!(members_ids(), vec![2, 4]); - assert_ok!(Elections::remove_member(Origin::root(), 2, true, false)); + assert_ok!(Elections::remove_member(RuntimeOrigin::root(), 2, true, false)); assert_eq!(members_ids(), vec![4, 5]); }); } @@ -2683,15 +2698,15 @@ mod tests { #[test] fn can_renounce_candidacy_member_with_runners_bond_is_refunded() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2699,7 +2714,7 @@ mod tests { assert_eq!(members_ids(), vec![4, 5]); assert_eq!(runners_up_ids(), vec![2, 3]); - assert_ok!(Elections::renounce_candidacy(Origin::signed(4), Renouncing::Member)); + assert_ok!(Elections::renounce_candidacy(RuntimeOrigin::signed(4), Renouncing::Member)); assert_eq!(balances(&4), (38, 2)); // 2 is voting bond. assert_eq!(members_ids(), vec![3, 5]); @@ -2710,11 +2725,11 @@ mod tests { #[test] fn can_renounce_candidacy_member_without_runners_bond_is_refunded() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2722,7 +2737,7 @@ mod tests { assert_eq!(members_ids(), vec![4, 5]); assert!(runners_up_ids().is_empty()); - assert_ok!(Elections::renounce_candidacy(Origin::signed(4), Renouncing::Member)); + assert_ok!(Elections::renounce_candidacy(RuntimeOrigin::signed(4), Renouncing::Member)); assert_eq!(balances(&4), (38, 2)); // 2 is voting bond. // no replacement @@ -2734,15 +2749,15 @@ mod tests { #[test] fn can_renounce_candidacy_runner_up() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(5), vec![4], 50)); - assert_ok!(vote(Origin::signed(4), vec![5], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![4], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![5], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2750,7 +2765,10 @@ mod tests { assert_eq!(members_ids(), vec![4, 5]); assert_eq!(runners_up_ids(), vec![2, 3]); - assert_ok!(Elections::renounce_candidacy(Origin::signed(3), Renouncing::RunnerUp)); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(3), + Renouncing::RunnerUp + )); assert_eq!(balances(&3), (28, 2)); // 2 is voting bond. assert_eq!(members_ids(), vec![4, 5]); @@ -2761,22 +2779,25 @@ mod tests { #[test] fn runner_up_replacement_works_when_out_of_order() { ExtBuilder::default().desired_runners_up(2).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![5], 20)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(5), vec![2], 50)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![5], 20)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![2], 50)); System::set_block_number(5); Elections::on_initialize(System::block_number()); assert_eq!(members_ids(), vec![2, 4]); assert_eq!(runners_up_ids(), vec![5, 3]); - assert_ok!(Elections::renounce_candidacy(Origin::signed(3), Renouncing::RunnerUp)); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(3), + Renouncing::RunnerUp + )); assert_eq!(members_ids(), vec![2, 4]); assert_eq!(runners_up_ids(), vec![5]); }); @@ -2785,11 +2806,14 @@ mod tests { #[test] fn can_renounce_candidacy_candidate() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); assert_eq!(balances(&5), (47, 3)); assert_eq!(candidate_ids(), vec![5]); - assert_ok!(Elections::renounce_candidacy(Origin::signed(5), Renouncing::Candidate(1))); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(5), + Renouncing::Candidate(1) + )); assert_eq!(balances(&5), (50, 0)); assert!(candidate_ids().is_empty()); }) @@ -2799,15 +2823,15 @@ mod tests { fn wrong_renounce_candidacy_should_fail() { ExtBuilder::default().build_and_execute(|| { assert_noop!( - Elections::renounce_candidacy(Origin::signed(5), Renouncing::Candidate(0)), + Elections::renounce_candidacy(RuntimeOrigin::signed(5), Renouncing::Candidate(0)), Error::::InvalidRenouncing, ); assert_noop!( - Elections::renounce_candidacy(Origin::signed(5), Renouncing::Member), + Elections::renounce_candidacy(RuntimeOrigin::signed(5), Renouncing::Member), Error::::InvalidRenouncing, ); assert_noop!( - Elections::renounce_candidacy(Origin::signed(5), Renouncing::RunnerUp), + Elections::renounce_candidacy(RuntimeOrigin::signed(5), Renouncing::RunnerUp), Error::::InvalidRenouncing, ); }) @@ -2816,13 +2840,13 @@ mod tests { #[test] fn non_member_renounce_member_should_fail() { ExtBuilder::default().desired_runners_up(1).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2831,7 +2855,7 @@ mod tests { assert_eq!(runners_up_ids(), vec![3]); assert_noop!( - Elections::renounce_candidacy(Origin::signed(3), Renouncing::Member), + Elections::renounce_candidacy(RuntimeOrigin::signed(3), Renouncing::Member), Error::::InvalidRenouncing, ); }) @@ -2840,13 +2864,13 @@ mod tests { #[test] fn non_runner_up_renounce_runner_up_should_fail() { ExtBuilder::default().desired_runners_up(1).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2855,7 +2879,7 @@ mod tests { assert_eq!(runners_up_ids(), vec![3]); assert_noop!( - Elections::renounce_candidacy(Origin::signed(4), Renouncing::RunnerUp), + Elections::renounce_candidacy(RuntimeOrigin::signed(4), Renouncing::RunnerUp), Error::::InvalidRenouncing, ); }) @@ -2864,27 +2888,33 @@ mod tests { #[test] fn wrong_candidate_count_renounce_should_fail() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); assert_noop!( - Elections::renounce_candidacy(Origin::signed(4), Renouncing::Candidate(2)), + Elections::renounce_candidacy(RuntimeOrigin::signed(4), Renouncing::Candidate(2)), Error::::InvalidWitnessData, ); - assert_ok!(Elections::renounce_candidacy(Origin::signed(4), Renouncing::Candidate(3))); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(4), + Renouncing::Candidate(3) + )); }) } #[test] fn renounce_candidacy_count_can_overestimate() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); // while we have only 3 candidates. - assert_ok!(Elections::renounce_candidacy(Origin::signed(4), Renouncing::Candidate(4))); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(4), + Renouncing::Candidate(4) + )); }) } @@ -2894,13 +2924,13 @@ mod tests { .desired_runners_up(2) .desired_members(1) .build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 5)); - assert_ok!(vote(Origin::signed(3), vec![3], 15)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 5)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 15)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2908,8 +2938,8 @@ mod tests { assert_eq!(members_ids(), vec![5]); assert_eq!(runners_up_ids(), vec![4, 3]); - assert_ok!(submit_candidacy(Origin::signed(2))); - assert_ok!(vote(Origin::signed(2), vec![2], 10)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 10)); System::set_block_number(10); Elections::on_initialize(System::block_number()); @@ -2930,13 +2960,13 @@ mod tests { .desired_runners_up(2) .desired_members(1) .build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2949,8 +2979,8 @@ mod tests { assert_eq!(balances(&2), (15, 5)); // this guy will shift everyone down. - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); System::set_block_number(10); Elections::on_initialize(System::block_number()); @@ -2973,13 +3003,13 @@ mod tests { .desired_runners_up(2) .desired_members(1) .build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -2992,8 +3022,8 @@ mod tests { assert_eq!(balances(&2), (15, 5)); // swap some votes. - assert_ok!(vote(Origin::signed(4), vec![2], 40)); - assert_ok!(vote(Origin::signed(2), vec![4], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![2], 40)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![4], 20)); System::set_block_number(10); Elections::on_initialize(System::block_number()); @@ -3013,13 +3043,13 @@ mod tests { #[test] fn remove_and_replace_member_works() { let setup = || { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); - assert_ok!(vote(Origin::signed(5), vec![5], 50)); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5], 50)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -3040,7 +3070,10 @@ mod tests { // member removed, no replacement found. ExtBuilder::default().desired_runners_up(1).build_and_execute(|| { setup(); - assert_ok!(Elections::renounce_candidacy(Origin::signed(3), Renouncing::RunnerUp)); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(3), + Renouncing::RunnerUp + )); assert_eq!(Elections::remove_and_replace_member(&4, false), Ok(false)); assert_eq!(members_ids(), vec![5]); @@ -3063,15 +3096,15 @@ mod tests { .build_and_execute(|| { assert_eq!(Elections::candidates().len(), 0); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); assert_eq!(Elections::candidates().len(), 3); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -3089,15 +3122,15 @@ mod tests { .build_and_execute(|| { assert_eq!(Elections::candidates().len(), 0); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); assert_eq!(Elections::candidates().len(), 3); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -3115,15 +3148,15 @@ mod tests { .build_and_execute(|| { assert_eq!(Elections::candidates().len(), 0); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); assert_eq!(Elections::candidates().len(), 3); - assert_ok!(vote(Origin::signed(4), vec![4], 40)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); - assert_ok!(vote(Origin::signed(2), vec![2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 40)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2], 20)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -3138,17 +3171,17 @@ mod tests { #[test] fn dupe_vote_is_moot() { ExtBuilder::default().desired_members(1).build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); - assert_ok!(submit_candidacy(Origin::signed(2))); - assert_ok!(submit_candidacy(Origin::signed(1))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(2))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(1))); // all these duplicate votes will not cause 2 to win. - assert_ok!(vote(Origin::signed(1), vec![2, 2, 2, 2], 5)); - assert_ok!(vote(Origin::signed(2), vec![2, 2, 2, 2], 20)); + assert_ok!(vote(RuntimeOrigin::signed(1), vec![2, 2, 2, 2], 5)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![2, 2, 2, 2], 20)); - assert_ok!(vote(Origin::signed(3), vec![3], 30)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 30)); System::set_block_number(5); Elections::on_initialize(System::block_number()); @@ -3160,24 +3193,33 @@ mod tests { #[test] fn remove_defunct_voter_works() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(submit_candidacy(Origin::signed(5))); - assert_ok!(submit_candidacy(Origin::signed(4))); - assert_ok!(submit_candidacy(Origin::signed(3))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(5))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(4))); + assert_ok!(submit_candidacy(RuntimeOrigin::signed(3))); // defunct - assert_ok!(vote(Origin::signed(5), vec![5, 4], 5)); + assert_ok!(vote(RuntimeOrigin::signed(5), vec![5, 4], 5)); // defunct - assert_ok!(vote(Origin::signed(4), vec![4], 5)); + assert_ok!(vote(RuntimeOrigin::signed(4), vec![4], 5)); // ok - assert_ok!(vote(Origin::signed(3), vec![3], 5)); + assert_ok!(vote(RuntimeOrigin::signed(3), vec![3], 5)); // ok - assert_ok!(vote(Origin::signed(2), vec![3, 4], 5)); - - assert_ok!(Elections::renounce_candidacy(Origin::signed(5), Renouncing::Candidate(3))); - assert_ok!(Elections::renounce_candidacy(Origin::signed(4), Renouncing::Candidate(2))); - assert_ok!(Elections::renounce_candidacy(Origin::signed(3), Renouncing::Candidate(1))); - - assert_ok!(Elections::clean_defunct_voters(Origin::root(), 4, 2)); + assert_ok!(vote(RuntimeOrigin::signed(2), vec![3, 4], 5)); + + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(5), + Renouncing::Candidate(3) + )); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(4), + Renouncing::Candidate(2) + )); + assert_ok!(Elections::renounce_candidacy( + RuntimeOrigin::signed(3), + Renouncing::Candidate(1) + )); + + assert_ok!(Elections::clean_defunct_voters(RuntimeOrigin::root(), 4, 2)); }) } } diff --git a/frame/examples/basic/Cargo.toml b/frame/examples/basic/Cargo.toml index a5f0c7c89321a..e06bfa374cd9b 100644 --- a/frame/examples/basic/Cargo.toml +++ b/frame/examples/basic/Cargo.toml @@ -31,7 +31,7 @@ sp-core = { version = "6.0.0", default-features = false, path = "../../../primit default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/examples/basic/src/benchmarking.rs b/frame/examples/basic/src/benchmarking.rs index 93e14f358208e..13f069c23e27b 100644 --- a/frame/examples/basic/src/benchmarking.rs +++ b/frame/examples/basic/src/benchmarking.rs @@ -34,25 +34,26 @@ use frame_system::RawOrigin; // Details on using the benchmarks macro can be seen at: // https://paritytech.github.io/substrate/master/frame_benchmarking/trait.Benchmarking.html#tymethod.benchmarks benchmarks! { - // This will measure the execution time of `set_dummy` for b in [1..1000] range. + // This will measure the execution time of `set_dummy`. set_dummy_benchmark { - // This is the benchmark setup phase - let b in 1 .. 1000; - }: set_dummy(RawOrigin::Root, b.into()) // The execution phase is just running `set_dummy` extrinsic call + // This is the benchmark setup phase. + // `set_dummy` is a constant time function, hence we hard-code some random value here. + let value = 1000u32.into(); + }: set_dummy(RawOrigin::Root, value) // The execution phase is just running `set_dummy` extrinsic call verify { // This is the optional benchmark verification phase, asserting certain states. - assert_eq!(Pallet::::dummy(), Some(b.into())) + assert_eq!(Pallet::::dummy(), Some(value)) } - // This will measure the execution time of `accumulate_dummy` for b in [1..1000] range. + // This will measure the execution time of `accumulate_dummy`. // The benchmark execution phase is shorthanded. When the name of the benchmark case is the same // as the extrinsic call. `_(...)` is used to represent the extrinsic name. // The benchmark verification phase is omitted. accumulate_dummy { - let b in 1 .. 1000; + let value = 1000u32.into(); // The caller account is whitelisted for DB reads/write by the benchmarking macro. let caller: T::AccountId = whitelisted_caller(); - }: _(RawOrigin::Signed(caller), b.into()) + }: _(RawOrigin::Signed(caller), value) // This will measure the execution time of sorting a vector. sort_vector { @@ -63,7 +64,7 @@ benchmarks! { } }: { // The benchmark execution phase could also be a closure with custom code - m.sort_unstable(); + m.sort(); } // This line generates test cases for benchmarking, and could be run by: diff --git a/frame/examples/basic/src/lib.rs b/frame/examples/basic/src/lib.rs index ad46bdc4185bd..256529421caae 100644 --- a/frame/examples/basic/src/lib.rs +++ b/frame/examples/basic/src/lib.rs @@ -273,9 +273,9 @@ use codec::{Decode, Encode}; use frame_support::{ - dispatch::DispatchResult, + dispatch::{ClassifyDispatch, DispatchClass, DispatchResult, Pays, PaysFee, WeighData}, traits::IsSubType, - weights::{ClassifyDispatch, DispatchClass, Pays, PaysFee, WeighData, Weight}, + weights::Weight, }; use frame_system::ensure_signed; use log::info; @@ -370,7 +370,7 @@ pub mod pallet { type MagicNumber: Get; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Type representing the weight of this pallet type WeightInfo: WeightInfo; @@ -498,7 +498,7 @@ pub mod pallet { // The weight for this extrinsic we rely on the auto-generated `WeightInfo` from the // benchmark toolchain. #[pallet::weight( - ::WeightInfo::accumulate_dummy((*increase_by).saturated_into()) + ::WeightInfo::accumulate_dummy() )] pub fn accumulate_dummy(origin: OriginFor, increase_by: T::Balance) -> DispatchResult { // This is a public call, so we ensure that the origin is some signed account. @@ -655,7 +655,7 @@ pub mod pallet { impl Pallet { // Add public immutables and private mutables. #[allow(dead_code)] - fn accumulate_foo(origin: T::Origin, increase_by: T::Balance) -> DispatchResult { + fn accumulate_foo(origin: T::RuntimeOrigin, increase_by: T::Balance) -> DispatchResult { let _sender = ensure_signed(origin)?; let prev = >::get(); @@ -719,11 +719,11 @@ impl sp_std::fmt::Debug for WatchDummy { impl SignedExtension for WatchDummy where - ::Call: IsSubType>, + ::RuntimeCall: IsSubType>, { const IDENTIFIER: &'static str = "WatchDummy"; type AccountId = T::AccountId; - type Call = ::Call; + type Call = ::RuntimeCall; type AdditionalSigned = (); type Pre = (); diff --git a/frame/examples/basic/src/tests.rs b/frame/examples/basic/src/tests.rs index f6afb7a0c77f1..97fbddfbc41e0 100644 --- a/frame/examples/basic/src/tests.rs +++ b/frame/examples/basic/src/tests.rs @@ -19,9 +19,10 @@ use crate::*; use frame_support::{ - assert_ok, parameter_types, + assert_ok, + dispatch::{DispatchInfo, GetDispatchInfo}, + parameter_types, traits::{ConstU64, OnInitialize}, - weights::{DispatchInfo, GetDispatchInfo}, }; use sp_core::H256; // The testing primitives are very useful for avoiding having to work with signatures @@ -59,16 +60,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -87,7 +88,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); @@ -95,7 +96,7 @@ impl pallet_balances::Config for Test { impl Config for Test { type MagicNumber = ConstU64<1_000_000_000>; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } @@ -127,12 +128,12 @@ fn it_works_for_optional_value() { assert_eq!(Example::dummy(), Some(val1)); // Check that accumulate works when we have Some value in Dummy already. - assert_ok!(Example::accumulate_dummy(Origin::signed(1), val2)); + assert_ok!(Example::accumulate_dummy(RuntimeOrigin::signed(1), val2)); assert_eq!(Example::dummy(), Some(val1 + val2)); // Check that accumulate works when we Dummy has None in it. >::on_initialize(2); - assert_ok!(Example::accumulate_dummy(Origin::signed(1), val1)); + assert_ok!(Example::accumulate_dummy(RuntimeOrigin::signed(1), val1)); assert_eq!(Example::dummy(), Some(val1 + val2 + val1)); }); } @@ -141,7 +142,7 @@ fn it_works_for_optional_value() { fn it_works_for_default_value() { new_test_ext().execute_with(|| { assert_eq!(Example::foo(), 24); - assert_ok!(Example::accumulate_foo(Origin::signed(1), 1)); + assert_ok!(Example::accumulate_foo(RuntimeOrigin::signed(1), 1)); assert_eq!(Example::foo(), 25); }); } @@ -150,7 +151,7 @@ fn it_works_for_default_value() { fn set_dummy_works() { new_test_ext().execute_with(|| { let test_val = 133; - assert_ok!(Example::set_dummy(Origin::root(), test_val.into())); + assert_ok!(Example::set_dummy(RuntimeOrigin::root(), test_val.into())); assert_eq!(Example::dummy(), Some(test_val)); }); } @@ -190,11 +191,13 @@ fn weights_work() { let default_call = pallet_example_basic::Call::::accumulate_dummy { increase_by: 10 }; let info1 = default_call.get_dispatch_info(); // aka. `let info = as GetDispatchInfo>::get_dispatch_info(&default_call);` - assert!(info1.weight > Weight::zero()); + // TODO: account for proof size weight + assert!(info1.weight.ref_time() > 0); // `set_dummy` is simpler than `accumulate_dummy`, and the weight // should be less. let custom_call = pallet_example_basic::Call::::set_dummy { new_value: 20 }; let info2 = custom_call.get_dispatch_info(); - assert!(info1.weight > info2.weight); + // TODO: account for proof size weight + assert!(info1.weight.ref_time() > info2.weight.ref_time()); } diff --git a/frame/examples/basic/src/weights.rs b/frame/examples/basic/src/weights.rs index 986648b4302bc..a69f0824eac11 100644 --- a/frame/examples/basic/src/weights.rs +++ b/frame/examples/basic/src/weights.rs @@ -1,6 +1,6 @@ // This file is part of Substrate. -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. +// Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,34 +17,26 @@ //! Autogenerated weights for pallet_example_basic //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-03-15, STEPS: `[100, ]`, REPEAT: 10, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-10-09, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `Shawns-MacBook-Pro.local`, CPU: `` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: // ./target/release/substrate // benchmark -// --chain -// dev -// --execution -// wasm -// --wasm-execution -// compiled -// --pallet -// pallet_example_basic -// --extrinsic -// * -// --steps -// 100 -// --repeat -// 10 -// --raw -// --output -// ./ +// pallet +// --chain=dev +// --execution=wasm +// --wasm-execution=compiled +// --pallet=pallet_example_basic +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --output=./ // --template // ./.maintain/frame-weight-template.hbs - #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] @@ -54,48 +46,50 @@ use sp_std::marker::PhantomData; /// Weight functions needed for pallet_example_basic. pub trait WeightInfo { - fn set_dummy_benchmark(b: u32, ) -> Weight; - fn accumulate_dummy(b: u32, ) -> Weight; + fn set_dummy_benchmark() -> Weight; + fn accumulate_dummy() -> Weight; fn sort_vector(x: u32, ) -> Weight; } /// Weights for pallet_example_basic using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - fn set_dummy_benchmark(b: u32, ) -> Weight { - Weight::from_ref_time(5_834_000 as u64) - .saturating_add(Weight::from_ref_time(24_000 as u64).saturating_mul(b as u64)) + // Storage: BasicExample Dummy (r:0 w:1) + fn set_dummy_benchmark() -> Weight { + Weight::from_ref_time(19_000_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } - fn accumulate_dummy(b: u32, ) -> Weight { - Weight::from_ref_time(51_353_000 as u64) - .saturating_add(Weight::from_ref_time(14_000 as u64).saturating_mul(b as u64)) + // Storage: BasicExample Dummy (r:1 w:1) + fn accumulate_dummy() -> Weight { + Weight::from_ref_time(18_000_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } + /// The range of component `x` is `[0, 10000]`. fn sort_vector(x: u32, ) -> Weight { - Weight::from_ref_time(2_569_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(x as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 2 + .saturating_add(Weight::from_ref_time(520 as u64).saturating_mul(x as u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - fn set_dummy_benchmark(b: u32, ) -> Weight { - Weight::from_ref_time(5_834_000 as u64) - .saturating_add(Weight::from_ref_time(24_000 as u64).saturating_mul(b as u64)) + // Storage: BasicExample Dummy (r:0 w:1) + fn set_dummy_benchmark() -> Weight { + Weight::from_ref_time(19_000_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } - fn accumulate_dummy(b: u32, ) -> Weight { - Weight::from_ref_time(51_353_000 as u64) - .saturating_add(Weight::from_ref_time(14_000 as u64).saturating_mul(b as u64)) + // Storage: BasicExample Dummy (r:1 w:1) + fn accumulate_dummy() -> Weight { + Weight::from_ref_time(18_000_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } + /// The range of component `x` is `[0, 10000]`. fn sort_vector(x: u32, ) -> Weight { - Weight::from_ref_time(2_569_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(4_000 as u64).saturating_mul(x as u64)) + Weight::from_ref_time(0 as u64) + // Standard Error: 2 + .saturating_add(Weight::from_ref_time(520 as u64).saturating_mul(x as u64)) } } diff --git a/frame/examples/offchain-worker/src/lib.rs b/frame/examples/offchain-worker/src/lib.rs index b40311051594b..fdf8b61a01acd 100644 --- a/frame/examples/offchain-worker/src/lib.rs +++ b/frame/examples/offchain-worker/src/lib.rs @@ -126,10 +126,7 @@ pub mod pallet { type AuthorityId: AppCrypto; /// The overarching event type. - type Event: From> + IsType<::Event>; - - /// The overarching dispatch call type. - type Call: From>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; // Configuration parameters diff --git a/frame/examples/offchain-worker/src/tests.rs b/frame/examples/offchain-worker/src/tests.rs index 5b03614333cc9..72c001fd6e6cc 100644 --- a/frame/examples/offchain-worker/src/tests.rs +++ b/frame/examples/offchain-worker/src/tests.rs @@ -60,8 +60,8 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -69,7 +69,7 @@ impl frame_system::Config for Test { type AccountId = sp_core::sr25519::Public; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -82,7 +82,7 @@ impl frame_system::Config for Test { type MaxConsumers = ConstU32<16>; } -type Extrinsic = TestXt; +type Extrinsic = TestXt; type AccountId = <::Signer as IdentifyAccount>::AccountId; impl frame_system::offchain::SigningTypes for Test { @@ -92,22 +92,22 @@ impl frame_system::offchain::SigningTypes for Test { impl frame_system::offchain::SendTransactionTypes for Test where - Call: From, + RuntimeCall: From, { - type OverarchingCall = Call; + type OverarchingCall = RuntimeCall; type Extrinsic = Extrinsic; } impl frame_system::offchain::CreateSignedTransaction for Test where - Call: From, + RuntimeCall: From, { fn create_transaction>( - call: Call, + call: RuntimeCall, _public: ::Signer, _account: AccountId, nonce: u64, - ) -> Option<(Call, ::SignaturePayload)> { + ) -> Option<(RuntimeCall, ::SignaturePayload)> { Some((call, (nonce, ()))) } } @@ -117,9 +117,8 @@ parameter_types! { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type AuthorityId = crypto::TestAuthId; - type Call = Call; type GracePeriod = ConstU64<5>; type UnsignedInterval = ConstU64<128>; type UnsignedPriority = UnsignedPriority; @@ -135,10 +134,10 @@ fn it_aggregates_the_price() { sp_io::TestExternalities::default().execute_with(|| { assert_eq!(Example::average_price(), None); - assert_ok!(Example::submit_price(Origin::signed(test_pub()), 27)); + assert_ok!(Example::submit_price(RuntimeOrigin::signed(test_pub()), 27)); assert_eq!(Example::average_price(), Some(27)); - assert_ok!(Example::submit_price(Origin::signed(test_pub()), 43)); + assert_ok!(Example::submit_price(RuntimeOrigin::signed(test_pub()), 43)); assert_eq!(Example::average_price(), Some(35)); }); } @@ -233,7 +232,7 @@ fn should_submit_signed_transaction_on_chain() { assert!(pool_state.read().transactions.is_empty()); let tx = Extrinsic::decode(&mut &*tx).unwrap(); assert_eq!(tx.signature.unwrap().0, 0); - assert_eq!(tx.call, Call::Example(crate::Call::submit_price { price: 15523 })); + assert_eq!(tx.call, RuntimeCall::Example(crate::Call::submit_price { price: 15523 })); }); } @@ -278,7 +277,7 @@ fn should_submit_unsigned_transaction_on_chain_for_any_account() { let tx = pool_state.write().transactions.pop().unwrap(); let tx = Extrinsic::decode(&mut &*tx).unwrap(); assert_eq!(tx.signature, None); - if let Call::Example(crate::Call::submit_price_unsigned_with_signed_payload { + if let RuntimeCall::Example(crate::Call::submit_price_unsigned_with_signed_payload { price_payload: body, signature, }) = tx.call @@ -337,7 +336,7 @@ fn should_submit_unsigned_transaction_on_chain_for_all_accounts() { let tx = pool_state.write().transactions.pop().unwrap(); let tx = Extrinsic::decode(&mut &*tx).unwrap(); assert_eq!(tx.signature, None); - if let Call::Example(crate::Call::submit_price_unsigned_with_signed_payload { + if let RuntimeCall::Example(crate::Call::submit_price_unsigned_with_signed_payload { price_payload: body, signature, }) = tx.call @@ -379,7 +378,10 @@ fn should_submit_raw_unsigned_transaction_on_chain() { assert_eq!(tx.signature, None); assert_eq!( tx.call, - Call::Example(crate::Call::submit_price_unsigned { block_number: 1, price: 15523 }) + RuntimeCall::Example(crate::Call::submit_price_unsigned { + block_number: 1, + price: 15523 + }) ); }); } diff --git a/frame/examples/parallel/src/lib.rs b/frame/examples/parallel/src/lib.rs index 7b8948c2ebd09..3432a79638664 100644 --- a/frame/examples/parallel/src/lib.rs +++ b/frame/examples/parallel/src/lib.rs @@ -41,10 +41,7 @@ pub mod pallet { use frame_system::pallet_prelude::*; #[pallet::config] - pub trait Config: frame_system::Config { - /// The overarching dispatch call type. - type Call: From>; - } + pub trait Config: frame_system::Config {} #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] diff --git a/frame/examples/parallel/src/tests.rs b/frame/examples/parallel/src/tests.rs index 67d823d8b204b..fdef24a39ae36 100644 --- a/frame/examples/parallel/src/tests.rs +++ b/frame/examples/parallel/src/tests.rs @@ -45,8 +45,8 @@ parameter_types! { impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type PalletInfo = PalletInfo; type Index = u64; type BlockNumber = u64; @@ -55,7 +55,7 @@ impl frame_system::Config for Test { type AccountId = sp_core::sr25519::Public; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU64<250>; type DbWeight = (); type BlockWeights = (); @@ -70,16 +70,14 @@ impl frame_system::Config for Test { type MaxConsumers = frame_support::traits::ConstU32<16>; } -impl Config for Test { - type Call = Call; -} +impl Config for Test {} fn test_pub(n: u8) -> sp_core::sr25519::Public { sp_core::sr25519::Public::from_raw([n; 32]) } -fn test_origin(n: u8) -> Origin { - Origin::signed(test_pub(n)) +fn test_origin(n: u8) -> RuntimeOrigin { + RuntimeOrigin::signed(test_pub(n)) } #[test] @@ -105,7 +103,7 @@ fn it_can_enlist() { }, ]; - Example::enlist_participants(Origin::signed(test_pub(1)), participants) + Example::enlist_participants(RuntimeOrigin::signed(test_pub(1)), participants) .expect("Failed to enlist"); assert_eq!(Example::participants().len(), 2); diff --git a/frame/executive/Cargo.toml b/frame/executive/Cargo.toml index 93d31125f9078..d95ccdb16f703 100644 --- a/frame/executive/Cargo.toml +++ b/frame/executive/Cargo.toml @@ -33,6 +33,7 @@ log = { version = "0.4.17", default-features = false } [dev-dependencies] hex-literal = "0.3.4" +array-bytes = "4.1" sp-keystore = { version = "0.12.0", path = "../../primitives/keystore" } pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-transaction-payment = { version = "4.0.0-dev", path = "../transaction-payment" } diff --git a/frame/executive/src/lib.rs b/frame/executive/src/lib.rs index b5836ef45e8c3..6515ace896f0e 100644 --- a/frame/executive/src/lib.rs +++ b/frame/executive/src/lib.rs @@ -52,7 +52,7 @@ //! `Executive` type declaration from the node template. //! //! ``` -//! +//! //! # use sp_runtime::generic; //! # use frame_executive as executive; //! # pub struct UncheckedExtrinsic {}; @@ -123,12 +123,12 @@ use aquamarine::aquamarine; use crate::traits::AtLeast32BitUnsigned; use codec::{Codec, Decode, Encode}; use frame_support::{ - dispatch::PostDispatchInfo, + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo}, traits::{ EnsureInherentsAreFirst, ExecuteBlock, Get, OffchainWorker, OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade, }, - weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Weight}, + weights::Weight, }; use schnorrkel::vrf::{VRFOutput, VRFProof}; use sp_runtime::{ @@ -144,7 +144,7 @@ use sp_std::{collections::btree_set::BTreeSet, marker::PhantomData, prelude::*}; pub type CheckedOf = >::Checked; pub type CallOf = as Applyable>::Call; -pub type OriginOf = as Dispatchable>::Origin; +pub type OriginOf = as Dispatchable>::RuntimeOrigin; #[cfg_attr(doc, aquamarine)] /// Main entry point for certain runtime actions as e.g. `execute_block`. @@ -357,8 +357,7 @@ where pub fn try_runtime_upgrade() -> Result { <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::pre_upgrade().unwrap(); let weight = Self::execute_on_runtime_upgrade(); - <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::post_upgrade().unwrap(); - + <(COnRuntimeUpgrade, AllPalletsWithSystem) as OnRuntimeUpgrade>::post_upgrade(Vec::::new()).unwrap(); Ok(weight) } } @@ -652,7 +651,7 @@ where let max_weight = >::get().max_block; let remaining_weight = max_weight.saturating_sub(weight.total()); - if remaining_weight > Weight::zero() { + if remaining_weight.all_gt(Weight::zero()) { let used_weight = >::on_idle( block_number, remaining_weight, @@ -781,8 +780,9 @@ where #[cfg(test)] mod tests { use super::*; - use hex_literal::hex; + use sp_core::{sr25519, testing::SR25519, Pair, ShufflingSeed, H256}; + use sp_ver::calculate_next_seed_from_bytes; use frame_support::{ @@ -796,7 +796,7 @@ mod tests { use frame_system::{Call as SystemCall, ChainContext, LastRuntimeUpgradeInfo}; use pallet_balances::Call as BalancesCall; use pallet_transaction_payment::CurrencyAdapter; - use sp_core::{crypto::key_types::AURA, sr25519, Pair, ShufflingSeed, H256}; + use sp_core::{crypto::key_types::AURA}; use sp_keystore::{ vrf::{VRFTranscriptData, VRFTranscriptValue}, SyncCryptoStore, @@ -961,7 +961,7 @@ mod tests { frame_system::limits::BlockWeights::builder() .base_block(Weight::from_ref_time(10)) .for_class(DispatchClass::all(), |weights| weights.base_extrinsic = Weight::from_ref_time(5)) - .for_class(DispatchClass::non_mandatory(), |weights| weights.max_total = Weight::from_ref_time(1024).into()) + .for_class(DispatchClass::non_mandatory(), |weights| weights.max_total = Weight::from_ref_time(1024).set_proof_size(u64::MAX).into()) .build_or_panic(); pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 10, @@ -972,18 +972,18 @@ mod tests { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = BlockWeights; type BlockLength = (); - type Origin = Origin; - type Call = Call; + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; type Index = u64; + type RuntimeCall = RuntimeCall; type BlockNumber = u64; type Hash = sp_core::H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; - type DbWeight = (); type Version = RuntimeVersion; type PalletInfo = PalletInfo; type AccountData = pallet_balances::AccountData; @@ -1001,7 +1001,7 @@ mod tests { } impl pallet_balances::Config for Runtime { type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; @@ -1015,7 +1015,7 @@ mod tests { pub const TransactionByteFee: Balance = 0; } impl pallet_transaction_payment::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter; type OperationalFeeMultiplier = ConstU8<5>; type WeightToFee = IdentityFee; @@ -1027,12 +1027,12 @@ mod tests { pub struct RuntimeVersion; impl frame_support::traits::Get for RuntimeVersion { fn get() -> sp_version::RuntimeVersion { - RUNTIME_VERSION.with(|v| v.borrow().clone()) + RuntimeVersionTestValues::get().clone() } } - thread_local! { - pub static RUNTIME_VERSION: std::cell::RefCell = + parameter_types! { + pub static RuntimeVersionTestValues: sp_version::RuntimeVersion = Default::default(); } @@ -1042,7 +1042,7 @@ mod tests { frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, ); - type TestXt = sp_runtime::testing::TestXt; + type TestXt = sp_runtime::testing::TestXt; type TestBlock = Block; type TestUncheckedExtrinsic = TestXt; @@ -1081,14 +1081,14 @@ mod tests { Some((who, extra(nonce, fee))) } - fn call_transfer(dest: u64, value: u64) -> Call { - Call::Balances(BalancesCall::transfer { dest, value }) + fn call_transfer(dest: u64, value: u64) -> RuntimeCall { + RuntimeCall::Balances(BalancesCall::transfer { dest, value }) } fn enqueue_txs( txs: Vec<(Option<::AccountId>, Vec)>, - ) -> Call { - Call::System(frame_system::Call::enqueue_txs { txs }) + ) -> RuntimeCall { + RuntimeCall::System(frame_system::Call::enqueue_txs { txs }) } #[test] @@ -1140,11 +1140,15 @@ mod tests { fn block_import_works() { block_import_works_inner( new_test_ext_v0(1), - hex!("2aaebbb0ef77452cf561abc6f738c33299c09b121fc3aa2ac388ccb878a2ea10").into(), + array_bytes::hex_n_into_unchecked( + "ddceab450519bbc0aebe68a8017e02db370d4a534faab424e7f111a257c8bbca", + ), ); block_import_works_inner( new_test_ext(1), - hex!("e5c485cf9d53f651188469fabd91bc765ee1d6ddf17a96533b6b7acb60f697ea").into(), + array_bytes::hex_n_into_unchecked( + "7723223a19520c37ed5340623d480414d0e287f0189bf8c9f268d80832a2de5e", + ), ); } fn block_import_works_inner(mut ext: sp_io::TestExternalities, state_root: H256) { @@ -1154,10 +1158,9 @@ mod tests { parent_hash: [69u8; 32].into(), number: 1, state_root, - extrinsics_root: hex!( - "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314" - ) - .into(), + extrinsics_root: array_bytes::hex_n_into_unchecked( + "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314", + ), digest: Digest { logs: vec![] }, count: 0, seed: Default::default(), @@ -1176,10 +1179,9 @@ mod tests { parent_hash: [69u8; 32].into(), number: 1, state_root: [0u8; 32].into(), - extrinsics_root: hex!( - "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314" - ) - .into(), + extrinsics_root: array_bytes::hex_n_into_unchecked( + "03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314", + ), digest: Digest { logs: vec![] }, count: 0, seed: Default::default(), @@ -1197,10 +1199,9 @@ mod tests { header: Header { parent_hash: [69u8; 32].into(), number: 1, - state_root: hex!( - "75e7d8f360d375bbe91bcf8019c01ab6362448b4a89e3b329717eb9d910340e5" - ) - .into(), + state_root: array_bytes::hex_n_into_unchecked( + "75e7d8f360d375bbe91bcf8019c01ab6362448b4a89e3b329717eb9d910340e5", + ), extrinsics_root: [0u8; 32].into(), digest: Digest { logs: vec![] }, count: 0, @@ -1237,7 +1238,7 @@ mod tests { let mut t = new_test_ext(10000); // given: TestXt uses the encoded len as fixed Len: let xt = TestXt::new( - Call::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), sign_extra(1, 0, 0), ); let encoded = xt.encode(); @@ -1260,7 +1261,7 @@ mod tests { for nonce in 0..=num_to_exhaust_block { let xt = TestXt::new( - Call::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), sign_extra(1, nonce.into(), 0), ); let res = Executive::apply_extrinsic(xt); @@ -1285,15 +1286,15 @@ mod tests { #[test] fn block_weight_and_size_is_stored_per_tx() { let xt = TestXt::new( - Call::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), sign_extra(1, 0, 0), ); let x1 = TestXt::new( - Call::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), sign_extra(1, 1, 0), ); let x2 = TestXt::new( - Call::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), sign_extra(1, 2, 0), ); let len = xt.clone().encode().len() as u32; @@ -1349,8 +1350,8 @@ mod tests { #[test] fn validate_unsigned() { - let valid = TestXt::new(Call::Custom(custom::Call::allowed_unsigned {}), None); - let invalid = TestXt::new(Call::Custom(custom::Call::unallowed_unsigned {}), None); + let valid = TestXt::new(RuntimeCall::Custom(custom::Call::allowed_unsigned {}), None); + let invalid = TestXt::new(RuntimeCall::Custom(custom::Call::unallowed_unsigned {}), None); let mut t = new_test_ext(1); t.execute_with(|| { @@ -1388,7 +1389,7 @@ mod tests { id, &1, 110, lock, ); let xt = TestXt::new( - Call::System(SystemCall::remark { remark: vec![1u8] }), + RuntimeCall::System(SystemCall::remark { remark: vec![1u8] }), sign_extra(1, 0, 0), ); let weight = xt.get_dispatch_info().weight + @@ -1443,14 +1444,13 @@ mod tests { #[test] fn runtime_upgraded_should_work() { new_test_ext(1).execute_with(|| { - RUNTIME_VERSION.with(|v| *v.borrow_mut() = Default::default()); + RuntimeVersionTestValues::mutate(|v| *v = Default::default()); // It should be added at genesis assert!(frame_system::LastRuntimeUpgrade::::exists()); assert!(!Executive::runtime_upgraded()); - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = - sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } }); assert!(Executive::runtime_upgraded()); assert_eq!( @@ -1458,8 +1458,8 @@ mod tests { frame_system::LastRuntimeUpgrade::::get(), ); - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = sp_version::RuntimeVersion { + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, spec_name: "test".into(), ..Default::default() @@ -1471,8 +1471,8 @@ mod tests { frame_system::LastRuntimeUpgrade::::get(), ); - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = sp_version::RuntimeVersion { + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, spec_name: "test".into(), impl_version: 2, @@ -1520,9 +1520,8 @@ mod tests { fn custom_runtime_upgrade_is_called_before_modules() { new_test_ext(1).execute_with(|| { // Make sure `on_runtime_upgrade` is called. - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = - sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } }); Executive::initialize_block(&Header::new( @@ -1542,9 +1541,8 @@ mod tests { fn event_from_runtime_upgrade_is_included() { new_test_ext(1).execute_with(|| { // Make sure `on_runtime_upgrade` is called. - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = - sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } }); // set block number to non zero so events are not exlcuded @@ -1567,15 +1565,14 @@ mod tests { #[test] fn custom_runtime_upgrade_is_called_when_using_execute_block_trait() { let xt = TestXt::new( - Call::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), sign_extra(1, 0, 0), ); let header = new_test_ext(1).execute_with(|| { // Make sure `on_runtime_upgrade` is called. - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = - sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } }); // Let's build some fake block. @@ -1593,15 +1590,14 @@ mod tests { }); // Reset to get the correct new genesis below. - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = sp_version::RuntimeVersion { spec_version: 0, ..Default::default() } + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 0, ..Default::default() } }); new_test_ext(1).execute_with(|| { // Make sure `on_runtime_upgrade` is called. - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = - sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } }); >>::execute_block(Block::new(header, vec![xt])); @@ -1615,9 +1611,8 @@ mod tests { fn all_weights_are_recorded_correctly() { new_test_ext(1).execute_with(|| { // Make sure `on_runtime_upgrade` is called for maximum complexity - RUNTIME_VERSION.with(|v| { - *v.borrow_mut() = - sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } + RuntimeVersionTestValues::mutate(|v| { + *v = sp_version::RuntimeVersion { spec_version: 1, ..Default::default() } }); let block_number = 1; @@ -1669,7 +1664,7 @@ mod tests { #[test] fn calculating_storage_root_twice_works() { - let call = Call::Custom(custom::Call::calculate_storage_root {}); + let call = RuntimeCall::Custom(custom::Call::calculate_storage_root {}); let xt = TestXt::new(call, sign_extra(1, 0, 0)); let header = new_test_ext(1).execute_with(|| { @@ -1696,10 +1691,10 @@ mod tests { // System::enqueue_txs needs to be executed after extrinsics fn invalid_inherent_position_fail() { let xt1 = TestXt::new( - Call::Balances(BalancesCall::transfer { dest: 33, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 33, value: 0 }), sign_extra(1, 0, 0), ); - let xt2 = TestXt::new(Call::Custom(custom::Call::inherent_call {}), None); + let xt2 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), None); let header = new_test_ext(1).execute_with(|| { // Let's build some fake block. @@ -1724,7 +1719,7 @@ mod tests { #[test] fn valid_inherents_position_works() { - let xt1 = TestXt::new(Call::Custom(custom::Call::inherent_call {}), None); + let xt1 = TestXt::new(RuntimeCall::Custom(custom::Call::inherent_call {}), None); let xt2 = TestXt::new(call_transfer(33, 0), sign_extra(1, 0, 0)); let header = new_test_ext(1).execute_with(|| { @@ -1837,7 +1832,7 @@ mod tests { parent_hash: [69u8; 32].into(), number: 1, state_root: hex!( - "3ed46f3dc020e22a8b44e83b26e74a24c18abb237d9a0a11866dca91679a390c" + "c1a5373581a3142b5107428aae1fd4e43259287c84db11f67a6525656c65f70c" ) .into(), extrinsics_root: hex!( @@ -1895,7 +1890,7 @@ mod tests { parent_hash: System::parent_hash(), number: 1, state_root: hex!( - "fe2d25a1c581d3687aedf829d9501ced883e3d707df29edfc204840c9cf48f98" + "c6bbd33a1161f1b0d719594304a81c6cc97a183a64a09e1903cb58ed6e247148" ) .into(), extrinsics_root: hex!( @@ -1922,7 +1917,7 @@ mod tests { parent_hash: System::parent_hash(), number: 2, state_root: hex!( - "5daf0be3b765fd9ec95744d9702057072694d604e202cc6513b030aabc45e709" + "30078f391818adda0ccfbbfb39abe63ed367041077a4d6c16187c5f412281aa7" ) .into(), extrinsics_root: hex!( @@ -1984,7 +1979,7 @@ mod tests { parent_hash: System::parent_hash(), number: 1, state_root: hex!( - "13051d7e53ff634b944d2f69ddec9bae20a27a4aa38d3b9d3dd07cb6a8bd8562" + "347bf9906542825357b29ff5a31d6ef55fe25365cc46a105b2eec18e7d942c39" ) .into(), extrinsics_root: hex!( @@ -2046,7 +2041,7 @@ mod tests { parent_hash: System::parent_hash(), number: 1, state_root: hex!( - "13051d7e53ff634b944d2f69ddec9bae20a27a4aa38d3b9d3dd07cb6a8bd8562" + "347bf9906542825357b29ff5a31d6ef55fe25365cc46a105b2eec18e7d942c39" ) .into(), extrinsics_root: hex!( @@ -2185,7 +2180,7 @@ mod tests { parent_hash: System::parent_hash(), number: 1, state_root: hex!( - "fe2d25a1c581d3687aedf829d9501ced883e3d707df29edfc204840c9cf48f98" + "c6bbd33a1161f1b0d719594304a81c6cc97a183a64a09e1903cb58ed6e247148" ) .into(), extrinsics_root: hex!( @@ -2218,7 +2213,7 @@ mod tests { parent_hash: System::parent_hash(), number: 2, state_root: hex!( - "4ab6e8a20156dd052a820850664e5cee199a89dad7729d3d0fd0fd44648a96d7" + "cecc44cf1dbd96b64fc7817d3e421c0ef623ae3d49a872d9bca67b635455c0e8" ) .into(), extrinsics_root: hex!( @@ -2283,7 +2278,7 @@ mod tests { parent_hash: System::parent_hash(), number: 1, state_root: hex!( - "926530bbf299279ba239dd0d4e231c8877f0ec6915ef5e12537d852e3b086aa2" + "1f1e089a56d87fd7d636593b3716d27be16cf596c5842ce364679127fdcc7315" ) .into(), extrinsics_root: hex!( @@ -2311,7 +2306,7 @@ mod tests { parent_hash: System::parent_hash(), number: 2, state_root: hex!( - "731cbafcc8ed9d71d196ded36aca9fbdcaef925945d36de12f410a83e831a96b" + "a82520d8f5343f23813ef7de98efb35cfba8a5d9e5a6010aff93e607de61d588" ) .into(), extrinsics_root: hex!( @@ -2374,7 +2369,7 @@ mod tests { parent_hash: System::parent_hash(), number: 1, state_root: hex!( - "fe2d25a1c581d3687aedf829d9501ced883e3d707df29edfc204840c9cf48f98" + "c6bbd33a1161f1b0d719594304a81c6cc97a183a64a09e1903cb58ed6e247148" ) .into(), extrinsics_root: hex!( @@ -2433,7 +2428,7 @@ mod tests { parent_hash: System::parent_hash(), number: 1, state_root: hex!( - "fe2d25a1c581d3687aedf829d9501ced883e3d707df29edfc204840c9cf48f98" + "c6bbd33a1161f1b0d719594304a81c6cc97a183a64a09e1903cb58ed6e247148" ) .into(), extrinsics_root: hex!( diff --git a/frame/fast-unstake/Cargo.toml b/frame/fast-unstake/Cargo.toml new file mode 100644 index 0000000000000..69aeaff35993c --- /dev/null +++ b/frame/fast-unstake/Cargo.toml @@ -0,0 +1,68 @@ +[package] +name = "pallet-fast-unstake" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Unlicense" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME fast unstake pallet" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +log = { version = "0.4.17", default-features = false } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } + +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } + +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +sp-staking = { default-features = false, path = "../../primitives/staking" } + +pallet-balances = { default-features = false, path = "../balances" } +pallet-timestamp = { default-features = false, path = "../timestamp" } +pallet-staking = { default-features = false, path = "../staking" } +frame-election-provider-support = { default-features = false, path = "../election-provider-support" } + +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } + +[dev-dependencies] +pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } +sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } +substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } +sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } + +[features] +default = ["std"] +std = [ + "codec/std", + "log/std", + "scale-info/std", + + "frame-support/std", + "frame-system/std", + + "sp-io/std", + "sp-staking/std", + "sp-runtime/std", + "sp-std/std", + + "pallet-staking/std", + "pallet-balances/std", + "pallet-timestamp/std", + "frame-election-provider-support/std", + + "frame-benchmarking/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-staking/runtime-benchmarks", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/frame/fast-unstake/src/benchmarking.rs b/frame/fast-unstake/src/benchmarking.rs new file mode 100644 index 0000000000000..8770cc6b64c0d --- /dev/null +++ b/frame/fast-unstake/src/benchmarking.rs @@ -0,0 +1,206 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Benchmarking for pallet-fast-unstake. + +#![cfg(feature = "runtime-benchmarks")] + +use crate::{types::*, Pallet as FastUnstake, *}; +use frame_benchmarking::{benchmarks, whitelist_account}; +use frame_support::{ + assert_ok, + traits::{Currency, EnsureOrigin, Get, Hooks}, +}; +use frame_system::RawOrigin; +use pallet_staking::Pallet as Staking; +use sp_runtime::traits::{StaticLookup, Zero}; +use sp_staking::EraIndex; +use sp_std::prelude::*; + +const USER_SEED: u32 = 0; +const DEFAULT_BACKER_PER_VALIDATOR: u32 = 128; +const MAX_VALIDATORS: u32 = 128; + +type CurrencyOf = ::Currency; + +fn l( + who: T::AccountId, +) -> <::Lookup as StaticLookup>::Source { + T::Lookup::unlookup(who) +} + +fn create_unexposed_nominator() -> T::AccountId { + let account = frame_benchmarking::account::("nominator_42", 0, USER_SEED); + fund_and_bond_account::(&account); + account +} + +fn fund_and_bond_account(account: &T::AccountId) { + let stake = CurrencyOf::::minimum_balance() * 100u32.into(); + CurrencyOf::::make_free_balance_be(&account, stake * 10u32.into()); + + let account_lookup = l::(account.clone()); + // bond and nominate ourselves, this will guarantee that we are not backing anyone. + assert_ok!(Staking::::bond( + RawOrigin::Signed(account.clone()).into(), + account_lookup.clone(), + stake, + pallet_staking::RewardDestination::Controller, + )); + assert_ok!(Staking::::nominate( + RawOrigin::Signed(account.clone()).into(), + vec![account_lookup] + )); +} + +pub(crate) fn fast_unstake_events() -> Vec> { + frame_system::Pallet::::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| ::RuntimeEvent::from(e).try_into().ok()) + .collect::>() +} + +fn setup_staking(v: u32, until: EraIndex) { + let ed = CurrencyOf::::minimum_balance(); + + log!(debug, "registering {} validators and {} eras.", v, until); + + // our validators don't actually need to registered in staking -- just generate `v` random + // accounts. + let validators = (0..v) + .map(|x| frame_benchmarking::account::("validator", x, USER_SEED)) + .collect::>(); + + for era in 0..=until { + let others = (0..DEFAULT_BACKER_PER_VALIDATOR) + .map(|s| { + let who = frame_benchmarking::account::("nominator", era, s); + let value = ed; + pallet_staking::IndividualExposure { who, value } + }) + .collect::>(); + let exposure = + pallet_staking::Exposure { total: Default::default(), own: Default::default(), others }; + validators.iter().for_each(|v| { + Staking::::add_era_stakers(era, v.clone(), exposure.clone()); + }); + } +} + +fn on_idle_full_block() { + let remaining_weight = ::BlockWeights::get().max_block; + FastUnstake::::on_idle(Zero::zero(), remaining_weight); +} + +benchmarks! { + // on_idle, we we don't check anyone, but fully unbond and move them to another pool. + on_idle_unstake { + ErasToCheckPerBlock::::put(1); + let who = create_unexposed_nominator::(); + assert_ok!(FastUnstake::::register_fast_unstake( + RawOrigin::Signed(who.clone()).into(), + )); + + // run on_idle once. This will check era 0. + assert_eq!(Head::::get(), None); + on_idle_full_block::(); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { stash: who.clone(), checked: vec![0].try_into().unwrap(), deposit: T::Deposit::get() }) + ); + } + : { + on_idle_full_block::(); + } + verify { + assert!(matches!( + fast_unstake_events::().last(), + Some(Event::Unstaked { .. }) + )); + } + + // on_idle, when we check some number of eras, + on_idle_check { + // number of eras multiplied by validators in that era. + let x in (::BondingDuration::get() * 1) .. (::BondingDuration::get() * MAX_VALIDATORS); + + let v = x / ::BondingDuration::get(); + let u = ::BondingDuration::get(); + + ErasToCheckPerBlock::::put(u); + pallet_staking::CurrentEra::::put(u); + + // setup staking with v validators and u eras of data (0..=u) + setup_staking::(v, u); + let who = create_unexposed_nominator::(); + assert_ok!(FastUnstake::::register_fast_unstake( + RawOrigin::Signed(who.clone()).into(), + )); + + // no one is queued thus far. + assert_eq!(Head::::get(), None); + } + : { + on_idle_full_block::(); + } + verify { + let checked: frame_support::BoundedVec<_, _> = (1..=u).rev().collect::>().try_into().unwrap(); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { stash: who.clone(), checked, deposit: T::Deposit::get() }) + ); + assert!(matches!( + fast_unstake_events::().last(), + Some(Event::Checking { .. }) + )); + } + + register_fast_unstake { + ErasToCheckPerBlock::::put(1); + let who = create_unexposed_nominator::(); + whitelist_account!(who); + assert_eq!(Queue::::count(), 0); + + } + :_(RawOrigin::Signed(who.clone())) + verify { + assert_eq!(Queue::::count(), 1); + } + + deregister { + ErasToCheckPerBlock::::put(1); + let who = create_unexposed_nominator::(); + assert_ok!(FastUnstake::::register_fast_unstake( + RawOrigin::Signed(who.clone()).into(), + )); + assert_eq!(Queue::::count(), 1); + whitelist_account!(who); + } + :_(RawOrigin::Signed(who.clone())) + verify { + assert_eq!(Queue::::count(), 0); + } + + control { + let origin = ::ControlOrigin::successful_origin(); + } + : _(origin, 128) + verify {} + + impl_benchmark_test_suite!(Pallet, crate::mock::ExtBuilder::default().build(), crate::mock::Runtime) +} diff --git a/frame/fast-unstake/src/lib.rs b/frame/fast-unstake/src/lib.rs new file mode 100644 index 0000000000000..8fdb7a79dd537 --- /dev/null +++ b/frame/fast-unstake/src/lib.rs @@ -0,0 +1,483 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! A pallet that's designed to JUST do the following: +//! +//! If a nominator is not exposed in any `ErasStakers` (i.e. "has not actively backed any +//! validators in the last `BondingDuration` days"), then they can register themselves in this +//! pallet, unstake faster than having to wait an entire bonding duration. +//! +//! Appearing in the exposure of a validator means being exposed equal to that validator from the +//! point of view of the staking system. This usually means earning rewards with the validator, and +//! also being at the risk of slashing with the validator. This is equivalent to the "Active +//! Nominator" role explained in the +//! [February Staking Update](https://polkadot.network/blog/staking-update-february-2022/). +//! +//! This pallet works off the basis of `on_idle`, meaning that it provides no guarantee about when +//! it will succeed, if at all. Moreover, the queue implementation is unordered. In case of +//! congestion, no FIFO ordering is provided. +//! +//! Stakers who are certain about NOT being exposed can register themselves with +//! [`Call::register_fast_unstake`]. This will chill, and fully unbond the staker, and place them in +//! the queue to be checked. +//! +//! Once queued, but not being actively processed, stakers can withdraw their request via +//! [`Call::deregister`]. +//! +//! Once queued, a staker wishing to unbond can perform no further action in pallet-staking. This is +//! to prevent them from accidentally exposing themselves behind a validator etc. +//! +//! Once processed, if successful, no additional fee for the checking process is taken, and the +//! staker is instantly unbonded. +//! +//! If unsuccessful, meaning that the staker was exposed sometime in the last `BondingDuration` eras +//! they will end up being slashed for the amount of wasted work they have inflicted on the chian. + +#![cfg_attr(not(feature = "std"), no_std)] + +pub use pallet::*; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +// NOTE: enable benchmarking in tests as well. +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +pub mod types; +pub mod weights; + +pub const LOG_TARGET: &'static str = "runtime::fast-unstake"; + +// syntactic sugar for logging. +#[macro_export] +macro_rules! log { + ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { + log::$level!( + target: crate::LOG_TARGET, + concat!("[{:?}] 💨 ", $patter), >::block_number() $(, $values)* + ) + }; +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use crate::types::*; + use frame_election_provider_support::ElectionProviderBase; + use frame_support::{ + pallet_prelude::*, + traits::{Defensive, ReservableCurrency}, + }; + use frame_system::{pallet_prelude::*, RawOrigin}; + use pallet_staking::Pallet as Staking; + use sp_runtime::{ + traits::{Saturating, Zero}, + DispatchResult, + }; + use sp_staking::EraIndex; + use sp_std::{prelude::*, vec::Vec}; + pub use weights::WeightInfo; + + #[derive(scale_info::TypeInfo, codec::Encode, codec::Decode, codec::MaxEncodedLen)] + #[codec(mel_bound(T: Config))] + #[scale_info(skip_type_params(T))] + pub struct MaxChecking(sp_std::marker::PhantomData); + impl frame_support::traits::Get for MaxChecking { + fn get() -> u32 { + ::BondingDuration::get() + 1 + } + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + pallet_staking::Config { + /// The overarching event type. + type RuntimeEvent: From> + + IsType<::RuntimeEvent> + + TryInto>; + + /// The currency used for deposits. + type DepositCurrency: ReservableCurrency>; + + /// Deposit to take for unstaking, to make sure we're able to slash the it in order to cover + /// the costs of resources on unsuccessful unstake. + type Deposit: Get>; + + /// The origin that can control this pallet. + type ControlOrigin: frame_support::traits::EnsureOrigin; + + /// The weight information of this pallet. + type WeightInfo: WeightInfo; + } + + /// The current "head of the queue" being unstaked. + #[pallet::storage] + pub type Head = + StorageValue<_, UnstakeRequest, BalanceOf>, OptionQuery>; + + /// The map of all accounts wishing to be unstaked. + /// + /// Keeps track of `AccountId` wishing to unstake and it's corresponding deposit. + #[pallet::storage] + pub type Queue = CountedStorageMap<_, Twox64Concat, T::AccountId, BalanceOf>; + + /// Number of eras to check per block. + /// + /// If set to 0, this pallet does absolutely nothing. + /// + /// Based on the amount of weight available at `on_idle`, up to this many eras of a single + /// nominator might be checked. + #[pallet::storage] + pub type ErasToCheckPerBlock = StorageValue<_, u32, ValueQuery>; + + /// The events of this pallet. + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A staker was unstaked. + Unstaked { stash: T::AccountId, result: DispatchResult }, + /// A staker was slashed for requesting fast-unstake whilst being exposed. + Slashed { stash: T::AccountId, amount: BalanceOf }, + /// A staker was partially checked for the given eras, but the process did not finish. + Checking { stash: T::AccountId, eras: Vec }, + /// Some internal error happened while migrating stash. They are removed as head as a + /// consequence. + Errored { stash: T::AccountId }, + /// An internal error happened. Operations will be paused now. + InternalError, + } + + #[pallet::error] + #[cfg_attr(test, derive(PartialEq))] + pub enum Error { + /// The provided Controller account was not found. + /// + /// This means that the given account is not bonded. + NotController, + /// The bonded account has already been queued. + AlreadyQueued, + /// The bonded account has active unlocking chunks. + NotFullyBonded, + /// The provided un-staker is not in the `Queue`. + NotQueued, + /// The provided un-staker is already in Head, and cannot deregister. + AlreadyHead, + /// The call is not allowed at this point because the pallet is not active. + CallNotAllowed, + } + + #[pallet::hooks] + impl Hooks for Pallet { + fn on_idle(_: T::BlockNumber, remaining_weight: Weight) -> Weight { + if remaining_weight.any_lt(T::DbWeight::get().reads(2)) { + return Weight::from_ref_time(0) + } + + Self::do_on_idle(remaining_weight) + } + } + + #[pallet::call] + impl Pallet { + /// Register oneself for fast-unstake. + /// + /// The dispatch origin of this call must be signed by the controller account, similar to + /// `staking::unbond`. + /// + /// The stash associated with the origin must have no ongoing unlocking chunks. If + /// successful, this will fully unbond and chill the stash. Then, it will enqueue the stash + /// to be checked in further blocks. + /// + /// If by the time this is called, the stash is actually eligible for fast-unstake, then + /// they are guaranteed to remain eligible, because the call will chill them as well. + /// + /// If the check works, the entire staking data is removed, i.e. the stash is fully + /// unstaked. + /// + /// If the check fails, the stash remains chilled and waiting for being unbonded as in with + /// the normal staking system, but they lose part of their unbonding chunks due to consuming + /// the chain's resources. + #[pallet::weight(::WeightInfo::register_fast_unstake())] + pub fn register_fast_unstake(origin: OriginFor) -> DispatchResult { + let ctrl = ensure_signed(origin)?; + + ensure!(ErasToCheckPerBlock::::get() != 0, >::CallNotAllowed); + + let ledger = + pallet_staking::Ledger::::get(&ctrl).ok_or(Error::::NotController)?; + ensure!(!Queue::::contains_key(&ledger.stash), Error::::AlreadyQueued); + ensure!( + Head::::get().map_or(true, |UnstakeRequest { stash, .. }| stash != ledger.stash), + Error::::AlreadyHead + ); + // second part of the && is defensive. + ensure!( + ledger.active == ledger.total && ledger.unlocking.is_empty(), + Error::::NotFullyBonded + ); + + // chill and fully unstake. + Staking::::chill(RawOrigin::Signed(ctrl.clone()).into())?; + Staking::::unbond(RawOrigin::Signed(ctrl).into(), ledger.total)?; + + T::DepositCurrency::reserve(&ledger.stash, T::Deposit::get())?; + + // enqueue them. + Queue::::insert(ledger.stash, T::Deposit::get()); + Ok(()) + } + + /// Deregister oneself from the fast-unstake. + /// + /// This is useful if one is registered, they are still waiting, and they change their mind. + /// + /// Note that the associated stash is still fully unbonded and chilled as a consequence of + /// calling `register_fast_unstake`. This should probably be followed by a call to + /// `Staking::rebond`. + #[pallet::weight(::WeightInfo::deregister())] + pub fn deregister(origin: OriginFor) -> DispatchResult { + let ctrl = ensure_signed(origin)?; + + ensure!(ErasToCheckPerBlock::::get() != 0, >::CallNotAllowed); + + let stash = pallet_staking::Ledger::::get(&ctrl) + .map(|l| l.stash) + .ok_or(Error::::NotController)?; + ensure!(Queue::::contains_key(&stash), Error::::NotQueued); + ensure!( + Head::::get().map_or(true, |UnstakeRequest { stash, .. }| stash != stash), + Error::::AlreadyHead + ); + let deposit = Queue::::take(stash.clone()); + + if let Some(deposit) = deposit.defensive() { + let remaining = T::DepositCurrency::unreserve(&stash, deposit); + if !remaining.is_zero() { + frame_support::defensive!("`not enough balance to unreserve`"); + ErasToCheckPerBlock::::put(0); + Self::deposit_event(Event::::InternalError) + } + } + + Ok(()) + } + + /// Control the operation of this pallet. + /// + /// Dispatch origin must be signed by the [`Config::ControlOrigin`]. + #[pallet::weight(::WeightInfo::control())] + pub fn control(origin: OriginFor, unchecked_eras_to_check: EraIndex) -> DispatchResult { + let _ = T::ControlOrigin::ensure_origin(origin)?; + ErasToCheckPerBlock::::put(unchecked_eras_to_check); + Ok(()) + } + } + + impl Pallet { + /// process up to `remaining_weight`. + /// + /// Returns the actual weight consumed. + /// + /// Written for readability in mind, not efficiency. For example: + /// + /// 1. We assume this is only ever called once per `on_idle`. This is because we know that + /// in all use cases, even a single nominator cannot be unbonded in a single call. Multiple + /// calls to this function are thus not needed. + /// + /// 2. We will only mark a staker as unstaked if at the beginning of a check cycle, they are + /// found out to have no eras to check. At the end of a check cycle, even if they are fully + /// checked, we don't finish the process. + pub(crate) fn do_on_idle(remaining_weight: Weight) -> Weight { + let mut eras_to_check_per_block = ErasToCheckPerBlock::::get(); + if eras_to_check_per_block.is_zero() { + return T::DbWeight::get().reads(1) + } + + // NOTE: here we're assuming that the number of validators has only ever increased, + // meaning that the number of exposures to check is either this per era, or less. + let validator_count = pallet_staking::ValidatorCount::::get(); + + // determine the number of eras to check. This is based on both `ErasToCheckPerBlock` + // and `remaining_weight` passed on to us from the runtime executive. + let max_weight = |v, u| { + ::WeightInfo::on_idle_check(v * u) + .max(::WeightInfo::on_idle_unstake()) + }; + while max_weight(validator_count, eras_to_check_per_block).any_gt(remaining_weight) { + eras_to_check_per_block.saturating_dec(); + if eras_to_check_per_block.is_zero() { + log!(debug, "early existing because eras_to_check_per_block is zero"); + return T::DbWeight::get().reads(2) + } + } + + if <::ElectionProvider as ElectionProviderBase>::ongoing() + { + // NOTE: we assume `ongoing` does not consume any weight. + // there is an ongoing election -- we better not do anything. Imagine someone is not + // exposed anywhere in the last era, and the snapshot for the election is already + // taken. In this time period, we don't want to accidentally unstake them. + return T::DbWeight::get().reads(2) + } + + let UnstakeRequest { stash, mut checked, deposit } = + match Head::::take().or_else(|| { + // NOTE: there is no order guarantees in `Queue`. + Queue::::drain() + .map(|(stash, deposit)| UnstakeRequest { + stash, + deposit, + checked: Default::default(), + }) + .next() + }) { + None => { + // There's no `Head` and nothing in the `Queue`, nothing to do here. + return T::DbWeight::get().reads(4) + }, + Some(head) => head, + }; + + log!( + debug, + "checking {:?}, eras_to_check_per_block = {:?}, remaining_weight = {:?}", + stash, + eras_to_check_per_block, + remaining_weight + ); + + // the range that we're allowed to check in this round. + let current_era = pallet_staking::CurrentEra::::get().unwrap_or_default(); + let bonding_duration = ::BondingDuration::get(); + // prune all the old eras that we don't care about. This will help us keep the bound + // of `checked`. + checked.retain(|e| *e >= current_era.saturating_sub(bonding_duration)); + let unchecked_eras_to_check = { + // get the last available `bonding_duration` eras up to current era in reverse + // order. + let total_check_range = (current_era.saturating_sub(bonding_duration)..= + current_era) + .rev() + .collect::>(); + debug_assert!( + total_check_range.len() <= (bonding_duration + 1) as usize, + "{:?}", + total_check_range + ); + + // remove eras that have already been checked, take a maximum of + // eras_to_check_per_block. + total_check_range + .into_iter() + .filter(|e| !checked.contains(e)) + .take(eras_to_check_per_block as usize) + .collect::>() + }; + + log!( + debug, + "{} eras to check: {:?}", + unchecked_eras_to_check.len(), + unchecked_eras_to_check + ); + + if unchecked_eras_to_check.is_empty() { + // `stash` is not exposed in any era now -- we can let go of them now. + let num_slashing_spans = Staking::::slashing_spans(&stash).iter().count() as u32; + + let result = pallet_staking::Pallet::::force_unstake( + RawOrigin::Root.into(), + stash.clone(), + num_slashing_spans, + ); + + let remaining = T::DepositCurrency::unreserve(&stash, deposit); + if !remaining.is_zero() { + frame_support::defensive!("`not enough balance to unreserve`"); + ErasToCheckPerBlock::::put(0); + Self::deposit_event(Event::::InternalError) + } else { + log!(info, "unstaked {:?}, outcome: {:?}", stash, result); + Self::deposit_event(Event::::Unstaked { stash, result }); + } + + ::WeightInfo::on_idle_unstake() + } else { + // eras remaining to be checked. + let mut eras_checked = 0u32; + let is_exposed = unchecked_eras_to_check.iter().any(|e| { + eras_checked.saturating_inc(); + Self::is_exposed_in_era(&stash, e) + }); + + log!( + debug, + "checked {:?} eras, exposed? {}, (v: {:?}, u: {:?})", + eras_checked, + is_exposed, + validator_count, + unchecked_eras_to_check.len() + ); + + // NOTE: you can be extremely unlucky and get slashed here: You are not exposed in + // the last 28 eras, have registered yourself to be unstaked, midway being checked, + // you are exposed. + if is_exposed { + T::DepositCurrency::slash_reserved(&stash, deposit); + log!(info, "slashed {:?} by {:?}", stash, deposit); + Self::deposit_event(Event::::Slashed { stash, amount: deposit }); + } else { + // Not exposed in these eras. + match checked.try_extend(unchecked_eras_to_check.clone().into_iter()) { + Ok(_) => { + Head::::put(UnstakeRequest { + stash: stash.clone(), + checked, + deposit, + }); + Self::deposit_event(Event::::Checking { + stash, + eras: unchecked_eras_to_check, + }); + }, + Err(_) => { + // don't put the head back in -- there is an internal error in the + // pallet. + frame_support::defensive!("`checked is pruned via retain above`"); + ErasToCheckPerBlock::::put(0); + Self::deposit_event(Event::::InternalError); + }, + } + } + + ::WeightInfo::on_idle_check(validator_count * eras_checked) + } + } + + /// Checks whether an account `staker` has been exposed in an era. + fn is_exposed_in_era(staker: &T::AccountId, era: &EraIndex) -> bool { + pallet_staking::ErasStakers::::iter_prefix(era).any(|(validator, exposures)| { + validator == *staker || exposures.others.iter().any(|i| i.who == *staker) + }) + } + } +} diff --git a/frame/fast-unstake/src/mock.rs b/frame/fast-unstake/src/mock.rs new file mode 100644 index 0000000000000..71fc2d4ba905a --- /dev/null +++ b/frame/fast-unstake/src/mock.rs @@ -0,0 +1,348 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::{self as fast_unstake}; +use frame_support::{ + pallet_prelude::*, parameter_types, traits::ConstU64, weights::constants::WEIGHT_PER_SECOND, +}; +use sp_runtime::traits::{Convert, IdentityLookup}; + +use pallet_staking::{Exposure, IndividualExposure, StakerStatus}; +use sp_std::prelude::*; + +pub type AccountId = u128; +pub type AccountIndex = u32; +pub type BlockNumber = u64; +pub type Balance = u128; +pub type T = Runtime; + +parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max( + (2u64 * WEIGHT_PER_SECOND).set_proof_size(u64::MAX), + ); +} + +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = BlockWeights; + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = AccountIndex; + type BlockNumber = BlockNumber; + type RuntimeCall = RuntimeCall; + type Hash = sp_core::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = sp_runtime::testing::Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<5>; + type WeightInfo = (); +} + +parameter_types! { + pub static ExistentialDeposit: Balance = 1; +} + +impl pallet_balances::Config for Runtime { + type MaxLocks = ConstU32<128>; + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); +} + +pallet_staking_reward_curve::build! { + const I_NPOS: sp_runtime::curve::PiecewiseLinear<'static> = curve!( + min_inflation: 0_025_000, + max_inflation: 0_100_000, + ideal_stake: 0_500_000, + falloff: 0_050_000, + max_piece_count: 40, + test_precision: 0_005_000, + ); +} + +parameter_types! { + pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; + pub static BondingDuration: u32 = 3; + pub static CurrentEra: u32 = 0; + pub static Ongoing: bool = false; +} + +pub struct MockElection; +impl frame_election_provider_support::ElectionProviderBase for MockElection { + type AccountId = AccountId; + type BlockNumber = BlockNumber; + type DataProvider = Staking; + type Error = (); + + fn ongoing() -> bool { + Ongoing::get() + } +} + +impl frame_election_provider_support::ElectionProvider for MockElection { + fn elect() -> Result, Self::Error> { + Err(()) + } +} + +impl pallet_staking::Config for Runtime { + type MaxNominations = ConstU32<16>; + type Currency = Balances; + type CurrencyBalance = Balance; + type UnixTime = pallet_timestamp::Pallet; + type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; + type RewardRemainder = (); + type RuntimeEvent = RuntimeEvent; + type Slash = (); + type Reward = (); + type SessionsPerEra = (); + type SlashDeferDuration = (); + type SlashCancelOrigin = frame_system::EnsureRoot; + type BondingDuration = BondingDuration; + type SessionInterface = (); + type EraPayout = pallet_staking::ConvertCurve; + type NextNewSession = (); + type HistoryDepth = ConstU32<84>; + type MaxNominatorRewardedPerValidator = ConstU32<64>; + type OffendingValidatorsThreshold = (); + type ElectionProvider = MockElection; + type GenesisElectionProvider = Self::ElectionProvider; + type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; + type TargetList = pallet_staking::UseValidatorsMap; + type MaxUnlockingChunks = ConstU32<32>; + type OnStakerSlash = (); + type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; + type WeightInfo = (); +} + +pub struct BalanceToU256; +impl Convert for BalanceToU256 { + fn convert(n: Balance) -> sp_core::U256 { + n.into() + } +} + +pub struct U256ToBalance; +impl Convert for U256ToBalance { + fn convert(n: sp_core::U256) -> Balance { + n.try_into().unwrap() + } +} + +parameter_types! { + pub static DepositAmount: u128 = 7; +} + +impl fast_unstake::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Deposit = DepositAmount; + type DepositCurrency = Balances; + type ControlOrigin = frame_system::EnsureRoot; + type WeightInfo = (); +} + +type Block = frame_system::mocking::MockBlock; +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +frame_support::construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: frame_system, + Timestamp: pallet_timestamp, + Balances: pallet_balances, + Staking: pallet_staking, + FastUnstake: fast_unstake, + } +); + +parameter_types! { + static FastUnstakeEvents: u32 = 0; +} + +pub(crate) fn fast_unstake_events_since_last_call() -> Vec> { + let events = System::events() + .into_iter() + .map(|r| r.event) + .filter_map(|e| if let RuntimeEvent::FastUnstake(inner) = e { Some(inner) } else { None }) + .collect::>(); + let already_seen = FastUnstakeEvents::get(); + FastUnstakeEvents::set(events.len() as u32); + events.into_iter().skip(already_seen as usize).collect() +} + +pub struct ExtBuilder { + exposed_nominators: Vec<(AccountId, AccountId, Balance)>, +} + +impl Default for ExtBuilder { + fn default() -> Self { + Self { + exposed_nominators: vec![ + (1, 2, 7 + 100), + (3, 4, 7 + 100), + (5, 6, 7 + 100), + (7, 8, 7 + 100), + (9, 10, 7 + 100), + ], + } + } +} + +pub(crate) const VALIDATORS_PER_ERA: AccountId = 32; +pub(crate) const VALIDATOR_PREFIX: AccountId = 100; +pub(crate) const NOMINATORS_PER_VALIDATOR_PER_ERA: AccountId = 4; +pub(crate) const NOMINATOR_PREFIX: AccountId = 1000; + +impl ExtBuilder { + pub(crate) fn register_stakers_for_era(era: u32) { + // validators are prefixed with 100 and nominators with 1000 to prevent conflict. Make sure + // all the other accounts used in tests are below 100. Also ensure here that we don't + // overlap. + assert!(VALIDATOR_PREFIX + VALIDATORS_PER_ERA < NOMINATOR_PREFIX); + + (VALIDATOR_PREFIX..VALIDATOR_PREFIX + VALIDATORS_PER_ERA) + .map(|v| { + // for the sake of sanity, let's register this taker as an actual validator. + let others = (NOMINATOR_PREFIX.. + (NOMINATOR_PREFIX + NOMINATORS_PER_VALIDATOR_PER_ERA)) + .map(|n| IndividualExposure { who: n, value: 0 as Balance }) + .collect::>(); + (v, Exposure { total: 0, own: 0, others }) + }) + .for_each(|(validator, exposure)| { + pallet_staking::ErasStakers::::insert(era, validator, exposure); + }); + } + + pub(crate) fn build(self) -> sp_io::TestExternalities { + sp_tracing::try_init_simple(); + let mut storage = + frame_system::GenesisConfig::default().build_storage::().unwrap(); + + let validators_range = VALIDATOR_PREFIX..VALIDATOR_PREFIX + VALIDATORS_PER_ERA; + let nominators_range = + NOMINATOR_PREFIX..NOMINATOR_PREFIX + NOMINATORS_PER_VALIDATOR_PER_ERA; + + let _ = pallet_balances::GenesisConfig:: { + balances: self + .exposed_nominators + .clone() + .into_iter() + .map(|(stash, _, balance)| (stash, balance * 2)) + .chain( + self.exposed_nominators + .clone() + .into_iter() + .map(|(_, ctrl, balance)| (ctrl, balance * 2)), + ) + .chain(validators_range.clone().map(|x| (x, 7 + 100))) + .chain(nominators_range.clone().map(|x| (x, 7 + 100))) + .collect::>(), + } + .assimilate_storage(&mut storage); + + let _ = pallet_staking::GenesisConfig:: { + stakers: self + .exposed_nominators + .into_iter() + .map(|(x, y, z)| (x, y, z, pallet_staking::StakerStatus::Nominator(vec![42]))) + .chain(validators_range.map(|x| (x, x, 100, StakerStatus::Validator))) + .chain(nominators_range.map(|x| (x, x, 100, StakerStatus::Nominator(vec![x])))) + .collect::>(), + ..Default::default() + } + .assimilate_storage(&mut storage); + + let mut ext = sp_io::TestExternalities::from(storage); + + ext.execute_with(|| { + // for events to be deposited. + frame_system::Pallet::::set_block_number(1); + + for era in 0..=(BondingDuration::get()) { + Self::register_stakers_for_era(era); + } + + // because we read this value as a measure of how many validators we have. + pallet_staking::ValidatorCount::::put(VALIDATORS_PER_ERA as u32); + }); + ext + } + + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + self.build().execute_with(|| { + test(); + }) + } +} + +pub(crate) fn run_to_block(n: u64, on_idle: bool) { + let current_block = System::block_number(); + assert!(n > current_block); + while System::block_number() < n { + Balances::on_finalize(System::block_number()); + Staking::on_finalize(System::block_number()); + FastUnstake::on_finalize(System::block_number()); + + System::set_block_number(System::block_number() + 1); + + Balances::on_initialize(System::block_number()); + Staking::on_initialize(System::block_number()); + FastUnstake::on_initialize(System::block_number()); + if on_idle { + FastUnstake::on_idle(System::block_number(), BlockWeights::get().max_block); + } + } +} + +pub(crate) fn next_block(on_idle: bool) { + let current = System::block_number(); + run_to_block(current + 1, on_idle); +} + +pub fn assert_unstaked(stash: &AccountId) { + assert!(!pallet_staking::Bonded::::contains_key(stash)); + assert!(!pallet_staking::Payee::::contains_key(stash)); + assert!(!pallet_staking::Validators::::contains_key(stash)); + assert!(!pallet_staking::Nominators::::contains_key(stash)); +} diff --git a/frame/fast-unstake/src/tests.rs b/frame/fast-unstake/src/tests.rs new file mode 100644 index 0000000000000..6e617fd992028 --- /dev/null +++ b/frame/fast-unstake/src/tests.rs @@ -0,0 +1,999 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests for pallet-fast-unstake. + +use super::*; +use crate::{mock::*, types::*, weights::WeightInfo, Event}; +use frame_support::{assert_noop, assert_ok, bounded_vec, pallet_prelude::*, traits::Currency}; +use pallet_staking::{CurrentEra, IndividualExposure, RewardDestination}; + +use sp_runtime::traits::BadOrigin; +use sp_staking::StakingInterface; + +#[test] +fn test_setup_works() { + ExtBuilder::default().build_and_execute(|| { + assert_eq!(Staking::bonding_duration(), 3); + }); +} + +#[test] +fn register_works() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); + // Controller account registers for fast unstake. + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + // Ensure stash is in the queue. + assert_ne!(Queue::::get(1), None); + }); +} + +#[test] +fn register_insufficient_funds_fails() { + use pallet_balances::Error as BalancesError; + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); + ::DepositCurrency::make_free_balance_be(&1, 3); + + // Controller account registers for fast unstake. + assert_noop!( + FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2)), + BalancesError::::InsufficientBalance, + ); + + // Ensure stash is in the queue. + assert_eq!(Queue::::get(1), None); + }); +} + +#[test] +fn register_disabled_fails() { + ExtBuilder::default().build_and_execute(|| { + assert_noop!( + FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2)), + Error::::CallNotAllowed + ); + }); +} + +#[test] +fn cannot_register_if_not_bonded() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); + // Mint accounts 1 and 2 with 200 tokens. + for _ in 1..2 { + let _ = Balances::make_free_balance_be(&1, 200); + } + // Attempt to fast unstake. + assert_noop!( + FastUnstake::register_fast_unstake(RuntimeOrigin::signed(1)), + Error::::NotController + ); + }); +} + +#[test] +fn cannot_register_if_in_queue() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); + // Insert some Queue item + Queue::::insert(1, 10); + // Cannot re-register, already in queue + assert_noop!( + FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2)), + Error::::AlreadyQueued + ); + }); +} + +#[test] +fn cannot_register_if_head() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); + // Insert some Head item for stash + Head::::put(UnstakeRequest { + stash: 1, + checked: bounded_vec![], + deposit: DepositAmount::get(), + }); + // Controller attempts to regsiter + assert_noop!( + FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2)), + Error::::AlreadyHead + ); + }); +} + +#[test] +fn cannot_register_if_has_unlocking_chunks() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); + // Start unbonding half of staked tokens + assert_ok!(Staking::unbond(RuntimeOrigin::signed(2), 50_u128)); + // Cannot register for fast unstake with unlock chunks active + assert_noop!( + FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2)), + Error::::NotFullyBonded + ); + }); +} + +#[test] +fn deregister_works() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); + + assert_eq!(::DepositCurrency::reserved_balance(&1), 0); + + // Controller account registers for fast unstake. + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_eq!(::DepositCurrency::reserved_balance(&1), DepositAmount::get()); + + // Controller then changes mind and deregisters. + assert_ok!(FastUnstake::deregister(RuntimeOrigin::signed(2))); + assert_eq!(::DepositCurrency::reserved_balance(&1), 0); + + // Ensure stash no longer exists in the queue. + assert_eq!(Queue::::get(1), None); + }); +} + +#[test] +fn deregister_disabled_fails() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + ErasToCheckPerBlock::::put(0); + assert_noop!(FastUnstake::deregister(RuntimeOrigin::signed(2)), Error::::CallNotAllowed); + }); +} + +#[test] +fn cannot_deregister_if_not_controller() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); + // Controller account registers for fast unstake. + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + // Stash tries to deregister. + assert_noop!(FastUnstake::deregister(RuntimeOrigin::signed(1)), Error::::NotController); + }); +} + +#[test] +fn cannot_deregister_if_not_queued() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); + // Controller tries to deregister without first registering + assert_noop!(FastUnstake::deregister(RuntimeOrigin::signed(2)), Error::::NotQueued); + }); +} + +#[test] +fn cannot_deregister_already_head() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); + // Controller attempts to register, should fail + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + // Insert some Head item for stash. + Head::::put(UnstakeRequest { + stash: 1, + checked: bounded_vec![], + deposit: DepositAmount::get(), + }); + // Controller attempts to deregister + assert_noop!(FastUnstake::deregister(RuntimeOrigin::signed(2)), Error::::AlreadyHead); + }); +} + +#[test] +fn control_works() { + ExtBuilder::default().build_and_execute(|| { + // account with control (root) origin wants to only check 1 era per block. + assert_ok!(FastUnstake::control(RuntimeOrigin::root(), 1_u32)); + }); +} + +#[test] +fn control_must_be_control_origin() { + ExtBuilder::default().build_and_execute(|| { + // account without control (root) origin wants to only check 1 era per block. + assert_noop!(FastUnstake::control(RuntimeOrigin::signed(1), 1_u32), BadOrigin); + }); +} + +mod on_idle { + use super::*; + + #[test] + fn early_exit() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + // set up Queue item + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_eq!(Queue::::get(1), Some(DepositAmount::get())); + + // call on_idle with no remaining weight + FastUnstake::on_idle(System::block_number(), Weight::from_ref_time(0)); + + // assert nothing changed in Queue and Head + assert_eq!(Head::::get(), None); + assert_eq!(Queue::::get(1), Some(DepositAmount::get())); + }); + } + + #[test] + fn respects_weight() { + ExtBuilder::default().build_and_execute(|| { + // we want to check all eras in one block... + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + // given + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_eq!(Queue::::get(1), Some(DepositAmount::get())); + + assert_eq!(Queue::::count(), 1); + assert_eq!(Head::::get(), None); + + // when: call fast unstake with not enough weight to process the whole thing, just one + // era. + let remaining_weight = ::WeightInfo::on_idle_check( + pallet_staking::ValidatorCount::::get() * 1, + ); + assert_eq!(FastUnstake::on_idle(0, remaining_weight), remaining_weight); + + // then + assert_eq!( + fast_unstake_events_since_last_call(), + vec![Event::Checking { stash: 1, eras: vec![3] }] + ); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3] + }) + ); + + // when: another 1 era. + let remaining_weight = ::WeightInfo::on_idle_check( + pallet_staking::ValidatorCount::::get() * 1, + ); + assert_eq!(FastUnstake::on_idle(0, remaining_weight), remaining_weight); + + // then: + assert_eq!( + fast_unstake_events_since_last_call(), + vec![Event::Checking { stash: 1, eras: bounded_vec![2] }] + ); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2] + }) + ); + + // when: then 5 eras, we only need 2 more. + let remaining_weight = ::WeightInfo::on_idle_check( + pallet_staking::ValidatorCount::::get() * 5, + ); + assert_eq!( + FastUnstake::on_idle(0, remaining_weight), + // note the amount of weight consumed: 2 eras worth of weight. + ::WeightInfo::on_idle_check( + pallet_staking::ValidatorCount::::get() * 2, + ) + ); + + // then: + assert_eq!( + fast_unstake_events_since_last_call(), + vec![Event::Checking { stash: 1, eras: vec![1, 0] }] + ); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1, 0] + }) + ); + + // when: not enough weight to unstake: + let remaining_weight = + ::WeightInfo::on_idle_unstake() - Weight::from_ref_time(1); + assert_eq!(FastUnstake::on_idle(0, remaining_weight), Weight::from_ref_time(0)); + + // then nothing happens: + assert_eq!(fast_unstake_events_since_last_call(), vec![]); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1, 0] + }) + ); + + // when: enough weight to get over at least one iteration: then we are unblocked and can + // unstake. + let remaining_weight = ::WeightInfo::on_idle_check( + pallet_staking::ValidatorCount::::get() * 1, + ); + assert_eq!( + FastUnstake::on_idle(0, remaining_weight), + ::WeightInfo::on_idle_unstake() + ); + + // then we finish the unbonding: + assert_eq!( + fast_unstake_events_since_last_call(), + vec![Event::Unstaked { stash: 1, result: Ok(()) }] + ); + assert_eq!(Head::::get(), None,); + + assert_unstaked(&1); + }); + } + + #[test] + fn if_head_not_set_one_random_fetched_from_queue() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + // given + assert_eq!(::DepositCurrency::reserved_balance(&1), 0); + + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(4))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(6))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(8))); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(10))); + + assert_eq!(::DepositCurrency::reserved_balance(&1), DepositAmount::get()); + + assert_eq!(Queue::::count(), 5); + assert_eq!(Head::::get(), None); + + // when + next_block(true); + + // then + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1, 0] + }) + ); + assert_eq!(Queue::::count(), 4); + + // when + next_block(true); + + // then + assert_eq!(Head::::get(), None,); + assert_eq!(Queue::::count(), 4); + + // when + next_block(true); + + // then + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 5, + checked: bounded_vec![3, 2, 1, 0] + }), + ); + assert_eq!(Queue::::count(), 3); + + assert_eq!(::DepositCurrency::reserved_balance(&1), 0); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, + Event::Unstaked { stash: 1, result: Ok(()) }, + Event::Checking { stash: 5, eras: vec![3, 2, 1, 0] } + ] + ); + }); + } + + #[test] + fn successful_multi_queue() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + // register multi accounts for fast unstake + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_eq!(Queue::::get(1), Some(DepositAmount::get())); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(4))); + assert_eq!(Queue::::get(3), Some(DepositAmount::get())); + + // assert 2 queue items are in Queue & None in Head to start with + assert_eq!(Queue::::count(), 2); + assert_eq!(Head::::get(), None); + + // process on idle and check eras for next Queue item + next_block(true); + + // process on idle & let go of current Head + next_block(true); + + // confirm Head / Queue items remaining + assert_eq!(Queue::::count(), 1); + assert_eq!(Head::::get(), None); + + // process on idle and check eras for next Queue item + next_block(true); + + // process on idle & let go of current Head + next_block(true); + + // Head & Queue should now be empty + assert_eq!(Head::::get(), None); + assert_eq!(Queue::::count(), 0); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, + Event::Unstaked { stash: 1, result: Ok(()) }, + Event::Checking { stash: 3, eras: vec![3, 2, 1, 0] }, + Event::Unstaked { stash: 3, result: Ok(()) }, + ] + ); + + assert_unstaked(&1); + assert_unstaked(&3); + }); + } + + #[test] + fn successful_unstake() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + // register for fast unstake + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_eq!(Queue::::get(1), Some(DepositAmount::get())); + + // process on idle + next_block(true); + + // assert queue item has been moved to head + assert_eq!(Queue::::get(1), None); + + // assert head item present + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1, 0] + }) + ); + + next_block(true); + assert_eq!(Head::::get(), None,); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, + Event::Unstaked { stash: 1, result: Ok(()) } + ] + ); + assert_unstaked(&1); + }); + } + + #[test] + fn successful_unstake_all_eras_per_block() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + Balances::make_free_balance_be(&2, 100); + + // register for fast unstake + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_eq!(Queue::::get(1), Some(DepositAmount::get())); + + // process on idle + next_block(true); + + // assert queue item has been moved to head + assert_eq!(Queue::::get(1), None); + + // assert head item present + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1, 0] + }) + ); + + next_block(true); + assert_eq!(Head::::get(), None,); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: 1, eras: vec![3, 2, 1, 0] }, + Event::Unstaked { stash: 1, result: Ok(()) } + ] + ); + assert_unstaked(&1); + }); + } + + #[test] + fn successful_unstake_one_era_per_block() { + ExtBuilder::default().build_and_execute(|| { + // put 1 era per block + ErasToCheckPerBlock::::put(1); + CurrentEra::::put(BondingDuration::get()); + + // register for fast unstake + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_eq!(Queue::::get(1), Some(DepositAmount::get())); + + // process on idle + next_block(true); + + // assert queue item has been moved to head + assert_eq!(Queue::::get(1), None); + + // assert head item present + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3] + }) + ); + + next_block(true); + + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2] + }) + ); + + next_block(true); + + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1] + }) + ); + + next_block(true); + + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1, 0] + }) + ); + + next_block(true); + + assert_eq!(Head::::get(), None,); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: 1, eras: vec![3] }, + Event::Checking { stash: 1, eras: vec![2] }, + Event::Checking { stash: 1, eras: vec![1] }, + Event::Checking { stash: 1, eras: vec![0] }, + Event::Unstaked { stash: 1, result: Ok(()) } + ] + ); + assert_unstaked(&1); + }); + } + + #[test] + fn old_checked_era_pruned() { + // the only scenario where checked era pruning (checked.retain) comes handy is a follows: + // the whole vector is full and at capacity and in the next call we are ready to unstake, + // but then a new era happens. + ExtBuilder::default().build_and_execute(|| { + // given + ErasToCheckPerBlock::::put(1); + CurrentEra::::put(BondingDuration::get()); + + // register for fast unstake + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + assert_eq!(Queue::::get(1), Some(DepositAmount::get())); + + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3] + }) + ); + + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2] + }) + ); + + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1] + }) + ); + + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 1, 0] + }) + ); + + // when: a new era happens right before one is free. + CurrentEra::::put(CurrentEra::::get().unwrap() + 1); + ExtBuilder::register_stakers_for_era(CurrentEra::::get().unwrap()); + + // then + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + stash: 1, + // note era 0 is pruned to keep the vector length sane. + checked: bounded_vec![3, 2, 1, 4], + deposit: DepositAmount::get(), + }) + ); + + next_block(true); + assert_eq!(Head::::get(), None); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: 1, eras: vec![3] }, + Event::Checking { stash: 1, eras: vec![2] }, + Event::Checking { stash: 1, eras: vec![1] }, + Event::Checking { stash: 1, eras: vec![0] }, + Event::Checking { stash: 1, eras: vec![4] }, + Event::Unstaked { stash: 1, result: Ok(()) } + ] + ); + assert_unstaked(&1); + }); + } + + #[test] + fn unstake_paused_mid_election() { + ExtBuilder::default().build_and_execute(|| { + // give: put 1 era per block + ErasToCheckPerBlock::::put(1); + CurrentEra::::put(BondingDuration::get()); + + // register for fast unstake + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(2))); + + // process 2 blocks + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3] + }) + ); + + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2] + }) + ); + + // when + Ongoing::set(true); + + // then nothing changes + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2] + }) + ); + + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2] + }) + ); + + // then we register a new era. + Ongoing::set(false); + CurrentEra::::put(CurrentEra::::get().unwrap() + 1); + ExtBuilder::register_stakers_for_era(CurrentEra::::get().unwrap()); + + // then we can progress again, but notice that the new era that had to be checked. + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 4] + }) + ); + + // progress to end + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 1, + checked: bounded_vec![3, 2, 4, 1] + }) + ); + + // but notice that we don't care about era 0 instead anymore! we're done. + next_block(true); + assert_eq!(Head::::get(), None); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: 1, eras: vec![3] }, + Event::Checking { stash: 1, eras: vec![2] }, + Event::Checking { stash: 1, eras: vec![4] }, + Event::Checking { stash: 1, eras: vec![1] }, + Event::Unstaked { stash: 1, result: Ok(()) } + ] + ); + + assert_unstaked(&1); + }); + } + + #[test] + fn exposed_nominator_cannot_unstake() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(1); + CurrentEra::::put(BondingDuration::get()); + + // create an exposed nominator in era 1 + let exposed = 666 as AccountId; + pallet_staking::ErasStakers::::mutate(1, VALIDATORS_PER_ERA, |expo| { + expo.others.push(IndividualExposure { who: exposed, value: 0 as Balance }); + }); + Balances::make_free_balance_be(&exposed, 100); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(exposed), + exposed, + 10, + RewardDestination::Staked + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(exposed), vec![exposed])); + + Balances::make_free_balance_be(&exposed, 100_000); + // register the exposed one. + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(exposed))); + + // a few blocks later, we realize they are slashed + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: exposed, + checked: bounded_vec![3] + }) + ); + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: exposed, + checked: bounded_vec![3, 2] + }) + ); + next_block(true); + assert_eq!(Head::::get(), None); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: exposed, eras: vec![3] }, + Event::Checking { stash: exposed, eras: vec![2] }, + Event::Slashed { stash: exposed, amount: DepositAmount::get() } + ] + ); + }); + } + + #[test] + fn exposed_nominator_cannot_unstake_multi_check() { + ExtBuilder::default().build_and_execute(|| { + // same as the previous check, but we check 2 eras per block, and we make the exposed be + // exposed in era 0, so that it is detected halfway in a check era. + ErasToCheckPerBlock::::put(2); + CurrentEra::::put(BondingDuration::get()); + + // create an exposed nominator in era 1 + let exposed = 666 as AccountId; + pallet_staking::ErasStakers::::mutate(0, VALIDATORS_PER_ERA, |expo| { + expo.others.push(IndividualExposure { who: exposed, value: 0 as Balance }); + }); + Balances::make_free_balance_be(&exposed, DepositAmount::get() + 100); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(exposed), + exposed, + 10, + RewardDestination::Staked + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(exposed), vec![exposed])); + + // register the exposed one. + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(exposed))); + + // a few blocks later, we realize they are slashed + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: exposed, + checked: bounded_vec![3, 2] + }) + ); + next_block(true); + assert_eq!(Head::::get(), None); + + assert_eq!( + fast_unstake_events_since_last_call(), + // we slash them + vec![ + Event::Checking { stash: exposed, eras: vec![3, 2] }, + Event::Slashed { stash: exposed, amount: DepositAmount::get() } + ] + ); + }); + } + + #[test] + fn validators_cannot_bail() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + // a validator switches role and register... + assert_ok!(Staking::nominate( + RuntimeOrigin::signed(VALIDATOR_PREFIX), + vec![VALIDATOR_PREFIX] + )); + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(VALIDATOR_PREFIX))); + + // but they indeed are exposed! + assert!(pallet_staking::ErasStakers::::contains_key( + BondingDuration::get() - 1, + VALIDATOR_PREFIX + )); + + // process a block, this validator is exposed and has been slashed. + next_block(true); + assert_eq!(Head::::get(), None); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![Event::Slashed { stash: 100, amount: DepositAmount::get() }] + ); + }); + } + + #[test] + fn unexposed_validator_can_fast_unstake() { + ExtBuilder::default().build_and_execute(|| { + ErasToCheckPerBlock::::put(BondingDuration::get() + 1); + CurrentEra::::put(BondingDuration::get()); + + // create a new validator that 100% not exposed. + Balances::make_free_balance_be(&42, 100 + DepositAmount::get()); + assert_ok!(Staking::bond(RuntimeOrigin::signed(42), 42, 10, RewardDestination::Staked)); + assert_ok!(Staking::validate(RuntimeOrigin::signed(42), Default::default())); + + // let them register: + assert_ok!(FastUnstake::register_fast_unstake(RuntimeOrigin::signed(42))); + + // 2 block's enough to unstake them. + next_block(true); + assert_eq!( + Head::::get(), + Some(UnstakeRequest { + deposit: DepositAmount::get(), + stash: 42, + checked: bounded_vec![3, 2, 1, 0] + }) + ); + next_block(true); + assert_eq!(Head::::get(), None); + + assert_eq!( + fast_unstake_events_since_last_call(), + vec![ + Event::Checking { stash: 42, eras: vec![3, 2, 1, 0] }, + Event::Unstaked { stash: 42, result: Ok(()) } + ] + ); + }); + } +} diff --git a/frame/fast-unstake/src/types.rs b/frame/fast-unstake/src/types.rs new file mode 100644 index 0000000000000..08b9ab4326eb2 --- /dev/null +++ b/frame/fast-unstake/src/types.rs @@ -0,0 +1,48 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Types used in the Fast Unstake pallet. + +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{ + traits::{Currency, Get}, + BoundedVec, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, +}; +use scale_info::TypeInfo; +use sp_staking::EraIndex; +use sp_std::{fmt::Debug, prelude::*}; + +pub type BalanceOf = <::Currency as Currency< + ::AccountId, +>>::Balance; + +/// An unstake request. +#[derive( + Encode, Decode, EqNoBound, PartialEqNoBound, Clone, TypeInfo, RuntimeDebugNoBound, MaxEncodedLen, +)] +pub struct UnstakeRequest< + AccountId: Eq + PartialEq + Debug, + MaxChecked: Get, + Balance: PartialEq + Debug, +> { + /// Their stash account. + pub(crate) stash: AccountId, + /// The list of eras for which they have been checked. + pub(crate) checked: BoundedVec, + /// Deposit to be slashed if the unstake was unsuccessful. + pub(crate) deposit: Balance, +} diff --git a/frame/fast-unstake/src/weights.rs b/frame/fast-unstake/src/weights.rs new file mode 100644 index 0000000000000..04857d0dcc865 --- /dev/null +++ b/frame/fast-unstake/src/weights.rs @@ -0,0 +1,210 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for pallet_fast_unstake +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-09-07, STEPS: `10`, REPEAT: 1, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `Kians-MacBook-Pro-2.local`, CPU: `` +//! EXECUTION: Some(Native), WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// target/release/substrate +// benchmark +// pallet +// --steps=10 +// --repeat=1 +// --pallet=pallet_fast_unstake +// --extrinsic=* +// --execution=native +// --output +// weight.rs +// --template +// ./.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_fast_unstake. +pub trait WeightInfo { + fn on_idle_unstake() -> Weight; + fn on_idle_check(x: u32, ) -> Weight; + fn register_fast_unstake() -> Weight; + fn deregister() -> Weight; + fn control() -> Weight; +} + +/// Weights for pallet_fast_unstake using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + // Storage: Staking ValidatorCount (r:1 w:0) + // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + // Storage: FastUnstake Head (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking SlashingSpans (r:1 w:0) + // Storage: Staking Bonded (r:2 w:1) + // Storage: Staking Ledger (r:2 w:2) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:0) + // Storage: System Account (r:3 w:2) + // Storage: Balances Locks (r:2 w:2) + // Storage: NominationPools MinJoinBond (r:1 w:0) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) + // Storage: NominationPools MaxPoolMembers (r:1 w:0) + // Storage: NominationPools CounterForPoolMembers (r:1 w:1) + // Storage: BagsList ListNodes (r:1 w:0) + // Storage: Staking Payee (r:0 w:1) + fn on_idle_unstake() -> Weight { + Weight::from_ref_time(102_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(25 as u64)) + .saturating_add(T::DbWeight::get().writes(13 as u64)) + } + // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + // Storage: Staking ValidatorCount (r:1 w:0) + // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + // Storage: FastUnstake Head (r:1 w:1) + // Storage: FastUnstake Queue (r:2 w:1) + // Storage: FastUnstake CounterForQueue (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking ErasStakers (r:1344 w:0) + /// The range of component `x` is `[672, 86016]`. + fn on_idle_check(x: u32, ) -> Weight { + Weight::from_ref_time(0 as u64) + // Standard Error: 244_000 + .saturating_add(Weight::from_ref_time(13_913_000 as u64).saturating_mul(x as u64)) + .saturating_add(T::DbWeight::get().reads(585 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(x as u64))) + .saturating_add(T::DbWeight::get().writes(3 as u64)) + } + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking Nominators (r:1 w:1) + // Storage: FastUnstake Queue (r:1 w:1) + // Storage: FastUnstake Head (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: BagsList ListNodes (r:1 w:1) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: FastUnstake CounterForQueue (r:1 w:1) + fn register_fast_unstake() -> Weight { + Weight::from_ref_time(57_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(12 as u64)) + .saturating_add(T::DbWeight::get().writes(9 as u64)) + } + // Storage: Staking Ledger (r:1 w:0) + // Storage: FastUnstake Queue (r:1 w:1) + // Storage: FastUnstake Head (r:1 w:0) + // Storage: FastUnstake CounterForQueue (r:1 w:1) + fn deregister() -> Weight { + Weight::from_ref_time(15_000_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) + } + // Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) + fn control() -> Weight { + Weight::from_ref_time(3_000_000 as u64) + .saturating_add(T::DbWeight::get().writes(1 as u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + // Storage: Staking ValidatorCount (r:1 w:0) + // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + // Storage: FastUnstake Head (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking SlashingSpans (r:1 w:0) + // Storage: Staking Bonded (r:2 w:1) + // Storage: Staking Ledger (r:2 w:2) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking Nominators (r:1 w:0) + // Storage: System Account (r:3 w:2) + // Storage: Balances Locks (r:2 w:2) + // Storage: NominationPools MinJoinBond (r:1 w:0) + // Storage: NominationPools PoolMembers (r:1 w:1) + // Storage: NominationPools BondedPools (r:1 w:1) + // Storage: NominationPools RewardPools (r:1 w:1) + // Storage: NominationPools MaxPoolMembersPerPool (r:1 w:0) + // Storage: NominationPools MaxPoolMembers (r:1 w:0) + // Storage: NominationPools CounterForPoolMembers (r:1 w:1) + // Storage: BagsList ListNodes (r:1 w:0) + // Storage: Staking Payee (r:0 w:1) + fn on_idle_unstake() -> Weight { + Weight::from_ref_time(102_000_000 as u64) + .saturating_add(RocksDbWeight::get().reads(25 as u64)) + .saturating_add(RocksDbWeight::get().writes(13 as u64)) + } + // Storage: FastUnstake ErasToCheckPerBlock (r:1 w:0) + // Storage: Staking ValidatorCount (r:1 w:0) + // Storage: ElectionProviderMultiPhase CurrentPhase (r:1 w:0) + // Storage: FastUnstake Head (r:1 w:1) + // Storage: FastUnstake Queue (r:2 w:1) + // Storage: FastUnstake CounterForQueue (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Staking ErasStakers (r:1344 w:0) + /// The range of component `x` is `[672, 86016]`. + fn on_idle_check(x: u32, ) -> Weight { + Weight::from_ref_time(0 as u64) + // Standard Error: 244_000 + .saturating_add(Weight::from_ref_time(13_913_000 as u64).saturating_mul(x as u64)) + .saturating_add(RocksDbWeight::get().reads(585 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(x as u64))) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) + } + // Storage: Staking Ledger (r:1 w:1) + // Storage: Staking Nominators (r:1 w:1) + // Storage: FastUnstake Queue (r:1 w:1) + // Storage: FastUnstake Head (r:1 w:0) + // Storage: Staking Validators (r:1 w:0) + // Storage: Staking CounterForNominators (r:1 w:1) + // Storage: BagsList ListNodes (r:1 w:1) + // Storage: BagsList ListBags (r:1 w:1) + // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: Staking CurrentEra (r:1 w:0) + // Storage: Balances Locks (r:1 w:1) + // Storage: FastUnstake CounterForQueue (r:1 w:1) + fn register_fast_unstake() -> Weight { + Weight::from_ref_time(57_000_000 as u64) + .saturating_add(RocksDbWeight::get().reads(12 as u64)) + .saturating_add(RocksDbWeight::get().writes(9 as u64)) + } + // Storage: Staking Ledger (r:1 w:0) + // Storage: FastUnstake Queue (r:1 w:1) + // Storage: FastUnstake Head (r:1 w:0) + // Storage: FastUnstake CounterForQueue (r:1 w:1) + fn deregister() -> Weight { + Weight::from_ref_time(15_000_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) + } + // Storage: FastUnstake ErasToCheckPerBlock (r:0 w:1) + fn control() -> Weight { + Weight::from_ref_time(3_000_000 as u64) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) + } +} diff --git a/frame/gilt/Cargo.toml b/frame/gilt/Cargo.toml index d6f61c6d250ba..8c60c847027a3 100644 --- a/frame/gilt/Cargo.toml +++ b/frame/gilt/Cargo.toml @@ -31,7 +31,7 @@ sp-io = { version = "6.0.0", path = "../../primitives/io" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "scale-info/std", diff --git a/frame/gilt/src/benchmarking.rs b/frame/gilt/src/benchmarking.rs index 3df08372f499b..92ebf81854f23 100644 --- a/frame/gilt/src/benchmarking.rs +++ b/frame/gilt/src/benchmarking.rs @@ -77,7 +77,7 @@ benchmarks! { set_target { let origin = T::AdminOrigin::successful_origin(); - }: _(origin, Default::default()) + }: _(origin, Default::default()) verify {} thaw { @@ -97,7 +97,7 @@ benchmarks! { pursue_target_per_item { // bids taken - let b in 1..T::MaxQueueLen::get(); + let b in 0..T::MaxQueueLen::get(); let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, T::MinFreeze::get() * BalanceOf::::from(b + 1)); @@ -113,7 +113,7 @@ benchmarks! { pursue_target_per_queue { // total queues hit - let q in 1..T::QueueCount::get(); + let q in 0..T::QueueCount::get(); let caller: T::AccountId = whitelisted_caller(); T::Currency::make_free_balance_be(&caller, T::MinFreeze::get() * BalanceOf::::from(q + 1)); diff --git a/frame/gilt/src/lib.rs b/frame/gilt/src/lib.rs index b94b7d164f04c..28a0f5fd56e67 100644 --- a/frame/gilt/src/lib.rs +++ b/frame/gilt/src/lib.rs @@ -98,7 +98,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// Overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Currency type that this works on. type Currency: ReservableCurrency; @@ -116,7 +116,7 @@ pub mod pallet { + MaxEncodedLen; /// Origin required for setting the target proportion to be under gilt. - type AdminOrigin: EnsureOrigin; + type AdminOrigin: EnsureOrigin; /// Unbalanced handler to account for funds created (in case of a higher total issuance over /// freezing period). diff --git a/frame/gilt/src/mock.rs b/frame/gilt/src/mock.rs index 369b34ba77f44..e1cdf6507ef58 100644 --- a/frame/gilt/src/mock.rs +++ b/frame/gilt/src/mock.rs @@ -49,8 +49,8 @@ impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -58,7 +58,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); @@ -75,7 +75,7 @@ impl frame_system::Config for Test { impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = frame_support::traits::ConstU64<1>; type AccountStore = System; type WeightInfo = (); @@ -92,7 +92,7 @@ ord_parameter_types! { } impl pallet_gilt::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type CurrencyBalance = ::Balance; type AdminOrigin = frame_system::EnsureSignedBy; diff --git a/frame/gilt/src/tests.rs b/frame/gilt/src/tests.rs index 486601b5b2f21..2ac369dd3b8b3 100644 --- a/frame/gilt/src/tests.rs +++ b/frame/gilt/src/tests.rs @@ -49,8 +49,8 @@ fn set_target_works() { new_test_ext().execute_with(|| { run_to_block(1); let e = DispatchError::BadOrigin; - assert_noop!(Gilt::set_target(Origin::signed(2), Perquintill::from_percent(50)), e); - assert_ok!(Gilt::set_target(Origin::signed(1), Perquintill::from_percent(50))); + assert_noop!(Gilt::set_target(RuntimeOrigin::signed(2), Perquintill::from_percent(50)), e); + assert_ok!(Gilt::set_target(RuntimeOrigin::signed(1), Perquintill::from_percent(50))); assert_eq!( ActiveTotal::::get(), @@ -68,13 +68,19 @@ fn set_target_works() { fn place_bid_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_noop!(Gilt::place_bid(Origin::signed(1), 1, 2), Error::::AmountTooSmall); assert_noop!( - Gilt::place_bid(Origin::signed(1), 101, 2), + Gilt::place_bid(RuntimeOrigin::signed(1), 1, 2), + Error::::AmountTooSmall + ); + assert_noop!( + Gilt::place_bid(RuntimeOrigin::signed(1), 101, 2), BalancesError::::InsufficientBalance ); - assert_noop!(Gilt::place_bid(Origin::signed(1), 10, 4), Error::::DurationTooBig); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 2)); + assert_noop!( + Gilt::place_bid(RuntimeOrigin::signed(1), 10, 4), + Error::::DurationTooBig + ); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); assert_eq!(Balances::reserved_balance(1), 10); assert_eq!(Queues::::get(2), vec![GiltBid { amount: 10, who: 1 }]); assert_eq!(QueueTotals::::get(), vec![(0, 0), (1, 10), (0, 0)]); @@ -85,16 +91,16 @@ fn place_bid_works() { fn place_bid_queuing_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 20, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 5, 2)); - assert_noop!(Gilt::place_bid(Origin::signed(1), 5, 2), Error::::BidTooLow); - assert_ok!(Gilt::place_bid(Origin::signed(1), 15, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 20, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 5, 2)); + assert_noop!(Gilt::place_bid(RuntimeOrigin::signed(1), 5, 2), Error::::BidTooLow); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 15, 2)); assert_eq!(Balances::reserved_balance(1), 45); - assert_ok!(Gilt::place_bid(Origin::signed(1), 25, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 25, 2)); assert_eq!(Balances::reserved_balance(1), 60); - assert_noop!(Gilt::place_bid(Origin::signed(1), 10, 2), Error::::BidTooLow); + assert_noop!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2), Error::::BidTooLow); assert_eq!( Queues::::get(2), vec![ @@ -111,11 +117,11 @@ fn place_bid_queuing_works() { fn place_bid_fails_when_queue_full() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 10, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(3), 10, 2)); - assert_noop!(Gilt::place_bid(Origin::signed(4), 10, 2), Error::::BidTooLow); - assert_ok!(Gilt::place_bid(Origin::signed(4), 10, 3)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(3), 10, 2)); + assert_noop!(Gilt::place_bid(RuntimeOrigin::signed(4), 10, 2), Error::::BidTooLow); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(4), 10, 3)); }); } @@ -123,11 +129,11 @@ fn place_bid_fails_when_queue_full() { fn multiple_place_bids_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 3)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 3)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 10, 2)); assert_eq!(Balances::reserved_balance(1), 40); assert_eq!(Balances::reserved_balance(2), 10); @@ -149,9 +155,9 @@ fn multiple_place_bids_works() { fn retract_single_item_queue_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 2)); - assert_ok!(Gilt::retract_bid(Origin::signed(1), 10, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Gilt::retract_bid(RuntimeOrigin::signed(1), 10, 1)); assert_eq!(Balances::reserved_balance(1), 10); assert_eq!(Queues::::get(1), vec![]); @@ -164,12 +170,12 @@ fn retract_single_item_queue_works() { fn retract_with_other_and_duplicate_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 10, 2)); - assert_ok!(Gilt::retract_bid(Origin::signed(1), 10, 2)); + assert_ok!(Gilt::retract_bid(RuntimeOrigin::signed(1), 10, 2)); assert_eq!(Balances::reserved_balance(1), 20); assert_eq!(Balances::reserved_balance(2), 10); assert_eq!(Queues::::get(1), vec![GiltBid { amount: 10, who: 1 },]); @@ -185,11 +191,11 @@ fn retract_with_other_and_duplicate_works() { fn retract_non_existent_item_fails() { new_test_ext().execute_with(|| { run_to_block(1); - assert_noop!(Gilt::retract_bid(Origin::signed(1), 10, 1), Error::::NotFound); - assert_ok!(Gilt::place_bid(Origin::signed(1), 10, 1)); - assert_noop!(Gilt::retract_bid(Origin::signed(1), 20, 1), Error::::NotFound); - assert_noop!(Gilt::retract_bid(Origin::signed(1), 10, 2), Error::::NotFound); - assert_noop!(Gilt::retract_bid(Origin::signed(2), 10, 1), Error::::NotFound); + assert_noop!(Gilt::retract_bid(RuntimeOrigin::signed(1), 10, 1), Error::::NotFound); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 10, 1)); + assert_noop!(Gilt::retract_bid(RuntimeOrigin::signed(1), 20, 1), Error::::NotFound); + assert_noop!(Gilt::retract_bid(RuntimeOrigin::signed(1), 10, 2), Error::::NotFound); + assert_noop!(Gilt::retract_bid(RuntimeOrigin::signed(2), 10, 1), Error::::NotFound); }); } @@ -197,8 +203,8 @@ fn retract_non_existent_item_fails() { fn basic_enlarge_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 40, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 40, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 40, 2)); Gilt::enlarge(40, 2); // Takes 2/2, then stopped because it reaches its max amount @@ -228,10 +234,10 @@ fn basic_enlarge_works() { fn enlarge_respects_bids_limit() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 40, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 40, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(3), 40, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(4), 40, 3)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 40, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(3), 40, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(4), 40, 3)); Gilt::enlarge(100, 2); // Should have taken 4/3 and 2/2, then stopped because it's only allowed 2. @@ -269,7 +275,7 @@ fn enlarge_respects_bids_limit() { fn enlarge_respects_amount_limit_and_will_split() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 80, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 80, 1)); Gilt::enlarge(40, 2); // Takes 2/2, then stopped because it reaches its max amount @@ -296,14 +302,14 @@ fn enlarge_respects_amount_limit_and_will_split() { fn basic_thaw_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 40, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); Gilt::enlarge(40, 1); run_to_block(3); - assert_noop!(Gilt::thaw(Origin::signed(1), 0), Error::::NotExpired); + assert_noop!(Gilt::thaw(RuntimeOrigin::signed(1), 0), Error::::NotExpired); run_to_block(4); - assert_noop!(Gilt::thaw(Origin::signed(1), 1), Error::::Unknown); - assert_noop!(Gilt::thaw(Origin::signed(2), 0), Error::::NotOwner); - assert_ok!(Gilt::thaw(Origin::signed(1), 0)); + assert_noop!(Gilt::thaw(RuntimeOrigin::signed(1), 1), Error::::Unknown); + assert_noop!(Gilt::thaw(RuntimeOrigin::signed(2), 0), Error::::NotOwner); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); assert_eq!( ActiveTotal::::get(), @@ -324,7 +330,7 @@ fn basic_thaw_works() { fn thaw_when_issuance_higher_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 100, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 100, 1)); Gilt::enlarge(100, 1); // Everybody else's balances goes up by 50% @@ -333,7 +339,7 @@ fn thaw_when_issuance_higher_works() { Balances::make_free_balance_be(&4, 150); run_to_block(4); - assert_ok!(Gilt::thaw(Origin::signed(1), 0)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); assert_eq!(Balances::free_balance(1), 150); assert_eq!(Balances::reserved_balance(1), 0); @@ -347,16 +353,16 @@ fn thaw_with_ignored_issuance_works() { // Give account zero some balance. Balances::make_free_balance_be(&0, 200); - assert_ok!(Gilt::place_bid(Origin::signed(1), 100, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 100, 1)); Gilt::enlarge(100, 1); // Account zero transfers 50 into everyone else's accounts. - assert_ok!(Balances::transfer(Origin::signed(0), 2, 50)); - assert_ok!(Balances::transfer(Origin::signed(0), 3, 50)); - assert_ok!(Balances::transfer(Origin::signed(0), 4, 50)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(0), 2, 50)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(0), 3, 50)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(0), 4, 50)); run_to_block(4); - assert_ok!(Gilt::thaw(Origin::signed(1), 0)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); // Account zero changes have been ignored. assert_eq!(Balances::free_balance(1), 150); @@ -368,7 +374,7 @@ fn thaw_with_ignored_issuance_works() { fn thaw_when_issuance_lower_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 100, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 100, 1)); Gilt::enlarge(100, 1); // Everybody else's balances goes down by 25% @@ -377,7 +383,7 @@ fn thaw_when_issuance_lower_works() { Balances::make_free_balance_be(&4, 75); run_to_block(4); - assert_ok!(Gilt::thaw(Origin::signed(1), 0)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); assert_eq!(Balances::free_balance(1), 75); assert_eq!(Balances::reserved_balance(1), 0); @@ -388,9 +394,9 @@ fn thaw_when_issuance_lower_works() { fn multiple_thaws_works() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 40, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 60, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 50, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 60, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 50, 1)); Gilt::enlarge(200, 3); // Double everyone's free balances. @@ -399,9 +405,9 @@ fn multiple_thaws_works() { Balances::make_free_balance_be(&4, 200); run_to_block(4); - assert_ok!(Gilt::thaw(Origin::signed(1), 0)); - assert_ok!(Gilt::thaw(Origin::signed(1), 1)); - assert_ok!(Gilt::thaw(Origin::signed(2), 2)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 1)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(2), 2)); assert_eq!(Balances::free_balance(1), 200); assert_eq!(Balances::free_balance(2), 200); @@ -412,9 +418,9 @@ fn multiple_thaws_works() { fn multiple_thaws_works_in_alternative_thaw_order() { new_test_ext().execute_with(|| { run_to_block(1); - assert_ok!(Gilt::place_bid(Origin::signed(1), 40, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 60, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 50, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 60, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 50, 1)); Gilt::enlarge(200, 3); // Double everyone's free balances. @@ -423,9 +429,9 @@ fn multiple_thaws_works_in_alternative_thaw_order() { Balances::make_free_balance_be(&4, 200); run_to_block(4); - assert_ok!(Gilt::thaw(Origin::signed(2), 2)); - assert_ok!(Gilt::thaw(Origin::signed(1), 1)); - assert_ok!(Gilt::thaw(Origin::signed(1), 0)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(2), 2)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 1)); + assert_ok!(Gilt::thaw(RuntimeOrigin::signed(1), 0)); assert_eq!(Balances::free_balance(1), 200); assert_eq!(Balances::free_balance(2), 200); @@ -436,12 +442,12 @@ fn multiple_thaws_works_in_alternative_thaw_order() { fn enlargement_to_target_works() { new_test_ext().execute_with(|| { run_to_block(2); - assert_ok!(Gilt::place_bid(Origin::signed(1), 40, 1)); - assert_ok!(Gilt::place_bid(Origin::signed(1), 40, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 40, 2)); - assert_ok!(Gilt::place_bid(Origin::signed(2), 40, 3)); - assert_ok!(Gilt::place_bid(Origin::signed(3), 40, 3)); - assert_ok!(Gilt::set_target(Origin::signed(1), Perquintill::from_percent(40))); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 1)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(1), 40, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 40, 2)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(2), 40, 3)); + assert_ok!(Gilt::place_bid(RuntimeOrigin::signed(3), 40, 3)); + assert_ok!(Gilt::set_target(RuntimeOrigin::signed(1), Perquintill::from_percent(40))); run_to_block(3); assert_eq!(Queues::::get(1), vec![GiltBid { amount: 40, who: 1 },]); @@ -540,7 +546,7 @@ fn enlargement_to_target_works() { ); // Set target a bit higher to use up the remaining bid. - assert_ok!(Gilt::set_target(Origin::signed(1), Perquintill::from_percent(60))); + assert_ok!(Gilt::set_target(RuntimeOrigin::signed(1), Perquintill::from_percent(60))); run_to_block(10); // Two new gilts should have been issued to 1 & 2 for 40 each & duration of 2. diff --git a/frame/grandpa/Cargo.toml b/frame/grandpa/Cargo.toml index 2090a4ea2e228..4bd17b914cefa 100644 --- a/frame/grandpa/Cargo.toml +++ b/frame/grandpa/Cargo.toml @@ -45,7 +45,7 @@ sp-keyring = { version = "6.0.0", path = "../../primitives/keyring" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/grandpa/src/lib.rs b/frame/grandpa/src/lib.rs index 1781f0a8e40a2..fe5b9861853bf 100644 --- a/frame/grandpa/src/lib.rs +++ b/frame/grandpa/src/lib.rs @@ -40,11 +40,11 @@ use fg_primitives::{ GRANDPA_ENGINE_ID, }; use frame_support::{ - dispatch::DispatchResultWithPostInfo, + dispatch::{DispatchResultWithPostInfo, Pays}, pallet_prelude::Get, storage, traits::{KeyOwnerProofSystem, OneSessionHandler}, - weights::{Pays, Weight}, + weights::Weight, WeakBoundedVec, }; use scale_info::TypeInfo; @@ -87,12 +87,9 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The event type of this module. - type Event: From - + Into<::Event> - + IsType<::Event>; - - /// The function call. - type Call: From>; + type RuntimeEvent: From + + Into<::RuntimeEvent> + + IsType<::RuntimeEvent>; /// The proof of key ownership, used for validating equivocation reports /// The proof must include the session index and validator count of the diff --git a/frame/grandpa/src/mock.rs b/frame/grandpa/src/mock.rs index d246466cf0db4..573a74d2bfae8 100644 --- a/frame/grandpa/src/mock.rs +++ b/frame/grandpa/src/mock.rs @@ -79,16 +79,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -103,10 +103,10 @@ impl frame_system::Config for Test { impl frame_system::offchain::SendTransactionTypes for Test where - Call: From, + RuntimeCall: From, { - type OverarchingCall = Call; - type Extrinsic = TestXt; + type OverarchingCall = RuntimeCall; + type Extrinsic = TestXt; } parameter_types! { @@ -116,7 +116,7 @@ parameter_types! { /// Custom `SessionHandler` since we use `TestSessionKeys` as `Keys`. impl pallet_session::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = u64; type ValidatorIdOf = pallet_staking::StashOf; type ShouldEndSession = pallet_session::PeriodicSessions, ConstU64<0>>; @@ -145,7 +145,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type Balance = u128; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU128<1>; type AccountStore = System; type WeightInfo = (); @@ -188,7 +188,7 @@ impl pallet_staking::Config for Test { type MaxNominations = ConstU32<16>; type RewardRemainder = (); type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type CurrencyBalance = ::Balance; type Slash = (); @@ -206,14 +206,16 @@ impl pallet_staking::Config for Test { type ElectionProvider = onchain::UnboundedExecution; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; + type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = ConstU32<84>; type OnStakerSlash = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); } impl pallet_offences::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type IdentificationTuple = pallet_session::historical::IdentificationTuple; type OnOffenceHandler = Staking; } @@ -224,8 +226,7 @@ parameter_types! { } impl Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; type KeyOwnerProofSystem = Historical; diff --git a/frame/grandpa/src/tests.rs b/frame/grandpa/src/tests.rs index 9c39069bf9538..626decd12821e 100644 --- a/frame/grandpa/src/tests.rs +++ b/frame/grandpa/src/tests.rs @@ -25,8 +25,8 @@ use codec::Encode; use fg_primitives::ScheduledChange; use frame_support::{ assert_err, assert_noop, assert_ok, + dispatch::{GetDispatchInfo, Pays}, traits::{Currency, OnFinalize, OneSessionHandler}, - weights::{GetDispatchInfo, Pays}, }; use frame_system::{EventRecord, Phase}; use sp_core::H256; @@ -359,7 +359,7 @@ fn report_equivocation_current_set_works() { // report the equivocation and the tx should be dispatched successfully assert_ok!(Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ),); @@ -437,7 +437,7 @@ fn report_equivocation_old_set_works() { // report the equivocation using the key ownership proof generated on // the old set, the tx should be dispatched successfully assert_ok!(Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ),); @@ -500,7 +500,7 @@ fn report_equivocation_invalid_set_id() { // the call for reporting the equivocation should error assert_err!( Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ), @@ -541,7 +541,7 @@ fn report_equivocation_invalid_session() { // proof from the previous set, the session should be invalid. assert_err!( Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ), @@ -586,7 +586,7 @@ fn report_equivocation_invalid_key_owner_proof() { // proof for a different key than the one in the equivocation proof. assert_err!( Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), invalid_key_owner_proof, ), @@ -617,7 +617,7 @@ fn report_equivocation_invalid_equivocation_proof() { let assert_invalid_equivocation_proof = |equivocation_proof| { assert_err!( Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof.clone(), ), @@ -723,7 +723,7 @@ fn report_equivocation_validate_unsigned_prevents_duplicates() { // we submit the report Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ) @@ -823,7 +823,7 @@ fn report_equivocation_has_valid_weight() { .map(::WeightInfo::report_equivocation) .collect::>() .windows(2) - .all(|w| w[0] < w[1])); + .all(|w| w[0].ref_time() < w[1].ref_time())); } #[test] @@ -856,12 +856,12 @@ fn valid_equivocation_reports_dont_pay_fees() { .get_dispatch_info(); // it should have non-zero weight and the fee has to be paid. - assert!(info.weight > Weight::zero()); + assert!(info.weight.any_gt(Weight::zero())); assert_eq!(info.pays_fee, Pays::Yes); // report the equivocation. let post_info = Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof.clone()), key_owner_proof.clone(), ) @@ -875,7 +875,7 @@ fn valid_equivocation_reports_dont_pay_fees() { // report the equivocation again which is invalid now since it is // duplicate. let post_info = Grandpa::report_equivocation_unsigned( - Origin::none(), + RuntimeOrigin::none(), Box::new(equivocation_proof), key_owner_proof, ) diff --git a/frame/identity/Cargo.toml b/frame/identity/Cargo.toml index 8e821537fd9b2..92e55c5c2b934 100644 --- a/frame/identity/Cargo.toml +++ b/frame/identity/Cargo.toml @@ -31,7 +31,7 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "scale-info/std", diff --git a/frame/identity/src/benchmarking.rs b/frame/identity/src/benchmarking.rs index 5d409f48bf567..c628387a4d22e 100644 --- a/frame/identity/src/benchmarking.rs +++ b/frame/identity/src/benchmarking.rs @@ -32,7 +32,7 @@ use sp_runtime::traits::Bounded; const SEED: u32 = 0; -fn assert_last_event(generic_event: ::Event) { +fn assert_last_event(generic_event: ::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } @@ -76,9 +76,11 @@ fn create_sub_accounts( } // Set identity so `set_subs` does not fail. - let _ = T::Currency::make_free_balance_be(who, BalanceOf::::max_value() / 2u32.into()); - let info = create_identity_info::(1); - Identity::::set_identity(who_origin.into(), Box::new(info))?; + if IdentityOf::::get(who).is_none() { + let _ = T::Currency::make_free_balance_be(who, BalanceOf::::max_value() / 2u32.into()); + let info = create_identity_info::(1); + Identity::::set_identity(who_origin.into(), Box::new(info))?; + } Ok(subs) } @@ -121,24 +123,24 @@ benchmarks! { ensure!(Registrars::::get().len() as u32 == r, "Registrars not set up correctly."); let origin = T::RegistrarOrigin::successful_origin(); let account = T::Lookup::unlookup(account("registrar", r + 1, SEED)); - }: _(origin, account) + }: _(origin, account) verify { ensure!(Registrars::::get().len() as u32 == r + 1, "Registrars not added."); } set_identity { let r in 1 .. T::MaxRegistrars::get() => add_registrars::(r)?; - let x in 1 .. T::MaxAdditionalFields::get(); + let x in 0 .. T::MaxAdditionalFields::get(); let caller = { // The target user let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); - let caller_origin: ::Origin = RawOrigin::Signed(caller.clone()).into(); + let caller_origin: ::RuntimeOrigin = RawOrigin::Signed(caller.clone()).into(); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); // Add an initial identity let initial_info = create_identity_info::(1); - Identity::::set_identity(caller_origin.clone(), Box::new(initial_info))?; + Identity::::set_identity(caller_origin.clone(), Box::new(initial_info.clone()))?; // User requests judgement from all the registrars, and they approve for i in 0..r { @@ -147,7 +149,8 @@ benchmarks! { RawOrigin::Signed(account("registrar", i, SEED)).into(), i, caller_lookup.clone(), - Judgement::Reasonable + Judgement::Reasonable, + T::Hashing::hash_of(&initial_info), )?; } caller @@ -163,7 +166,7 @@ benchmarks! { set_subs_new { let caller: T::AccountId = whitelisted_caller(); // Create a new subs vec with s sub accounts - let s in 1 .. T::MaxSubAccounts::get() => (); + let s in 0 .. T::MaxSubAccounts::get() => (); let subs = create_sub_accounts::(&caller, s)?; ensure!(SubsOf::::get(&caller).1.len() == 0, "Caller already has subs"); }: set_subs(RawOrigin::Signed(caller.clone()), subs) @@ -174,7 +177,7 @@ benchmarks! { set_subs_old { let caller: T::AccountId = whitelisted_caller(); // Give them p many previous sub accounts. - let p in 1 .. T::MaxSubAccounts::get() => { + let p in 0 .. T::MaxSubAccounts::get() => { let _ = add_sub_accounts::(&caller, p)?; }; // Remove all subs. @@ -190,23 +193,23 @@ benchmarks! { clear_identity { let caller: T::AccountId = whitelisted_caller(); - let caller_origin = ::Origin::from(RawOrigin::Signed(caller.clone())); + let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); let caller_lookup = ::unlookup(caller.clone()); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let r in 1 .. T::MaxRegistrars::get() => add_registrars::(r)?; - let s in 1 .. T::MaxSubAccounts::get() => { + let s in 0 .. T::MaxSubAccounts::get() => { // Give them s many sub accounts let caller: T::AccountId = whitelisted_caller(); let _ = add_sub_accounts::(&caller, s)?; }; - let x in 1 .. T::MaxAdditionalFields::get() => { - // Create their main identity with x additional fields - let info = create_identity_info::(x); - let caller: T::AccountId = whitelisted_caller(); - let caller_origin = ::Origin::from(RawOrigin::Signed(caller)); - Identity::::set_identity(caller_origin, Box::new(info))?; - }; + let x in 0 .. T::MaxAdditionalFields::get(); + + // Create their main identity with x additional fields + let info = create_identity_info::(x); + let caller: T::AccountId = whitelisted_caller(); + let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); + Identity::::set_identity(caller_origin.clone(), Box::new(info.clone()))?; // User requests judgement from all the registrars, and they approve for i in 0..r { @@ -215,7 +218,8 @@ benchmarks! { RawOrigin::Signed(account("registrar", i, SEED)).into(), i, caller_lookup.clone(), - Judgement::Reasonable + Judgement::Reasonable, + T::Hashing::hash_of(&info), )?; } ensure!(IdentityOf::::contains_key(&caller), "Identity does not exist."); @@ -229,11 +233,11 @@ benchmarks! { let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let r in 1 .. T::MaxRegistrars::get() => add_registrars::(r)?; - let x in 1 .. T::MaxAdditionalFields::get() => { + let x in 0 .. T::MaxAdditionalFields::get() => { // Create their main identity with x additional fields let info = create_identity_info::(x); let caller: T::AccountId = whitelisted_caller(); - let caller_origin = ::Origin::from(RawOrigin::Signed(caller)); + let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller)); Identity::::set_identity(caller_origin, Box::new(info))?; }; }: _(RawOrigin::Signed(caller.clone()), r - 1, 10u32.into()) @@ -243,15 +247,15 @@ benchmarks! { cancel_request { let caller: T::AccountId = whitelisted_caller(); - let caller_origin = ::Origin::from(RawOrigin::Signed(caller.clone())); + let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller.clone())); let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let r in 1 .. T::MaxRegistrars::get() => add_registrars::(r)?; - let x in 1 .. T::MaxAdditionalFields::get() => { + let x in 0 .. T::MaxAdditionalFields::get() => { // Create their main identity with x additional fields let info = create_identity_info::(x); let caller: T::AccountId = whitelisted_caller(); - let caller_origin = ::Origin::from(RawOrigin::Signed(caller)); + let caller_origin = ::RuntimeOrigin::from(RawOrigin::Signed(caller)); Identity::::set_identity(caller_origin, Box::new(info))?; }; @@ -319,7 +323,7 @@ benchmarks! { provide_judgement { // The user let user: T::AccountId = account("user", r, SEED); - let user_origin = ::Origin::from(RawOrigin::Signed(user.clone())); + let user_origin = ::RuntimeOrigin::from(RawOrigin::Signed(user.clone())); let user_lookup = ::unlookup(user.clone()); let _ = T::Currency::make_free_balance_be(&user, BalanceOf::::max_value()); @@ -328,31 +332,32 @@ benchmarks! { let _ = T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); let r in 1 .. T::MaxRegistrars::get() - 1 => add_registrars::(r)?; - let x in 1 .. T::MaxAdditionalFields::get() => { - let info = create_identity_info::(x); - Identity::::set_identity(user_origin.clone(), Box::new(info))?; - }; + let x in 0 .. T::MaxAdditionalFields::get(); + + let info = create_identity_info::(x); + let info_hash = T::Hashing::hash_of(&info); + Identity::::set_identity(user_origin.clone(), Box::new(info))?; let registrar_origin = T::RegistrarOrigin::successful_origin(); Identity::::add_registrar(registrar_origin, caller_lookup)?; Identity::::request_judgement(user_origin, r, 10u32.into())?; - }: _(RawOrigin::Signed(caller), r, user_lookup, Judgement::Reasonable) + }: _(RawOrigin::Signed(caller), r, user_lookup, Judgement::Reasonable, info_hash) verify { assert_last_event::(Event::::JudgementGiven { target: user, registrar_index: r }.into()) } kill_identity { let r in 1 .. T::MaxRegistrars::get() => add_registrars::(r)?; - let s in 1 .. T::MaxSubAccounts::get(); - let x in 1 .. T::MaxAdditionalFields::get(); + let s in 0 .. T::MaxSubAccounts::get(); + let x in 0 .. T::MaxAdditionalFields::get(); let target: T::AccountId = account("target", 0, SEED); - let target_origin: ::Origin = RawOrigin::Signed(target.clone()).into(); + let target_origin: ::RuntimeOrigin = RawOrigin::Signed(target.clone()).into(); let target_lookup = T::Lookup::unlookup(target.clone()); let _ = T::Currency::make_free_balance_be(&target, BalanceOf::::max_value()); let info = create_identity_info::(x); - Identity::::set_identity(target_origin.clone(), Box::new(info))?; + Identity::::set_identity(target_origin.clone(), Box::new(info.clone()))?; let _ = add_sub_accounts::(&target, s)?; // User requests judgement from all the registrars, and they approve @@ -362,18 +367,19 @@ benchmarks! { RawOrigin::Signed(account("registrar", i, SEED)).into(), i, target_lookup.clone(), - Judgement::Reasonable + Judgement::Reasonable, + T::Hashing::hash_of(&info), )?; } ensure!(IdentityOf::::contains_key(&target), "Identity not set"); let origin = T::ForceOrigin::successful_origin(); - }: _(origin, target_lookup) + }: _(origin, target_lookup) verify { ensure!(!IdentityOf::::contains_key(&target), "Identity not removed"); } add_sub { - let s in 1 .. T::MaxSubAccounts::get() - 1; + let s in 0 .. T::MaxSubAccounts::get() - 1; let caller: T::AccountId = whitelisted_caller(); let _ = add_sub_accounts::(&caller, s)?; @@ -409,7 +415,7 @@ benchmarks! { } quit_sub { - let s in 1 .. T::MaxSubAccounts::get() - 1; + let s in 0 .. T::MaxSubAccounts::get() - 1; let caller: T::AccountId = whitelisted_caller(); let sup = account("super", 0, SEED); diff --git a/frame/identity/src/lib.rs b/frame/identity/src/lib.rs index 0f80acceb949c..8b22ecedaec19 100644 --- a/frame/identity/src/lib.rs +++ b/frame/identity/src/lib.rs @@ -79,7 +79,7 @@ mod types; pub mod weights; use frame_support::traits::{BalanceStatus, Currency, OnUnbalanced, ReservableCurrency}; -use sp_runtime::traits::{AppendZerosInput, Saturating, StaticLookup, Zero}; +use sp_runtime::traits::{AppendZerosInput, Hash, Saturating, StaticLookup, Zero}; use sp_std::prelude::*; pub use weights::WeightInfo; @@ -105,7 +105,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The currency trait. type Currency: ReservableCurrency; @@ -142,10 +142,10 @@ pub mod pallet { type Slashed: OnUnbalanced>; /// The origin which may forcibly set or remove a name. Root can always do this. - type ForceOrigin: EnsureOrigin; + type ForceOrigin: EnsureOrigin; /// The origin which may add or remove registrars. Root can always do this. - type RegistrarOrigin: EnsureOrigin; + type RegistrarOrigin: EnsureOrigin; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; @@ -236,6 +236,8 @@ pub mod pallet { NotSub, /// Sub-account isn't owned by sender. NotOwned, + /// The provided judgement was for a different identity. + JudgementForDifferentIdentity, } #[pallet::event] @@ -746,6 +748,7 @@ pub mod pallet { /// - `target`: the account whose identity the judgement is upon. This must be an account /// with a registered identity. /// - `judgement`: the judgement of the registrar of index `reg_index` about `target`. + /// - `identity`: The hash of the [`IdentityInfo`] for that the judgement is provided. /// /// Emits `JudgementGiven` if successful. /// @@ -765,6 +768,7 @@ pub mod pallet { #[pallet::compact] reg_index: RegistrarIndex, target: AccountIdLookupOf, judgement: Judgement>, + identity: T::Hash, ) -> DispatchResultWithPostInfo { let sender = ensure_signed(origin)?; let target = T::Lookup::lookup(target)?; @@ -772,10 +776,14 @@ pub mod pallet { >::get() .get(reg_index as usize) .and_then(Option::as_ref) - .and_then(|r| if r.account == sender { Some(r) } else { None }) + .filter(|r| r.account == sender) .ok_or(Error::::InvalidIndex)?; let mut id = >::get(&target).ok_or(Error::::InvalidTarget)?; + if T::Hashing::hash_of(&id.info) != identity { + return Err(Error::::JudgementForDifferentIdentity.into()) + } + let item = (reg_index, judgement); match id.judgements.binary_search_by_key(®_index, |x| x.0) { Ok(position) => { diff --git a/frame/identity/src/tests.rs b/frame/identity/src/tests.rs index a0773e9904a1c..20628da50937a 100644 --- a/frame/identity/src/tests.rs +++ b/frame/identity/src/tests.rs @@ -56,16 +56,16 @@ impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); @@ -81,7 +81,7 @@ impl frame_system::Config for Test { impl pallet_balances::Config for Test { type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -103,7 +103,7 @@ ord_parameter_types! { type EnsureOneOrRoot = EitherOfDiverse, EnsureSignedBy>; type EnsureTwoOrRoot = EitherOfDiverse, EnsureSignedBy>; impl pallet_identity::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type Slashed = (); type BasicDeposit = ConstU64<10>; @@ -148,41 +148,44 @@ fn editing_subaccounts_should_work() { new_test_ext().execute_with(|| { let data = |x| Data::Raw(vec![x; 1].try_into().unwrap()); - assert_noop!(Identity::add_sub(Origin::signed(10), 20, data(1)), Error::::NoIdentity); + assert_noop!( + Identity::add_sub(RuntimeOrigin::signed(10), 20, data(1)), + Error::::NoIdentity + ); - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); // first sub account - assert_ok!(Identity::add_sub(Origin::signed(10), 1, data(1))); + assert_ok!(Identity::add_sub(RuntimeOrigin::signed(10), 1, data(1))); assert_eq!(SuperOf::::get(1), Some((10, data(1)))); assert_eq!(Balances::free_balance(10), 80); // second sub account - assert_ok!(Identity::add_sub(Origin::signed(10), 2, data(2))); + assert_ok!(Identity::add_sub(RuntimeOrigin::signed(10), 2, data(2))); assert_eq!(SuperOf::::get(1), Some((10, data(1)))); assert_eq!(SuperOf::::get(2), Some((10, data(2)))); assert_eq!(Balances::free_balance(10), 70); // third sub account is too many assert_noop!( - Identity::add_sub(Origin::signed(10), 3, data(3)), + Identity::add_sub(RuntimeOrigin::signed(10), 3, data(3)), Error::::TooManySubAccounts ); // rename first sub account - assert_ok!(Identity::rename_sub(Origin::signed(10), 1, data(11))); + assert_ok!(Identity::rename_sub(RuntimeOrigin::signed(10), 1, data(11))); assert_eq!(SuperOf::::get(1), Some((10, data(11)))); assert_eq!(SuperOf::::get(2), Some((10, data(2)))); assert_eq!(Balances::free_balance(10), 70); // remove first sub account - assert_ok!(Identity::remove_sub(Origin::signed(10), 1)); + assert_ok!(Identity::remove_sub(RuntimeOrigin::signed(10), 1)); assert_eq!(SuperOf::::get(1), None); assert_eq!(SuperOf::::get(2), Some((10, data(2)))); assert_eq!(Balances::free_balance(10), 80); // add third sub account - assert_ok!(Identity::add_sub(Origin::signed(10), 3, data(3))); + assert_ok!(Identity::add_sub(RuntimeOrigin::signed(10), 3, data(3))); assert_eq!(SuperOf::::get(1), None); assert_eq!(SuperOf::::get(2), Some((10, data(2)))); assert_eq!(SuperOf::::get(3), Some((10, data(3)))); @@ -195,27 +198,27 @@ fn resolving_subaccount_ownership_works() { new_test_ext().execute_with(|| { let data = |x| Data::Raw(vec![x; 1].try_into().unwrap()); - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); - assert_ok!(Identity::set_identity(Origin::signed(20), Box::new(twenty()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(20), Box::new(twenty()))); // 10 claims 1 as a subaccount - assert_ok!(Identity::add_sub(Origin::signed(10), 1, data(1))); + assert_ok!(Identity::add_sub(RuntimeOrigin::signed(10), 1, data(1))); assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(10), 80); assert_eq!(Balances::reserved_balance(10), 20); // 20 cannot claim 1 now assert_noop!( - Identity::add_sub(Origin::signed(20), 1, data(1)), + Identity::add_sub(RuntimeOrigin::signed(20), 1, data(1)), Error::::AlreadyClaimed ); // 1 wants to be with 20 so it quits from 10 - assert_ok!(Identity::quit_sub(Origin::signed(1))); + assert_ok!(Identity::quit_sub(RuntimeOrigin::signed(1))); // 1 gets the 10 that 10 paid. assert_eq!(Balances::free_balance(1), 20); assert_eq!(Balances::free_balance(10), 80); assert_eq!(Balances::reserved_balance(10), 10); // 20 can claim 1 now - assert_ok!(Identity::add_sub(Origin::signed(20), 1, data(1))); + assert_ok!(Identity::add_sub(RuntimeOrigin::signed(20), 1, data(1))); }); } @@ -232,10 +235,10 @@ fn trailing_zeros_decodes_into_default_data() { #[test] fn adding_registrar_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); - assert_ok!(Identity::set_fee(Origin::signed(3), 0, 10)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); + assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10)); let fields = IdentityFields(IdentityField::Display | IdentityField::Legal); - assert_ok!(Identity::set_fields(Origin::signed(3), 0, fields)); + assert_ok!(Identity::set_fields(RuntimeOrigin::signed(3), 0, fields)); assert_eq!( Identity::registrars(), vec![Some(RegistrarInfo { account: 3, fee: 10, fields })] @@ -247,11 +250,11 @@ fn adding_registrar_should_work() { fn amount_of_registrars_is_limited() { new_test_ext().execute_with(|| { for i in 1..MaxRegistrars::get() + 1 { - assert_ok!(Identity::add_registrar(Origin::signed(1), i as u64)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), i as u64)); } let last_registrar = MaxRegistrars::get() as u64 + 1; assert_noop!( - Identity::add_registrar(Origin::signed(1), last_registrar), + Identity::add_registrar(RuntimeOrigin::signed(1), last_registrar), Error::::TooManyRegistrars ); }); @@ -260,18 +263,18 @@ fn amount_of_registrars_is_limited() { #[test] fn registration_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); - assert_ok!(Identity::set_fee(Origin::signed(3), 0, 10)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); + assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10)); let mut three_fields = ten(); three_fields.additional.try_push(Default::default()).unwrap(); three_fields.additional.try_push(Default::default()).unwrap(); - assert_eq!(three_fields.additional.try_push(Default::default()), Err(())); - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); + assert!(three_fields.additional.try_push(Default::default()).is_err()); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); assert_eq!(Identity::identity(10).unwrap().info, ten()); assert_eq!(Balances::free_balance(10), 90); - assert_ok!(Identity::clear_identity(Origin::signed(10))); + assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(10))); assert_eq!(Balances::free_balance(10), 100); - assert_noop!(Identity::clear_identity(Origin::signed(10)), Error::::NotNamed); + assert_noop!(Identity::clear_identity(RuntimeOrigin::signed(10)), Error::::NotNamed); }); } @@ -279,27 +282,70 @@ fn registration_should_work() { fn uninvited_judgement_should_work() { new_test_ext().execute_with(|| { assert_noop!( - Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::Reasonable), + Identity::provide_judgement( + RuntimeOrigin::signed(3), + 0, + 10, + Judgement::Reasonable, + H256::random() + ), Error::::InvalidIndex ); - assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); assert_noop!( - Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::Reasonable), + Identity::provide_judgement( + RuntimeOrigin::signed(3), + 0, + 10, + Judgement::Reasonable, + H256::random() + ), Error::::InvalidTarget ); - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + assert_noop!( + Identity::provide_judgement( + RuntimeOrigin::signed(3), + 0, + 10, + Judgement::Reasonable, + H256::random() + ), + Error::::JudgementForDifferentIdentity + ); + + let identity_hash = BlakeTwo256::hash_of(&ten()); + assert_noop!( - Identity::provide_judgement(Origin::signed(10), 0, 10, Judgement::Reasonable), + Identity::provide_judgement( + RuntimeOrigin::signed(10), + 0, + 10, + Judgement::Reasonable, + identity_hash + ), Error::::InvalidIndex ); assert_noop!( - Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::FeePaid(1)), + Identity::provide_judgement( + RuntimeOrigin::signed(3), + 0, + 10, + Judgement::FeePaid(1), + identity_hash + ), Error::::InvalidJudgement ); - assert_ok!(Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::Reasonable)); + assert_ok!(Identity::provide_judgement( + RuntimeOrigin::signed(3), + 0, + 10, + Judgement::Reasonable, + identity_hash + )); assert_eq!(Identity::identity(10).unwrap().judgements, vec![(0, Judgement::Reasonable)]); }); } @@ -307,10 +353,16 @@ fn uninvited_judgement_should_work() { #[test] fn clearing_judgement_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); - assert_ok!(Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::Reasonable)); - assert_ok!(Identity::clear_identity(Origin::signed(10))); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + assert_ok!(Identity::provide_judgement( + RuntimeOrigin::signed(3), + 0, + 10, + Judgement::Reasonable, + BlakeTwo256::hash_of(&ten()) + )); + assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(10))); assert_eq!(Identity::identity(10), None); }); } @@ -318,12 +370,15 @@ fn clearing_judgement_should_work() { #[test] fn killing_slashing_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); - assert_noop!(Identity::kill_identity(Origin::signed(1), 10), BadOrigin); - assert_ok!(Identity::kill_identity(Origin::signed(2), 10)); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + assert_noop!(Identity::kill_identity(RuntimeOrigin::signed(1), 10), BadOrigin); + assert_ok!(Identity::kill_identity(RuntimeOrigin::signed(2), 10)); assert_eq!(Identity::identity(10), None); assert_eq!(Balances::free_balance(10), 90); - assert_noop!(Identity::kill_identity(Origin::signed(2), 10), Error::::NotNamed); + assert_noop!( + Identity::kill_identity(RuntimeOrigin::signed(2), 10), + Error::::NotNamed + ); }); } @@ -331,17 +386,20 @@ fn killing_slashing_should_work() { fn setting_subaccounts_should_work() { new_test_ext().execute_with(|| { let mut subs = vec![(20, Data::Raw(vec![40; 1].try_into().unwrap()))]; - assert_noop!(Identity::set_subs(Origin::signed(10), subs.clone()), Error::::NotFound); + assert_noop!( + Identity::set_subs(RuntimeOrigin::signed(10), subs.clone()), + Error::::NotFound + ); - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); - assert_ok!(Identity::set_subs(Origin::signed(10), subs.clone())); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + assert_ok!(Identity::set_subs(RuntimeOrigin::signed(10), subs.clone())); assert_eq!(Balances::free_balance(10), 80); assert_eq!(Identity::subs_of(10), (10, vec![20].try_into().unwrap())); assert_eq!(Identity::super_of(20), Some((10, Data::Raw(vec![40; 1].try_into().unwrap())))); // push another item and re-set it. subs.push((30, Data::Raw(vec![50; 1].try_into().unwrap()))); - assert_ok!(Identity::set_subs(Origin::signed(10), subs.clone())); + assert_ok!(Identity::set_subs(RuntimeOrigin::signed(10), subs.clone())); assert_eq!(Balances::free_balance(10), 70); assert_eq!(Identity::subs_of(10), (20, vec![20, 30].try_into().unwrap())); assert_eq!(Identity::super_of(20), Some((10, Data::Raw(vec![40; 1].try_into().unwrap())))); @@ -349,7 +407,7 @@ fn setting_subaccounts_should_work() { // switch out one of the items and re-set. subs[0] = (40, Data::Raw(vec![60; 1].try_into().unwrap())); - assert_ok!(Identity::set_subs(Origin::signed(10), subs.clone())); + assert_ok!(Identity::set_subs(RuntimeOrigin::signed(10), subs.clone())); assert_eq!(Balances::free_balance(10), 70); // no change in the balance assert_eq!(Identity::subs_of(10), (20, vec![40, 30].try_into().unwrap())); assert_eq!(Identity::super_of(20), None); @@ -357,7 +415,7 @@ fn setting_subaccounts_should_work() { assert_eq!(Identity::super_of(40), Some((10, Data::Raw(vec![60; 1].try_into().unwrap())))); // clear - assert_ok!(Identity::set_subs(Origin::signed(10), vec![])); + assert_ok!(Identity::set_subs(RuntimeOrigin::signed(10), vec![])); assert_eq!(Balances::free_balance(10), 90); assert_eq!(Identity::subs_of(10), (0, BoundedVec::default())); assert_eq!(Identity::super_of(30), None); @@ -365,7 +423,7 @@ fn setting_subaccounts_should_work() { subs.push((20, Data::Raw(vec![40; 1].try_into().unwrap()))); assert_noop!( - Identity::set_subs(Origin::signed(10), subs.clone()), + Identity::set_subs(RuntimeOrigin::signed(10), subs.clone()), Error::::TooManySubAccounts ); }); @@ -374,12 +432,12 @@ fn setting_subaccounts_should_work() { #[test] fn clearing_account_should_remove_subaccounts_and_refund() { new_test_ext().execute_with(|| { - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); assert_ok!(Identity::set_subs( - Origin::signed(10), + RuntimeOrigin::signed(10), vec![(20, Data::Raw(vec![40; 1].try_into().unwrap()))] )); - assert_ok!(Identity::clear_identity(Origin::signed(10))); + assert_ok!(Identity::clear_identity(RuntimeOrigin::signed(10))); assert_eq!(Balances::free_balance(10), 100); assert!(Identity::super_of(20).is_none()); }); @@ -388,12 +446,12 @@ fn clearing_account_should_remove_subaccounts_and_refund() { #[test] fn killing_account_should_remove_subaccounts_and_not_refund() { new_test_ext().execute_with(|| { - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); assert_ok!(Identity::set_subs( - Origin::signed(10), + RuntimeOrigin::signed(10), vec![(20, Data::Raw(vec![40; 1].try_into().unwrap()))] )); - assert_ok!(Identity::kill_identity(Origin::signed(2), 10)); + assert_ok!(Identity::kill_identity(RuntimeOrigin::signed(2), 10)); assert_eq!(Balances::free_balance(10), 80); assert!(Identity::super_of(20).is_none()); }); @@ -402,18 +460,30 @@ fn killing_account_should_remove_subaccounts_and_not_refund() { #[test] fn cancelling_requested_judgement_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); - assert_ok!(Identity::set_fee(Origin::signed(3), 0, 10)); - assert_noop!(Identity::cancel_request(Origin::signed(10), 0), Error::::NoIdentity); - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); - assert_ok!(Identity::request_judgement(Origin::signed(10), 0, 10)); - assert_ok!(Identity::cancel_request(Origin::signed(10), 0)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); + assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10)); + assert_noop!( + Identity::cancel_request(RuntimeOrigin::signed(10), 0), + Error::::NoIdentity + ); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); + assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10)); + assert_ok!(Identity::cancel_request(RuntimeOrigin::signed(10), 0)); assert_eq!(Balances::free_balance(10), 90); - assert_noop!(Identity::cancel_request(Origin::signed(10), 0), Error::::NotFound); + assert_noop!( + Identity::cancel_request(RuntimeOrigin::signed(10), 0), + Error::::NotFound + ); - assert_ok!(Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::Reasonable)); + assert_ok!(Identity::provide_judgement( + RuntimeOrigin::signed(3), + 0, + 10, + Judgement::Reasonable, + BlakeTwo256::hash_of(&ten()) + )); assert_noop!( - Identity::cancel_request(Origin::signed(10), 0), + Identity::cancel_request(RuntimeOrigin::signed(10), 0), Error::::JudgementGiven ); }); @@ -422,49 +492,61 @@ fn cancelling_requested_judgement_should_work() { #[test] fn requesting_judgement_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); - assert_ok!(Identity::set_fee(Origin::signed(3), 0, 10)); - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); + assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10)); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); assert_noop!( - Identity::request_judgement(Origin::signed(10), 0, 9), + Identity::request_judgement(RuntimeOrigin::signed(10), 0, 9), Error::::FeeChanged ); - assert_ok!(Identity::request_judgement(Origin::signed(10), 0, 10)); + assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10)); // 10 for the judgement request, 10 for the identity. assert_eq!(Balances::free_balance(10), 80); // Re-requesting won't work as we already paid. assert_noop!( - Identity::request_judgement(Origin::signed(10), 0, 10), + Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10), Error::::StickyJudgement ); - assert_ok!(Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::Erroneous)); + assert_ok!(Identity::provide_judgement( + RuntimeOrigin::signed(3), + 0, + 10, + Judgement::Erroneous, + BlakeTwo256::hash_of(&ten()) + )); // Registrar got their payment now. assert_eq!(Balances::free_balance(3), 20); // Re-requesting still won't work as it's erroneous. assert_noop!( - Identity::request_judgement(Origin::signed(10), 0, 10), + Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10), Error::::StickyJudgement ); // Requesting from a second registrar still works. - assert_ok!(Identity::add_registrar(Origin::signed(1), 4)); - assert_ok!(Identity::request_judgement(Origin::signed(10), 1, 10)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 4)); + assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 1, 10)); // Re-requesting after the judgement has been reduced works. - assert_ok!(Identity::provide_judgement(Origin::signed(3), 0, 10, Judgement::OutOfDate)); - assert_ok!(Identity::request_judgement(Origin::signed(10), 0, 10)); + assert_ok!(Identity::provide_judgement( + RuntimeOrigin::signed(3), + 0, + 10, + Judgement::OutOfDate, + BlakeTwo256::hash_of(&ten()) + )); + assert_ok!(Identity::request_judgement(RuntimeOrigin::signed(10), 0, 10)); }); } #[test] fn field_deposit_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); - assert_ok!(Identity::set_fee(Origin::signed(3), 0, 10)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); + assert_ok!(Identity::set_fee(RuntimeOrigin::signed(3), 0, 10)); assert_ok!(Identity::set_identity( - Origin::signed(10), + RuntimeOrigin::signed(10), Box::new(IdentityInfo { additional: vec![ ( @@ -488,23 +570,23 @@ fn field_deposit_should_work() { #[test] fn setting_account_id_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Identity::add_registrar(Origin::signed(1), 3)); + assert_ok!(Identity::add_registrar(RuntimeOrigin::signed(1), 3)); // account 4 cannot change the first registrar's identity since it's owned by 3. assert_noop!( - Identity::set_account_id(Origin::signed(4), 0, 3), + Identity::set_account_id(RuntimeOrigin::signed(4), 0, 3), Error::::InvalidIndex ); // account 3 can, because that's the registrar's current account. - assert_ok!(Identity::set_account_id(Origin::signed(3), 0, 4)); + assert_ok!(Identity::set_account_id(RuntimeOrigin::signed(3), 0, 4)); // account 4 can now, because that's their new ID. - assert_ok!(Identity::set_account_id(Origin::signed(4), 0, 3)); + assert_ok!(Identity::set_account_id(RuntimeOrigin::signed(4), 0, 3)); }); } #[test] fn test_has_identity() { new_test_ext().execute_with(|| { - assert_ok!(Identity::set_identity(Origin::signed(10), Box::new(ten()))); + assert_ok!(Identity::set_identity(RuntimeOrigin::signed(10), Box::new(ten()))); assert!(Identity::has_identity(&10, IdentityField::Display as u64)); assert!(Identity::has_identity(&10, IdentityField::Legal as u64)); assert!(Identity::has_identity( diff --git a/frame/im-online/Cargo.toml b/frame/im-online/Cargo.toml index a90b95b21cd88..8c08ad1a8a89a 100644 --- a/frame/im-online/Cargo.toml +++ b/frame/im-online/Cargo.toml @@ -33,6 +33,7 @@ pallet-session = { version = "4.0.0-dev", path = "../session" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/im-online/src/lib.rs b/frame/im-online/src/lib.rs index 34c1c70d79f75..342522ff29b19 100644 --- a/frame/im-online/src/lib.rs +++ b/frame/im-online/src/lib.rs @@ -337,7 +337,7 @@ pub mod pallet { type MaxPeerDataEncodingSize: Get; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// A type for retrieving the validators supposed to be online in a session. type ValidatorSet: ValidatorSetWithIdentification; diff --git a/frame/im-online/src/mock.rs b/frame/im-online/src/mock.rs index b734bd37b6fd4..5782e1a615b8e 100644 --- a/frame/im-online/src/mock.rs +++ b/frame/im-online/src/mock.rs @@ -19,8 +19,6 @@ #![cfg(test)] -use std::cell::RefCell; - use frame_support::{ parameter_types, traits::{ConstU32, ConstU64}, @@ -57,18 +55,18 @@ frame_support::construct_runtime!( } ); -thread_local! { - pub static VALIDATORS: RefCell>> = RefCell::new(Some(vec![ +parameter_types! { + pub static Validators: Option> = Some(vec![ 1, 2, 3, - ])); + ]); } pub struct TestSessionManager; impl pallet_session::SessionManager for TestSessionManager { fn new_session(_new_index: SessionIndex) -> Option> { - VALIDATORS.with(|l| l.borrow_mut().take()) + Validators::mutate(|l| l.take()) } fn end_session(_: SessionIndex) {} fn start_session(_: SessionIndex) {} @@ -76,10 +74,8 @@ impl pallet_session::SessionManager for TestSessionManager { impl pallet_session::historical::SessionManager for TestSessionManager { fn new_session(_new_index: SessionIndex) -> Option> { - VALIDATORS.with(|l| { - l.borrow_mut() - .take() - .map(|validators| validators.iter().map(|v| (*v, *v)).collect()) + Validators::mutate(|l| { + l.take().map(|validators| validators.iter().map(|v| (*v, *v)).collect()) }) } fn end_session(_: SessionIndex) {} @@ -87,19 +83,19 @@ impl pallet_session::historical::SessionManager for TestSessionManager } /// An extrinsic type used for tests. -pub type Extrinsic = TestXt; +pub type Extrinsic = TestXt; type IdentificationTuple = (u64, u64); type Offence = crate::UnresponsivenessOffence; -thread_local! { - pub static OFFENCES: RefCell, Offence)>> = RefCell::new(vec![]); +parameter_types! { + pub static Offences: Vec<(Vec, Offence)> = vec![]; } /// A mock offence report handler. pub struct OffenceHandler; impl ReportOffence for OffenceHandler { fn report_offence(reporters: Vec, offence: Offence) -> Result<(), OffenceError> { - OFFENCES.with(|l| l.borrow_mut().push((reporters, offence))); + Offences::mutate(|l| l.push((reporters, offence))); Ok(()) } @@ -115,7 +111,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { result.execute_with(|| { for i in 1..=6 { System::inc_providers(&i); - assert_eq!(Session::set_keys(Origin::signed(i), (i - 1).into(), vec![]), Ok(())); + assert_eq!(Session::set_keys(RuntimeOrigin::signed(i), (i - 1).into(), vec![]), Ok(())); } }); result @@ -131,16 +127,16 @@ impl frame_system::Config for Runtime { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -166,7 +162,7 @@ impl pallet_session::Config for Runtime { type ValidatorId = u64; type ValidatorIdOf = ConvertInto; type Keys = UintAuthorityId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type NextSessionRotation = pallet_session::PeriodicSessions; type WeightInfo = (); } @@ -183,12 +179,12 @@ impl pallet_authorship::Config for Runtime { type EventHandler = ImOnline; } -thread_local! { - pub static MOCK_CURRENT_SESSION_PROGRESS: RefCell>> = RefCell::new(None); +parameter_types! { + pub static MockCurrentSessionProgress: Option> = None; } -thread_local! { - pub static MOCK_AVERAGE_SESSION_LENGTH: RefCell> = RefCell::new(None); +parameter_types! { + pub static MockAverageSessionLength: Option = None; } pub struct TestNextSessionRotation; @@ -196,7 +192,7 @@ pub struct TestNextSessionRotation; impl frame_support::traits::EstimateNextSessionRotation for TestNextSessionRotation { fn average_session_length() -> u64 { // take the mock result if any and return it - let mock = MOCK_AVERAGE_SESSION_LENGTH.with(|p| p.borrow_mut().take()); + let mock = MockAverageSessionLength::mutate(|p| p.take()); mock.unwrap_or(pallet_session::PeriodicSessions::::average_session_length()) } @@ -208,7 +204,7 @@ impl frame_support::traits::EstimateNextSessionRotation for TestNextSession ); // take the mock result if any and return it - let mock = MOCK_CURRENT_SESSION_PROGRESS.with(|p| p.borrow_mut().take()); + let mock = MockCurrentSessionProgress::mutate(|p| p.take()); (mock.unwrap_or(estimate), weight) } @@ -220,7 +216,7 @@ impl frame_support::traits::EstimateNextSessionRotation for TestNextSession impl Config for Runtime { type AuthorityId = UintAuthorityId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorSet = Historical; type NextSessionRotation = TestNextSessionRotation; type ReportUnresponsiveness = OffenceHandler; @@ -233,9 +229,9 @@ impl Config for Runtime { impl frame_system::offchain::SendTransactionTypes for Runtime where - Call: From, + RuntimeCall: From, { - type OverarchingCall = Call; + type OverarchingCall = RuntimeCall; type Extrinsic = Extrinsic; } diff --git a/frame/im-online/src/tests.rs b/frame/im-online/src/tests.rs index 05e1af169dba9..366119278d836 100644 --- a/frame/im-online/src/tests.rs +++ b/frame/im-online/src/tests.rs @@ -68,7 +68,7 @@ fn should_report_offline_validators() { advance_session(); // enact the change and buffer another one let validators = vec![1, 2, 3, 4, 5, 6]; - VALIDATORS.with(|l| *l.borrow_mut() = Some(validators.clone())); + Validators::mutate(|l| *l = Some(validators.clone())); advance_session(); // when @@ -76,7 +76,7 @@ fn should_report_offline_validators() { advance_session(); // then - let offences = OFFENCES.with(|l| l.replace(vec![])); + let offences = Offences::take(); assert_eq!( offences, vec![( @@ -96,7 +96,7 @@ fn should_report_offline_validators() { advance_session(); // then - let offences = OFFENCES.with(|l| l.replace(vec![])); + let offences = Offences::take(); assert_eq!( offences, vec![( @@ -141,7 +141,7 @@ fn heartbeat( "invalid validators len", e @ _ => <&'static str>::from(e), })?; - ImOnline::heartbeat(Origin::none(), heartbeat, signature) + ImOnline::heartbeat(RuntimeOrigin::none(), heartbeat, signature) } #[test] @@ -149,7 +149,7 @@ fn should_mark_online_validator_when_heartbeat_is_received() { new_test_ext().execute_with(|| { advance_session(); // given - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); + Validators::mutate(|l| *l = Some(vec![1, 2, 3, 4, 5, 6])); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one advance_session(); @@ -184,7 +184,7 @@ fn late_heartbeat_and_invalid_keys_len_should_fail() { new_test_ext().execute_with(|| { advance_session(); // given - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); + Validators::mutate(|l| *l = Some(vec![1, 2, 3, 4, 5, 6])); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one advance_session(); @@ -226,7 +226,7 @@ fn should_generate_heartbeats() { // buffer new validators Session::rotate_session(); // enact the change and buffer another one - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); + Validators::mutate(|l| *l = Some(vec![1, 2, 3, 4, 5, 6])); Session::rotate_session(); // when @@ -240,7 +240,8 @@ fn should_generate_heartbeats() { // check stuff about the transaction. let ex: Extrinsic = Decode::decode(&mut &*transaction).unwrap(); let heartbeat = match ex.call { - crate::mock::Call::ImOnline(crate::Call::heartbeat { heartbeat, .. }) => heartbeat, + crate::mock::RuntimeCall::ImOnline(crate::Call::heartbeat { heartbeat, .. }) => + heartbeat, e => panic!("Unexpected call: {:?}", e), }; @@ -262,7 +263,7 @@ fn should_cleanup_received_heartbeats_on_session_end() { new_test_ext().execute_with(|| { advance_session(); - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3])); + Validators::mutate(|l| *l = Some(vec![1, 2, 3])); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one @@ -293,7 +294,7 @@ fn should_mark_online_validator_when_block_is_authored() { new_test_ext().execute_with(|| { advance_session(); // given - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); + Validators::mutate(|l| *l = Some(vec![1, 2, 3, 4, 5, 6])); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one advance_session(); @@ -330,7 +331,7 @@ fn should_not_send_a_report_if_already_online() { ext.execute_with(|| { advance_session(); // given - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![1, 2, 3, 4, 5, 6])); + Validators::mutate(|l| *l = Some(vec![1, 2, 3, 4, 5, 6])); assert_eq!(Session::validators(), Vec::::new()); // enact the change and buffer another one advance_session(); @@ -355,7 +356,8 @@ fn should_not_send_a_report_if_already_online() { // check stuff about the transaction. let ex: Extrinsic = Decode::decode(&mut &*transaction).unwrap(); let heartbeat = match ex.call { - crate::mock::Call::ImOnline(crate::Call::heartbeat { heartbeat, .. }) => heartbeat, + crate::mock::RuntimeCall::ImOnline(crate::Call::heartbeat { heartbeat, .. }) => + heartbeat, e => panic!("Unexpected call: {:?}", e), }; @@ -393,12 +395,12 @@ fn should_handle_missing_progress_estimates() { Session::rotate_session(); // enact the change and buffer another one - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![0, 1, 2])); + Validators::mutate(|l| *l = Some(vec![0, 1, 2])); Session::rotate_session(); // we will return `None` on the next call to `estimate_current_session_progress` // and the offchain worker should fallback to checking `HeartbeatAfter` - MOCK_CURRENT_SESSION_PROGRESS.with(|p| *p.borrow_mut() = Some(None)); + MockCurrentSessionProgress::mutate(|p| *p = Some(None)); ImOnline::offchain_worker(block); assert_eq!(state.read().transactions.len(), 3); @@ -427,26 +429,25 @@ fn should_handle_non_linear_session_progress() { // mock the session length as being 10 blocks long, // enact the change and buffer another one - VALIDATORS.with(|l| *l.borrow_mut() = Some(vec![0, 1, 2])); + Validators::mutate(|l| *l = Some(vec![0, 1, 2])); // mock the session length has being 10 which should make us assume the fallback for half // session will be reached by block 5. - MOCK_AVERAGE_SESSION_LENGTH.with(|p| *p.borrow_mut() = Some(10)); + MockAverageSessionLength::mutate(|p| *p = Some(10)); Session::rotate_session(); // if we don't have valid results for the current session progres then // we'll fallback to `HeartbeatAfter` and only heartbeat on block 5. - MOCK_CURRENT_SESSION_PROGRESS.with(|p| *p.borrow_mut() = Some(None)); + MockCurrentSessionProgress::mutate(|p| *p = Some(None)); assert_eq!(ImOnline::send_heartbeats(2).err(), Some(OffchainErr::TooEarly)); - MOCK_CURRENT_SESSION_PROGRESS.with(|p| *p.borrow_mut() = Some(None)); + MockCurrentSessionProgress::mutate(|p| *p = Some(None)); assert!(ImOnline::send_heartbeats(5).ok().is_some()); // if we have a valid current session progress then we'll heartbeat as soon // as we're past 80% of the session regardless of the block number - MOCK_CURRENT_SESSION_PROGRESS - .with(|p| *p.borrow_mut() = Some(Some(Permill::from_percent(81)))); + MockCurrentSessionProgress::mutate(|p| *p = Some(Some(Permill::from_percent(81)))); assert!(ImOnline::send_heartbeats(2).ok().is_some()); }); @@ -464,8 +465,7 @@ fn test_does_not_heartbeat_early_in_the_session() { ext.execute_with(|| { // mock current session progress as being 5%. we only randomly start // heartbeating after 10% of the session has elapsed. - MOCK_CURRENT_SESSION_PROGRESS - .with(|p| *p.borrow_mut() = Some(Some(Permill::from_float(0.05)))); + MockCurrentSessionProgress::mutate(|p| *p = Some(Some(Permill::from_float(0.05)))); assert_eq!(ImOnline::send_heartbeats(2).err(), Some(OffchainErr::TooEarly)); }); } @@ -483,9 +483,8 @@ fn test_probability_of_heartbeating_increases_with_session_progress() { let set_test = |progress, random: f64| { // the average session length is 100 blocks, therefore the residual // probability of sending a heartbeat is 1% - MOCK_AVERAGE_SESSION_LENGTH.with(|p| *p.borrow_mut() = Some(100)); - MOCK_CURRENT_SESSION_PROGRESS - .with(|p| *p.borrow_mut() = Some(Some(Permill::from_float(progress)))); + MockAverageSessionLength::mutate(|p| *p = Some(100)); + MockCurrentSessionProgress::mutate(|p| *p = Some(Some(Permill::from_float(progress)))); let mut seed = [0u8; 32]; let encoded = ((random * Permill::ACCURACY as f64) as u32).encode(); diff --git a/frame/indices/Cargo.toml b/frame/indices/Cargo.toml index 90eb18a106000..adc3f2a6ea90f 100644 --- a/frame/indices/Cargo.toml +++ b/frame/indices/Cargo.toml @@ -30,6 +30,7 @@ pallet-balances = { version = "4.0.0-dev", path = "../balances" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/indices/src/lib.rs b/frame/indices/src/lib.rs index 49380f18e24db..41893254c3c97 100644 --- a/frame/indices/src/lib.rs +++ b/frame/indices/src/lib.rs @@ -68,7 +68,7 @@ pub mod pallet { type Deposit: Get>; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; diff --git a/frame/indices/src/mock.rs b/frame/indices/src/mock.rs index 693296a3b1064..fd2e9fff16885 100644 --- a/frame/indices/src/mock.rs +++ b/frame/indices/src/mock.rs @@ -52,8 +52,8 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -61,7 +61,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = Indices; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -80,7 +80,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); @@ -90,7 +90,7 @@ impl Config for Test { type AccountIndex = u64; type Currency = Balances; type Deposit = ConstU64<1>; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } diff --git a/frame/indices/src/tests.rs b/frame/indices/src/tests.rs index 4e6c59703ca36..bed6cfffaa825 100644 --- a/frame/indices/src/tests.rs +++ b/frame/indices/src/tests.rs @@ -104,7 +104,7 @@ fn transfer_index_on_accounts_should_work() { fn force_transfer_index_on_preowned_should_work() { new_test_ext().execute_with(|| { assert_ok!(Indices::claim(Some(1).into(), 0)); - assert_ok!(Indices::force_transfer(Origin::root(), Id(3), 0, false)); + assert_ok!(Indices::force_transfer(RuntimeOrigin::root(), Id(3), 0, false)); assert_eq!(Balances::reserved_balance(1), 0); assert_eq!(Balances::reserved_balance(3), 0); assert_eq!(Indices::lookup_index(0), Some(3)); @@ -114,7 +114,7 @@ fn force_transfer_index_on_preowned_should_work() { #[test] fn force_transfer_index_on_free_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Indices::force_transfer(Origin::root(), Id(3), 0, false)); + assert_ok!(Indices::force_transfer(RuntimeOrigin::root(), Id(3), 0, false)); assert_eq!(Balances::reserved_balance(3), 0); assert_eq!(Indices::lookup_index(0), Some(3)); }); diff --git a/frame/lottery/Cargo.toml b/frame/lottery/Cargo.toml index 8f7c8eefe800d..486bb356059f6 100644 --- a/frame/lottery/Cargo.toml +++ b/frame/lottery/Cargo.toml @@ -32,6 +32,7 @@ sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/lottery/src/benchmarking.rs b/frame/lottery/src/benchmarking.rs index 1c850e66f9c6e..fba722a07fabd 100644 --- a/frame/lottery/src/benchmarking.rs +++ b/frame/lottery/src/benchmarking.rs @@ -78,7 +78,7 @@ benchmarks! { let calls = vec![frame_system::Call::::remark { remark: vec![] }.into(); n as usize]; let origin = T::ManagerOrigin::successful_origin(); assert!(CallIndices::::get().is_empty()); - }: _(origin, calls) + }: _(origin, calls) verify { if !n.is_zero() { assert!(!CallIndices::::get().is_empty()); @@ -90,7 +90,7 @@ benchmarks! { let end = 10u32.into(); let payout = 5u32.into(); let origin = T::ManagerOrigin::successful_origin(); - }: _(origin, price, end, payout, true) + }: _(origin, price, end, payout, true) verify { assert!(crate::Lottery::::get().is_some()); } @@ -99,7 +99,7 @@ benchmarks! { setup_lottery::(true)?; assert_eq!(crate::Lottery::::get().unwrap().repeat, true); let origin = T::ManagerOrigin::successful_origin(); - }: _(origin) + }: _(origin) verify { assert_eq!(crate::Lottery::::get().unwrap().repeat, false); } diff --git a/frame/lottery/src/lib.rs b/frame/lottery/src/lib.rs index 02df65a3336bf..c501a30ef5f4a 100644 --- a/frame/lottery/src/lib.rs +++ b/frame/lottery/src/lib.rs @@ -96,17 +96,17 @@ pub struct LotteryConfig { } pub trait ValidateCall { - fn validate_call(call: &::Call) -> bool; + fn validate_call(call: &::RuntimeCall) -> bool; } impl ValidateCall for () { - fn validate_call(_: &::Call) -> bool { + fn validate_call(_: &::RuntimeCall) -> bool { false } } impl ValidateCall for Pallet { - fn validate_call(call: &::Call) -> bool { + fn validate_call(call: &::RuntimeCall) -> bool { let valid_calls = CallIndices::::get(); let call_index = match Self::call_to_index(call) { Ok(call_index) => call_index, @@ -134,8 +134,8 @@ pub mod pallet { type PalletId: Get; /// A dispatchable call. - type Call: Parameter - + Dispatchable + type RuntimeCall: Parameter + + Dispatchable + GetDispatchInfo + From>; @@ -146,10 +146,10 @@ pub mod pallet { type Randomness: Randomness; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The manager origin. - type ManagerOrigin: EnsureOrigin; + type ManagerOrigin: EnsureOrigin; /// The max number of calls available in a single lottery. #[pallet::constant] @@ -300,7 +300,10 @@ pub mod pallet { T::WeightInfo::buy_ticket() .saturating_add(call.get_dispatch_info().weight) )] - pub fn buy_ticket(origin: OriginFor, call: Box<::Call>) -> DispatchResult { + pub fn buy_ticket( + origin: OriginFor, + call: Box<::RuntimeCall>, + ) -> DispatchResult { let caller = ensure_signed(origin.clone())?; call.clone().dispatch(origin).map_err(|e| e.error)?; @@ -315,7 +318,10 @@ pub mod pallet { /// /// This extrinsic must be called by the Manager origin. #[pallet::weight(T::WeightInfo::set_calls(calls.len() as u32))] - pub fn set_calls(origin: OriginFor, calls: Vec<::Call>) -> DispatchResult { + pub fn set_calls( + origin: OriginFor, + calls: Vec<::RuntimeCall>, + ) -> DispatchResult { T::ManagerOrigin::ensure_origin(origin)?; ensure!(calls.len() <= T::MaxCalls::get() as usize, Error::::TooManyCalls); if calls.is_empty() { @@ -404,7 +410,7 @@ impl Pallet { /// Converts a vector of calls into a vector of call indices. fn calls_to_indices( - calls: &[::Call], + calls: &[::RuntimeCall], ) -> Result, DispatchError> { let mut indices = BoundedVec::::with_bounded_capacity(calls.len()); for c in calls.iter() { @@ -415,7 +421,7 @@ impl Pallet { } /// Convert a call to it's call index by encoding the call and taking the first two bytes. - fn call_to_index(call: &::Call) -> Result { + fn call_to_index(call: &::RuntimeCall) -> Result { let encoded_call = call.encode(); if encoded_call.len() < 2 { return Err(Error::::EncodingFailed.into()) @@ -424,7 +430,7 @@ impl Pallet { } /// Logic for buying a ticket. - fn do_buy_ticket(caller: &T::AccountId, call: &::Call) -> DispatchResult { + fn do_buy_ticket(caller: &T::AccountId, call: &::RuntimeCall) -> DispatchResult { // Check the call is valid lottery let config = Lottery::::get().ok_or(Error::::NotConfigured)?; let block_number = frame_system::Pallet::::block_number(); diff --git a/frame/lottery/src/mock.rs b/frame/lottery/src/mock.rs index 592551fb6b93f..1977da5959d39 100644 --- a/frame/lottery/src/mock.rs +++ b/frame/lottery/src/mock.rs @@ -57,16 +57,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type BlockNumber = u64; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -84,7 +84,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -97,10 +97,10 @@ parameter_types! { impl Config for Test { type PalletId = LotteryPalletId; - type Call = Call; + type RuntimeCall = RuntimeCall; type Currency = Balances; type Randomness = TestRandomness; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ManagerOrigin = EnsureRoot; type MaxCalls = ConstU32<2>; type ValidateCall = Lottery; diff --git a/frame/lottery/src/tests.rs b/frame/lottery/src/tests.rs index d8dd6e4b7fe6c..0eaf080564008 100644 --- a/frame/lottery/src/tests.rs +++ b/frame/lottery/src/tests.rs @@ -20,7 +20,8 @@ use super::*; use frame_support::{assert_noop, assert_ok, assert_storage_noop}; use mock::{ - new_test_ext, run_to_block, Balances, BalancesCall, Call, Lottery, Origin, SystemCall, Test, + new_test_ext, run_to_block, Balances, BalancesCall, Lottery, RuntimeCall, RuntimeOrigin, + SystemCall, Test, }; use pallet_balances::Error as BalancesError; use sp_runtime::traits::BadOrigin; @@ -43,20 +44,20 @@ fn basic_end_to_end_works() { let length = 20; let delay = 5; let calls = vec![ - Call::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - Call::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), ]; // Set calls for the lottery - assert_ok!(Lottery::set_calls(Origin::root(), calls)); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls)); // Start lottery, it repeats - assert_ok!(Lottery::start_lottery(Origin::root(), price, length, delay, true)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), price, length, delay, true)); assert!(crate::Lottery::::get().is_some()); assert_eq!(Balances::free_balance(&1), 100); - let call = Box::new(Call::Balances(BalancesCall::transfer { dest: 2, value: 20 })); - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call.clone())); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 20 })); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone())); // 20 from the transfer, 10 from buying a ticket assert_eq!(Balances::free_balance(&1), 100 - 20 - 10); assert_eq!(Participants::::get(&1).1.len(), 1); @@ -65,14 +66,14 @@ fn basic_end_to_end_works() { assert_eq!(Tickets::::get(0), Some(1)); // More ticket purchases - assert_ok!(Lottery::buy_ticket(Origin::signed(2), call.clone())); - assert_ok!(Lottery::buy_ticket(Origin::signed(3), call.clone())); - assert_ok!(Lottery::buy_ticket(Origin::signed(4), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(2), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(3), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(4), call.clone())); assert_eq!(TicketsCount::::get(), 4); // Go to end run_to_block(20); - assert_ok!(Lottery::buy_ticket(Origin::signed(5), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(5), call.clone())); // Ticket isn't bought assert_eq!(TicketsCount::::get(), 4); @@ -99,15 +100,15 @@ fn stop_repeat_works() { let delay = 5; // Set no calls for the lottery. - assert_ok!(Lottery::set_calls(Origin::root(), vec![])); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), vec![])); // Start lottery, it repeats. - assert_ok!(Lottery::start_lottery(Origin::root(), price, length, delay, true)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), price, length, delay, true)); // Non-manager fails to `stop_repeat`. - assert_noop!(Lottery::stop_repeat(Origin::signed(1)), DispatchError::BadOrigin); + assert_noop!(Lottery::stop_repeat(RuntimeOrigin::signed(1)), DispatchError::BadOrigin); // Manager can `stop_repeat`, even twice. - assert_ok!(Lottery::stop_repeat(Origin::root())); - assert_ok!(Lottery::stop_repeat(Origin::root())); + assert_ok!(Lottery::stop_repeat(RuntimeOrigin::root())); + assert_ok!(Lottery::stop_repeat(RuntimeOrigin::root())); // Lottery still exists. assert!(crate::Lottery::::get().is_some()); @@ -127,26 +128,26 @@ fn set_calls_works() { assert!(!CallIndices::::exists()); let calls = vec![ - Call::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - Call::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), ]; - assert_ok!(Lottery::set_calls(Origin::root(), calls)); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls)); assert!(CallIndices::::exists()); let too_many_calls = vec![ - Call::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - Call::Balances(BalancesCall::transfer { dest: 0, value: 0 }), - Call::System(SystemCall::remark { remark: vec![] }), + RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::System(SystemCall::remark { remark: vec![] }), ]; assert_noop!( - Lottery::set_calls(Origin::root(), too_many_calls), + Lottery::set_calls(RuntimeOrigin::root(), too_many_calls), Error::::TooManyCalls, ); // Clear calls - assert_ok!(Lottery::set_calls(Origin::root(), vec![])); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), vec![])); assert!(CallIndices::::get().is_empty()); }); } @@ -155,8 +156,8 @@ fn set_calls_works() { fn call_to_indices_works() { new_test_ext().execute_with(|| { let calls = vec![ - Call::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - Call::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), ]; let indices = Lottery::calls_to_indices(&calls).unwrap().into_inner(); // Only comparing the length since it is otherwise dependant on the API @@ -164,9 +165,9 @@ fn call_to_indices_works() { assert_eq!(indices.len(), calls.len()); let too_many_calls = vec![ - Call::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - Call::Balances(BalancesCall::transfer { dest: 0, value: 0 }), - Call::System(SystemCall::remark { remark: vec![] }), + RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::System(SystemCall::remark { remark: vec![] }), ]; assert_noop!(Lottery::calls_to_indices(&too_many_calls), Error::::TooManyCalls); }); @@ -181,16 +182,16 @@ fn start_lottery_works() { // Setup ignores bad origin assert_noop!( - Lottery::start_lottery(Origin::signed(1), price, length, delay, false), + Lottery::start_lottery(RuntimeOrigin::signed(1), price, length, delay, false), BadOrigin, ); // All good - assert_ok!(Lottery::start_lottery(Origin::root(), price, length, delay, false)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), price, length, delay, false)); // Can't open another one if lottery is already present assert_noop!( - Lottery::start_lottery(Origin::root(), price, length, delay, false), + Lottery::start_lottery(RuntimeOrigin::root(), price, length, delay, false), Error::::InProgress, ); }); @@ -202,45 +203,49 @@ fn buy_ticket_works_as_simple_passthrough() { // as a simple passthrough to the real call. new_test_ext().execute_with(|| { // No lottery set up - let call = Box::new(Call::Balances(BalancesCall::transfer { dest: 2, value: 20 })); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 20 })); // This is just a basic transfer then - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone())); assert_eq!(Balances::free_balance(&1), 100 - 20); assert_eq!(TicketsCount::::get(), 0); // Lottery is set up, but too expensive to enter, so `do_buy_ticket` fails. let calls = vec![ - Call::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), - Call::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), ]; - assert_ok!(Lottery::set_calls(Origin::root(), calls)); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls)); // Ticket price of 60 would kill the user's account - assert_ok!(Lottery::start_lottery(Origin::root(), 60, 10, 5, false)); - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call.clone())); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 60, 10, 5, false)); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone())); assert_eq!(Balances::free_balance(&1), 100 - 20 - 20); assert_eq!(TicketsCount::::get(), 0); // If call would fail, the whole thing still fails the same - let fail_call = Box::new(Call::Balances(BalancesCall::transfer { dest: 2, value: 1000 })); + let fail_call = + Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 1000 })); assert_noop!( - Lottery::buy_ticket(Origin::signed(1), fail_call), + Lottery::buy_ticket(RuntimeOrigin::signed(1), fail_call), BalancesError::::InsufficientBalance, ); - let bad_origin_call = - Box::new(Call::Balances(BalancesCall::force_transfer { source: 0, dest: 0, value: 0 })); - assert_noop!(Lottery::buy_ticket(Origin::signed(1), bad_origin_call), BadOrigin,); + let bad_origin_call = Box::new(RuntimeCall::Balances(BalancesCall::force_transfer { + source: 0, + dest: 0, + value: 0, + })); + assert_noop!(Lottery::buy_ticket(RuntimeOrigin::signed(1), bad_origin_call), BadOrigin,); // User can call other txs, but doesn't get a ticket let remark_call = - Box::new(Call::System(SystemCall::remark { remark: b"hello, world!".to_vec() })); - assert_ok!(Lottery::buy_ticket(Origin::signed(2), remark_call)); + Box::new(RuntimeCall::System(SystemCall::remark { remark: b"hello, world!".to_vec() })); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(2), remark_call)); assert_eq!(TicketsCount::::get(), 0); let successful_call = - Box::new(Call::Balances(BalancesCall::transfer { dest: 2, value: 1 })); - assert_ok!(Lottery::buy_ticket(Origin::signed(2), successful_call)); + Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 1 })); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(2), successful_call)); assert_eq!(TicketsCount::::get(), 1); }); } @@ -250,42 +255,43 @@ fn buy_ticket_works() { new_test_ext().execute_with(|| { // Set calls for the lottery. let calls = vec![ - Call::System(SystemCall::remark { remark: vec![] }), - Call::Balances(BalancesCall::transfer { dest: 0, value: 0 }), + RuntimeCall::System(SystemCall::remark { remark: vec![] }), + RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 }), ]; - assert_ok!(Lottery::set_calls(Origin::root(), calls)); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls)); // Can't buy ticket before start - let call = Box::new(Call::Balances(BalancesCall::transfer { dest: 2, value: 1 })); - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call.clone())); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 1 })); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone())); assert_eq!(TicketsCount::::get(), 0); // Start lottery - assert_ok!(Lottery::start_lottery(Origin::root(), 1, 20, 5, false)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 1, 20, 5, false)); // Go to start, buy ticket for transfer run_to_block(5); - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call)); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call)); assert_eq!(TicketsCount::::get(), 1); // Can't buy another of the same ticket (even if call is slightly changed) - let call = Box::new(Call::Balances(BalancesCall::transfer { dest: 3, value: 30 })); - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call)); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 3, value: 30 })); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call)); assert_eq!(TicketsCount::::get(), 1); // Buy ticket for remark - let call = Box::new(Call::System(SystemCall::remark { remark: b"hello, world!".to_vec() })); - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call.clone())); + let call = + Box::new(RuntimeCall::System(SystemCall::remark { remark: b"hello, world!".to_vec() })); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone())); assert_eq!(TicketsCount::::get(), 2); // Go to end, can't buy tickets anymore run_to_block(20); - assert_ok!(Lottery::buy_ticket(Origin::signed(2), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(2), call.clone())); assert_eq!(TicketsCount::::get(), 2); // Go to payout, can't buy tickets when there is no lottery open run_to_block(25); - assert_ok!(Lottery::buy_ticket(Origin::signed(2), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(2), call.clone())); assert_eq!(TicketsCount::::get(), 0); assert_eq!(LotteryIndex::::get(), 1); }); @@ -296,9 +302,9 @@ fn buy_ticket_works() { #[test] fn do_buy_ticket_already_participating() { new_test_ext().execute_with(|| { - let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; - assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); - assert_ok!(Lottery::start_lottery(Origin::root(), 1, 10, 10, false)); + let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone())); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 1, 10, 10, false)); // Buying once works. assert_ok!(Lottery::do_buy_ticket(&1, &calls[0])); @@ -311,16 +317,16 @@ fn do_buy_ticket_already_participating() { #[test] fn buy_ticket_already_participating() { new_test_ext().execute_with(|| { - let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; - assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); - assert_ok!(Lottery::start_lottery(Origin::root(), 1, 10, 10, false)); + let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone())); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 1, 10, 10, false)); // Buying once works. let call = Box::new(calls[0].clone()); - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call.clone())); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call.clone())); // Buying the same ticket again returns Ok, but changes nothing. - assert_storage_noop!(Lottery::buy_ticket(Origin::signed(1), call).unwrap()); + assert_storage_noop!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call).unwrap()); // Exactly one ticket exists. assert_eq!(TicketsCount::::get(), 1); @@ -331,14 +337,14 @@ fn buy_ticket_already_participating() { #[test] fn buy_ticket_insufficient_balance() { new_test_ext().execute_with(|| { - let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; - assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); + let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone())); // Price set to 100. - assert_ok!(Lottery::start_lottery(Origin::root(), 100, 10, 10, false)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 100, 10, 10, false)); let call = Box::new(calls[0].clone()); // Buying a ticket returns Ok, but changes nothing. - assert_storage_noop!(Lottery::buy_ticket(Origin::signed(1), call).unwrap()); + assert_storage_noop!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call).unwrap()); assert!(TicketsCount::::get().is_zero()); }); } @@ -346,10 +352,10 @@ fn buy_ticket_insufficient_balance() { #[test] fn do_buy_ticket_insufficient_balance() { new_test_ext().execute_with(|| { - let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; - assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); + let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone())); // Price set to 101. - assert_ok!(Lottery::start_lottery(Origin::root(), 101, 10, 10, false)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 101, 10, 10, false)); // Buying fails with InsufficientBalance. assert_noop!( @@ -363,10 +369,10 @@ fn do_buy_ticket_insufficient_balance() { #[test] fn do_buy_ticket_keep_alive() { new_test_ext().execute_with(|| { - let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; - assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); + let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone())); // Price set to 100. - assert_ok!(Lottery::start_lottery(Origin::root(), 100, 10, 10, false)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 100, 10, 10, false)); // Buying fails with KeepAlive. assert_noop!(Lottery::do_buy_ticket(&1, &calls[0]), BalancesError::::KeepAlive); @@ -382,9 +388,9 @@ fn no_participants_works() { let delay = 5; // Set no calls for the lottery. - assert_ok!(Lottery::set_calls(Origin::root(), vec![])); + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), vec![])); // Start lottery. - assert_ok!(Lottery::start_lottery(Origin::root(), 10, length, delay, false)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 10, length, delay, false)); // End the lottery, no one wins. run_to_block(length + delay); @@ -399,7 +405,7 @@ fn start_lottery_will_create_account() { let delay = 5; assert_eq!(Balances::total_balance(&Lottery::account_id()), 0); - assert_ok!(Lottery::start_lottery(Origin::root(), price, length, delay, false)); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), price, length, delay, false)); assert_eq!(Balances::total_balance(&Lottery::account_id()), 1); }); } @@ -415,13 +421,13 @@ fn choose_ticket_trivial_cases() { #[test] fn choose_account_one_participant() { new_test_ext().execute_with(|| { - let calls = vec![Call::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; - assert_ok!(Lottery::set_calls(Origin::root(), calls.clone())); - assert_ok!(Lottery::start_lottery(Origin::root(), 10, 10, 10, false)); + let calls = vec![RuntimeCall::Balances(BalancesCall::transfer { dest: 0, value: 0 })]; + assert_ok!(Lottery::set_calls(RuntimeOrigin::root(), calls.clone())); + assert_ok!(Lottery::start_lottery(RuntimeOrigin::root(), 10, 10, 10, false)); let call = Box::new(calls[0].clone()); // Buy one ticket with account 1. - assert_ok!(Lottery::buy_ticket(Origin::signed(1), call)); + assert_ok!(Lottery::buy_ticket(RuntimeOrigin::signed(1), call)); // Account 1 is always the winner. assert_eq!(Lottery::choose_account().unwrap(), 1); }); diff --git a/frame/membership/Cargo.toml b/frame/membership/Cargo.toml index 0473fd46956af..8ec1087e5ac0e 100644 --- a/frame/membership/Cargo.toml +++ b/frame/membership/Cargo.toml @@ -28,7 +28,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/membership/src/lib.rs b/frame/membership/src/lib.rs index b4c9c3b38f1da..af2f2ddcf42f0 100644 --- a/frame/membership/src/lib.rs +++ b/frame/membership/src/lib.rs @@ -55,22 +55,23 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Required origin for adding a member (though can always be Root). - type AddOrigin: EnsureOrigin; + type AddOrigin: EnsureOrigin; /// Required origin for removing a member (though can always be Root). - type RemoveOrigin: EnsureOrigin; + type RemoveOrigin: EnsureOrigin; /// Required origin for adding and removing a member in a single action. - type SwapOrigin: EnsureOrigin; + type SwapOrigin: EnsureOrigin; /// Required origin for resetting membership. - type ResetOrigin: EnsureOrigin; + type ResetOrigin: EnsureOrigin; /// Required origin for setting or resetting the prime member. - type PrimeOrigin: EnsureOrigin; + type PrimeOrigin: EnsureOrigin; /// The receiver of the signal for when the membership has been initialized. This happens /// pre-genesis and will usually be the same as `MembershipChanged`. If you need to do @@ -147,7 +148,7 @@ pub mod pallet { /// One of the members' keys changed. KeyChanged, /// Phantom member, never used. - Dummy { _phantom_data: PhantomData<(T::AccountId, >::Event)> }, + Dummy { _phantom_data: PhantomData<(T::AccountId, >::RuntimeEvent)> }, } #[pallet::error] @@ -542,16 +543,16 @@ mod tests { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -600,7 +601,7 @@ mod tests { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type AddOrigin = EnsureSignedBy; type RemoveOrigin = EnsureSignedBy; type SwapOrigin = EnsureSignedBy; @@ -646,13 +647,16 @@ mod tests { #[test] fn prime_member_works() { new_test_ext().execute_with(|| { - assert_noop!(Membership::set_prime(Origin::signed(4), 20), BadOrigin); - assert_noop!(Membership::set_prime(Origin::signed(5), 15), Error::::NotMember); - assert_ok!(Membership::set_prime(Origin::signed(5), 20)); + assert_noop!(Membership::set_prime(RuntimeOrigin::signed(4), 20), BadOrigin); + assert_noop!( + Membership::set_prime(RuntimeOrigin::signed(5), 15), + Error::::NotMember + ); + assert_ok!(Membership::set_prime(RuntimeOrigin::signed(5), 20)); assert_eq!(Membership::prime(), Some(20)); assert_eq!(PRIME.with(|m| *m.borrow()), Membership::prime()); - assert_ok!(Membership::clear_prime(Origin::signed(5))); + assert_ok!(Membership::clear_prime(RuntimeOrigin::signed(5))); assert_eq!(Membership::prime(), None); assert_eq!(PRIME.with(|m| *m.borrow()), Membership::prime()); }); @@ -661,12 +665,12 @@ mod tests { #[test] fn add_member_works() { new_test_ext().execute_with(|| { - assert_noop!(Membership::add_member(Origin::signed(5), 15), BadOrigin); + assert_noop!(Membership::add_member(RuntimeOrigin::signed(5), 15), BadOrigin); assert_noop!( - Membership::add_member(Origin::signed(1), 10), + Membership::add_member(RuntimeOrigin::signed(1), 10), Error::::AlreadyMember ); - assert_ok!(Membership::add_member(Origin::signed(1), 15)); + assert_ok!(Membership::add_member(RuntimeOrigin::signed(1), 15)); assert_eq!(Membership::members(), vec![10, 15, 20, 30]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); }); @@ -675,13 +679,13 @@ mod tests { #[test] fn remove_member_works() { new_test_ext().execute_with(|| { - assert_noop!(Membership::remove_member(Origin::signed(5), 20), BadOrigin); + assert_noop!(Membership::remove_member(RuntimeOrigin::signed(5), 20), BadOrigin); assert_noop!( - Membership::remove_member(Origin::signed(2), 15), + Membership::remove_member(RuntimeOrigin::signed(2), 15), Error::::NotMember ); - assert_ok!(Membership::set_prime(Origin::signed(5), 20)); - assert_ok!(Membership::remove_member(Origin::signed(2), 20)); + assert_ok!(Membership::set_prime(RuntimeOrigin::signed(5), 20)); + assert_ok!(Membership::remove_member(RuntimeOrigin::signed(2), 20)); assert_eq!(Membership::members(), vec![10, 30]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); assert_eq!(Membership::prime(), None); @@ -692,24 +696,24 @@ mod tests { #[test] fn swap_member_works() { new_test_ext().execute_with(|| { - assert_noop!(Membership::swap_member(Origin::signed(5), 10, 25), BadOrigin); + assert_noop!(Membership::swap_member(RuntimeOrigin::signed(5), 10, 25), BadOrigin); assert_noop!( - Membership::swap_member(Origin::signed(3), 15, 25), + Membership::swap_member(RuntimeOrigin::signed(3), 15, 25), Error::::NotMember ); assert_noop!( - Membership::swap_member(Origin::signed(3), 10, 30), + Membership::swap_member(RuntimeOrigin::signed(3), 10, 30), Error::::AlreadyMember ); - assert_ok!(Membership::set_prime(Origin::signed(5), 20)); - assert_ok!(Membership::swap_member(Origin::signed(3), 20, 20)); + assert_ok!(Membership::set_prime(RuntimeOrigin::signed(5), 20)); + assert_ok!(Membership::swap_member(RuntimeOrigin::signed(3), 20, 20)); assert_eq!(Membership::members(), vec![10, 20, 30]); assert_eq!(Membership::prime(), Some(20)); assert_eq!(PRIME.with(|m| *m.borrow()), Membership::prime()); - assert_ok!(Membership::set_prime(Origin::signed(5), 10)); - assert_ok!(Membership::swap_member(Origin::signed(3), 10, 25)); + assert_ok!(Membership::set_prime(RuntimeOrigin::signed(5), 10)); + assert_ok!(Membership::swap_member(RuntimeOrigin::signed(3), 10, 25)); assert_eq!(Membership::members(), vec![20, 25, 30]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); assert_eq!(Membership::prime(), None); @@ -720,7 +724,7 @@ mod tests { #[test] fn swap_member_works_that_does_not_change_order() { new_test_ext().execute_with(|| { - assert_ok!(Membership::swap_member(Origin::signed(3), 10, 5)); + assert_ok!(Membership::swap_member(RuntimeOrigin::signed(3), 10, 5)); assert_eq!(Membership::members(), vec![5, 20, 30]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); }); @@ -729,16 +733,16 @@ mod tests { #[test] fn change_key_works() { new_test_ext().execute_with(|| { - assert_ok!(Membership::set_prime(Origin::signed(5), 10)); + assert_ok!(Membership::set_prime(RuntimeOrigin::signed(5), 10)); assert_noop!( - Membership::change_key(Origin::signed(3), 25), + Membership::change_key(RuntimeOrigin::signed(3), 25), Error::::NotMember ); assert_noop!( - Membership::change_key(Origin::signed(10), 20), + Membership::change_key(RuntimeOrigin::signed(10), 20), Error::::AlreadyMember ); - assert_ok!(Membership::change_key(Origin::signed(10), 40)); + assert_ok!(Membership::change_key(RuntimeOrigin::signed(10), 40)); assert_eq!(Membership::members(), vec![20, 30, 40]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); assert_eq!(Membership::prime(), Some(40)); @@ -749,7 +753,7 @@ mod tests { #[test] fn change_key_works_that_does_not_change_order() { new_test_ext().execute_with(|| { - assert_ok!(Membership::change_key(Origin::signed(10), 5)); + assert_ok!(Membership::change_key(RuntimeOrigin::signed(10), 5)); assert_eq!(Membership::members(), vec![5, 20, 30]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); }); @@ -758,19 +762,19 @@ mod tests { #[test] fn reset_members_works() { new_test_ext().execute_with(|| { - assert_ok!(Membership::set_prime(Origin::signed(5), 20)); + assert_ok!(Membership::set_prime(RuntimeOrigin::signed(5), 20)); assert_noop!( - Membership::reset_members(Origin::signed(1), bounded_vec![20, 40, 30]), + Membership::reset_members(RuntimeOrigin::signed(1), bounded_vec![20, 40, 30]), BadOrigin ); - assert_ok!(Membership::reset_members(Origin::signed(4), vec![20, 40, 30])); + assert_ok!(Membership::reset_members(RuntimeOrigin::signed(4), vec![20, 40, 30])); assert_eq!(Membership::members(), vec![20, 30, 40]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); assert_eq!(Membership::prime(), Some(20)); assert_eq!(PRIME.with(|m| *m.borrow()), Membership::prime()); - assert_ok!(Membership::reset_members(Origin::signed(4), vec![10, 40, 30])); + assert_ok!(Membership::reset_members(RuntimeOrigin::signed(4), vec![10, 40, 30])); assert_eq!(Membership::members(), vec![10, 30, 40]); assert_eq!(MEMBERS.with(|m| m.borrow().clone()), Membership::members().to_vec()); assert_eq!(Membership::prime(), None); diff --git a/frame/merkle-mountain-range/Cargo.toml b/frame/merkle-mountain-range/Cargo.toml index 75301afed0094..91ec19d731094 100644 --- a/frame/merkle-mountain-range/Cargo.toml +++ b/frame/merkle-mountain-range/Cargo.toml @@ -25,15 +25,15 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primit sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } [dev-dependencies] +array-bytes = "4.1" env_logger = "0.9" -hex-literal = "0.3" itertools = "0.10.3" [features] default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "mmr-lib/std", diff --git a/frame/merkle-mountain-range/rpc/src/lib.rs b/frame/merkle-mountain-range/rpc/src/lib.rs index 75032d40f492a..ffc7ac2da56bf 100644 --- a/frame/merkle-mountain-range/rpc/src/lib.rs +++ b/frame/merkle-mountain-range/rpc/src/lib.rs @@ -30,10 +30,10 @@ use jsonrpsee::{ }; use serde::{Deserialize, Serialize}; -use sp_api::ProvideRuntimeApi; +use sp_api::{NumberFor, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use sp_core::Bytes; -use sp_mmr_primitives::{BatchProof, Error as MmrError, LeafIndex, Proof}; +use sp_mmr_primitives::{BatchProof, Error as MmrError, Proof}; use sp_runtime::{generic::BlockId, traits::Block as BlockT}; pub use sp_mmr_primitives::MmrApi as MmrRuntimeApi; @@ -96,11 +96,11 @@ impl LeafBatchProof { /// MMR RPC methods. #[rpc(client, server)] -pub trait MmrApi { - /// Generate MMR proof for given leaf index. +pub trait MmrApi { + /// Generate MMR proof for given block number. /// /// This method calls into a runtime with MMR pallet included and attempts to generate - /// MMR proof for leaf at given `leaf_index`. + /// MMR proof for a block with a specified `block_number`. /// Optionally, a block hash at which the runtime should be queried can be specified. /// /// Returns the (full) leaf itself and a proof for this leaf (compact encoding, i.e. hash of @@ -108,24 +108,49 @@ pub trait MmrApi { #[method(name = "mmr_generateProof")] fn generate_proof( &self, - leaf_index: LeafIndex, + block_number: BlockNumber, at: Option, ) -> RpcResult>; - /// Generate MMR proof for the given leaf indices. + /// Generate MMR proof for the given block numbers. /// /// This method calls into a runtime with MMR pallet included and attempts to generate - /// MMR proof for a set of leaves at the given `leaf_indices`. + /// MMR proof for a set of blocks with the specific `block_numbers`. /// Optionally, a block hash at which the runtime should be queried can be specified. /// /// Returns the leaves and a proof for these leaves (compact encoding, i.e. hash of /// the leaves). Both parameters are SCALE-encoded. /// The order of entries in the `leaves` field of the returned struct - /// is the same as the order of the entries in `leaf_indices` supplied + /// is the same as the order of the entries in `block_numbers` supplied #[method(name = "mmr_generateBatchProof")] fn generate_batch_proof( &self, - leaf_indices: Vec, + block_numbers: Vec, + at: Option, + ) -> RpcResult>; + + /// Generate a MMR proof for the given `block_numbers` given the `best_known_block_number`. + /// + /// This method calls into a runtime with MMR pallet included and attempts to generate + /// a MMR proof for the set of blocks that have the given `block_numbers` with MMR given the + /// `best_known_block_number`. `best_known_block_number` must be larger than all the + /// `block_numbers` for the function to succeed. + /// + /// Optionally, a block hash at which the runtime should be queried can be specified. + /// Note that specifying the block hash isn't super-useful here, unless you're generating + /// proof using non-finalized blocks where there are several competing forks. That's because + /// MMR state will be fixed to the state with `best_known_block_number`, which already points to + /// some historical block. + /// + /// Returns the leaves and a proof for these leaves (compact encoding, i.e. hash of + /// the leaves). Both parameters are SCALE-encoded. + /// The order of entries in the `leaves` field of the returned struct + /// is the same as the order of the entries in `block_numbers` supplied + #[method(name = "mmr_generateHistoricalBatchProof")] + fn generate_historical_batch_proof( + &self, + block_numbers: Vec, + best_known_block_number: BlockNumber, at: Option, ) -> RpcResult>; } @@ -144,16 +169,17 @@ impl Mmr { } #[async_trait] -impl MmrApiServer<::Hash> for Mmr +impl MmrApiServer<::Hash, NumberFor> + for Mmr where Block: BlockT, Client: Send + Sync + 'static + ProvideRuntimeApi + HeaderBackend, - Client::Api: MmrRuntimeApi, + Client::Api: MmrRuntimeApi>, MmrHash: Codec + Send + Sync + 'static, { fn generate_proof( &self, - leaf_index: LeafIndex, + block_number: NumberFor, at: Option<::Hash>, ) -> RpcResult> { let api = self.client.runtime_api(); @@ -163,7 +189,7 @@ where .generate_proof_with_context( &BlockId::hash(block_hash), sp_core::ExecutionContext::OffchainCall(None), - leaf_index, + block_number, ) .map_err(runtime_error_into_rpc_error)? .map_err(mmr_error_into_rpc_error)?; @@ -173,7 +199,7 @@ where fn generate_batch_proof( &self, - leaf_indices: Vec, + block_numbers: Vec>, at: Option<::Hash>, ) -> RpcResult::Hash>> { let api = self.client.runtime_api(); @@ -185,7 +211,31 @@ where .generate_batch_proof_with_context( &BlockId::hash(block_hash), sp_core::ExecutionContext::OffchainCall(None), - leaf_indices, + block_numbers, + ) + .map_err(runtime_error_into_rpc_error)? + .map_err(mmr_error_into_rpc_error)?; + + Ok(LeafBatchProof::new(block_hash, leaves, proof)) + } + + fn generate_historical_batch_proof( + &self, + block_numbers: Vec>, + best_known_block_number: NumberFor, + at: Option<::Hash>, + ) -> RpcResult::Hash>> { + let api = self.client.runtime_api(); + let block_hash = at.unwrap_or_else(|| + // If the block hash is not supplied assume the best block. + self.client.info().best_hash); + + let (leaves, proof) = api + .generate_historical_batch_proof_with_context( + &BlockId::hash(block_hash), + sp_core::ExecutionContext::OffchainCall(None), + block_numbers, + best_known_block_number, ) .map_err(runtime_error_into_rpc_error)? .map_err(mmr_error_into_rpc_error)?; diff --git a/frame/merkle-mountain-range/src/benchmarking.rs b/frame/merkle-mountain-range/src/benchmarking.rs index b698e432534d8..d24364a55f9e6 100644 --- a/frame/merkle-mountain-range/src/benchmarking.rs +++ b/frame/merkle-mountain-range/src/benchmarking.rs @@ -17,6 +17,8 @@ //! Benchmarks for the MMR pallet. +#![cfg(feature = "runtime-benchmarks")] + use crate::*; use frame_benchmarking::benchmarks_instance_pallet; use frame_support::traits::OnInitialize; diff --git a/frame/merkle-mountain-range/src/lib.rs b/frame/merkle-mountain-range/src/lib.rs index 4644ebcb7da1c..92ab8702b65c0 100644 --- a/frame/merkle-mountain-range/src/lib.rs +++ b/frame/merkle-mountain-range/src/lib.rs @@ -57,13 +57,13 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::Encode; -use frame_support::weights::Weight; +use frame_support::{log, traits::Get, weights::Weight}; use sp_runtime::{ - traits::{self, One, Saturating}, + traits::{self, CheckedSub, One, Saturating, UniqueSaturatedInto}, SaturatedConversion, }; -#[cfg(any(feature = "runtime-benchmarks", test))] +#[cfg(feature = "runtime-benchmarks")] mod benchmarking; mod default_weights; mod mmr; @@ -103,6 +103,15 @@ pub trait WeightInfo { fn on_initialize(peaks: NodeIndex) -> Weight; } +/// A MMR specific to the pallet. +type ModuleMmr = mmr::Mmr>; + +/// Leaf data. +type LeafOf = <>::LeafData as primitives::LeafDataProvider>::LeafData; + +/// Hashing used for the pallet. +pub(crate) type HashingOf = >::Hashing; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -166,7 +175,7 @@ pub mod pallet { /// Note that the leaf at each block MUST be unique. You may want to include a block hash or /// block number as an easiest way to ensure that. /// Also note that the leaf added by each block is expected to only reference data coming - /// from ancestor blocks (leaves are saved offchain using `(parent_hash, pos)` key to be + /// from ancestor blocks (leaves are saved offchain using `(pos, parent_hash)` key to be /// fork-resistant, as such conflicts could only happen on 1-block deep forks, which means /// two forks with identical line of ancestors compete to write the same offchain key, but /// that's fine as long as leaves only contain data coming from ancestors - conflicting @@ -212,12 +221,22 @@ pub mod pallet { let leaves = Self::mmr_leaves(); let peaks_before = mmr::utils::NodesUtils::new(leaves).number_of_peaks(); let data = T::LeafData::leaf_data(); + // append new leaf to MMR let mut mmr: ModuleMmr = mmr::Mmr::new(leaves); - mmr.push(data).expect("MMR push never fails."); - - // update the size - let (leaves, root) = mmr.finalize().expect("MMR finalize never fails."); + // MMR push never fails, but better safe than sorry. + if mmr.push(data).is_none() { + log::error!(target: "runtime::mmr", "MMR push failed"); + return T::WeightInfo::on_initialize(peaks_before) + } + // Update the size, `mmr.finalize()` should also never fail. + let (leaves, root) = match mmr.finalize() { + Ok((leaves, root)) => (leaves, root), + Err(e) => { + log::error!(target: "runtime::mmr", "MMR finalize failed: {:?}", e); + return T::WeightInfo::on_initialize(peaks_before) + }, + }; >::on_new_root(&root); >::put(leaves); @@ -230,21 +249,35 @@ pub mod pallet { fn offchain_worker(n: T::BlockNumber) { use mmr::storage::{OffchainStorage, Storage}; - // MMR pallet uses offchain storage to hold full MMR and leaves. - // The leaves are saved under fork-unique keys `(parent_hash, pos)`. - // MMR Runtime depends on `frame_system::block_hash(block_num)` mappings to find - // parent hashes for particular nodes or leaves. - // This MMR offchain worker function moves a rolling window of the same size - // as `frame_system::block_hash` map, where nodes/leaves added by blocks that are just + // The MMR nodes can be found in offchain db under either: + // - fork-unique keys `(prefix, pos, parent_hash)`, or, + // - "canonical" keys `(prefix, pos)`, + // depending on how many blocks in the past the node at position `pos` was + // added to the MMR. + // + // For the fork-unique keys, the MMR pallet depends on + // `frame_system::block_hash(parent_num)` mappings to find the relevant parent block + // hashes, so it is limited by `frame_system::BlockHashCount` in terms of how many + // historical forks it can track. Nodes added to MMR by block `N` can be found in + // offchain db at: + // - fork-unique keys `(prefix, pos, parent_hash)` when (`N` >= `latest_block` - + // `frame_system::BlockHashCount`); + // - "canonical" keys `(prefix, pos)` when (`N` < `latest_block` - + // `frame_system::BlockHashCount`); + // + // The offchain worker is responsible for maintaining the nodes' positions in + // offchain db as the chain progresses by moving a rolling window of the same size as + // `frame_system::block_hash` map, where nodes/leaves added by blocks that are just // about to exit the window are "canonicalized" so that their offchain key no longer - // depends on `parent_hash` therefore on access to `frame_system::block_hash`. + // depends on `parent_hash`. // // This approach works to eliminate fork-induced leaf collisions in offchain db, // under the assumption that no fork will be deeper than `frame_system::BlockHashCount` - // blocks (2400 blocks on Polkadot, Kusama, Rococo, etc): - // entries pertaining to block `N` where `N < current-2400` are moved to a key based - // solely on block number. The only way to have collisions is if two competing forks - // are deeper than 2400 blocks and they both "canonicalize" their view of block `N`. + // blocks: + // entries pertaining to block `N` where `N < current-BlockHashCount` are moved to a + // key based solely on block number. The only way to have collisions is if two + // competing forks are deeper than `frame_system::BlockHashCount` blocks and they + // both "canonicalize" their view of block `N` // Once a block is canonicalized, all MMR entries pertaining to sibling blocks from // other forks are pruned from offchain db. Storage::>::canonicalize_and_prune(n); @@ -252,15 +285,6 @@ pub mod pallet { } } -/// A MMR specific to the pallet. -type ModuleMmr = mmr::Mmr>; - -/// Leaf data. -type LeafOf = <>::LeafData as primitives::LeafDataProvider>::LeafData; - -/// Hashing used for the pallet. -pub(crate) type HashingOf = >::Hashing; - /// Stateless MMR proof verification for batch of leaves. /// /// This function can be used to verify received MMR [primitives::BatchProof] (`proof`) @@ -290,19 +314,32 @@ impl, I: 'static> Pallet { /// /// This combination makes the offchain (key,value) entry resilient to chain forks. fn node_offchain_key( - parent_hash: ::Hash, pos: NodeIndex, + parent_hash: ::Hash, ) -> sp_std::prelude::Vec { - (T::INDEXING_PREFIX, parent_hash, pos).encode() + (T::INDEXING_PREFIX, pos, parent_hash).encode() } /// Build canonical offchain key for node `pos` in MMR. /// /// Used for nodes added by now finalized blocks. + /// Never read keys using `node_canon_offchain_key` unless you sure that + /// there's no `node_offchain_key` key in the storage. fn node_canon_offchain_key(pos: NodeIndex) -> sp_std::prelude::Vec { (T::INDEXING_PREFIX, pos).encode() } + /// Return size of rolling window of leaves saved in offchain under fork-unique keys. + /// + /// Leaves outside this window are canonicalized. + /// Window size is `frame_system::BlockHashCount - 1` to make sure fork-unique keys + /// can be built using `frame_system::block_hash` map. + fn offchain_canonicalization_window() -> LeafIndex { + let window_size: LeafIndex = + ::BlockHashCount::get().unique_saturated_into(); + window_size.saturating_sub(1) + } + /// Provide the parent number for the block that added `leaf_index` to the MMR. fn leaf_index_to_parent_block_num( leaf_index: LeafIndex, @@ -318,19 +355,75 @@ impl, I: 'static> Pallet { .saturating_add(leaf_index.saturated_into()) } - /// Generate a MMR proof for the given `leaf_indices`. + /// Convert a `block_num` into a leaf index. + fn block_num_to_leaf_index(block_num: T::BlockNumber) -> Result + where + T: frame_system::Config, + { + // leaf_idx = (leaves_count - 1) - (current_block_num - block_num); + let best_block_num = >::block_number(); + let blocks_diff = best_block_num.checked_sub(&block_num).ok_or_else(|| { + primitives::Error::BlockNumToLeafIndex + .log_debug("The provided block_number is greater than the best block number.") + })?; + let blocks_diff_as_leaf_idx = blocks_diff.try_into().map_err(|_| { + primitives::Error::BlockNumToLeafIndex + .log_debug("The `blocks_diff` couldn't be converted to `LeafIndex`.") + })?; + + let leaf_idx = Self::mmr_leaves() + .checked_sub(1) + .and_then(|last_leaf_idx| last_leaf_idx.checked_sub(blocks_diff_as_leaf_idx)) + .ok_or_else(|| { + primitives::Error::BlockNumToLeafIndex + .log_debug("There aren't enough leaves in the chain.") + })?; + Ok(leaf_idx) + } + + /// Generate a MMR proof for the given `block_numbers`. /// /// Note this method can only be used from an off-chain context /// (Offchain Worker or Runtime API call), since it requires /// all the leaves to be present. /// It may return an error or panic if used incorrectly. pub fn generate_batch_proof( - leaf_indices: Vec, + block_numbers: Vec, + ) -> Result< + (Vec>, primitives::BatchProof<>::Hash>), + primitives::Error, + > { + Self::generate_historical_batch_proof( + block_numbers, + >::block_number(), + ) + } + + /// Generate a MMR proof for the given `block_numbers` given the `best_known_block_number`. + /// + /// Note this method can only be used from an off-chain context + /// (Offchain Worker or Runtime API call), since it requires + /// all the leaves to be present. + /// It may return an error or panic if used incorrectly. + pub fn generate_historical_batch_proof( + block_numbers: Vec, + best_known_block_number: T::BlockNumber, ) -> Result< (Vec>, primitives::BatchProof<>::Hash>), primitives::Error, > { - let mmr: ModuleMmr = mmr::Mmr::new(Self::mmr_leaves()); + let leaves_count = + Self::block_num_to_leaf_index(best_known_block_number)?.saturating_add(1); + + // we need to translate the block_numbers into leaf indices. + let leaf_indices = block_numbers + .iter() + .map(|block_num| -> Result { + Self::block_num_to_leaf_index(*block_num) + }) + .collect::, _>>()?; + + let mmr: ModuleMmr = mmr::Mmr::new(leaves_count); mmr.generate_batch_proof(leaf_indices) } diff --git a/frame/merkle-mountain-range/src/mmr/storage.rs b/frame/merkle-mountain-range/src/mmr/storage.rs index 8b623edf56957..870ce81226bd2 100644 --- a/frame/merkle-mountain-range/src/mmr/storage.rs +++ b/frame/merkle-mountain-range/src/mmr/storage.rs @@ -18,11 +18,10 @@ //! A MMR storage implementations. use codec::Encode; -use frame_support::traits::Get; +use frame_support::log::{debug, error, trace}; use mmr_lib::helper; use sp_core::offchain::StorageKind; use sp_io::{offchain, offchain_index}; -use sp_runtime::traits::UniqueSaturatedInto; use sp_std::iter::Peekable; #[cfg(not(feature = "std"))] use sp_std::prelude::*; @@ -133,15 +132,14 @@ where // Effectively move a rolling window of fork-unique leaves. Once out of the window, leaves // are "canonicalized" in offchain by moving them under `Pallet::node_canon_offchain_key`. let leaves = NumberOfLeaves::::get(); - let window_size = - ::BlockHashCount::get().unique_saturated_into(); + let window_size = Pallet::::offchain_canonicalization_window(); if leaves >= window_size { // Move the rolling window towards the end of `block_num->hash` mappings available // in the runtime: we "canonicalize" the leaf at the end, let to_canon_leaf = leaves.saturating_sub(window_size); // and all the nodes added by that leaf. let to_canon_nodes = NodesUtils::right_branch_ending_in_leaf(to_canon_leaf); - frame_support::log::debug!( + debug!( target: "runtime::mmr::offchain", "Nodes to canon for leaf {}: {:?}", to_canon_leaf, to_canon_nodes ); @@ -149,7 +147,7 @@ where let to_canon_block_num = Pallet::::leaf_index_to_parent_block_num(to_canon_leaf, leaves); // Only entries under this hash (retrieved from state on current canon fork) are to be - // persisted. All other entries added by same block number will be cleared. + // persisted. All entries added by same block number on other forks will be cleared. let to_canon_hash = >::block_hash(to_canon_block_num); Self::canonicalize_nodes_for_hash(&to_canon_nodes, to_canon_hash); @@ -159,7 +157,7 @@ where Self::prune_nodes_for_forks(&to_canon_nodes, forks); }) .unwrap_or_else(|| { - frame_support::log::error!( + error!( target: "runtime::mmr::offchain", "Offchain: could not prune: no entry in pruning map for block {:?}", to_canon_block_num @@ -171,8 +169,8 @@ where fn prune_nodes_for_forks(nodes: &[NodeIndex], forks: Vec<::Hash>) { for hash in forks { for pos in nodes { - let key = Pallet::::node_offchain_key(hash, *pos); - frame_support::log::debug!( + let key = Pallet::::node_offchain_key(*pos, hash); + debug!( target: "runtime::mmr::offchain", "Clear elem at pos {} with key {:?}", pos, key @@ -187,19 +185,19 @@ where to_canon_hash: ::Hash, ) { for pos in to_canon_nodes { - let key = Pallet::::node_offchain_key(to_canon_hash, *pos); + let key = Pallet::::node_offchain_key(*pos, to_canon_hash); // Retrieve the element from Off-chain DB under fork-aware key. if let Some(elem) = offchain::local_storage_get(StorageKind::PERSISTENT, &key) { let canon_key = Pallet::::node_canon_offchain_key(*pos); // Add under new canon key. offchain::local_storage_set(StorageKind::PERSISTENT, &canon_key, &elem); - frame_support::log::debug!( + debug!( target: "runtime::mmr::offchain", "Moved elem at pos {} from key {:?} to canon key {:?}", pos, key, canon_key ); } else { - frame_support::log::error!( + error!( target: "runtime::mmr::offchain", "Could not canonicalize elem at pos {} using key {:?}", pos, key @@ -220,21 +218,18 @@ where // Find out which leaf added node `pos` in the MMR. let ancestor_leaf_idx = NodesUtils::leaf_index_that_added_node(pos); - let window_size = - ::BlockHashCount::get().unique_saturated_into(); + let window_size = Pallet::::offchain_canonicalization_window(); // Leaves older than this window should have been canonicalized. if leaves.saturating_sub(ancestor_leaf_idx) > window_size { let key = Pallet::::node_canon_offchain_key(pos); - frame_support::log::debug!( + debug!( target: "runtime::mmr::offchain", "offchain db get {}: leaf idx {:?}, key {:?}", pos, ancestor_leaf_idx, key ); // Just for safety, to easily handle runtime upgrades where any of the window params // change and maybe we mess up storage migration, // return _if and only if_ node is found (in normal conditions it's always found), - if let Some(elem) = - sp_io::offchain::local_storage_get(sp_core::offchain::StorageKind::PERSISTENT, &key) - { + if let Some(elem) = sp_io::offchain::local_storage_get(StorageKind::PERSISTENT, &key) { return Ok(codec::Decode::decode(&mut &*elem).ok()) } // BUT if we DID MESS UP, fall through to searching node using fork-specific key. @@ -244,20 +239,20 @@ where let ancestor_parent_block_num = Pallet::::leaf_index_to_parent_block_num(ancestor_leaf_idx, leaves); let ancestor_parent_hash = >::block_hash(ancestor_parent_block_num); - let key = Pallet::::node_offchain_key(ancestor_parent_hash, pos); - frame_support::log::debug!( + let key = Pallet::::node_offchain_key(pos, ancestor_parent_hash); + debug!( target: "runtime::mmr::offchain", "offchain db get {}: leaf idx {:?}, hash {:?}, key {:?}", pos, ancestor_leaf_idx, ancestor_parent_hash, key ); // Retrieve the element from Off-chain DB. - Ok(sp_io::offchain::local_storage_get(sp_core::offchain::StorageKind::PERSISTENT, &key) + Ok(sp_io::offchain::local_storage_get(StorageKind::PERSISTENT, &key) .or_else(|| { // Again, this is just us being extra paranoid. // We get here only if we mess up a storage migration for a runtime upgrades where // say the window is increased, and for a little while following the upgrade there's // leaves inside new 'window' that had been already canonicalized before upgrade. let key = Pallet::::node_canon_offchain_key(pos); - sp_io::offchain::local_storage_get(sp_core::offchain::StorageKind::PERSISTENT, &key) + sp_io::offchain::local_storage_get(StorageKind::PERSISTENT, &key) }) .and_then(|v| codec::Decode::decode(&mut &*v).ok())) } @@ -282,9 +277,8 @@ where return Ok(()) } - frame_support::log::trace!( - target: "runtime::mmr", - "elems: {:?}", + trace!( + target: "runtime::mmr", "elems: {:?}", elems.iter().map(|elem| elem.hash()).collect::>() ); @@ -309,25 +303,12 @@ where // in offchain DB to avoid DB collisions and overwrites in case of forks. let parent_hash = >::parent_hash(); for elem in elems { - // For now we store this leaf offchain keyed by `(parent_hash, node_index)` - // to make it fork-resistant. - // Offchain worker task will "canonicalize" it `frame_system::BlockHashCount` blocks - // later when we are not worried about forks anymore (highly unlikely to have a fork - // in the chain that deep). - // "Canonicalization" in this case means moving this leaf under a new key based - // only on the leaf's `node_index`. - let key = Pallet::::node_offchain_key(parent_hash, node_index); - frame_support::log::debug!( - target: "runtime::mmr::offchain", "offchain db set: pos {} parent_hash {:?} key {:?}", - node_index, parent_hash, key - ); - // Indexing API is used to store the full node content (both leaf and inner). - elem.using_encoded(|elem| offchain_index::set(&key, elem)); - // On-chain we are going to only store new peaks. if peaks_to_store.next_if_eq(&node_index).is_some() { >::insert(node_index, elem.hash()); } + // We are storing full node off-chain (using indexing API). + Self::store_to_offchain(node_index, parent_hash, &elem); // Increase the indices. if let Node::Data(..) = elem { @@ -348,6 +329,38 @@ where } } +impl Storage +where + T: Config, + I: 'static, + L: primitives::FullLeaf, +{ + fn store_to_offchain( + pos: NodeIndex, + parent_hash: ::Hash, + node: &NodeOf, + ) { + let encoded_node = node.encode(); + // We store this leaf offchain keyed by `(parent_hash, node_index)` to make it + // fork-resistant. Offchain worker task will "canonicalize" it + // `frame_system::BlockHashCount` blocks later, when we are not worried about forks anymore + // (multi-era-deep forks should not happen). + let key = Pallet::::node_offchain_key(pos, parent_hash); + debug!( + target: "runtime::mmr::offchain", "offchain db set: pos {} parent_hash {:?} key {:?}", + pos, parent_hash, key + ); + // Indexing API is used to store the full node content. + offchain_index::set(&key, &encoded_node); + // We also directly save the full node under the "canonical" key. + // This is superfluous for the normal case - this entry will possibly be overwritten + // by forks, and will also be overwritten by "offchain_worker canonicalization". + // But it is required for blocks imported during initial sync where none of the above apply + // (`offchain_worker` doesn't run for initial sync blocks). + offchain_index::set(&Pallet::::node_canon_offchain_key(pos), &encoded_node); + } +} + fn peaks_to_prune_and_store( old_size: NodeIndex, new_size: NodeIndex, @@ -356,8 +369,8 @@ fn peaks_to_prune_and_store( // both collections may share a common prefix. let peaks_before = if old_size == 0 { vec![] } else { helper::get_peaks(old_size) }; let peaks_after = helper::get_peaks(new_size); - frame_support::log::trace!(target: "runtime::mmr", "peaks_before: {:?}", peaks_before); - frame_support::log::trace!(target: "runtime::mmr", "peaks_after: {:?}", peaks_after); + trace!(target: "runtime::mmr", "peaks_before: {:?}", peaks_before); + trace!(target: "runtime::mmr", "peaks_after: {:?}", peaks_after); let mut peaks_before = peaks_before.into_iter().peekable(); let mut peaks_after = peaks_after.into_iter().peekable(); diff --git a/frame/merkle-mountain-range/src/mock.rs b/frame/merkle-mountain-range/src/mock.rs index b2b6821fcd054..16f0922633088 100644 --- a/frame/merkle-mountain-range/src/mock.rs +++ b/frame/merkle-mountain-range/src/mock.rs @@ -19,14 +19,17 @@ use crate as pallet_mmr; use crate::*; use codec::{Decode, Encode}; -use frame_support::traits::{ConstU32, ConstU64}; +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64}, +}; use sp_core::H256; use sp_mmr_primitives::{Compact, LeafDataProvider}; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup, Keccak256}, }; -use sp_std::{cell::RefCell, prelude::*}; +use sp_std::prelude::*; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -44,8 +47,8 @@ frame_support::construct_runtime!( impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -53,7 +56,7 @@ impl frame_system::Config for Test { type AccountId = sp_core::sr25519::Public; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type DbWeight = (); type BlockWeights = (); @@ -91,14 +94,14 @@ impl LeafData { } } -thread_local! { - pub static LEAF_DATA: RefCell = RefCell::new(Default::default()); +parameter_types! { + pub static LeafDataTestValue: LeafData = Default::default(); } impl LeafDataProvider for LeafData { type LeafData = Self; fn leaf_data() -> Self::LeafData { - LEAF_DATA.with(|r| r.borrow().clone()) + LeafDataTestValue::get().clone() } } diff --git a/frame/merkle-mountain-range/src/tests.rs b/frame/merkle-mountain-range/src/tests.rs index e13f89617bb9a..dbbdc12c8e1d5 100644 --- a/frame/merkle-mountain-range/src/tests.rs +++ b/frame/merkle-mountain-range/src/tests.rs @@ -42,7 +42,7 @@ fn register_offchain_ext(ext: &mut sp_io::TestExternalities) { fn new_block() -> Weight { let number = frame_system::Pallet::::block_number() + 1; let hash = H256::repeat_byte(number as u8); - LEAF_DATA.with(|r| r.borrow_mut().a = number); + LeafDataTestValue::mutate(|r| r.a = number); frame_system::Pallet::::reset_events(); frame_system::Pallet::::initialize(&number, &hash, &Default::default()); @@ -169,25 +169,22 @@ fn should_append_to_mmr_when_on_initialize_is_called() { ext.persist_offchain_overlay(); let offchain_db = ext.offchain_db(); - assert_eq!( - offchain_db.get(&MMR::node_offchain_key(parent_b1, 0)).map(decode_node), - Some(mmr::Node::Data(((0, H256::repeat_byte(1)), LeafData::new(1),))) - ); - assert_eq!( - offchain_db.get(&MMR::node_offchain_key(parent_b2, 1)).map(decode_node), - Some(mmr::Node::Data(((1, H256::repeat_byte(2)), LeafData::new(2),))) - ); - assert_eq!( - offchain_db.get(&MMR::node_offchain_key(parent_b2, 2)).map(decode_node), - Some(mmr::Node::Hash(hex( - "672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854" - ))) - ); - assert_eq!(offchain_db.get(&MMR::node_offchain_key(parent_b2, 3)), None); - assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(0)), None); - assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(1)), None); - assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(2)), None); + let expected = Some(mmr::Node::Data(((0, H256::repeat_byte(1)), LeafData::new(1)))); + assert_eq!(offchain_db.get(&MMR::node_offchain_key(0, parent_b1)).map(decode_node), expected); + assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(0)).map(decode_node), expected); + + let expected = Some(mmr::Node::Data(((1, H256::repeat_byte(2)), LeafData::new(2)))); + assert_eq!(offchain_db.get(&MMR::node_offchain_key(1, parent_b2)).map(decode_node), expected); + assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(1)).map(decode_node), expected); + + let expected = Some(mmr::Node::Hash(hex( + "672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854", + ))); + assert_eq!(offchain_db.get(&MMR::node_offchain_key(2, parent_b2)).map(decode_node), expected); + assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(2)).map(decode_node), expected); + + assert_eq!(offchain_db.get(&MMR::node_offchain_key(3, parent_b2)), None); assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(3)), None); } @@ -227,18 +224,35 @@ fn should_generate_proofs_correctly() { let _ = env_logger::try_init(); let mut ext = new_test_ext(); // given - ext.execute_with(|| add_blocks(7)); + let num_blocks: u64 = 7; + ext.execute_with(|| add_blocks(num_blocks as usize)); ext.persist_offchain_overlay(); // Try to generate proofs now. This requires the offchain extensions to be present // to retrieve full leaf data. register_offchain_ext(&mut ext); ext.execute_with(|| { - // when generate proofs for all leaves - let proofs = (0_u64..crate::NumberOfLeaves::::get()) + let best_block_number = frame_system::Pallet::::block_number(); + // when generate proofs for all leaves. + let proofs = (1_u64..=best_block_number) + .into_iter() + .map(|block_num| crate::Pallet::::generate_batch_proof(vec![block_num]).unwrap()) + .collect::>(); + // when generate historical proofs for all leaves + let historical_proofs = (1_u64..best_block_number) .into_iter() - .map(|leaf_index| { - crate::Pallet::::generate_batch_proof(vec![leaf_index]).unwrap() + .map(|block_num| { + let mut proofs = vec![]; + for leaves_count in block_num..=num_blocks { + proofs.push( + crate::Pallet::::generate_historical_batch_proof( + vec![block_num], + leaves_count, + ) + .unwrap(), + ) + } + proofs }) .collect::>(); @@ -258,9 +272,83 @@ fn should_generate_proofs_correctly() { } ) ); + assert_eq!( + historical_proofs[0][0], + ( + vec![Compact::new(((0, H256::repeat_byte(1)).into(), LeafData::new(1).into(),))], + BatchProof { leaf_indices: vec![0], leaf_count: 1, items: vec![] } + ) + ); + + // D + // / \ + // / \ + // A B C + // / \ / \ / \ + // 1 2 3 4 5 6 7 + // + // we're proving 3 => we need { 4, A, C++7 } + assert_eq!( + proofs[2], + ( + vec![Compact::new(((2, H256::repeat_byte(3)).into(), LeafData::new(3).into(),))], + BatchProof { + leaf_indices: vec![2], + leaf_count: 7, + items: vec![ + hex("1b14c1dc7d3e4def11acdf31be0584f4b85c3673f1ff72a3af467b69a3b0d9d0"), + hex("672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854"), + hex("dca421199bdcc55bb773c6b6967e8d16675de69062b52285ca63685241fdf626"), + ], + } + ) + ); + // A + // / \ + // 1 2 3 + // + // we're proving 3 => we need { A } + assert_eq!( + historical_proofs[2][0], + ( + vec![Compact::new(((2, H256::repeat_byte(3)).into(), LeafData::new(3).into(),))], + BatchProof { + leaf_indices: vec![2], + leaf_count: 3, + items: vec![hex( + "672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854" + )], + } + ) + ); + // D + // / \ + // / \ + // A B + // / \ / \ + // 1 2 3 4 5 + // we're proving 3 => we need { 4, A, 5 } + assert_eq!( + historical_proofs[2][2], + ( + vec![Compact::new(((2, H256::repeat_byte(3)).into(), LeafData::new(3).into(),))], + BatchProof { + leaf_indices: vec![2], + leaf_count: 5, + items: vec![ + hex("1b14c1dc7d3e4def11acdf31be0584f4b85c3673f1ff72a3af467b69a3b0d9d0"), + hex("672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854"), + hex("3b031d22e24f1126c8f7d2f394b663f9b960ed7abbedb7152e17ce16112656d0") + ], + } + ) + ); + assert_eq!(historical_proofs[2][4], proofs[2]); + assert_eq!( proofs[4], ( + // NOTE: the leaf index is equivalent to the block number(in this case 5) - 1 vec![Compact::new(((4, H256::repeat_byte(5)).into(), LeafData::new(5).into(),))], BatchProof { leaf_indices: vec![4], @@ -273,6 +361,21 @@ fn should_generate_proofs_correctly() { } ) ); + assert_eq!( + historical_proofs[4][0], + ( + vec![Compact::new(((4, H256::repeat_byte(5)).into(), LeafData::new(5).into(),))], + BatchProof { + leaf_indices: vec![4], + leaf_count: 5, + items: vec![hex( + "ae88a0825da50e953e7a359c55fe13c8015e48d03d301b8bdfc9193874da9252" + ),], + } + ) + ); + assert_eq!(historical_proofs[4][2], proofs[4]); + assert_eq!( proofs[6], ( @@ -287,6 +390,7 @@ fn should_generate_proofs_correctly() { } ) ); + assert_eq!(historical_proofs[5][1], proofs[5]); }); } @@ -302,13 +406,13 @@ fn should_generate_batch_proof_correctly() { // to retrieve full leaf data. register_offchain_ext(&mut ext); ext.execute_with(|| { - // when generate proofs for all leaves - let (.., proof) = crate::Pallet::::generate_batch_proof(vec![0, 4, 5]).unwrap(); - + // when generate proofs for a batch of leaves + let (.., proof) = crate::Pallet::::generate_batch_proof(vec![1, 5, 6]).unwrap(); // then assert_eq!( proof, BatchProof { + // the leaf indices are equivalent to the above specified block numbers - 1. leaf_indices: vec![0, 4, 5], leaf_count: 7, items: vec![ @@ -318,6 +422,28 @@ fn should_generate_batch_proof_correctly() { ], } ); + + // when generate historical proofs for a batch of leaves + let (.., historical_proof) = + crate::Pallet::::generate_historical_batch_proof(vec![1, 5, 6], 6).unwrap(); + // then + assert_eq!( + historical_proof, + BatchProof { + leaf_indices: vec![0, 4, 5], + leaf_count: 6, + items: vec![ + hex("ad4cbc033833612ccd4626d5f023b9dfc50a35e838514dd1f3c86f8506728705"), + hex("cb24f4614ad5b2a5430344c99545b421d9af83c46fd632d70a332200884b4d46"), + ], + } + ); + + // when generate historical proofs for a batch of leaves + let (.., historical_proof) = + crate::Pallet::::generate_historical_batch_proof(vec![1, 5, 6], 7).unwrap(); + // then + assert_eq!(historical_proof, proof); }); } @@ -338,11 +464,33 @@ fn should_verify() { // when crate::Pallet::::generate_batch_proof(vec![5]).unwrap() }); + let (simple_historical_leaves, simple_historical_proof5) = ext.execute_with(|| { + // when + crate::Pallet::::generate_historical_batch_proof(vec![5], 6).unwrap() + }); + let (advanced_historical_leaves, advanced_historical_proof5) = ext.execute_with(|| { + // when + crate::Pallet::::generate_historical_batch_proof(vec![5], 7).unwrap() + }); ext.execute_with(|| { add_blocks(7); // then assert_eq!(crate::Pallet::::verify_leaves(leaves, proof5), Ok(())); + assert_eq!( + crate::Pallet::::verify_leaves( + simple_historical_leaves, + simple_historical_proof5 + ), + Ok(()) + ); + assert_eq!( + crate::Pallet::::verify_leaves( + advanced_historical_leaves, + advanced_historical_proof5 + ), + Ok(()) + ); }); } @@ -350,16 +498,40 @@ fn should_verify() { fn should_verify_batch_proofs() { fn generate_and_verify_batch_proof( ext: &mut sp_io::TestExternalities, - leaves: &Vec, + block_numbers: &Vec, blocks_to_add: usize, ) { - let (leaves, proof) = ext - .execute_with(|| crate::Pallet::::generate_batch_proof(leaves.to_vec()).unwrap()); + let (leaves, proof) = ext.execute_with(|| { + crate::Pallet::::generate_batch_proof(block_numbers.to_vec()).unwrap() + }); + + let mmr_size = ext.execute_with(|| crate::Pallet::::mmr_leaves()); + let min_mmr_size = block_numbers.iter().max().unwrap() + 1; + + // generate historical proofs for all possible mmr sizes, + // lower bound being index of highest leaf to be proven + let historical_proofs = (min_mmr_size..=mmr_size) + .map(|mmr_size| { + ext.execute_with(|| { + crate::Pallet::::generate_historical_batch_proof( + block_numbers.to_vec(), + mmr_size, + ) + .unwrap() + }) + }) + .collect::>(); ext.execute_with(|| { add_blocks(blocks_to_add); // then assert_eq!(crate::Pallet::::verify_leaves(leaves, proof), Ok(())); + historical_proofs.iter().for_each(|(leaves, proof)| { + assert_eq!( + crate::Pallet::::verify_leaves(leaves.clone(), proof.clone()), + Ok(()) + ); + }); }) } @@ -372,39 +544,41 @@ fn should_verify_batch_proofs() { // to retrieve full leaf data when generating proofs register_offchain_ext(&mut ext); - // verify that up to n=10, valid proofs are generated for all possible leaf combinations - for n in 0..10 { + // verify that up to n=10, valid proofs are generated for all possible block number + // combinations. + for n in 1..=10 { ext.execute_with(|| new_block()); ext.persist_offchain_overlay(); - // generate powerset (skipping empty set) of all possible leaf combinations for mmr size n - let leaves_set: Vec> = (0..n).into_iter().powerset().skip(1).collect(); + // generate powerset (skipping empty set) of all possible block number combinations for mmr + // size n. + let blocks_set: Vec> = (1..=n).into_iter().powerset().skip(1).collect(); - leaves_set.iter().for_each(|leaves_subset| { - generate_and_verify_batch_proof(&mut ext, leaves_subset, 0); + blocks_set.iter().for_each(|blocks_subset| { + generate_and_verify_batch_proof(&mut ext, &blocks_subset, 0); ext.persist_offchain_overlay(); }); } - // verify that up to n=15, valid proofs are generated for all possible 2-leaf combinations - for n in 10..15 { - // (MMR Leafs) + // verify that up to n=15, valid proofs are generated for all possible 2-block number + // combinations. + for n in 11..=15 { ext.execute_with(|| new_block()); ext.persist_offchain_overlay(); - // generate all possible 2-leaf combinations for mmr size n - let leaves_set: Vec> = (0..n).into_iter().combinations(2).collect(); + // generate all possible 2-block number combinations for mmr size n. + let blocks_set: Vec> = (1..=n).into_iter().combinations(2).collect(); - leaves_set.iter().for_each(|leaves_subset| { - generate_and_verify_batch_proof(&mut ext, leaves_subset, 0); + blocks_set.iter().for_each(|blocks_subset| { + generate_and_verify_batch_proof(&mut ext, &blocks_subset, 0); ext.persist_offchain_overlay(); }); } - generate_and_verify_batch_proof(&mut ext, &vec![7, 11], 20); + generate_and_verify_batch_proof(&mut ext, &vec![8, 12], 20); ext.execute_with(|| add_blocks(1000)); ext.persist_offchain_overlay(); - generate_and_verify_batch_proof(&mut ext, &vec![7, 11, 100, 800], 100); + generate_and_verify_batch_proof(&mut ext, &vec![8, 12, 100, 800], 100); } #[test] @@ -414,7 +588,13 @@ fn verification_should_be_stateless() { // Start off with chain initialisation and storing indexing data off-chain // (MMR Leafs) let mut ext = new_test_ext(); - ext.execute_with(|| add_blocks(7)); + let (root_6, root_7) = ext.execute_with(|| { + add_blocks(6); + let root_6 = crate::Pallet::::mmr_root_hash(); + add_blocks(1); + let root_7 = crate::Pallet::::mmr_root_hash(); + (root_6, root_7) + }); ext.persist_offchain_overlay(); // Try to generate proof now. This requires the offchain extensions to be present @@ -424,12 +604,27 @@ fn verification_should_be_stateless() { // when crate::Pallet::::generate_batch_proof(vec![5]).unwrap() }); - let root = ext.execute_with(|| crate::Pallet::::mmr_root_hash()); + let (_, historical_proof5) = ext.execute_with(|| { + // when + crate::Pallet::::generate_historical_batch_proof(vec![5], 6).unwrap() + }); // Verify proof without relying on any on-chain data. let leaf = crate::primitives::DataOrHash::Data(leaves[0].clone()); assert_eq!( - crate::verify_leaves_proof::<::Hashing, _>(root, vec![leaf], proof5), + crate::verify_leaves_proof::<::Hashing, _>( + root_7, + vec![leaf.clone()], + proof5 + ), + Ok(()) + ); + assert_eq!( + crate::verify_leaves_proof::<::Hashing, _>( + root_6, + vec![leaf], + historical_proof5 + ), Ok(()) ); } @@ -441,7 +636,13 @@ fn should_verify_batch_proof_statelessly() { // Start off with chain initialisation and storing indexing data off-chain // (MMR Leafs) let mut ext = new_test_ext(); - ext.execute_with(|| add_blocks(7)); + let (root_6, root_7) = ext.execute_with(|| { + add_blocks(6); + let root_6 = crate::Pallet::::mmr_root_hash(); + add_blocks(1); + let root_7 = crate::Pallet::::mmr_root_hash(); + (root_6, root_7) + }); ext.persist_offchain_overlay(); // Try to generate proof now. This requires the offchain extensions to be present @@ -449,14 +650,17 @@ fn should_verify_batch_proof_statelessly() { register_offchain_ext(&mut ext); let (leaves, proof) = ext.execute_with(|| { // when - crate::Pallet::::generate_batch_proof(vec![0, 4, 5]).unwrap() + crate::Pallet::::generate_batch_proof(vec![1, 4, 5]).unwrap() + }); + let (historical_leaves, historical_proof) = ext.execute_with(|| { + // when + crate::Pallet::::generate_historical_batch_proof(vec![1, 4, 5], 6).unwrap() }); - let root = ext.execute_with(|| crate::Pallet::::mmr_root_hash()); // Verify proof without relying on any on-chain data. assert_eq!( crate::verify_leaves_proof::<::Hashing, _>( - root, + root_7, leaves .into_iter() .map(|leaf| crate::primitives::DataOrHash::Data(leaf)) @@ -465,6 +669,17 @@ fn should_verify_batch_proof_statelessly() { ), Ok(()) ); + assert_eq!( + crate::verify_leaves_proof::<::Hashing, _>( + root_6, + historical_leaves + .into_iter() + .map(|leaf| crate::primitives::DataOrHash::Data(leaf)) + .collect(), + historical_proof + ), + Ok(()) + ); } #[test] @@ -597,16 +812,20 @@ fn should_canonicalize_offchain() { let parent_num: BlockNumber = (block_num - 1).into(); let leaf_index = u64::from(block_num - 1); let pos = helper::leaf_index_to_pos(leaf_index.into()); - // not canon, - assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(pos)), None); let parent_hash = >::block_hash(parent_num); - // but available in fork-proof storage. + // Available in offchain db under both fork-proof key and canon key. + // We'll later check it is pruned from fork-proof key. + let expected = Some(mmr::Node::Data(( + (leaf_index, H256::repeat_byte(u8::try_from(block_num).unwrap())), + LeafData::new(block_num.into()), + ))); assert_eq!( - offchain_db.get(&MMR::node_offchain_key(parent_hash, pos)).map(decode_node), - Some(mmr::Node::Data(( - (leaf_index, H256::repeat_byte(u8::try_from(block_num).unwrap())), - LeafData::new(block_num.into()), - ))) + offchain_db.get(&MMR::node_canon_offchain_key(pos)).map(decode_node), + expected + ); + assert_eq!( + offchain_db.get(&MMR::node_offchain_key(pos, parent_hash)).map(decode_node), + expected ); } @@ -617,12 +836,16 @@ fn should_canonicalize_offchain() { let verify = |pos: NodeIndex, leaf_index: LeafIndex, expected: H256| { let parent_num: BlockNumber = leaf_index.try_into().unwrap(); let parent_hash = >::block_hash(parent_num); - // not canon, - assert_eq!(offchain_db.get(&MMR::node_canon_offchain_key(pos)), None); - // but available in fork-proof storage. + // Available in offchain db under both fork-proof key and canon key. + // We'll later check it is pruned from fork-proof key. + let expected = Some(mmr::Node::Hash(expected)); assert_eq!( - offchain_db.get(&MMR::node_offchain_key(parent_hash, pos)).map(decode_node), - Some(mmr::Node::Hash(expected)) + offchain_db.get(&MMR::node_canon_offchain_key(pos)).map(decode_node), + expected + ); + assert_eq!( + offchain_db.get(&MMR::node_offchain_key(pos, parent_hash)).map(decode_node), + expected ); }; verify(2, 1, hex("672c04a9cd05a644789d769daa552d35d8de7c33129f8a7cbf49e595234c4854")); @@ -649,7 +872,7 @@ fn should_canonicalize_offchain() { let parent_num: BlockNumber = (block_num - 1).into(); let parent_hash = >::block_hash(parent_num); // no longer available in fork-proof storage (was pruned), - assert_eq!(offchain_db.get(&MMR::node_offchain_key(parent_hash, pos)), None); + assert_eq!(offchain_db.get(&MMR::node_offchain_key(pos, parent_hash)), None); // but available using canon key. assert_eq!( offchain_db.get(&MMR::node_canon_offchain_key(pos)).map(decode_node), @@ -668,7 +891,7 @@ fn should_canonicalize_offchain() { let parent_num: BlockNumber = leaf_index.try_into().unwrap(); let parent_hash = >::block_hash(parent_num); // no longer available in fork-proof storage (was pruned), - assert_eq!(offchain_db.get(&MMR::node_offchain_key(parent_hash, pos)), None); + assert_eq!(offchain_db.get(&MMR::node_offchain_key(pos, parent_hash)), None); // but available using canon key. assert_eq!( offchain_db.get(&MMR::node_canon_offchain_key(pos)).map(decode_node), @@ -705,7 +928,7 @@ fn should_verify_canonicalized() { // Generate proofs for some blocks. let (leaves, proofs) = - ext.execute_with(|| crate::Pallet::::generate_batch_proof(vec![0, 4, 5, 7]).unwrap()); + ext.execute_with(|| crate::Pallet::::generate_batch_proof(vec![1, 4, 5, 7]).unwrap()); // Verify all previously generated proofs. ext.execute_with(|| { assert_eq!(crate::Pallet::::verify_leaves(leaves, proofs), Ok(())); @@ -721,3 +944,36 @@ fn should_verify_canonicalized() { assert_eq!(crate::Pallet::::verify_leaves(leaves, proofs), Ok(())); }); } + +#[test] +fn does_not_panic_when_generating_historical_proofs() { + let _ = env_logger::try_init(); + let mut ext = new_test_ext(); + + // given 7 blocks (7 MMR leaves) + ext.execute_with(|| add_blocks(7)); + ext.persist_offchain_overlay(); + + // Try to generate historical proof with invalid arguments. This requires the offchain + // extensions to be present to retrieve full leaf data. + register_offchain_ext(&mut ext); + ext.execute_with(|| { + // when leaf index is invalid + assert_eq!( + crate::Pallet::::generate_historical_batch_proof(vec![10], 7), + Err(Error::BlockNumToLeafIndex), + ); + + // when leaves count is invalid + assert_eq!( + crate::Pallet::::generate_historical_batch_proof(vec![3], 100), + Err(Error::BlockNumToLeafIndex), + ); + + // when both leaf index and leaves count are invalid + assert_eq!( + crate::Pallet::::generate_historical_batch_proof(vec![10], 100), + Err(Error::BlockNumToLeafIndex), + ); + }); +} diff --git a/frame/multisig/Cargo.toml b/frame/multisig/Cargo.toml index a370215032714..bfd0870d30c22 100644 --- a/frame/multisig/Cargo.toml +++ b/frame/multisig/Cargo.toml @@ -22,6 +22,9 @@ sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +# third party +log = { version = "0.4.17", default-features = false } + [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } sp-core = { version = "6.0.0", path = "../../primitives/core" } @@ -29,6 +32,7 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/multisig/src/benchmarking.rs b/frame/multisig/src/benchmarking.rs index dafc421a7b72d..d949414e31cb3 100644 --- a/frame/multisig/src/benchmarking.rs +++ b/frame/multisig/src/benchmarking.rs @@ -31,7 +31,7 @@ const SEED: u32 = 0; fn setup_multi( s: u32, z: u32, -) -> Result<(Vec, OpaqueCall), &'static str> { +) -> Result<(Vec, Box<::RuntimeCall>), &'static str> { let mut signatories: Vec = Vec::new(); for i in 0..s { let signatory = account("signatory", i, SEED); @@ -41,11 +41,10 @@ fn setup_multi( signatories.push(signatory); } signatories.sort(); - // Must first convert to outer call type. - let call: ::Call = + // Must first convert to runtime call type. + let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![0; z as usize] }.into(); - let call_data = OpaqueCall::::from_encoded(call.encode()); - Ok((signatories, call_data)) + Ok((signatories, Box::new(call))) } benchmarks! { @@ -54,7 +53,7 @@ benchmarks! { let z in 0 .. 10_000; let max_signatories = T::MaxSignatories::get().into(); let (mut signatories, _) = setup_multi::(max_signatories, z)?; - let call: ::Call = frame_system::Call::::remark { + let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![0; z as usize] }.into(); let call_hash = call.using_encoded(blake2_256); @@ -74,35 +73,15 @@ benchmarks! { // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(call.encoded()); - let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); - let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - // Whitelist caller account from further DB operations. - let caller_key = frame_system::Account::::hashed_key_for(&caller); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, false, Weight::zero()) - verify { - assert!(Multisigs::::contains_key(multi_account_id, call_hash)); - assert!(!Calls::::contains_key(call_hash)); - } - - as_multi_create_store { - // Signatories, need at least 2 total people - let s in 2 .. T::MaxSignatories::get() as u32; - // Transaction Length - let z in 0 .. 10_000; - let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(call.encoded()); + let call_hash = call.using_encoded(blake2_256); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, true, Weight::zero()) + }: as_multi(RawOrigin::Signed(caller), s as u16, signatories, None, call, Weight::zero()) verify { assert!(Multisigs::::contains_key(multi_account_id, call_hash)); - assert!(Calls::::contains_key(call_hash)); } as_multi_approve { @@ -111,49 +90,22 @@ benchmarks! { // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(call.encoded()); - let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); - let mut signatories2 = signatories.clone(); - let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - // before the call, get the timepoint - let timepoint = Multisig::::timepoint(); - // Create the multi, storing for worst case - Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, Weight::zero())?; - assert!(Calls::::contains_key(call_hash)); - let caller2 = signatories2.remove(0); - // Whitelist caller account from further DB operations. - let caller_key = frame_system::Account::::hashed_key_for(&caller2); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, false, Weight::zero()) - verify { - let multisig = Multisigs::::get(multi_account_id, call_hash).ok_or("multisig not created")?; - assert_eq!(multisig.approvals.len(), 2); - } - - as_multi_approve_store { - // Signatories, need at least 3 people (so we don't complete the multisig) - let s in 3 .. T::MaxSignatories::get() as u32; - // Transaction Length - let z in 0 .. 10_000; - let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(call.encoded()); + let call_hash = call.using_encoded(blake2_256); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let mut signatories2 = signatories.clone(); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; // before the call, get the timepoint let timepoint = Multisig::::timepoint(); - // Create the multi, not storing - Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), false, Weight::zero())?; - assert!(!Calls::::contains_key(call_hash)); + // Create the multi + Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), Weight::zero())?; let caller2 = signatories2.remove(0); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller2); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, true, Weight::zero()) + }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, Weight::zero()) verify { let multisig = Multisigs::::get(multi_account_id, call_hash).ok_or("multisig not created")?; assert_eq!(multisig.approvals.len(), 2); - assert!(Calls::::contains_key(call_hash)); } as_multi_complete { @@ -162,27 +114,27 @@ benchmarks! { // Transaction Length let z in 0 .. 10_000; let (mut signatories, call) = setup_multi::(s, z)?; - let call_hash = blake2_256(call.encoded()); + let call_hash = call.using_encoded(blake2_256); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let mut signatories2 = signatories.clone(); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; // before the call, get the timepoint let timepoint = Multisig::::timepoint(); - // Create the multi, storing it for worst case - Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, Weight::zero())?; + // Create the multi + Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), Weight::zero())?; // Everyone except the first person approves for i in 1 .. s - 1 { let mut signatories_loop = signatories2.clone(); let caller_loop = signatories_loop.remove(i as usize); let o = RawOrigin::Signed(caller_loop).into(); - Multisig::::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), false, Weight::zero())?; + Multisig::::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), Weight::zero())?; } let caller2 = signatories2.remove(0); assert!(Multisigs::::contains_key(&multi_account_id, call_hash)); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller2); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, false, Weight::MAX) + }: as_multi(RawOrigin::Signed(caller2), s as u16, signatories2, Some(timepoint), call, Weight::MAX) verify { assert!(!Multisigs::::contains_key(&multi_account_id, call_hash)); } @@ -195,7 +147,7 @@ benchmarks! { let (mut signatories, call) = setup_multi::(s, z)?; let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - let call_hash = blake2_256(call.encoded()); + let call_hash = call.using_encoded(blake2_256); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); @@ -214,7 +166,7 @@ benchmarks! { let mut signatories2 = signatories.clone(); let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - let call_hash = blake2_256(call.encoded()); + let call_hash = call.using_encoded(blake2_256); // before the call, get the timepoint let timepoint = Multisig::::timepoint(); // Create the multi @@ -224,7 +176,6 @@ benchmarks! { signatories, None, call, - false, Weight::zero() )?; let caller2 = signatories2.remove(0); @@ -237,45 +188,6 @@ benchmarks! { assert_eq!(multisig.approvals.len(), 2); } - approve_as_multi_complete { - // Signatories, need at least 2 people - let s in 2 .. T::MaxSignatories::get() as u32; - // Transaction Length, not a component - let z = 10_000; - let (mut signatories, call) = setup_multi::(s, z)?; - let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); - let mut signatories2 = signatories.clone(); - let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - let call_hash = blake2_256(call.encoded()); - // before the call, get the timepoint - let timepoint = Multisig::::timepoint(); - // Create the multi - Multisig::::as_multi(RawOrigin::Signed(caller).into(), s as u16, signatories, None, call.clone(), true, Weight::zero())?; - // Everyone except the first person approves - for i in 1 .. s - 1 { - let mut signatories_loop = signatories2.clone(); - let caller_loop = signatories_loop.remove(i as usize); - let o = RawOrigin::Signed(caller_loop).into(); - Multisig::::as_multi(o, s as u16, signatories_loop, Some(timepoint), call.clone(), false, Weight::zero())?; - } - let caller2 = signatories2.remove(0); - assert!(Multisigs::::contains_key(&multi_account_id, call_hash)); - // Whitelist caller account from further DB operations. - let caller_key = frame_system::Account::::hashed_key_for(&caller2); - frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); - }: approve_as_multi( - RawOrigin::Signed(caller2), - s as u16, - signatories2, - Some(timepoint), - call_hash, - Weight::MAX - ) - verify { - assert!(!Multisigs::::contains_key(multi_account_id, call_hash)); - } - cancel_as_multi { // Signatories, need at least 2 people let s in 2 .. T::MaxSignatories::get() as u32; @@ -284,20 +196,18 @@ benchmarks! { let (mut signatories, call) = setup_multi::(s, z)?; let multi_account_id = Multisig::::multi_account_id(&signatories, s.try_into().unwrap()); let caller = signatories.pop().ok_or("signatories should have len 2 or more")?; - let call_hash = blake2_256(call.encoded()); + let call_hash = call.using_encoded(blake2_256); let timepoint = Multisig::::timepoint(); // Create the multi let o = RawOrigin::Signed(caller.clone()).into(); - Multisig::::as_multi(o, s as u16, signatories.clone(), None, call, true, Weight::zero())?; + Multisig::::as_multi(o, s as u16, signatories.clone(), None, call, Weight::zero())?; assert!(Multisigs::::contains_key(&multi_account_id, call_hash)); - assert!(Calls::::contains_key(call_hash)); // Whitelist caller account from further DB operations. let caller_key = frame_system::Account::::hashed_key_for(&caller); frame_benchmarking::benchmarking::add_to_whitelist(caller_key.into()); }: _(RawOrigin::Signed(caller), s as u16, signatories, timepoint, call_hash) verify { assert!(!Multisigs::::contains_key(multi_account_id, call_hash)); - assert!(!Calls::::contains_key(call_hash)); } impl_benchmark_test_suite!(Multisig, crate::tests::new_test_ext(), crate::tests::Test); diff --git a/frame/multisig/src/lib.rs b/frame/multisig/src/lib.rs index 10184ce84a9a8..07fbcb4c03117 100644 --- a/frame/multisig/src/lib.rs +++ b/frame/multisig/src/lib.rs @@ -47,17 +47,19 @@ #![cfg_attr(not(feature = "std"), no_std)] mod benchmarking; +pub mod migrations; mod tests; pub mod weights; use codec::{Decode, Encode}; use frame_support::{ dispatch::{ - DispatchErrorWithPostInfo, DispatchResult, DispatchResultWithPostInfo, PostDispatchInfo, + DispatchErrorWithPostInfo, DispatchResult, DispatchResultWithPostInfo, GetDispatchInfo, + PostDispatchInfo, }, ensure, - traits::{Currency, Get, ReservableCurrency, WrapperKeepOpaque}, - weights::{GetDispatchInfo, Weight}, + traits::{Currency, Get, ReservableCurrency}, + weights::Weight, RuntimeDebug, }; use frame_system::{self as system, RawOrigin}; @@ -72,6 +74,20 @@ pub use weights::WeightInfo; pub use pallet::*; +/// The log target of this pallet. +pub const LOG_TARGET: &'static str = "runtime::multisig"; + +// syntactic sugar for logging. +#[macro_export] +macro_rules! log { + ($level:tt, $patter:expr $(, $values:expr)* $(,)?) => { + log::$level!( + target: crate::LOG_TARGET, + concat!("[{:?}] ✍️ ", $patter), >::block_number() $(, $values)* + ) + }; +} + type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -99,12 +115,10 @@ pub struct Multisig { approvals: Vec, } -type OpaqueCall = WrapperKeepOpaque<::Call>; - type CallHash = [u8; 32]; enum CallOrHash { - Call(OpaqueCall, bool), + Call(::RuntimeCall), Hash([u8; 32]), } @@ -117,11 +131,11 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The overarching call type. - type Call: Parameter - + Dispatchable + type RuntimeCall: Parameter + + Dispatchable + GetDispatchInfo + From>; @@ -151,9 +165,13 @@ pub mod pallet { type WeightInfo: WeightInfo; } + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::without_storage_info] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); /// The set of open multisig operations. @@ -167,10 +185,6 @@ pub mod pallet { Multisig, T::AccountId>, >; - #[pallet::storage] - pub type Calls = - StorageMap<_, Identity, [u8; 32], (OpaqueCall, T::AccountId, BalanceOf)>; - #[pallet::error] pub enum Error { /// Threshold must be 2 or greater. @@ -266,7 +280,7 @@ pub mod pallet { pub fn as_multi_threshold_1( origin: OriginFor, other_signatories: Vec, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; let max_sigs = T::MaxSignatories::get() as usize; @@ -342,16 +356,15 @@ pub mod pallet { /// taken for its lifetime of `DepositBase + threshold * DepositFactor`. /// ------------------------------- /// - DB Weight: - /// - Reads: Multisig Storage, [Caller Account], Calls (if `store_call`) - /// - Writes: Multisig Storage, [Caller Account], Calls (if `store_call`) + /// - Reads: Multisig Storage, [Caller Account] + /// - Writes: Multisig Storage, [Caller Account] /// - Plus Call Weight /// # #[pallet::weight({ let s = other_signatories.len() as u32; - let z = call.encoded_len() as u32; + let z = call.using_encoded(|d| d.len()) as u32; T::WeightInfo::as_multi_create(s, z) - .max(T::WeightInfo::as_multi_create_store(s, z)) .max(T::WeightInfo::as_multi_approve(s, z)) .max(T::WeightInfo::as_multi_complete(s, z)) .saturating_add(*max_weight) @@ -361,8 +374,7 @@ pub mod pallet { threshold: u16, other_signatories: Vec, maybe_timepoint: Option>, - call: OpaqueCall, - store_call: bool, + call: Box<::RuntimeCall>, max_weight: Weight, ) -> DispatchResultWithPostInfo { let who = ensure_signed(origin)?; @@ -371,7 +383,7 @@ pub mod pallet { threshold, other_signatories, maybe_timepoint, - CallOrHash::Call(call, store_call), + CallOrHash::Call(*call), max_weight, ) } @@ -416,7 +428,6 @@ pub mod pallet { T::WeightInfo::approve_as_multi_create(s) .max(T::WeightInfo::approve_as_multi_approve(s)) - .max(T::WeightInfo::approve_as_multi_complete(s)) .saturating_add(*max_weight) })] pub fn approve_as_multi( @@ -461,8 +472,8 @@ pub mod pallet { /// - Storage: removes one item. /// ---------------------------------- /// - DB Weight: - /// - Read: Multisig Storage, [Caller Account], Refund Account, Calls - /// - Write: Multisig Storage, [Caller Account], Refund Account, Calls + /// - Read: Multisig Storage, [Caller Account], Refund Account + /// - Write: Multisig Storage, [Caller Account], Refund Account /// # #[pallet::weight(T::WeightInfo::cancel_as_multi(other_signatories.len() as u32))] pub fn cancel_as_multi( @@ -488,7 +499,6 @@ pub mod pallet { let err_amount = T::Currency::unreserve(&m.depositor, m.deposit); debug_assert!(err_amount.is_zero()); >::remove(&id, &call_hash); - Self::clear_call(&call_hash); Self::deposit_event(Event::MultisigCancelled { cancelling: who, @@ -530,13 +540,12 @@ impl Pallet { let id = Self::multi_account_id(&signatories, threshold); // Threshold > 1; this means it's a multi-step operation. We extract the `call_hash`. - let (call_hash, call_len, maybe_call, store) = match call_or_hash { - CallOrHash::Call(call, should_store) => { - let call_hash = blake2_256(call.encoded()); - let call_len = call.encoded_len(); - (call_hash, call_len, Some(call), should_store) + let (call_hash, call_len, maybe_call) = match call_or_hash { + CallOrHash::Call(call) => { + let (call_hash, call_len) = call.using_encoded(|d| (blake2_256(d), d.len())); + (call_hash, call_len, Some(call)) }, - CallOrHash::Hash(h) => (h, 0, None, false), + CallOrHash::Hash(h) => (h, 0, None), }; // Branch on whether the operation has already started or not. @@ -555,20 +564,16 @@ impl Pallet { } // We only bother fetching/decoding call if we know that we're ready to execute. - let maybe_approved_call = if approvals >= threshold { - Self::get_call(&call_hash, maybe_call.as_ref()) - } else { - None - }; - - if let Some((call, call_len)) = maybe_approved_call { + if let Some(call) = maybe_call.filter(|_| approvals >= threshold) { // verify weight - ensure!(call.get_dispatch_info().weight <= max_weight, Error::::MaxWeightTooLow); + ensure!( + call.get_dispatch_info().weight.all_lte(max_weight), + Error::::MaxWeightTooLow + ); // Clean up storage before executing call to avoid an possibility of reentrancy // attack. >::remove(&id, call_hash); - Self::clear_call(&call_hash); T::Currency::unreserve(&m.depositor, m.deposit); let result = call.dispatch(RawOrigin::Signed(id.clone()).into()); @@ -592,19 +597,6 @@ impl Pallet { // We cannot dispatch the call now; either it isn't available, or it is, but we // don't have threshold approvals even with our signature. - // Store the call if desired. - let stored = if let Some(data) = maybe_call.filter(|_| store) { - Self::store_call_and_reserve( - who.clone(), - &call_hash, - data, - BalanceOf::::zero(), - )?; - true - } else { - false - }; - if let Some(pos) = maybe_pos { // Record approval. m.approvals.insert(pos, who.clone()); @@ -618,17 +610,11 @@ impl Pallet { } else { // If we already approved and didn't store the Call, then this was useless and // we report an error. - ensure!(stored, Error::::AlreadyApproved); + Err(Error::::AlreadyApproved)? } - let final_weight = if stored { - T::WeightInfo::as_multi_approve_store( - other_signatories_len as u32, - call_len as u32, - ) - } else { - T::WeightInfo::as_multi_approve(other_signatories_len as u32, call_len as u32) - }; + let final_weight = + T::WeightInfo::as_multi_approve(other_signatories_len as u32, call_len as u32); // Call is not made, so the actual weight does not include call Ok(Some(final_weight).into()) } @@ -639,14 +625,7 @@ impl Pallet { // Just start the operation by recording it in storage. let deposit = T::DepositBase::get() + T::DepositFactor::get() * threshold.into(); - // Store the call if desired. - let stored = if let Some(data) = maybe_call.filter(|_| store) { - Self::store_call_and_reserve(who.clone(), &call_hash, data, deposit)?; - true - } else { - T::Currency::reserve(&who, deposit)?; - false - }; + T::Currency::reserve(&who, deposit)?; >::insert( &id, @@ -660,58 +639,13 @@ impl Pallet { ); Self::deposit_event(Event::NewMultisig { approving: who, multisig: id, call_hash }); - let final_weight = if stored { - T::WeightInfo::as_multi_create_store(other_signatories_len as u32, call_len as u32) - } else { - T::WeightInfo::as_multi_create(other_signatories_len as u32, call_len as u32) - }; + let final_weight = + T::WeightInfo::as_multi_create(other_signatories_len as u32, call_len as u32); // Call is not made, so the actual weight does not include call Ok(Some(final_weight).into()) } } - /// Place a call's encoded data in storage, reserving funds as appropriate. - /// - /// We store `data` here because storing `call` would result in needing another `.encode`. - /// - /// Returns a `bool` indicating whether the data did end up being stored. - fn store_call_and_reserve( - who: T::AccountId, - hash: &[u8; 32], - data: OpaqueCall, - other_deposit: BalanceOf, - ) -> DispatchResult { - ensure!(!Calls::::contains_key(hash), Error::::AlreadyStored); - let deposit = other_deposit + - T::DepositBase::get() + - T::DepositFactor::get() * - BalanceOf::::from(((data.encoded_len() + 31) / 32) as u32); - T::Currency::reserve(&who, deposit)?; - Calls::::insert(&hash, (data, who, deposit)); - Ok(()) - } - - /// Attempt to decode and return the call, provided by the user or from storage. - fn get_call( - hash: &[u8; 32], - maybe_known: Option<&OpaqueCall>, - ) -> Option<(::Call, usize)> { - maybe_known.map_or_else( - || { - Calls::::get(hash) - .and_then(|(data, ..)| Some((data.try_decode()?, data.encoded_len()))) - }, - |data| Some((data.try_decode()?, data.encoded_len())), - ) - } - - /// Attempt to remove a call from storage, returning any deposit on it to the owner. - fn clear_call(hash: &[u8; 32]) { - if let Some((_, who, deposit)) = Calls::::take(hash) { - T::Currency::unreserve(&who, deposit); - } - } - /// The current `Timepoint`. pub fn timepoint() -> Timepoint { Timepoint { diff --git a/frame/multisig/src/migrations.rs b/frame/multisig/src/migrations.rs new file mode 100644 index 0000000000000..5085297cde433 --- /dev/null +++ b/frame/multisig/src/migrations.rs @@ -0,0 +1,86 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Migrations for Multisig Pallet + +use super::*; +use frame_support::{ + dispatch::GetStorageVersion, + traits::{OnRuntimeUpgrade, WrapperKeepOpaque}, + Identity, +}; + +#[cfg(feature = "try-runtime")] +use frame_support::ensure; + +pub mod v1 { + use super::*; + + type OpaqueCall = WrapperKeepOpaque<::RuntimeCall>; + + #[frame_support::storage_alias] + type Calls = StorageMap< + Pallet, + Identity, + [u8; 32], + (OpaqueCall, ::AccountId, BalanceOf), + >; + + pub struct MigrateToV1(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV1 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + let onchain = Pallet::::on_chain_storage_version(); + + ensure!(onchain < 1, "this migration can be deleted"); + + log!(info, "Number of calls to refund and delete: {}", Calls::::iter().count()); + + Ok(Vec::new()) + } + + fn on_runtime_upgrade() -> Weight { + let current = Pallet::::current_storage_version(); + let onchain = Pallet::::on_chain_storage_version(); + + if onchain > 0 { + log!(info, "MigrateToV1 should be removed"); + return T::DbWeight::get().reads(1) + } + + Calls::::drain().for_each(|(_call_hash, (_data, caller, deposit))| { + T::Currency::unreserve(&caller, deposit); + }); + + current.put::>(); + + ::BlockWeights::get().max_block + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { + let onchain = Pallet::::on_chain_storage_version(); + ensure!(onchain < 2, "this migration needs to be removed"); + ensure!(onchain == 1, "this migration needs to be run"); + ensure!( + Calls::::iter().count() == 0, + "there are some dangling calls that need to be destroyed and refunded" + ); + Ok(()) + } + } +} diff --git a/frame/multisig/src/tests.rs b/frame/multisig/src/tests.rs index ddf5197ab734c..f753b6f386c56 100644 --- a/frame/multisig/src/tests.rs +++ b/frame/multisig/src/tests.rs @@ -34,7 +34,6 @@ use sp_runtime::{ type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; -type OpaqueCall = super::OpaqueCall; frame_support::construct_runtime!( pub enum Test where @@ -57,16 +56,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -84,7 +83,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -92,19 +91,19 @@ impl pallet_balances::Config for Test { } pub struct TestBaseCallFilter; -impl Contains for TestBaseCallFilter { - fn contains(c: &Call) -> bool { +impl Contains for TestBaseCallFilter { + fn contains(c: &RuntimeCall) -> bool { match *c { - Call::Balances(_) => true, + RuntimeCall::Balances(_) => true, // Needed for benchmarking - Call::System(frame_system::Call::remark { .. }) => true, + RuntimeCall::System(frame_system::Call::remark { .. }) => true, _ => false, } } } impl Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type Currency = Balances; type DepositBase = ConstU64<1>; type DepositFactor = ConstU64<1>; @@ -130,40 +129,37 @@ fn now() -> Timepoint { Multisig::timepoint() } -fn call_transfer(dest: u64, value: u64) -> Call { - Call::Balances(BalancesCall::transfer { dest, value }) +fn call_transfer(dest: u64, value: u64) -> Box { + Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest, value })) } #[test] fn multisig_deposit_is_taken_and_returned() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); assert_ok!(Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, - OpaqueCall::from_encoded(data.clone()), - false, + call.clone(), Weight::zero() )); assert_eq!(Balances::free_balance(1), 2); assert_eq!(Balances::reserved_balance(1), 3); assert_ok!(Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(now()), - OpaqueCall::from_encoded(data), - false, + call, call_weight )); assert_eq!(Balances::free_balance(1), 5); @@ -171,103 +167,13 @@ fn multisig_deposit_is_taken_and_returned() { }); } -#[test] -fn multisig_deposit_is_taken_and_returned_with_call_storage() { - new_test_ext().execute_with(|| { - let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); - - let call = call_transfer(6, 15); - let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); - let hash = blake2_256(&data); - assert_ok!(Multisig::as_multi( - Origin::signed(1), - 2, - vec![2, 3], - None, - OpaqueCall::from_encoded(data), - true, - Weight::zero() - )); - assert_eq!(Balances::free_balance(1), 0); - assert_eq!(Balances::reserved_balance(1), 5); - - assert_ok!(Multisig::approve_as_multi( - Origin::signed(2), - 2, - vec![1, 3], - Some(now()), - hash, - call_weight - )); - assert_eq!(Balances::free_balance(1), 5); - assert_eq!(Balances::reserved_balance(1), 0); - }); -} - -#[test] -fn multisig_deposit_is_taken_and_returned_with_alt_call_storage() { - new_test_ext().execute_with(|| { - let multi = Multisig::multi_account_id(&[1, 2, 3][..], 3); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); - - let call = call_transfer(6, 15); - let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); - let hash = blake2_256(&data); - - assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), - 3, - vec![2, 3], - None, - hash, - Weight::zero() - )); - assert_eq!(Balances::free_balance(1), 1); - assert_eq!(Balances::reserved_balance(1), 4); - - assert_ok!(Multisig::as_multi( - Origin::signed(2), - 3, - vec![1, 3], - Some(now()), - OpaqueCall::from_encoded(data), - true, - Weight::zero() - )); - assert_eq!(Balances::free_balance(2), 3); - assert_eq!(Balances::reserved_balance(2), 2); - assert_eq!(Balances::free_balance(1), 1); - assert_eq!(Balances::reserved_balance(1), 4); - - assert_ok!(Multisig::approve_as_multi( - Origin::signed(3), - 3, - vec![1, 2], - Some(now()), - hash, - call_weight - )); - assert_eq!(Balances::free_balance(1), 5); - assert_eq!(Balances::reserved_balance(1), 0); - assert_eq!(Balances::free_balance(2), 5); - assert_eq!(Balances::reserved_balance(2), 0); - }); -} - #[test] fn cancel_multisig_returns_deposit() { new_test_ext().execute_with(|| { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, vec![2, 3], None, @@ -275,7 +181,7 @@ fn cancel_multisig_returns_deposit() { Weight::zero() )); assert_ok!(Multisig::approve_as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 3, vec![1, 3], Some(now()), @@ -284,7 +190,7 @@ fn cancel_multisig_returns_deposit() { )); assert_eq!(Balances::free_balance(1), 6); assert_eq!(Balances::reserved_balance(1), 4); - assert_ok!(Multisig::cancel_as_multi(Origin::signed(1), 3, vec![2, 3], now(), hash)); + assert_ok!(Multisig::cancel_as_multi(RuntimeOrigin::signed(1), 3, vec![2, 3], now(), hash)); assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::reserved_balance(1), 0); }); @@ -294,16 +200,16 @@ fn cancel_multisig_returns_deposit() { fn timepoint_checking_works() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); - let call = call_transfer(6, 15).encode(); - let hash = blake2_256(&call); + let call = call_transfer(6, 15); + let hash = blake2_256(&call.encode()); assert_noop!( Multisig::approve_as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(now()), @@ -314,7 +220,7 @@ fn timepoint_checking_works() { ); assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, @@ -324,12 +230,11 @@ fn timepoint_checking_works() { assert_noop!( Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], None, - OpaqueCall::from_encoded(call.clone()), - false, + call.clone(), Weight::zero() ), Error::::NoTimepoint, @@ -337,12 +242,11 @@ fn timepoint_checking_works() { let later = Timepoint { index: 1, ..now() }; assert_noop!( Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(later), - OpaqueCall::from_encoded(call), - false, + call, Weight::zero() ), Error::::WrongTimepoint, @@ -350,55 +254,19 @@ fn timepoint_checking_works() { }); } -#[test] -fn multisig_2_of_3_works_with_call_storing() { - new_test_ext().execute_with(|| { - let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); - - let call = call_transfer(6, 15); - let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); - let hash = blake2_256(&data); - assert_ok!(Multisig::as_multi( - Origin::signed(1), - 2, - vec![2, 3], - None, - OpaqueCall::from_encoded(data), - true, - Weight::zero() - )); - assert_eq!(Balances::free_balance(6), 0); - - assert_ok!(Multisig::approve_as_multi( - Origin::signed(2), - 2, - vec![1, 3], - Some(now()), - hash, - call_weight - )); - assert_eq!(Balances::free_balance(6), 15); - }); -} - #[test] fn multisig_2_of_3_works() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); - let hash = blake2_256(&data); + let hash = blake2_256(&call.encode()); assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, @@ -408,12 +276,11 @@ fn multisig_2_of_3_works() { assert_eq!(Balances::free_balance(6), 0); assert_ok!(Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(now()), - OpaqueCall::from_encoded(data), - false, + call, call_weight )); assert_eq!(Balances::free_balance(6), 15); @@ -424,16 +291,15 @@ fn multisig_2_of_3_works() { fn multisig_3_of_3_works() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 3); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); - let hash = blake2_256(&data); + let hash = blake2_256(&call.encode()); assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, vec![2, 3], None, @@ -441,7 +307,7 @@ fn multisig_3_of_3_works() { Weight::zero() )); assert_ok!(Multisig::approve_as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 3, vec![1, 3], Some(now()), @@ -451,12 +317,11 @@ fn multisig_3_of_3_works() { assert_eq!(Balances::free_balance(6), 0); assert_ok!(Multisig::as_multi( - Origin::signed(3), + RuntimeOrigin::signed(3), 3, vec![1, 2], Some(now()), - OpaqueCall::from_encoded(data), - false, + call, call_weight )); assert_eq!(Balances::free_balance(6), 15); @@ -469,7 +334,7 @@ fn cancel_multisig_works() { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, vec![2, 3], None, @@ -477,38 +342,7 @@ fn cancel_multisig_works() { Weight::zero() )); assert_ok!(Multisig::approve_as_multi( - Origin::signed(2), - 3, - vec![1, 3], - Some(now()), - hash, - Weight::zero() - )); - assert_noop!( - Multisig::cancel_as_multi(Origin::signed(2), 3, vec![1, 3], now(), hash), - Error::::NotOwner, - ); - assert_ok!(Multisig::cancel_as_multi(Origin::signed(1), 3, vec![2, 3], now(), hash),); - }); -} - -#[test] -fn cancel_multisig_with_call_storage_works() { - new_test_ext().execute_with(|| { - let call = call_transfer(6, 15).encode(); - let hash = blake2_256(&call); - assert_ok!(Multisig::as_multi( - Origin::signed(1), - 3, - vec![2, 3], - None, - OpaqueCall::from_encoded(call), - true, - Weight::zero() - )); - assert_eq!(Balances::free_balance(1), 4); - assert_ok!(Multisig::approve_as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 3, vec![1, 3], Some(now()), @@ -516,41 +350,10 @@ fn cancel_multisig_with_call_storage_works() { Weight::zero() )); assert_noop!( - Multisig::cancel_as_multi(Origin::signed(2), 3, vec![1, 3], now(), hash), + Multisig::cancel_as_multi(RuntimeOrigin::signed(2), 3, vec![1, 3], now(), hash), Error::::NotOwner, ); - assert_ok!(Multisig::cancel_as_multi(Origin::signed(1), 3, vec![2, 3], now(), hash),); - assert_eq!(Balances::free_balance(1), 10); - }); -} - -#[test] -fn cancel_multisig_with_alt_call_storage_works() { - new_test_ext().execute_with(|| { - let call = call_transfer(6, 15).encode(); - let hash = blake2_256(&call); - assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), - 3, - vec![2, 3], - None, - hash, - Weight::zero() - )); - assert_eq!(Balances::free_balance(1), 6); - assert_ok!(Multisig::as_multi( - Origin::signed(2), - 3, - vec![1, 3], - Some(now()), - OpaqueCall::from_encoded(call), - true, - Weight::zero() - )); - assert_eq!(Balances::free_balance(2), 8); - assert_ok!(Multisig::cancel_as_multi(Origin::signed(1), 3, vec![2, 3], now(), hash)); - assert_eq!(Balances::free_balance(1), 10); - assert_eq!(Balances::free_balance(2), 10); + assert_ok!(Multisig::cancel_as_multi(RuntimeOrigin::signed(1), 3, vec![2, 3], now(), hash),); }); } @@ -558,31 +361,28 @@ fn cancel_multisig_with_alt_call_storage_works() { fn multisig_2_of_3_as_multi_works() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); assert_ok!(Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, - OpaqueCall::from_encoded(data.clone()), - false, + call.clone(), Weight::zero() )); assert_eq!(Balances::free_balance(6), 0); assert_ok!(Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(now()), - OpaqueCall::from_encoded(data), - false, + call, call_weight )); assert_eq!(Balances::free_balance(6), 15); @@ -593,51 +393,45 @@ fn multisig_2_of_3_as_multi_works() { fn multisig_2_of_3_as_multi_with_many_calls_works() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call1 = call_transfer(6, 10); let call1_weight = call1.get_dispatch_info().weight; - let data1 = call1.encode(); let call2 = call_transfer(7, 5); let call2_weight = call2.get_dispatch_info().weight; - let data2 = call2.encode(); assert_ok!(Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, - OpaqueCall::from_encoded(data1.clone()), - false, + call1.clone(), Weight::zero() )); assert_ok!(Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], None, - OpaqueCall::from_encoded(data2.clone()), - false, + call2.clone(), Weight::zero() )); assert_ok!(Multisig::as_multi( - Origin::signed(3), + RuntimeOrigin::signed(3), 2, vec![1, 2], Some(now()), - OpaqueCall::from_encoded(data1), - false, + call1, call1_weight )); assert_ok!(Multisig::as_multi( - Origin::signed(3), + RuntimeOrigin::signed(3), 2, vec![1, 2], Some(now()), - OpaqueCall::from_encoded(data2), - false, + call2, call2_weight )); @@ -650,50 +444,45 @@ fn multisig_2_of_3_as_multi_with_many_calls_works() { fn multisig_2_of_3_cannot_reissue_same_call() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 10); let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); - let hash = blake2_256(&data); + let hash = blake2_256(&call.encode()); assert_ok!(Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, - OpaqueCall::from_encoded(data.clone()), - false, + call.clone(), Weight::zero() )); assert_ok!(Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(now()), - OpaqueCall::from_encoded(data.clone()), - false, + call.clone(), call_weight )); assert_eq!(Balances::free_balance(multi), 5); assert_ok!(Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, - OpaqueCall::from_encoded(data.clone()), - false, + call.clone(), Weight::zero() )); assert_ok!(Multisig::as_multi( - Origin::signed(3), + RuntimeOrigin::signed(3), 2, vec![1, 2], Some(now()), - OpaqueCall::from_encoded(data), - false, + call.clone(), call_weight )); @@ -714,27 +503,25 @@ fn multisig_2_of_3_cannot_reissue_same_call() { #[test] fn minimum_threshold_check_works() { new_test_ext().execute_with(|| { - let call = call_transfer(6, 15).encode(); + let call = call_transfer(6, 15); assert_noop!( Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 0, vec![2], None, - OpaqueCall::from_encoded(call.clone()), - false, + call.clone(), Weight::zero() ), Error::::MinimumThreshold, ); assert_noop!( Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 1, vec![2], None, - OpaqueCall::from_encoded(call.clone()), - false, + call.clone(), Weight::zero() ), Error::::MinimumThreshold, @@ -745,15 +532,14 @@ fn minimum_threshold_check_works() { #[test] fn too_many_signatories_fails() { new_test_ext().execute_with(|| { - let call = call_transfer(6, 15).encode(); + let call = call_transfer(6, 15); assert_noop!( Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3, 4], None, - OpaqueCall::from_encoded(call), - false, + call.clone(), Weight::zero() ), Error::::TooManySignatories, @@ -767,7 +553,7 @@ fn duplicate_approvals_are_ignored() { let call = call_transfer(6, 15).encode(); let hash = blake2_256(&call); assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, @@ -776,7 +562,7 @@ fn duplicate_approvals_are_ignored() { )); assert_noop!( Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], Some(now()), @@ -786,7 +572,7 @@ fn duplicate_approvals_are_ignored() { Error::::AlreadyApproved, ); assert_ok!(Multisig::approve_as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(now()), @@ -795,7 +581,7 @@ fn duplicate_approvals_are_ignored() { )); assert_noop!( Multisig::approve_as_multi( - Origin::signed(3), + RuntimeOrigin::signed(3), 2, vec![1, 2], Some(now()), @@ -811,15 +597,15 @@ fn duplicate_approvals_are_ignored() { fn multisig_1_of_3_works() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 1); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); - let call = call_transfer(6, 15).encode(); - let hash = blake2_256(&call); + let call = call_transfer(6, 15); + let hash = blake2_256(&call.encode()); assert_noop!( Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 1, vec![2, 3], None, @@ -830,18 +616,20 @@ fn multisig_1_of_3_works() { ); assert_noop!( Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 1, vec![2, 3], None, - OpaqueCall::from_encoded(call), - false, + call.clone(), Weight::zero() ), Error::::MinimumThreshold, ); - let boxed_call = Box::new(call_transfer(6, 15)); - assert_ok!(Multisig::as_multi_threshold_1(Origin::signed(1), vec![2, 3], boxed_call)); + assert_ok!(Multisig::as_multi_threshold_1( + RuntimeOrigin::signed(1), + vec![2, 3], + call_transfer(6, 15) + )); assert_eq!(Balances::free_balance(6), 15); }); @@ -850,9 +638,9 @@ fn multisig_1_of_3_works() { #[test] fn multisig_filters() { new_test_ext().execute_with(|| { - let call = Box::new(Call::System(frame_system::Call::set_code { code: vec![] })); + let call = Box::new(RuntimeCall::System(frame_system::Call::set_code { code: vec![] })); assert_noop!( - Multisig::as_multi_threshold_1(Origin::signed(1), vec![2], call.clone()), + Multisig::as_multi_threshold_1(RuntimeOrigin::signed(1), vec![2], call.clone()), DispatchError::from(frame_system::Error::::CallFiltered), ); }); @@ -862,31 +650,28 @@ fn multisig_filters() { fn weight_check_works() { new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 2); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); - let data = call.encode(); assert_ok!(Multisig::as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, vec![2, 3], None, - OpaqueCall::from_encoded(data.clone()), - false, + call.clone(), Weight::zero() )); assert_eq!(Balances::free_balance(6), 0); assert_noop!( Multisig::as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 2, vec![1, 3], Some(now()), - OpaqueCall::from_encoded(data), - false, + call, Weight::zero() ), Error::::MaxWeightTooLow, @@ -901,16 +686,15 @@ fn multisig_handles_no_preimage_after_all_approve() { // the call will go through. new_test_ext().execute_with(|| { let multi = Multisig::multi_account_id(&[1, 2, 3][..], 3); - assert_ok!(Balances::transfer(Origin::signed(1), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(2), multi, 5)); - assert_ok!(Balances::transfer(Origin::signed(3), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(2), multi, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), multi, 5)); let call = call_transfer(6, 15); let call_weight = call.get_dispatch_info().weight; - let data = call.encode(); - let hash = blake2_256(&data); + let hash = blake2_256(&call.encode()); assert_ok!(Multisig::approve_as_multi( - Origin::signed(1), + RuntimeOrigin::signed(1), 3, vec![2, 3], None, @@ -918,7 +702,7 @@ fn multisig_handles_no_preimage_after_all_approve() { Weight::zero() )); assert_ok!(Multisig::approve_as_multi( - Origin::signed(2), + RuntimeOrigin::signed(2), 3, vec![1, 3], Some(now()), @@ -926,7 +710,7 @@ fn multisig_handles_no_preimage_after_all_approve() { Weight::zero() )); assert_ok!(Multisig::approve_as_multi( - Origin::signed(3), + RuntimeOrigin::signed(3), 3, vec![1, 2], Some(now()), @@ -936,12 +720,11 @@ fn multisig_handles_no_preimage_after_all_approve() { assert_eq!(Balances::free_balance(6), 0); assert_ok!(Multisig::as_multi( - Origin::signed(3), + RuntimeOrigin::signed(3), 3, vec![1, 2], Some(now()), - OpaqueCall::from_encoded(data), - false, + call, call_weight )); assert_eq!(Balances::free_balance(6), 15); diff --git a/frame/multisig/src/weights.rs b/frame/multisig/src/weights.rs index d8d576775408a..de403b4d249e4 100644 --- a/frame/multisig/src/weights.rs +++ b/frame/multisig/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,22 +18,26 @@ //! Autogenerated weights for pallet_multisig //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-10-26, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_multisig // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json +// --pallet=pallet_multisig +// --chain=dev +// --header=./HEADER-APACHE2 // --output=./frame/multisig/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -46,213 +50,176 @@ use sp_std::marker::PhantomData; pub trait WeightInfo { fn as_multi_threshold_1(z: u32, ) -> Weight; fn as_multi_create(s: u32, z: u32, ) -> Weight; - fn as_multi_create_store(s: u32, z: u32, ) -> Weight; fn as_multi_approve(s: u32, z: u32, ) -> Weight; - fn as_multi_approve_store(s: u32, z: u32, ) -> Weight; fn as_multi_complete(s: u32, z: u32, ) -> Weight; fn approve_as_multi_create(s: u32, ) -> Weight; fn approve_as_multi_approve(s: u32, ) -> Weight; - fn approve_as_multi_complete(s: u32, ) -> Weight; fn cancel_as_multi(s: u32, ) -> Weight; } /// Weights for pallet_multisig using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - fn as_multi_threshold_1(_z: u32, ) -> Weight { - Weight::from_ref_time(17_537_000 as u64) + /// The range of component `z` is `[0, 10000]`. + fn as_multi_threshold_1(z: u32, ) -> Weight { + // Minimum execution time: 20_283 nanoseconds. + Weight::from_ref_time(20_861_089 as u64) + // Standard Error: 5 + .saturating_add(Weight::from_ref_time(583 as u64).saturating_mul(z as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// The range of component `s` is `[2, 100]`. + /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(36_535_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(99_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(z as u64)) + // Minimum execution time: 52_699 nanoseconds. + Weight::from_ref_time(40_874_603 as u64) + // Standard Error: 546 + .saturating_add(Weight::from_ref_time(131_727 as u64).saturating_mul(s as u64)) + // Standard Error: 5 + .saturating_add(Weight::from_ref_time(1_537 as u64).saturating_mul(z as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) - fn as_multi_create_store(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(39_918_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(95_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - } - // Storage: Multisig Multisigs (r:1 w:1) + /// The range of component `s` is `[3, 100]`. + /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(25_524_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(94_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(z as u64)) + // Minimum execution time: 39_843 nanoseconds. + Weight::from_ref_time(28_912_325 as u64) + // Standard Error: 734 + .saturating_add(Weight::from_ref_time(125_761 as u64).saturating_mul(s as u64)) + // Standard Error: 7 + .saturating_add(Weight::from_ref_time(1_542 as u64).saturating_mul(z as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) - fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(39_923_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(91_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `s` is `[2, 100]`. + /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(45_877_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(146_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + // Minimum execution time: 54_980 nanoseconds. + Weight::from_ref_time(42_087_213 as u64) + // Standard Error: 786 + .saturating_add(Weight::from_ref_time(153_935 as u64).saturating_mul(s as u64)) + // Standard Error: 7 + .saturating_add(Weight::from_ref_time(1_545 as u64).saturating_mul(z as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { - Weight::from_ref_time(34_309_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(114_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 37_802 nanoseconds. + Weight::from_ref_time(39_933_623 as u64) + // Standard Error: 1_059 + .saturating_add(Weight::from_ref_time(121_891 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:0) + /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { - Weight::from_ref_time(22_848_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(114_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 25_738 nanoseconds. + Weight::from_ref_time(27_676_766 as u64) + // Standard Error: 710 + .saturating_add(Weight::from_ref_time(125_733 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) - // Storage: System Account (r:1 w:1) - fn approve_as_multi_complete(s: u32, ) -> Weight { - Weight::from_ref_time(63_239_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(161_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) + /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { - Weight::from_ref_time(51_254_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(118_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + // Minimum execution time: 36_591 nanoseconds. + Weight::from_ref_time(38_707_543 as u64) + // Standard Error: 881 + .saturating_add(Weight::from_ref_time(126_198 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - fn as_multi_threshold_1(_z: u32, ) -> Weight { - Weight::from_ref_time(17_537_000 as u64) + /// The range of component `z` is `[0, 10000]`. + fn as_multi_threshold_1(z: u32, ) -> Weight { + // Minimum execution time: 20_283 nanoseconds. + Weight::from_ref_time(20_861_089 as u64) + // Standard Error: 5 + .saturating_add(Weight::from_ref_time(583 as u64).saturating_mul(z as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// The range of component `s` is `[2, 100]`. + /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(36_535_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(99_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(z as u64)) + // Minimum execution time: 52_699 nanoseconds. + Weight::from_ref_time(40_874_603 as u64) + // Standard Error: 546 + .saturating_add(Weight::from_ref_time(131_727 as u64).saturating_mul(s as u64)) + // Standard Error: 5 + .saturating_add(Weight::from_ref_time(1_537 as u64).saturating_mul(z as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) - // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) - fn as_multi_create_store(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(39_918_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(95_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - } - // Storage: Multisig Multisigs (r:1 w:1) + /// The range of component `s` is `[3, 100]`. + /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(25_524_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(94_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(1_000 as u64).saturating_mul(z as u64)) + // Minimum execution time: 39_843 nanoseconds. + Weight::from_ref_time(28_912_325 as u64) + // Standard Error: 734 + .saturating_add(Weight::from_ref_time(125_761 as u64).saturating_mul(s as u64)) + // Standard Error: 7 + .saturating_add(Weight::from_ref_time(1_542 as u64).saturating_mul(z as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) - fn as_multi_approve_store(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(39_923_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(91_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `s` is `[2, 100]`. + /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { - Weight::from_ref_time(45_877_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(146_000 as u64).saturating_mul(s as u64)) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(z as u64)) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + // Minimum execution time: 54_980 nanoseconds. + Weight::from_ref_time(42_087_213 as u64) + // Standard Error: 786 + .saturating_add(Weight::from_ref_time(153_935 as u64).saturating_mul(s as u64)) + // Standard Error: 7 + .saturating_add(Weight::from_ref_time(1_545 as u64).saturating_mul(z as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) + /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { - Weight::from_ref_time(34_309_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(114_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 37_802 nanoseconds. + Weight::from_ref_time(39_933_623 as u64) + // Standard Error: 1_059 + .saturating_add(Weight::from_ref_time(121_891 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:0) + /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { - Weight::from_ref_time(22_848_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(114_000 as u64).saturating_mul(s as u64)) + // Minimum execution time: 25_738 nanoseconds. + Weight::from_ref_time(27_676_766 as u64) + // Standard Error: 710 + .saturating_add(Weight::from_ref_time(125_733 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) - // Storage: System Account (r:1 w:1) - fn approve_as_multi_complete(s: u32, ) -> Weight { - Weight::from_ref_time(63_239_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(161_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - } - // Storage: Multisig Multisigs (r:1 w:1) - // Storage: Multisig Calls (r:1 w:1) + /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { - Weight::from_ref_time(51_254_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(118_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + // Minimum execution time: 36_591 nanoseconds. + Weight::from_ref_time(38_707_543 as u64) + // Standard Error: 881 + .saturating_add(Weight::from_ref_time(126_198 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } } diff --git a/frame/nicks/src/lib.rs b/frame/nicks/src/lib.rs index cf5af649b7843..b3238630d3174 100644 --- a/frame/nicks/src/lib.rs +++ b/frame/nicks/src/lib.rs @@ -58,7 +58,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The currency trait. type Currency: ReservableCurrency; @@ -71,7 +71,7 @@ pub mod pallet { type Slashed: OnUnbalanced>; /// The origin which may forcibly set or remove a name. Root can always do this. - type ForceOrigin: EnsureOrigin; + type ForceOrigin: EnsureOrigin; /// The minimum length a name may be. #[pallet::constant] @@ -140,7 +140,7 @@ pub mod pallet { let sender = ensure_signed(origin)?; let bounded_name: BoundedVec<_, _> = - name.try_into().map_err(|()| Error::::TooLong)?; + name.try_into().map_err(|_| Error::::TooLong)?; ensure!(bounded_name.len() >= T::MinLength::get() as usize, Error::::TooShort); let deposit = if let Some((_, deposit)) = >::get(&sender) { @@ -229,7 +229,7 @@ pub mod pallet { T::ForceOrigin::ensure_origin(origin)?; let bounded_name: BoundedVec<_, _> = - name.try_into().map_err(|()| Error::::TooLong)?; + name.try_into().map_err(|_| Error::::TooLong)?; let target = T::Lookup::lookup(target)?; let deposit = >::get(&target).map(|x| x.1).unwrap_or_else(Zero::zero); >::insert(&target, (bounded_name, deposit)); @@ -280,16 +280,16 @@ mod tests { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -307,7 +307,7 @@ mod tests { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -318,7 +318,7 @@ mod tests { pub const One: u64 = 1; } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ReservationFee = ConstU64<2>; type Slashed = (); @@ -338,9 +338,9 @@ mod tests { #[test] fn kill_name_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Nicks::set_name(Origin::signed(2), b"Dave".to_vec())); + assert_ok!(Nicks::set_name(RuntimeOrigin::signed(2), b"Dave".to_vec())); assert_eq!(Balances::total_balance(&2), 10); - assert_ok!(Nicks::kill_name(Origin::signed(1), 2)); + assert_ok!(Nicks::kill_name(RuntimeOrigin::signed(1), 2)); assert_eq!(Balances::total_balance(&2), 8); assert_eq!(>::get(2), None); }); @@ -350,17 +350,21 @@ mod tests { fn force_name_should_work() { new_test_ext().execute_with(|| { assert_noop!( - Nicks::set_name(Origin::signed(2), b"Dr. David Brubeck, III".to_vec()), + Nicks::set_name(RuntimeOrigin::signed(2), b"Dr. David Brubeck, III".to_vec()), Error::::TooLong, ); - assert_ok!(Nicks::set_name(Origin::signed(2), b"Dave".to_vec())); + assert_ok!(Nicks::set_name(RuntimeOrigin::signed(2), b"Dave".to_vec())); assert_eq!(Balances::reserved_balance(2), 2); assert_noop!( - Nicks::force_name(Origin::signed(1), 2, b"Dr. David Brubeck, III".to_vec()), + Nicks::force_name(RuntimeOrigin::signed(1), 2, b"Dr. David Brubeck, III".to_vec()), Error::::TooLong, ); - assert_ok!(Nicks::force_name(Origin::signed(1), 2, b"Dr. Brubeck, III".to_vec())); + assert_ok!(Nicks::force_name( + RuntimeOrigin::signed(1), + 2, + b"Dr. Brubeck, III".to_vec() + )); assert_eq!(Balances::reserved_balance(2), 2); let (name, amount) = >::get(2).unwrap(); assert_eq!(name, b"Dr. Brubeck, III".to_vec()); @@ -371,17 +375,17 @@ mod tests { #[test] fn normal_operation_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Nicks::set_name(Origin::signed(1), b"Gav".to_vec())); + assert_ok!(Nicks::set_name(RuntimeOrigin::signed(1), b"Gav".to_vec())); assert_eq!(Balances::reserved_balance(1), 2); assert_eq!(Balances::free_balance(1), 8); assert_eq!(>::get(1).unwrap().0, b"Gav".to_vec()); - assert_ok!(Nicks::set_name(Origin::signed(1), b"Gavin".to_vec())); + assert_ok!(Nicks::set_name(RuntimeOrigin::signed(1), b"Gavin".to_vec())); assert_eq!(Balances::reserved_balance(1), 2); assert_eq!(Balances::free_balance(1), 8); assert_eq!(>::get(1).unwrap().0, b"Gavin".to_vec()); - assert_ok!(Nicks::clear_name(Origin::signed(1))); + assert_ok!(Nicks::clear_name(RuntimeOrigin::signed(1))); assert_eq!(Balances::reserved_balance(1), 0); assert_eq!(Balances::free_balance(1), 10); }); @@ -390,24 +394,27 @@ mod tests { #[test] fn error_catching_should_work() { new_test_ext().execute_with(|| { - assert_noop!(Nicks::clear_name(Origin::signed(1)), Error::::Unnamed); + assert_noop!(Nicks::clear_name(RuntimeOrigin::signed(1)), Error::::Unnamed); assert_noop!( - Nicks::set_name(Origin::signed(3), b"Dave".to_vec()), + Nicks::set_name(RuntimeOrigin::signed(3), b"Dave".to_vec()), pallet_balances::Error::::InsufficientBalance ); assert_noop!( - Nicks::set_name(Origin::signed(1), b"Ga".to_vec()), + Nicks::set_name(RuntimeOrigin::signed(1), b"Ga".to_vec()), Error::::TooShort ); assert_noop!( - Nicks::set_name(Origin::signed(1), b"Gavin James Wood, Esquire".to_vec()), + Nicks::set_name(RuntimeOrigin::signed(1), b"Gavin James Wood, Esquire".to_vec()), Error::::TooLong ); - assert_ok!(Nicks::set_name(Origin::signed(1), b"Dave".to_vec())); - assert_noop!(Nicks::kill_name(Origin::signed(2), 1), BadOrigin); - assert_noop!(Nicks::force_name(Origin::signed(2), 1, b"Whatever".to_vec()), BadOrigin); + assert_ok!(Nicks::set_name(RuntimeOrigin::signed(1), b"Dave".to_vec())); + assert_noop!(Nicks::kill_name(RuntimeOrigin::signed(2), 1), BadOrigin); + assert_noop!( + Nicks::force_name(RuntimeOrigin::signed(2), 1, b"Whatever".to_vec()), + BadOrigin + ); }); } } diff --git a/frame/node-authorization/src/lib.rs b/frame/node-authorization/src/lib.rs index 427e71af6e8c4..638a96eb3321a 100644 --- a/frame/node-authorization/src/lib.rs +++ b/frame/node-authorization/src/lib.rs @@ -67,7 +67,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The maximum number of well known nodes that are allowed to set #[pallet::constant] @@ -78,16 +78,16 @@ pub mod pallet { type MaxPeerIdLength: Get; /// The origin which can add a well known node. - type AddOrigin: EnsureOrigin; + type AddOrigin: EnsureOrigin; /// The origin which can remove a well known node. - type RemoveOrigin: EnsureOrigin; + type RemoveOrigin: EnsureOrigin; /// The origin which can swap the well known nodes. - type SwapOrigin: EnsureOrigin; + type SwapOrigin: EnsureOrigin; /// The origin which can reset the well known nodes. - type ResetOrigin: EnsureOrigin; + type ResetOrigin: EnsureOrigin; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; diff --git a/frame/node-authorization/src/mock.rs b/frame/node-authorization/src/mock.rs index d959d1b8610f5..fcf7ff0189332 100644 --- a/frame/node-authorization/src/mock.rs +++ b/frame/node-authorization/src/mock.rs @@ -52,16 +52,16 @@ impl frame_system::Config for Test { type DbWeight = (); type BlockWeights = (); type BlockLength = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -82,7 +82,7 @@ ord_parameter_types! { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type MaxWellKnownNodes = ConstU32<4>; type MaxPeerIdLength = ConstU32<2>; type AddOrigin = EnsureSignedBy; diff --git a/frame/node-authorization/src/tests.rs b/frame/node-authorization/src/tests.rs index ba78d14912133..d9db09db4f46f 100644 --- a/frame/node-authorization/src/tests.rs +++ b/frame/node-authorization/src/tests.rs @@ -26,19 +26,27 @@ use sp_runtime::traits::BadOrigin; fn add_well_known_node_works() { new_test_ext().execute_with(|| { assert_noop!( - NodeAuthorization::add_well_known_node(Origin::signed(2), test_node(15), 15), + NodeAuthorization::add_well_known_node(RuntimeOrigin::signed(2), test_node(15), 15), BadOrigin ); assert_noop!( - NodeAuthorization::add_well_known_node(Origin::signed(1), PeerId(vec![1, 2, 3]), 15), + NodeAuthorization::add_well_known_node( + RuntimeOrigin::signed(1), + PeerId(vec![1, 2, 3]), + 15 + ), Error::::PeerIdTooLong ); assert_noop!( - NodeAuthorization::add_well_known_node(Origin::signed(1), test_node(20), 20), + NodeAuthorization::add_well_known_node(RuntimeOrigin::signed(1), test_node(20), 20), Error::::AlreadyJoined ); - assert_ok!(NodeAuthorization::add_well_known_node(Origin::signed(1), test_node(15), 15)); + assert_ok!(NodeAuthorization::add_well_known_node( + RuntimeOrigin::signed(1), + test_node(15), + 15 + )); assert_eq!( WellKnownNodes::::get(), BTreeSet::from_iter(vec![test_node(10), test_node(15), test_node(20), test_node(30)]) @@ -49,7 +57,7 @@ fn add_well_known_node_works() { assert_eq!(Owners::::get(test_node(15)), Some(15)); assert_noop!( - NodeAuthorization::add_well_known_node(Origin::signed(1), test_node(25), 25), + NodeAuthorization::add_well_known_node(RuntimeOrigin::signed(1), test_node(25), 25), Error::::TooManyNodes ); }); @@ -59,15 +67,18 @@ fn add_well_known_node_works() { fn remove_well_known_node_works() { new_test_ext().execute_with(|| { assert_noop!( - NodeAuthorization::remove_well_known_node(Origin::signed(3), test_node(20)), + NodeAuthorization::remove_well_known_node(RuntimeOrigin::signed(3), test_node(20)), BadOrigin ); assert_noop!( - NodeAuthorization::remove_well_known_node(Origin::signed(2), PeerId(vec![1, 2, 3])), + NodeAuthorization::remove_well_known_node( + RuntimeOrigin::signed(2), + PeerId(vec![1, 2, 3]) + ), Error::::PeerIdTooLong ); assert_noop!( - NodeAuthorization::remove_well_known_node(Origin::signed(2), test_node(40)), + NodeAuthorization::remove_well_known_node(RuntimeOrigin::signed(2), test_node(40)), Error::::NotExist ); @@ -77,7 +88,10 @@ fn remove_well_known_node_works() { ); assert!(AdditionalConnections::::contains_key(test_node(20))); - assert_ok!(NodeAuthorization::remove_well_known_node(Origin::signed(2), test_node(20))); + assert_ok!(NodeAuthorization::remove_well_known_node( + RuntimeOrigin::signed(2), + test_node(20) + )); assert_eq!( WellKnownNodes::::get(), BTreeSet::from_iter(vec![test_node(10), test_node(30)]) @@ -91,12 +105,16 @@ fn remove_well_known_node_works() { fn swap_well_known_node_works() { new_test_ext().execute_with(|| { assert_noop!( - NodeAuthorization::swap_well_known_node(Origin::signed(4), test_node(20), test_node(5)), + NodeAuthorization::swap_well_known_node( + RuntimeOrigin::signed(4), + test_node(20), + test_node(5) + ), BadOrigin ); assert_noop!( NodeAuthorization::swap_well_known_node( - Origin::signed(3), + RuntimeOrigin::signed(3), PeerId(vec![1, 2, 3]), test_node(20) ), @@ -104,7 +122,7 @@ fn swap_well_known_node_works() { ); assert_noop!( NodeAuthorization::swap_well_known_node( - Origin::signed(3), + RuntimeOrigin::signed(3), test_node(20), PeerId(vec![1, 2, 3]) ), @@ -112,7 +130,7 @@ fn swap_well_known_node_works() { ); assert_ok!(NodeAuthorization::swap_well_known_node( - Origin::signed(3), + RuntimeOrigin::signed(3), test_node(20), test_node(20) )); @@ -122,12 +140,16 @@ fn swap_well_known_node_works() { ); assert_noop!( - NodeAuthorization::swap_well_known_node(Origin::signed(3), test_node(15), test_node(5)), + NodeAuthorization::swap_well_known_node( + RuntimeOrigin::signed(3), + test_node(15), + test_node(5) + ), Error::::NotExist ); assert_noop!( NodeAuthorization::swap_well_known_node( - Origin::signed(3), + RuntimeOrigin::signed(3), test_node(20), test_node(30) ), @@ -139,7 +161,7 @@ fn swap_well_known_node_works() { BTreeSet::from_iter(vec![test_node(15)]), ); assert_ok!(NodeAuthorization::swap_well_known_node( - Origin::signed(3), + RuntimeOrigin::signed(3), test_node(20), test_node(5) )); @@ -162,14 +184,14 @@ fn reset_well_known_nodes_works() { new_test_ext().execute_with(|| { assert_noop!( NodeAuthorization::reset_well_known_nodes( - Origin::signed(3), + RuntimeOrigin::signed(3), vec![(test_node(15), 15), (test_node(5), 5), (test_node(20), 20)] ), BadOrigin ); assert_noop!( NodeAuthorization::reset_well_known_nodes( - Origin::signed(4), + RuntimeOrigin::signed(4), vec![ (test_node(15), 15), (test_node(5), 5), @@ -181,7 +203,7 @@ fn reset_well_known_nodes_works() { ); assert_ok!(NodeAuthorization::reset_well_known_nodes( - Origin::signed(4), + RuntimeOrigin::signed(4), vec![(test_node(15), 15), (test_node(5), 5), (test_node(20), 20)] )); assert_eq!( @@ -198,15 +220,15 @@ fn reset_well_known_nodes_works() { fn claim_node_works() { new_test_ext().execute_with(|| { assert_noop!( - NodeAuthorization::claim_node(Origin::signed(1), PeerId(vec![1, 2, 3])), + NodeAuthorization::claim_node(RuntimeOrigin::signed(1), PeerId(vec![1, 2, 3])), Error::::PeerIdTooLong ); assert_noop!( - NodeAuthorization::claim_node(Origin::signed(1), test_node(20)), + NodeAuthorization::claim_node(RuntimeOrigin::signed(1), test_node(20)), Error::::AlreadyClaimed ); - assert_ok!(NodeAuthorization::claim_node(Origin::signed(15), test_node(15))); + assert_ok!(NodeAuthorization::claim_node(RuntimeOrigin::signed(15), test_node(15))); assert_eq!(Owners::::get(test_node(15)), Some(15)); }); } @@ -215,21 +237,21 @@ fn claim_node_works() { fn remove_claim_works() { new_test_ext().execute_with(|| { assert_noop!( - NodeAuthorization::remove_claim(Origin::signed(15), PeerId(vec![1, 2, 3])), + NodeAuthorization::remove_claim(RuntimeOrigin::signed(15), PeerId(vec![1, 2, 3])), Error::::PeerIdTooLong ); assert_noop!( - NodeAuthorization::remove_claim(Origin::signed(15), test_node(15)), + NodeAuthorization::remove_claim(RuntimeOrigin::signed(15), test_node(15)), Error::::NotClaimed ); assert_noop!( - NodeAuthorization::remove_claim(Origin::signed(15), test_node(20)), + NodeAuthorization::remove_claim(RuntimeOrigin::signed(15), test_node(20)), Error::::NotOwner ); assert_noop!( - NodeAuthorization::remove_claim(Origin::signed(20), test_node(20)), + NodeAuthorization::remove_claim(RuntimeOrigin::signed(20), test_node(20)), Error::::PermissionDenied ); @@ -238,7 +260,7 @@ fn remove_claim_works() { test_node(15), BTreeSet::from_iter(vec![test_node(20)]), ); - assert_ok!(NodeAuthorization::remove_claim(Origin::signed(15), test_node(15))); + assert_ok!(NodeAuthorization::remove_claim(RuntimeOrigin::signed(15), test_node(15))); assert!(!Owners::::contains_key(test_node(15))); assert!(!AdditionalConnections::::contains_key(test_node(15))); }); @@ -248,20 +270,20 @@ fn remove_claim_works() { fn transfer_node_works() { new_test_ext().execute_with(|| { assert_noop!( - NodeAuthorization::transfer_node(Origin::signed(15), PeerId(vec![1, 2, 3]), 10), + NodeAuthorization::transfer_node(RuntimeOrigin::signed(15), PeerId(vec![1, 2, 3]), 10), Error::::PeerIdTooLong ); assert_noop!( - NodeAuthorization::transfer_node(Origin::signed(15), test_node(15), 10), + NodeAuthorization::transfer_node(RuntimeOrigin::signed(15), test_node(15), 10), Error::::NotClaimed ); assert_noop!( - NodeAuthorization::transfer_node(Origin::signed(15), test_node(20), 10), + NodeAuthorization::transfer_node(RuntimeOrigin::signed(15), test_node(20), 10), Error::::NotOwner ); - assert_ok!(NodeAuthorization::transfer_node(Origin::signed(20), test_node(20), 15)); + assert_ok!(NodeAuthorization::transfer_node(RuntimeOrigin::signed(20), test_node(20), 15)); assert_eq!(Owners::::get(test_node(20)), Some(15)); }); } @@ -271,7 +293,7 @@ fn add_connections_works() { new_test_ext().execute_with(|| { assert_noop!( NodeAuthorization::add_connections( - Origin::signed(15), + RuntimeOrigin::signed(15), PeerId(vec![1, 2, 3]), vec![test_node(5)] ), @@ -279,7 +301,7 @@ fn add_connections_works() { ); assert_noop!( NodeAuthorization::add_connections( - Origin::signed(15), + RuntimeOrigin::signed(15), test_node(15), vec![test_node(5)] ), @@ -288,7 +310,7 @@ fn add_connections_works() { assert_noop!( NodeAuthorization::add_connections( - Origin::signed(15), + RuntimeOrigin::signed(15), test_node(20), vec![test_node(5)] ), @@ -296,7 +318,7 @@ fn add_connections_works() { ); assert_ok!(NodeAuthorization::add_connections( - Origin::signed(20), + RuntimeOrigin::signed(20), test_node(20), vec![test_node(15), test_node(5), test_node(25), test_node(20)] )); @@ -312,7 +334,7 @@ fn remove_connections_works() { new_test_ext().execute_with(|| { assert_noop!( NodeAuthorization::remove_connections( - Origin::signed(15), + RuntimeOrigin::signed(15), PeerId(vec![1, 2, 3]), vec![test_node(5)] ), @@ -320,7 +342,7 @@ fn remove_connections_works() { ); assert_noop!( NodeAuthorization::remove_connections( - Origin::signed(15), + RuntimeOrigin::signed(15), test_node(15), vec![test_node(5)] ), @@ -329,7 +351,7 @@ fn remove_connections_works() { assert_noop!( NodeAuthorization::remove_connections( - Origin::signed(15), + RuntimeOrigin::signed(15), test_node(20), vec![test_node(5)] ), @@ -341,7 +363,7 @@ fn remove_connections_works() { BTreeSet::from_iter(vec![test_node(5), test_node(15), test_node(25)]), ); assert_ok!(NodeAuthorization::remove_connections( - Origin::signed(20), + RuntimeOrigin::signed(20), test_node(20), vec![test_node(15), test_node(5)] )); diff --git a/frame/nomination-pools/Cargo.toml b/frame/nomination-pools/Cargo.toml index 1d613511eacec..459ee5f440a12 100644 --- a/frame/nomination-pools/Cargo.toml +++ b/frame/nomination-pools/Cargo.toml @@ -29,10 +29,9 @@ log = { version = "0.4.0", default-features = false } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } +rand = { version = "0.8.5", features = ["small_rng"] } [features] -runtime-benchmarks = [] -try-runtime = [ "frame-support/try-runtime" ] default = ["std"] std = [ "codec/std", @@ -46,3 +45,10 @@ std = [ "sp-core/std", "log/std", ] +runtime-benchmarks = [ + "sp-staking/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime" +] +fuzz-test = [] diff --git a/frame/nomination-pools/benchmarking/Cargo.toml b/frame/nomination-pools/benchmarking/Cargo.toml index 2e045c95ec9b3..69ba6585481d5 100644 --- a/frame/nomination-pools/benchmarking/Cargo.toml +++ b/frame/nomination-pools/benchmarking/Cargo.toml @@ -22,12 +22,13 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " frame-election-provider-support = { version = "4.0.0-dev", default-features = false, path = "../../election-provider-support" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } -pallet-bags-list = { version = "4.0.0-dev", default-features = false, features = ["runtime-benchmarks"], path = "../../bags-list" } -pallet-staking = { version = "4.0.0-dev", default-features = false, features = ["runtime-benchmarks"], path = "../../staking" } -pallet-nomination-pools = { version = "1.0.0", default-features = false, path = "../", features = ["runtime-benchmarks"] } +pallet-bags-list = { version = "4.0.0-dev", default-features = false, path = "../../bags-list" } +pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../staking" } +pallet-nomination-pools = { version = "1.0.0", default-features = false, path = "../" } # Substrate Primitives sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } +sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime-interface" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } @@ -40,6 +41,7 @@ sp-io = { version = "6.0.0", path = "../../../primitives/io" } [features] default = ["std"] + std = [ "frame-benchmarking/std", "frame-election-provider-support/std", @@ -49,7 +51,20 @@ std = [ "pallet-staking/std", "pallet-nomination-pools/std", "sp-runtime/std", + "sp-runtime-interface/std", + "sp-io/std", "sp-staking/std", - "sp-std/std", - "pallet-balances/std", + "sp-std/std", +] + +runtime-benchmarks = [ + "frame-election-provider-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "sp-staking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "pallet-staking/runtime-benchmarks", + "pallet-nomination-pools/runtime-benchmarks", + "pallet-bags-list/runtime-benchmarks", ] diff --git a/frame/nomination-pools/benchmarking/src/lib.rs b/frame/nomination-pools/benchmarking/src/lib.rs index 07d5c63493ef8..c31bcb1546ecd 100644 --- a/frame/nomination-pools/benchmarking/src/lib.rs +++ b/frame/nomination-pools/benchmarking/src/lib.rs @@ -17,6 +17,7 @@ //! Benchmarks for the nomination pools coupled with the staking and bags list pallets. +#![cfg(feature = "runtime-benchmarks")] #![cfg_attr(not(feature = "std"), no_std)] #[cfg(test)] @@ -25,7 +26,7 @@ mod mock; use frame_benchmarking::{account, frame_support::traits::Currency, vec, whitelist_account, Vec}; use frame_election_provider_support::SortedListProvider; use frame_support::{assert_ok, ensure, traits::Get}; -use frame_system::RawOrigin as Origin; +use frame_system::RawOrigin as RuntimeOrigin; use pallet_nomination_pools::{ BalanceOf, BondExtra, BondedPoolInner, BondedPools, ConfigOp, MaxPoolMembers, MaxPoolMembersPerPool, MaxPools, Metadata, MinCreateBond, MinJoinBond, Pallet as Pools, @@ -41,19 +42,16 @@ type CurrencyOf = ::Currency; const USER_SEED: u32 = 0; const MAX_SPANS: u32 = 100; +type VoterBagsListInstance = pallet_bags_list::Instance1; pub trait Config: - pallet_nomination_pools::Config + pallet_staking::Config + pallet_bags_list::Config + pallet_nomination_pools::Config + + pallet_staking::Config + + pallet_bags_list::Config { } pub struct Pallet(Pools); -fn min_create_bond() -> BalanceOf { - MinCreateBond::::get() - .max(T::StakingInterface::minimum_bond()) - .max(CurrencyOf::::minimum_balance()) -} - fn create_funded_user_with_balance( string: &'static str, n: u32, @@ -76,7 +74,7 @@ fn create_pool_account( let pool_creator_lookup = T::Lookup::unlookup(pool_creator.clone()); Pools::::create( - Origin::Signed(pool_creator.clone()).into(), + RuntimeOrigin::Signed(pool_creator.clone()).into(), balance, pool_creator_lookup.clone(), pool_creator_lookup.clone(), @@ -199,7 +197,7 @@ impl ListScenario { maybe_pool.as_mut().map(|pool| pool.points -= amount) }); - Pools::::join(Origin::Signed(joiner.clone()).into(), amount, 1).unwrap(); + Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), amount, 1).unwrap(); // check that the vote weight is still the same as the original bonded let weight_of = pallet_staking::Pallet::::weight_of_fn(); @@ -216,7 +214,7 @@ impl ListScenario { frame_benchmarking::benchmarks! { join { - let origin_weight = min_create_bond::() * 2u32.into(); + let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); // setup the worst case list scenario. let scenario = ListScenario::::new(origin_weight, true)?; @@ -232,7 +230,7 @@ frame_benchmarking::benchmarks! { = create_funded_user_with_balance::("joiner", 0, joiner_free); whitelist_account!(joiner); - }: _(Origin::Signed(joiner.clone()), max_additional, 1) + }: _(RuntimeOrigin::Signed(joiner.clone()), max_additional, 1) verify { assert_eq!(CurrencyOf::::free_balance(&joiner), joiner_free - max_additional); assert_eq!( @@ -242,13 +240,13 @@ frame_benchmarking::benchmarks! { } bond_extra_transfer { - let origin_weight = min_create_bond::() * 2u32.into(); + let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); let scenario = ListScenario::::new(origin_weight, true)?; let extra = scenario.dest_weight - origin_weight; // creator of the src pool will bond-extra, bumping itself to dest bag. - }: bond_extra(Origin::Signed(scenario.creator1.clone()), BondExtra::FreeBalance(extra)) + }: bond_extra(RuntimeOrigin::Signed(scenario.creator1.clone()), BondExtra::FreeBalance(extra)) verify { assert!( T::StakingInterface::active_stake(&scenario.origin1).unwrap() >= @@ -257,7 +255,7 @@ frame_benchmarking::benchmarks! { } bond_extra_reward { - let origin_weight = min_create_bond::() * 2u32.into(); + let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); let scenario = ListScenario::::new(origin_weight, true)?; let extra = (scenario.dest_weight - origin_weight).max(CurrencyOf::::minimum_balance()); @@ -266,7 +264,7 @@ frame_benchmarking::benchmarks! { assert!(extra >= CurrencyOf::::minimum_balance()); CurrencyOf::::deposit_creating(&reward_account1, extra); - }: bond_extra(Origin::Signed(scenario.creator1.clone()), BondExtra::Rewards) + }: bond_extra(RuntimeOrigin::Signed(scenario.creator1.clone()), BondExtra::Rewards) verify { assert!( T::StakingInterface::active_stake(&scenario.origin1).unwrap() >= @@ -275,7 +273,7 @@ frame_benchmarking::benchmarks! { } claim_payout { - let origin_weight = min_create_bond::() * 2u32.into(); + let origin_weight = Pools::::depositor_min_bond() * 2u32.into(); let ed = CurrencyOf::::minimum_balance(); let (depositor, pool_account) = create_pool_account::(0, origin_weight); let reward_account = Pools::::create_reward_account(1); @@ -290,7 +288,7 @@ frame_benchmarking::benchmarks! { ); whitelist_account!(depositor); - }:_(Origin::Signed(depositor.clone())) + }:_(RuntimeOrigin::Signed(depositor.clone())) verify { assert_eq!( CurrencyOf::::free_balance(&depositor), @@ -305,7 +303,7 @@ frame_benchmarking::benchmarks! { unbond { // The weight the nominator will start at. The value used here is expected to be // significantly higher than the first position in a list (e.g. the first bag threshold). - let origin_weight = min_create_bond::() * 200u32.into(); + let origin_weight = Pools::::depositor_min_bond() * 200u32.into(); let scenario = ListScenario::::new(origin_weight, false)?; let amount = origin_weight - scenario.dest_weight; @@ -314,7 +312,7 @@ frame_benchmarking::benchmarks! { let member_id_lookup = T::Lookup::unlookup(member_id.clone()); let all_points = PoolMembers::::get(&member_id).unwrap().points; whitelist_account!(member_id); - }: _(Origin::Signed(member_id.clone()), member_id_lookup, all_points) + }: _(RuntimeOrigin::Signed(member_id.clone()), member_id_lookup, all_points) verify { let bonded_after = T::StakingInterface::active_stake(&scenario.origin1).unwrap(); // We at least went down to the destination bag @@ -336,13 +334,13 @@ frame_benchmarking::benchmarks! { pool_withdraw_unbonded { let s in 0 .. MAX_SPANS; - let min_create_bond = min_create_bond::(); + let min_create_bond = Pools::::depositor_min_bond(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond); // Add a new member let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); let joiner = create_funded_user_with_balance::("joiner", 0, min_join_bond * 2u32.into()); - Pools::::join(Origin::Signed(joiner.clone()).into(), min_join_bond, 1) + Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), min_join_bond, 1) .unwrap(); // Sanity check join worked @@ -353,7 +351,7 @@ frame_benchmarking::benchmarks! { assert_eq!(CurrencyOf::::free_balance(&joiner), min_join_bond); // Unbond the new member - Pools::::fully_unbond(Origin::Signed(joiner.clone()).into(), joiner.clone()).unwrap(); + Pools::::fully_unbond(RuntimeOrigin::Signed(joiner.clone()).into(), joiner.clone()).unwrap(); // Sanity check that unbond worked assert_eq!( @@ -367,7 +365,7 @@ frame_benchmarking::benchmarks! { // Add `s` count of slashing spans to storage. pallet_staking::benchmarking::add_slashing_spans::(&pool_account, s); whitelist_account!(pool_account); - }: _(Origin::Signed(pool_account.clone()), 1, s) + }: _(RuntimeOrigin::Signed(pool_account.clone()), 1, s) verify { // The joiners funds didn't change assert_eq!(CurrencyOf::::free_balance(&joiner), min_join_bond); @@ -378,14 +376,14 @@ frame_benchmarking::benchmarks! { withdraw_unbonded_update { let s in 0 .. MAX_SPANS; - let min_create_bond = min_create_bond::(); + let min_create_bond = Pools::::depositor_min_bond(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond); // Add a new member let min_join_bond = MinJoinBond::::get().max(CurrencyOf::::minimum_balance()); let joiner = create_funded_user_with_balance::("joiner", 0, min_join_bond * 2u32.into()); let joiner_lookup = T::Lookup::unlookup(joiner.clone()); - Pools::::join(Origin::Signed(joiner.clone()).into(), min_join_bond, 1) + Pools::::join(RuntimeOrigin::Signed(joiner.clone()).into(), min_join_bond, 1) .unwrap(); // Sanity check join worked @@ -397,7 +395,7 @@ frame_benchmarking::benchmarks! { // Unbond the new member pallet_staking::CurrentEra::::put(0); - Pools::::fully_unbond(Origin::Signed(joiner.clone()).into(), joiner.clone()).unwrap(); + Pools::::fully_unbond(RuntimeOrigin::Signed(joiner.clone()).into(), joiner.clone()).unwrap(); // Sanity check that unbond worked assert_eq!( @@ -411,7 +409,7 @@ frame_benchmarking::benchmarks! { pallet_staking::benchmarking::add_slashing_spans::(&pool_account, s); whitelist_account!(joiner); - }: withdraw_unbonded(Origin::Signed(joiner.clone()), joiner_lookup, s) + }: withdraw_unbonded(RuntimeOrigin::Signed(joiner.clone()), joiner_lookup, s) verify { assert_eq!( CurrencyOf::::free_balance(&joiner), @@ -424,7 +422,7 @@ frame_benchmarking::benchmarks! { withdraw_unbonded_kill { let s in 0 .. MAX_SPANS; - let min_create_bond = min_create_bond::(); + let min_create_bond = Pools::::depositor_min_bond(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond); let depositor_lookup = T::Lookup::unlookup(depositor.clone()); @@ -444,7 +442,7 @@ frame_benchmarking::benchmarks! { // up when unbonding. let reward_account = Pools::::create_reward_account(1); assert!(frame_system::Account::::contains_key(&reward_account)); - Pools::::fully_unbond(Origin::Signed(depositor.clone()).into(), depositor.clone()).unwrap(); + Pools::::fully_unbond(RuntimeOrigin::Signed(depositor.clone()).into(), depositor.clone()).unwrap(); // Sanity check that unbond worked assert_eq!( @@ -469,7 +467,7 @@ frame_benchmarking::benchmarks! { assert!(frame_system::Account::::contains_key(&reward_account)); whitelist_account!(depositor); - }: withdraw_unbonded(Origin::Signed(depositor.clone()), depositor_lookup, s) + }: withdraw_unbonded(RuntimeOrigin::Signed(depositor.clone()), depositor_lookup, s) verify { // Pool removal worked assert!(!pallet_staking::Ledger::::contains_key(&pool_account)); @@ -489,20 +487,20 @@ frame_benchmarking::benchmarks! { } create { - let min_create_bond = min_create_bond::(); + let min_create_bond = Pools::::depositor_min_bond(); let depositor: T::AccountId = account("depositor", USER_SEED, 0); let depositor_lookup = T::Lookup::unlookup(depositor.clone()); // Give the depositor some balance to bond CurrencyOf::::make_free_balance_be(&depositor, min_create_bond * 2u32.into()); - // Make sure no pools exist as a pre-condition for our verify checks + // Make sure no Pools exist at a pre-condition for our verify checks assert_eq!(RewardPools::::count(), 0); assert_eq!(BondedPools::::count(), 0); whitelist_account!(depositor); }: _( - Origin::Signed(depositor.clone()), + RuntimeOrigin::Signed(depositor.clone()), min_create_bond, depositor_lookup.clone(), depositor_lookup.clone(), @@ -536,7 +534,7 @@ frame_benchmarking::benchmarks! { let n in 1 .. T::MaxNominations::get(); // Create a pool - let min_create_bond = min_create_bond::() * 2u32.into(); + let min_create_bond = Pools::::depositor_min_bond() * 2u32.into(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond); // Create some accounts to nominate. For the sake of benchmarking they don't need to be @@ -546,7 +544,7 @@ frame_benchmarking::benchmarks! { .collect(); whitelist_account!(depositor); - }:_(Origin::Signed(depositor.clone()), 1, validators) + }:_(RuntimeOrigin::Signed(depositor.clone()), 1, validators) verify { assert_eq!(RewardPools::::count(), 1); assert_eq!(BondedPools::::count(), 1); @@ -573,7 +571,7 @@ frame_benchmarking::benchmarks! { set_state { // Create a pool - let min_create_bond = min_create_bond::(); + let min_create_bond = Pools::::depositor_min_bond(); let (depositor, pool_account) = create_pool_account::(0, min_create_bond); BondedPools::::mutate(&1, |maybe_pool| { // Force the pool into an invalid state @@ -582,7 +580,7 @@ frame_benchmarking::benchmarks! { let caller = account("caller", 0, USER_SEED); whitelist_account!(caller); - }:_(Origin::Signed(caller), 1, PoolState::Destroying) + }:_(RuntimeOrigin::Signed(caller), 1, PoolState::Destroying) verify { assert_eq!(BondedPools::::get(1).unwrap().state, PoolState::Destroying); } @@ -591,20 +589,20 @@ frame_benchmarking::benchmarks! { let n in 1 .. ::MaxMetadataLen::get(); // Create a pool - let (depositor, pool_account) = create_pool_account::(0, min_create_bond::() * 2u32.into()); + let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into()); // Create metadata of the max possible size let metadata: Vec = (0..n).map(|_| 42).collect(); whitelist_account!(depositor); - }:_(Origin::Signed(depositor), 1, metadata.clone()) + }:_(RuntimeOrigin::Signed(depositor), 1, metadata.clone()) verify { assert_eq!(Metadata::::get(&1), metadata); } set_configs { }:_( - Origin::Root, + RuntimeOrigin::Root, ConfigOp::Set(BalanceOf::::max_value()), ConfigOp::Set(BalanceOf::::max_value()), ConfigOp::Set(u32::MAX), @@ -620,10 +618,10 @@ frame_benchmarking::benchmarks! { update_roles { let first_id = pallet_nomination_pools::LastPoolId::::get() + 1; - let (root, _) = create_pool_account::(0, min_create_bond::() * 2u32.into()); + let (root, _) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into()); let random: T::AccountId = account("but is anything really random in computers..?", 0, USER_SEED); }:_( - Origin::Signed(root.clone()), + RuntimeOrigin::Signed(root.clone()), first_id, ConfigOp::Set(random.clone()), ConfigOp::Set(random.clone()), @@ -642,18 +640,18 @@ frame_benchmarking::benchmarks! { chill { // Create a pool - let (depositor, pool_account) = create_pool_account::(0, min_create_bond::() * 2u32.into()); + let (depositor, pool_account) = create_pool_account::(0, Pools::::depositor_min_bond() * 2u32.into()); // Nominate with the pool. let validators: Vec<_> = (0..T::MaxNominations::get()) .map(|i| account("stash", USER_SEED, i)) .collect(); - assert_ok!(Pools::::nominate(Origin::Signed(depositor.clone()).into(), 1, validators)); + assert_ok!(Pools::::nominate(RuntimeOrigin::Signed(depositor.clone()).into(), 1, validators)); assert!(T::StakingInterface::nominations(Pools::::create_bonded_account(1)).is_some()); whitelist_account!(depositor); - }:_(Origin::Signed(depositor.clone()), 1) + }:_(RuntimeOrigin::Signed(depositor.clone()), 1) verify { assert!(T::StakingInterface::nominations(Pools::::create_bonded_account(1)).is_none()); } diff --git a/frame/nomination-pools/benchmarking/src/mock.rs b/frame/nomination-pools/benchmarking/src/mock.rs index d239d4f072b80..0f617f0bf6f4b 100644 --- a/frame/nomination-pools/benchmarking/src/mock.rs +++ b/frame/nomination-pools/benchmarking/src/mock.rs @@ -15,6 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::VoterBagsListInstance; use frame_election_provider_support::VoteWeight; use frame_support::{pallet_prelude::*, parameter_types, traits::ConstU64, PalletId}; use sp_runtime::{ @@ -32,16 +33,16 @@ impl frame_system::Config for Runtime { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = AccountIndex; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_core::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type Version = (); type PalletInfo = PalletInfo; @@ -69,7 +70,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; @@ -96,7 +97,7 @@ impl pallet_staking::Config for Runtime { type UnixTime = pallet_timestamp::Pallet; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type RewardRemainder = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Slash = (); type Reward = (); type SessionsPerEra = (); @@ -111,8 +112,10 @@ impl pallet_staking::Config for Runtime { type ElectionProvider = frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking)>; type GenesisElectionProvider = Self::ElectionProvider; - type VoterList = pallet_bags_list::Pallet; + type VoterList = VoterList; + type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = ConstU32<84>; type OnStakerSlash = Pools; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); @@ -122,8 +125,8 @@ parameter_types! { pub static BagThresholds: &'static [VoteWeight] = &[10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; } -impl pallet_bags_list::Config for Runtime { - type Event = Event; +impl pallet_bags_list::Config for Runtime { + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type BagThresholds = BagThresholds; type ScoreProvider = Staking; @@ -151,7 +154,7 @@ parameter_types! { } impl pallet_nomination_pools::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type Currency = Balances; type CurrencyBalance = Balance; @@ -180,7 +183,7 @@ frame_support::construct_runtime!( Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, - BagsList: pallet_bags_list::{Pallet, Call, Storage, Event}, + VoterList: pallet_bags_list::::{Pallet, Call, Storage, Event}, Pools: pallet_nomination_pools::{Pallet, Call, Storage, Event}, } ); diff --git a/frame/nomination-pools/src/lib.rs b/frame/nomination-pools/src/lib.rs index 5e8f378568cb8..c73dc65f701c0 100644 --- a/frame/nomination-pools/src/lib.rs +++ b/frame/nomination-pools/src/lib.rs @@ -1152,7 +1152,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. type WeightInfo: weights::WeightInfo; @@ -1454,7 +1454,7 @@ pub mod pallet { PartialUnbondNotAllowedPermissionlessly, } - #[derive(Encode, Decode, PartialEq, TypeInfo, frame_support::PalletError)] + #[derive(Encode, Decode, PartialEq, TypeInfo, frame_support::PalletError, RuntimeDebug)] pub enum DefensiveError { /// There isn't enough space in the unbond pool. NotEnoughSpaceInUnbondPool, @@ -1759,8 +1759,8 @@ pub mod pallet { let bonded_pool = BondedPool::::get(member.pool_id) .defensive_ok_or::>(DefensiveError::PoolNotFound.into())?; - let mut sub_pools = SubPoolsStorage::::get(member.pool_id) - .defensive_ok_or::>(DefensiveError::SubPoolsNotFound.into())?; + let mut sub_pools = + SubPoolsStorage::::get(member.pool_id).ok_or(Error::::SubPoolsNotFound)?; bonded_pool.ok_to_withdraw_unbonded_with(&caller, &member_account)?; @@ -1888,10 +1888,10 @@ pub mod pallet { ); ensure!(!PoolMembers::::contains_key(&who), Error::::AccountBelongsToOtherPool); - let pool_id = LastPoolId::::mutate(|id| { - *id += 1; - *id - }); + let pool_id = LastPoolId::::try_mutate::<_, Error, _>(|id| { + *id = id.checked_add(1).ok_or(Error::::OverflowRisk)?; + Ok(*id) + })?; let mut bonded_pool = BondedPool::::new( pool_id, PoolRoles { @@ -2185,10 +2185,11 @@ impl Pallet { /// /// It is essentially `max { MinNominatorBond, MinCreateBond, MinJoinBond }`, where the former /// is coming from the staking pallet and the latter two are configured in this pallet. - fn depositor_min_bond() -> BalanceOf { + pub fn depositor_min_bond() -> BalanceOf { T::StakingInterface::minimum_bond() .max(MinCreateBond::::get()) .max(MinJoinBond::::get()) + .max(T::Currency::minimum_balance()) } /// Remove everything related to the given bonded pool. /// @@ -2417,16 +2418,46 @@ impl Pallet { for id in reward_pools { let account = Self::create_reward_account(id); - assert!(T::Currency::free_balance(&account) >= T::Currency::minimum_balance()); + assert!( + T::Currency::free_balance(&account) >= T::Currency::minimum_balance(), + "reward pool of {id}: {:?} (ed = {:?})", + T::Currency::free_balance(&account), + T::Currency::minimum_balance() + ); } let mut pools_members = BTreeMap::::new(); + let mut pools_members_pending_rewards = BTreeMap::>::new(); let mut all_members = 0u32; PoolMembers::::iter().for_each(|(_, d)| { - assert!(BondedPools::::contains_key(d.pool_id)); + let bonded_pool = BondedPools::::get(d.pool_id).unwrap(); assert!(!d.total_points().is_zero(), "no member should have zero points: {:?}", d); *pools_members.entry(d.pool_id).or_default() += 1; all_members += 1; + + let reward_pool = RewardPools::::get(d.pool_id).unwrap(); + if !bonded_pool.points.is_zero() { + let current_rc = + reward_pool.current_reward_counter(d.pool_id, bonded_pool.points).unwrap(); + *pools_members_pending_rewards.entry(d.pool_id).or_default() += + d.pending_rewards(current_rc).unwrap(); + } // else this pool has been heavily slashed and cannot have any rewards anymore. + }); + + RewardPools::::iter_keys().for_each(|id| { + // the sum of the pending rewards must be less than the leftover balance. Since the + // reward math rounds down, we might accumulate some dust here. + log!( + trace, + "pool {:?}, sum pending rewards = {:?}, remaining balance = {:?}", + id, + pools_members_pending_rewards.get(&id), + RewardPool::::current_balance(id) + ); + assert!( + RewardPool::::current_balance(id) >= + pools_members_pending_rewards.get(&id).map(|x| *x).unwrap_or_default() + ) }); BondedPools::::iter().for_each(|(id, inner)| { @@ -2471,6 +2502,7 @@ impl Pallet { sum_unbonding_balance ); } + Ok(()) } @@ -2492,7 +2524,7 @@ impl Pallet { impl OnStakerSlash> for Pallet { fn on_slash( pool_account: &T::AccountId, - // Bonded balance is always read directly from staking, therefore we need not update + // Bonded balance is always read directly from staking, therefore we don't need to update // anything here. slashed_bonded: BalanceOf, slashed_unlocking: &BTreeMap>, diff --git a/frame/nomination-pools/src/migration.rs b/frame/nomination-pools/src/migration.rs index bcf23ee863a39..b73141c95f72c 100644 --- a/frame/nomination-pools/src/migration.rs +++ b/frame/nomination-pools/src/migration.rs @@ -18,7 +18,7 @@ use super::*; use crate::log; use frame_support::traits::OnRuntimeUpgrade; -use sp_std::collections::btree_map::BTreeMap; +use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; pub mod v1 { use super::*; @@ -97,7 +97,7 @@ pub mod v1 { } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { + fn post_upgrade(_: Vec) -> Result<(), &'static str> { // new version must be set. assert_eq!(Pallet::::on_chain_storage_version(), 1); Pallet::::try_state(frame_system::Pallet::::block_number())?; @@ -119,7 +119,7 @@ pub mod v2 { ExtBuilder::default().build_and_execute(|| { let join = |x| { Balances::make_free_balance_be(&x, Balances::minimum_balance() + 10); - frame_support::assert_ok!(Pools::join(Origin::signed(x), 10, 1)); + frame_support::assert_ok!(Pools::join(RuntimeOrigin::signed(x), 10, 1)); }; assert_eq!(BondedPool::::get(1).unwrap().points, 10); @@ -347,7 +347,7 @@ pub mod v2 { } #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { + fn pre_upgrade() -> Result, &'static str> { // all reward accounts must have more than ED. RewardPools::::iter().for_each(|(id, _)| { assert!( @@ -356,11 +356,11 @@ pub mod v2 { ) }); - Ok(()) + Ok(Vec::new()) } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { + fn post_upgrade(_: Vec) -> Result<(), &'static str> { // new version must be set. assert_eq!(Pallet::::on_chain_storage_version(), 2); @@ -430,16 +430,16 @@ pub mod v3 { } #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { + fn pre_upgrade() -> Result, &'static str> { ensure!( Pallet::::current_storage_version() > Pallet::::on_chain_storage_version(), "the on_chain version is equal or more than the current one" ); - Ok(()) + Ok(Vec::new()) } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { + fn post_upgrade(_: Vec) -> Result<(), &'static str> { ensure!( Metadata::::iter_keys().all(|id| BondedPools::::contains_key(&id)), "not all of the stale metadata has been removed" diff --git a/frame/nomination-pools/src/mock.rs b/frame/nomination-pools/src/mock.rs index 4428c28558f18..1b3372dae56ee 100644 --- a/frame/nomination-pools/src/mock.rs +++ b/frame/nomination-pools/src/mock.rs @@ -4,6 +4,7 @@ use frame_support::{assert_ok, parameter_types, PalletId}; use frame_system::RawOrigin; use sp_runtime::FixedU128; +pub type BlockNumber = u64; pub type AccountId = u128; pub type Balance = u128; pub type RewardCounter = FixedU128; @@ -127,16 +128,16 @@ impl sp_staking::StakingInterface for StakingMock { impl frame_system::Config for Runtime { type SS58Prefix = (); type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; - type BlockNumber = u64; - type Call = Call; + type BlockNumber = BlockNumber; + type RuntimeCall = RuntimeCall; type Hash = sp_core::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = sp_runtime::traits::IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type DbWeight = (); type BlockLength = (); @@ -160,7 +161,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; @@ -188,7 +189,7 @@ parameter_types! { pub const PoolsPalletId: PalletId = PalletId(*b"py/nopls"); } impl pools::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type Currency = Balances; type CurrencyBalance = Balance; @@ -290,7 +291,7 @@ impl ExtBuilder { let amount_to_bond = Pools::depositor_min_bond(); Balances::make_free_balance_be(&10, amount_to_bond * 5); assert_ok!(Pools::create(RawOrigin::Signed(10).into(), amount_to_bond, 900, 901, 902)); - assert_ok!(Pools::set_metadata(Origin::signed(900), 1, vec![1, 1])); + assert_ok!(Pools::set_metadata(RuntimeOrigin::signed(900), 1, vec![1, 1])); let last_pool = LastPoolId::::get(); for (account_id, bonded) in self.members { Balances::make_free_balance_be(&account_id, bonded * 2); @@ -328,7 +329,7 @@ pub(crate) fn pool_events_since_last_call() -> Vec> { let events = System::events() .into_iter() .map(|r| r.event) - .filter_map(|e| if let Event::Pools(inner) = e { Some(inner) } else { None }) + .filter_map(|e| if let RuntimeEvent::Pools(inner) = e { Some(inner) } else { None }) .collect::>(); let already_seen = PoolsEvents::get(); PoolsEvents::set(&(events.len() as u32)); @@ -340,7 +341,7 @@ pub(crate) fn balances_events_since_last_call() -> Vec>(); let already_seen = BalancesEvents::get(); BalancesEvents::set(&(events.len() as u32)); @@ -352,7 +353,7 @@ pub fn fully_unbond_permissioned(member: AccountId) -> DispatchResult { let points = PoolMembers::::get(&member) .map(|d| d.active_points()) .unwrap_or_default(); - Pools::unbond(Origin::signed(member), member, points) + Pools::unbond(RuntimeOrigin::signed(member), member, points) } #[cfg(test)] diff --git a/frame/nomination-pools/src/tests.rs b/frame/nomination-pools/src/tests.rs index 20ba2b76fe31a..5074a7ffa695a 100644 --- a/frame/nomination-pools/src/tests.rs +++ b/frame/nomination-pools/src/tests.rs @@ -443,7 +443,7 @@ mod join { assert!(!PoolMembers::::contains_key(&11)); // When - assert_ok!(Pools::join(Origin::signed(11), 2, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(11), 2, 1)); // Then @@ -471,7 +471,7 @@ mod join { assert!(!PoolMembers::::contains_key(&12)); // When - assert_ok!(Pools::join(Origin::signed(12), 12, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(12), 12, 1)); // Then assert_eq!( @@ -494,15 +494,21 @@ mod join { assert_eq!(PoolMembers::::get(&10).unwrap().pool_id, 1); assert_noop!( - Pools::join(Origin::signed(10), 420, 123), + Pools::join(RuntimeOrigin::signed(10), 420, 123), Error::::AccountBelongsToOtherPool ); - assert_noop!(Pools::join(Origin::signed(11), 420, 123), Error::::PoolNotFound); + assert_noop!( + Pools::join(RuntimeOrigin::signed(11), 420, 123), + Error::::PoolNotFound + ); // Force the pools bonded balance to 0, simulating a 100% slash StakingMock::set_bonded_balance(Pools::create_bonded_account(1), 0); - assert_noop!(Pools::join(Origin::signed(11), 420, 1), Error::::OverflowRisk); + assert_noop!( + Pools::join(RuntimeOrigin::signed(11), 420, 1), + Error::::OverflowRisk + ); // Given a mocked bonded pool BondedPool:: { @@ -527,27 +533,33 @@ mod join { Pools::create_bonded_account(123), max_points_to_balance, ); - assert_noop!(Pools::join(Origin::signed(11), 420, 123), Error::::OverflowRisk); + assert_noop!( + Pools::join(RuntimeOrigin::signed(11), 420, 123), + Error::::OverflowRisk + ); StakingMock::set_bonded_balance( Pools::create_bonded_account(123), Balance::MAX / max_points_to_balance, ); // Balance needs to be gt Balance::MAX / `MaxPointsToBalance` - assert_noop!(Pools::join(Origin::signed(11), 5, 123), Error::::OverflowRisk); + assert_noop!( + Pools::join(RuntimeOrigin::signed(11), 5, 123), + Error::::OverflowRisk + ); StakingMock::set_bonded_balance(Pools::create_bonded_account(1), max_points_to_balance); // Cannot join a pool that isn't open unsafe_set_state(123, PoolState::Blocked); assert_noop!( - Pools::join(Origin::signed(11), max_points_to_balance, 123), + Pools::join(RuntimeOrigin::signed(11), max_points_to_balance, 123), Error::::NotOpen ); unsafe_set_state(123, PoolState::Destroying); assert_noop!( - Pools::join(Origin::signed(11), max_points_to_balance, 123), + Pools::join(RuntimeOrigin::signed(11), max_points_to_balance, 123), Error::::NotOpen ); @@ -556,7 +568,7 @@ mod join { // Then assert_noop!( - Pools::join(Origin::signed(11), 99, 123), + Pools::join(RuntimeOrigin::signed(11), 99, 123), Error::::MinimumBondNotMet ); }); @@ -578,7 +590,7 @@ mod join { }, } .put(); - let _ = Pools::join(Origin::signed(11), 420, 123); + let _ = Pools::join(RuntimeOrigin::signed(11), 420, 123); }); } @@ -591,7 +603,7 @@ mod join { let account = i + 100; Balances::make_free_balance_be(&account, 100 + Balances::minimum_balance()); - assert_ok!(Pools::join(Origin::signed(account), 100, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(account), 100, 1)); } Balances::make_free_balance_be(&103, 100 + Balances::minimum_balance()); @@ -608,7 +620,7 @@ mod join { ); assert_noop!( - Pools::join(Origin::signed(103), 100, 1), + Pools::join(RuntimeOrigin::signed(103), 100, 1), Error::::MaxPoolMembers ); @@ -617,7 +629,7 @@ mod join { assert_eq!(MaxPoolMembers::::get(), Some(4)); Balances::make_free_balance_be(&104, 100 + Balances::minimum_balance()); - assert_ok!(Pools::create(Origin::signed(104), 100, 104, 104, 104)); + assert_ok!(Pools::create(RuntimeOrigin::signed(104), 100, 104, 104, 104)); let pool_account = BondedPools::::iter() .find(|(_, bonded_pool)| bonded_pool.roles.depositor == 104) @@ -634,7 +646,7 @@ mod join { ); assert_noop!( - Pools::join(Origin::signed(103), 100, pool_account), + Pools::join(RuntimeOrigin::signed(103), 100, pool_account), Error::::MaxPoolMembers ); }); @@ -692,7 +704,7 @@ mod claim_payout { let _ = pool_events_since_last_call(); // When - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); // Then assert_eq!( @@ -708,7 +720,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 90); // When - assert_ok!(Pools::claim_payout(Origin::signed(40))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(40))); // Then assert_eq!( @@ -721,7 +733,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 50); // When - assert_ok!(Pools::claim_payout(Origin::signed(50))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(50))); // Then assert_eq!( @@ -737,7 +749,7 @@ mod claim_payout { assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += 50)); // When - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); // Then assert_eq!( @@ -750,7 +762,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 45); // When - assert_ok!(Pools::claim_payout(Origin::signed(40))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(40))); // Then assert_eq!( @@ -767,7 +779,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 75); // When - assert_ok!(Pools::claim_payout(Origin::signed(50))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(50))); // Then assert_eq!( @@ -780,7 +792,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 25); // When - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); // Then assert_eq!( @@ -797,7 +809,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 420); // When - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); // Then assert_eq!( @@ -816,7 +828,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 400); // When - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); // Then assert_eq!( @@ -829,7 +841,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 398); // When - assert_ok!(Pools::claim_payout(Origin::signed(40))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(40))); // Then assert_eq!( @@ -842,7 +854,7 @@ mod claim_payout { assert_eq!(Balances::free_balance(&default_reward_account()), ed + 210); // When - assert_ok!(Pools::claim_payout(Origin::signed(50))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(50))); // Then assert_eq!( @@ -862,7 +874,10 @@ mod claim_payout { // fully unbond the member. assert_ok!(fully_unbond_permissioned(11)); - assert_noop!(Pools::claim_payout(Origin::signed(11)), Error::::FullyUnbonding); + assert_noop!( + Pools::claim_payout(RuntimeOrigin::signed(11)), + Error::::FullyUnbonding + ); assert_eq!( pool_events_since_last_call(), @@ -1141,14 +1156,14 @@ mod claim_payout { // 20 joins afterwards. Balances::make_free_balance_be(&20, Balances::minimum_balance() + 10); - assert_ok!(Pools::join(Origin::signed(20), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); // reward by another 20 Balances::mutate_account(&default_reward_account(), |f| f.free += 20).unwrap(); // 10 should claim 10 + 10, 20 should claim 20 / 2. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), vec![ @@ -1163,8 +1178,8 @@ mod claim_payout { // any upcoming rewards are shared equally. Balances::mutate_account(&default_reward_account(), |f| f.free += 20).unwrap(); - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1184,13 +1199,13 @@ mod claim_payout { Balances::mutate_account(&default_reward_account(), |f| f.free += 3).unwrap(); Balances::make_free_balance_be(&20, Balances::minimum_balance() + 10); - assert_ok!(Pools::join(Origin::signed(20), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); Balances::mutate_account(&default_reward_account(), |f| f.free += 6).unwrap(); // 10 should claim 3, 20 should claim 3 + 3. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1206,8 +1221,8 @@ mod claim_payout { // any upcoming rewards are shared equally. Balances::mutate_account(&default_reward_account(), |f| f.free += 8).unwrap(); - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1220,8 +1235,8 @@ mod claim_payout { // uneven upcoming rewards are shared equally, rounded down. Balances::mutate_account(&default_reward_account(), |f| f.free += 7).unwrap(); - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1241,19 +1256,19 @@ mod claim_payout { Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); Balances::make_free_balance_be(&20, ed + 10); - assert_ok!(Pools::join(Origin::signed(20), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); Balances::mutate_account(&default_reward_account(), |f| f.free += 100).unwrap(); Balances::make_free_balance_be(&30, ed + 10); - assert_ok!(Pools::join(Origin::signed(30), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10, 1)); Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap(); // 10 should claim 10, 20 should claim nothing. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); - assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); assert_eq!( pool_events_since_last_call(), @@ -1271,9 +1286,9 @@ mod claim_payout { // any upcoming rewards are shared equally. Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); - assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); assert_eq!( pool_events_since_last_call(), @@ -1297,7 +1312,7 @@ mod claim_payout { assert_eq!(Pools::pending_rewards(20), None); Balances::make_free_balance_be(&20, ed + 10); - assert_ok!(Pools::join(Origin::signed(20), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); assert_eq!(Pools::pending_rewards(10), Some(30)); assert_eq!(Pools::pending_rewards(20), Some(0)); @@ -1309,7 +1324,7 @@ mod claim_payout { assert_eq!(Pools::pending_rewards(30), None); Balances::make_free_balance_be(&30, ed + 10); - assert_ok!(Pools::join(Origin::signed(30), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10, 1)); assert_eq!(Pools::pending_rewards(10), Some(30 + 50)); assert_eq!(Pools::pending_rewards(20), Some(50)); @@ -1322,17 +1337,17 @@ mod claim_payout { assert_eq!(Pools::pending_rewards(30), Some(20)); // 10 should claim 10, 20 should claim nothing. - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_eq!(Pools::pending_rewards(10), Some(0)); assert_eq!(Pools::pending_rewards(20), Some(50 + 20)); assert_eq!(Pools::pending_rewards(30), Some(20)); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!(Pools::pending_rewards(10), Some(0)); assert_eq!(Pools::pending_rewards(20), Some(0)); assert_eq!(Pools::pending_rewards(30), Some(20)); - assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); assert_eq!(Pools::pending_rewards(10), Some(0)); assert_eq!(Pools::pending_rewards(20), Some(0)); assert_eq!(Pools::pending_rewards(30), Some(0)); @@ -1345,16 +1360,16 @@ mod claim_payout { let ed = Balances::minimum_balance(); Balances::make_free_balance_be(&20, ed + 20); - assert_ok!(Pools::join(Origin::signed(20), 20, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); Balances::make_free_balance_be(&30, ed + 20); - assert_ok!(Pools::join(Origin::signed(30), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10, 1)); Balances::mutate_account(&default_reward_account(), |f| f.free += 40).unwrap(); // everyone claims. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); - assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); assert_eq!( pool_events_since_last_call(), @@ -1370,14 +1385,14 @@ mod claim_payout { ); // 30 now bumps itself to be like 20. - assert_ok!(Pools::bond_extra(Origin::signed(30), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(30), BondExtra::FreeBalance(10))); // more rewards come in. Balances::mutate_account(&default_reward_account(), |f| f.free += 100).unwrap(); - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); - assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); assert_eq!( pool_events_since_last_call(), @@ -1397,13 +1412,13 @@ mod claim_payout { let ed = Balances::minimum_balance(); Balances::make_free_balance_be(&20, ed + 20); - assert_ok!(Pools::join(Origin::signed(20), 20, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); // everyone claims. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1417,13 +1432,13 @@ mod claim_payout { ); // 20 unbonds to be equal to 10 (10 points each). - assert_ok!(Pools::unbond(Origin::signed(20), 20, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); // more rewards come in. Balances::mutate_account(&default_reward_account(), |f| f.free += 100).unwrap(); - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1442,16 +1457,16 @@ mod claim_payout { let ed = Balances::minimum_balance(); Balances::make_free_balance_be(&20, ed + 20); - assert_ok!(Pools::join(Origin::signed(20), 20, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); Balances::make_free_balance_be(&30, ed + 20); - assert_ok!(Pools::join(Origin::signed(30), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10, 1)); // 10 gets 10, 20 gets 20, 30 gets 10 Balances::mutate_account(&default_reward_account(), |f| f.free += 40).unwrap(); // some claim. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1469,8 +1484,8 @@ mod claim_payout { Balances::mutate_account(&default_reward_account(), |f| f.free += 80).unwrap(); // some claim. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1484,8 +1499,8 @@ mod claim_payout { Balances::mutate_account(&default_reward_account(), |f| f.free += 80).unwrap(); // some claim. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1496,7 +1511,7 @@ mod claim_payout { ); // now 30 claims all at once - assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); assert_eq!( pool_events_since_last_call(), @@ -1511,13 +1526,13 @@ mod claim_payout { let ed = Balances::minimum_balance(); Balances::make_free_balance_be(&20, ed + 200); - assert_ok!(Pools::join(Origin::signed(20), 20, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); // 10 gets 10, 20 gets 20, 30 gets 10 Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); // some claim. - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_eq!( pool_events_since_last_call(), @@ -1533,11 +1548,11 @@ mod claim_payout { Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap(); // and 20 bonds more -- they should not have more share of this reward. - assert_ok!(Pools::bond_extra(Origin::signed(20), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(20), BondExtra::FreeBalance(10))); // everyone claim. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1553,8 +1568,8 @@ mod claim_payout { Balances::mutate_account(&default_reward_account(), |f| f.free += 60).unwrap(); // everyone claim. - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -1584,7 +1599,7 @@ mod claim_payout { // create pool 2 Balances::make_free_balance_be(&20, 100); - assert_ok!(Pools::create(Origin::signed(20), 10, 20, 20, 20)); + assert_ok!(Pools::create(RuntimeOrigin::signed(20), 10, 20, 20, 20)); // has no impact -- initial let (member_20, _, reward_pool_20) = Pools::get_member_with_pools(&20).unwrap(); @@ -1600,7 +1615,7 @@ mod claim_payout { // create pool 3 Balances::make_free_balance_be(&30, 100); - assert_ok!(Pools::create(Origin::signed(30), 10, 30, 30, 30)); + assert_ok!(Pools::create(RuntimeOrigin::signed(30), 10, 30, 30, 30)); // reward counter is still the same. let (member_30, _, reward_pool_30) = Pools::get_member_with_pools(&30).unwrap(); @@ -1616,7 +1631,7 @@ mod claim_payout { assert_eq!(member_30.last_recorded_reward_counter, 0.into()); // and 30 can claim the reward now. - assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); assert_eq!( pool_events_since_last_call(), @@ -1640,7 +1655,7 @@ mod claim_payout { MaxPoolMembersPerPool::::set(None); let join = |x, y| { Balances::make_free_balance_be(&x, y + Balances::minimum_balance()); - assert_ok!(Pools::join(Origin::signed(x), y, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(x), y, 1)); }; { @@ -1722,7 +1737,10 @@ mod claim_payout { // 10 bonds extra without any rewards. { - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra( + RuntimeOrigin::signed(10), + BondExtra::FreeBalance(10) + )); let (member, _, reward_pool) = Pools::get_member_with_pools(&10).unwrap(); assert_eq!(member.last_recorded_reward_counter, 0.into()); assert_eq!(reward_pool.last_recorded_total_payouts, 0); @@ -1734,7 +1752,10 @@ mod claim_payout { Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); { - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra( + RuntimeOrigin::signed(10), + BondExtra::FreeBalance(10) + )); let (member, _, reward_pool) = Pools::get_member_with_pools(&10).unwrap(); // explanation: before bond_extra takes place, there is 40 points and 30 balance in // the system, RewardCounter is therefore 7.5 @@ -1748,7 +1769,10 @@ mod claim_payout { // 20 bonds extra again, without further rewards. { - assert_ok!(Pools::bond_extra(Origin::signed(20), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra( + RuntimeOrigin::signed(20), + BondExtra::FreeBalance(10) + )); let (member, _, reward_pool) = Pools::get_member_with_pools(&20).unwrap(); assert_eq!(member.last_recorded_reward_counter, RewardCounter::from_float(0.75)); assert_eq!( @@ -1774,6 +1798,54 @@ mod claim_payout { }) } + #[test] + fn bond_extra_pending_rewards_works() { + ExtBuilder::default().add_members(vec![(20, 20)]).build_and_execute(|| { + MaxPoolMembers::::set(None); + MaxPoolMembersPerPool::::set(None); + + // pool receives some rewards. + Balances::mutate_account(&default_reward_account(), |f| f.free += 30).unwrap(); + System::reset_events(); + + // 10 cashes it out, and bonds it. + { + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + let (member, _, reward_pool) = Pools::get_member_with_pools(&10).unwrap(); + // there is 30 points and 30 reward points in the system RC is 1. + assert_eq!(member.last_recorded_reward_counter, 1.into()); + assert_eq!(reward_pool.total_rewards_claimed, 10); + // these two are not updated -- only updated when the points change. + assert_eq!(reward_pool.last_recorded_total_payouts, 0); + assert_eq!(reward_pool.last_recorded_reward_counter, 0.into()); + + assert_eq!( + pool_events_since_last_call(), + vec![Event::PaidOut { member: 10, pool_id: 1, payout: 10 }] + ); + } + + // 20 re-bonds it. + { + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(20), BondExtra::Rewards)); + let (member, _, reward_pool) = Pools::get_member_with_pools(&10).unwrap(); + assert_eq!(member.last_recorded_reward_counter, 1.into()); + assert_eq!(reward_pool.total_rewards_claimed, 30); + // since points change, these two are updated. + assert_eq!(reward_pool.last_recorded_total_payouts, 30); + assert_eq!(reward_pool.last_recorded_reward_counter, 1.into()); + + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::PaidOut { member: 20, pool_id: 1, payout: 20 }, + Event::Bonded { member: 20, pool_id: 1, bonded: 20, joined: false } + ] + ); + } + }) + } + #[test] fn unbond_updates_recorded_data() { ExtBuilder::default() @@ -1795,7 +1867,7 @@ mod claim_payout { // 20 unbonds without any rewards. { - assert_ok!(Pools::unbond(Origin::signed(20), 20, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); let (member, _, reward_pool) = Pools::get_member_with_pools(&20).unwrap(); assert_eq!(member.last_recorded_reward_counter, 0.into()); assert_eq!(reward_pool.last_recorded_total_payouts, 0); @@ -1807,7 +1879,7 @@ mod claim_payout { // and 30 also unbonds half. { - assert_ok!(Pools::unbond(Origin::signed(30), 30, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(30), 30, 10)); let (member, _, reward_pool) = Pools::get_member_with_pools(&30).unwrap(); // 30 reward in the system, and 40 points before this unbond to collect it, // RewardCounter is 3/4. @@ -1824,7 +1896,7 @@ mod claim_payout { // 30 unbonds again, not change this time. { - assert_ok!(Pools::unbond(Origin::signed(30), 30, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(30), 30, 5)); let (member, _, reward_pool) = Pools::get_member_with_pools(&30).unwrap(); assert_eq!( member.last_recorded_reward_counter, @@ -1839,7 +1911,7 @@ mod claim_payout { // 20 unbonds again, not change this time, just collecting their reward. { - assert_ok!(Pools::unbond(Origin::signed(20), 20, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); let (member, _, reward_pool) = Pools::get_member_with_pools(&20).unwrap(); assert_eq!( member.last_recorded_reward_counter, @@ -1853,7 +1925,7 @@ mod claim_payout { } // trigger 10's reward as well to see all of the payouts. - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_eq!( pool_events_since_last_call(), @@ -1889,8 +1961,8 @@ mod claim_payout { Balances::mutate_account(&default_reward_account(), |f| f.free += 40).unwrap(); // everyone claims - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); // some dust (1) remains in the reward account. assert_eq!( @@ -1905,15 +1977,15 @@ mod claim_payout { ); // start dismantling the pool. - assert_ok!(Pools::set_state(Origin::signed(902), 1, PoolState::Destroying)); + assert_ok!(Pools::set_state(RuntimeOrigin::signed(902), 1, PoolState::Destroying)); assert_ok!(fully_unbond_permissioned(20)); CurrentEra::set(3); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(20), 20, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); assert_ok!(fully_unbond_permissioned(10)); CurrentEra::set(6); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); assert_eq!( pool_events_since_last_call(), @@ -1952,10 +2024,10 @@ mod claim_payout { .unwrap(); // everyone claims - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); - assert_ok!(Pools::claim_payout(Origin::signed(21))); - assert_ok!(Pools::claim_payout(Origin::signed(22))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(21))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(22))); assert_eq!( pool_events_since_last_call(), @@ -2009,18 +2081,18 @@ mod unbond { .add_members(vec![(20, 20)]) .build_and_execute(|| { // can unbond to above limit - assert_ok!(Pools::unbond(Origin::signed(20), 20, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 15); assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 5); // cannot go to below 10: assert_noop!( - Pools::unbond(Origin::signed(20), 20, 10), + Pools::unbond(RuntimeOrigin::signed(20), 20, 10), Error::::MinimumBondNotMet ); // but can go to 0 - assert_ok!(Pools::unbond(Origin::signed(20), 20, 15)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 15)); assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 0); assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 20); }) @@ -2041,23 +2113,23 @@ mod unbond { // cannot be kicked to above the limit. assert_noop!( - Pools::unbond(Origin::signed(kicker), 20, 5), + Pools::unbond(RuntimeOrigin::signed(kicker), 20, 5), Error::::PartialUnbondNotAllowedPermissionlessly ); // cannot go to below 10: assert_noop!( - Pools::unbond(Origin::signed(kicker), 20, 15), + Pools::unbond(RuntimeOrigin::signed(kicker), 20, 15), Error::::PartialUnbondNotAllowedPermissionlessly ); // but they themselves can do an unbond - assert_ok!(Pools::unbond(Origin::signed(20), 20, 2)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 2)); assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 18); assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 2); // can be kicked to 0. - assert_ok!(Pools::unbond(Origin::signed(kicker), 20, 18)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(kicker), 20, 18)); assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 0); assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 20); }) @@ -2078,23 +2150,23 @@ mod unbond { // cannot be kicked to above the limit. assert_noop!( - Pools::unbond(Origin::signed(random), 20, 5), + Pools::unbond(RuntimeOrigin::signed(random), 20, 5), Error::::PartialUnbondNotAllowedPermissionlessly ); // cannot go to below 10: assert_noop!( - Pools::unbond(Origin::signed(random), 20, 15), + Pools::unbond(RuntimeOrigin::signed(random), 20, 15), Error::::PartialUnbondNotAllowedPermissionlessly ); // but they themselves can do an unbond - assert_ok!(Pools::unbond(Origin::signed(20), 20, 2)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 2)); assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 18); assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 2); // but can go to 0 - assert_ok!(Pools::unbond(Origin::signed(random), 20, 18)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(random), 20, 18)); assert_eq!(PoolMembers::::get(20).unwrap().active_points(), 0); assert_eq!(PoolMembers::::get(20).unwrap().unbonding_points(), 20); }) @@ -2107,19 +2179,25 @@ mod unbond { // - depositor cannot unbond to below limit or 0 ExtBuilder::default().min_join_bond(10).build_and_execute(|| { // give the depositor some extra funds. - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); assert_eq!(PoolMembers::::get(10).unwrap().points, 20); // can unbond to above the limit. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 5)); assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 15); assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 5); // cannot go to below 10: - assert_noop!(Pools::unbond(Origin::signed(10), 10, 10), Error::::MinimumBondNotMet); + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(10), 10, 10), + Error::::MinimumBondNotMet + ); // cannot go to 0 either. - assert_noop!(Pools::unbond(Origin::signed(10), 10, 15), Error::::MinimumBondNotMet); + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(10), 10, 15), + Error::::MinimumBondNotMet + ); }) } @@ -2129,7 +2207,7 @@ mod unbond { // - depositor can never be kicked. ExtBuilder::default().min_join_bond(10).build_and_execute(|| { // give the depositor some extra funds. - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); assert_eq!(PoolMembers::::get(10).unwrap().points, 20); // set the stage @@ -2138,24 +2216,27 @@ mod unbond { // cannot be kicked to above limit. assert_noop!( - Pools::unbond(Origin::signed(kicker), 10, 5), + Pools::unbond(RuntimeOrigin::signed(kicker), 10, 5), Error::::PartialUnbondNotAllowedPermissionlessly ); // or below the limit assert_noop!( - Pools::unbond(Origin::signed(kicker), 10, 15), + Pools::unbond(RuntimeOrigin::signed(kicker), 10, 15), Error::::PartialUnbondNotAllowedPermissionlessly ); // or 0. assert_noop!( - Pools::unbond(Origin::signed(kicker), 10, 20), + Pools::unbond(RuntimeOrigin::signed(kicker), 10, 20), Error::::DoesNotHavePermission ); // they themselves cannot do it either - assert_noop!(Pools::unbond(Origin::signed(10), 10, 20), Error::::MinimumBondNotMet); + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(10), 10, 20), + Error::::MinimumBondNotMet + ); }) } @@ -2164,7 +2245,7 @@ mod unbond { // depositor can never be permissionlessly unbonded. ExtBuilder::default().min_join_bond(10).build_and_execute(|| { // give the depositor some extra funds. - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); assert_eq!(PoolMembers::::get(10).unwrap().points, 20); // set the stage @@ -2173,24 +2254,24 @@ mod unbond { // cannot be kicked to above limit. assert_noop!( - Pools::unbond(Origin::signed(random), 10, 5), + Pools::unbond(RuntimeOrigin::signed(random), 10, 5), Error::::PartialUnbondNotAllowedPermissionlessly ); // or below the limit assert_noop!( - Pools::unbond(Origin::signed(random), 10, 15), + Pools::unbond(RuntimeOrigin::signed(random), 10, 15), Error::::PartialUnbondNotAllowedPermissionlessly ); // or 0. assert_noop!( - Pools::unbond(Origin::signed(random), 10, 20), + Pools::unbond(RuntimeOrigin::signed(random), 10, 20), Error::::DoesNotHavePermission ); // they themselves can do it in this case though. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 20)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 20)); }) } @@ -2203,26 +2284,29 @@ mod unbond { .add_members(vec![(20, 20)]) .build_and_execute(|| { // give the depositor some extra funds. - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra( + RuntimeOrigin::signed(10), + BondExtra::FreeBalance(10) + )); assert_eq!(PoolMembers::::get(10).unwrap().points, 20); // set the stage unsafe_set_state(1, PoolState::Destroying); // can go above the limit - assert_ok!(Pools::unbond(Origin::signed(10), 10, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 5)); assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 15); assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 5); // but not below the limit assert_noop!( - Pools::unbond(Origin::signed(10), 10, 10), + Pools::unbond(RuntimeOrigin::signed(10), 10, 10), Error::::MinimumBondNotMet ); // and certainly not zero assert_noop!( - Pools::unbond(Origin::signed(10), 10, 15), + Pools::unbond(RuntimeOrigin::signed(10), 10, 15), Error::::MinimumBondNotMet ); }) @@ -2236,22 +2320,25 @@ mod unbond { // - depositor can unbond to 0 if last and destroying. ExtBuilder::default().min_join_bond(10).build_and_execute(|| { // give the depositor some extra funds. - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); assert_eq!(PoolMembers::::get(10).unwrap().points, 20); // set the stage unsafe_set_state(1, PoolState::Destroying); // can unbond to above the limit. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 5)); assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 15); assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 5); // still cannot go to below limit - assert_noop!(Pools::unbond(Origin::signed(10), 10, 10), Error::::MinimumBondNotMet); + assert_noop!( + Pools::unbond(RuntimeOrigin::signed(10), 10, 10), + Error::::MinimumBondNotMet + ); // can go to 0 too. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 15)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 15)); assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 0); assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 20); }) @@ -2378,8 +2465,8 @@ mod unbond { // When CurrentEra::set(3); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 40, 0)); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 550, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 40, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 550, 0)); assert_ok!(fully_unbond_permissioned(10)); // Then @@ -2477,12 +2564,12 @@ mod unbond { // When the nominator tries to kick, then its a noop assert_noop!( - Pools::fully_unbond(Origin::signed(901), 100), + Pools::fully_unbond(RuntimeOrigin::signed(901), 100), Error::::NotKickerOrDestroying ); // When the root kicks then its ok - assert_ok!(Pools::fully_unbond(Origin::signed(900), 100)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(900), 100)); assert_eq!( pool_events_since_last_call(), @@ -2502,7 +2589,7 @@ mod unbond { ); // When the state toggler kicks then its ok - assert_ok!(Pools::fully_unbond(Origin::signed(902), 200)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(902), 200)); assert_eq!( pool_events_since_last_call(), @@ -2553,13 +2640,13 @@ mod unbond { // A permissionless unbond attempt errors assert_noop!( - Pools::fully_unbond(Origin::signed(420), 100), + Pools::fully_unbond(RuntimeOrigin::signed(420), 100), Error::::NotKickerOrDestroying ); // permissionless unbond must be full assert_noop!( - Pools::unbond(Origin::signed(420), 100, 80), + Pools::unbond(RuntimeOrigin::signed(420), 100, 80), Error::::PartialUnbondNotAllowedPermissionlessly, ); @@ -2568,12 +2655,12 @@ mod unbond { // The depositor cannot be fully unbonded until they are the last member assert_noop!( - Pools::fully_unbond(Origin::signed(10), 10), + Pools::fully_unbond(RuntimeOrigin::signed(10), 10), Error::::MinimumBondNotMet, ); // Any account can unbond a member that is not the depositor - assert_ok!(Pools::fully_unbond(Origin::signed(420), 100)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(420), 100)); assert_eq!( pool_events_since_last_call(), @@ -2587,7 +2674,7 @@ mod unbond { // still permissionless unbond must be full assert_noop!( - Pools::unbond(Origin::signed(420), 100, 80), + Pools::unbond(RuntimeOrigin::signed(420), 100, 80), Error::::PartialUnbondNotAllowedPermissionlessly, ); @@ -2596,7 +2683,7 @@ mod unbond { // The depositor cannot be unbonded assert_noop!( - Pools::fully_unbond(Origin::signed(420), 10), + Pools::fully_unbond(RuntimeOrigin::signed(420), 10), Error::::DoesNotHavePermission ); @@ -2605,27 +2692,27 @@ mod unbond { // The depositor cannot be unbonded yet. assert_noop!( - Pools::fully_unbond(Origin::signed(420), 10), + Pools::fully_unbond(RuntimeOrigin::signed(420), 10), Error::::DoesNotHavePermission, ); // but when everyone is unbonded it can.. CurrentEra::set(3); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 100, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 100, 0)); // still permissionless unbond must be full. assert_noop!( - Pools::unbond(Origin::signed(420), 10, 5), + Pools::unbond(RuntimeOrigin::signed(420), 10, 5), Error::::PartialUnbondNotAllowedPermissionlessly, ); // depositor can never be unbonded permissionlessly . assert_noop!( - Pools::fully_unbond(Origin::signed(420), 10), + Pools::fully_unbond(RuntimeOrigin::signed(420), 10), Error::::DoesNotHavePermission ); // but depositor itself can do it. - assert_ok!(Pools::fully_unbond(Origin::signed(10), 10)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(10), 10)); assert_eq!(BondedPools::::get(1).unwrap().points, 0); assert_eq!( @@ -2648,7 +2735,7 @@ mod unbond { fn unbond_errors_correctly() { ExtBuilder::default().build_and_execute(|| { assert_noop!( - Pools::fully_unbond(Origin::signed(11), 11), + Pools::fully_unbond(RuntimeOrigin::signed(11), 11), Error::::PoolMemberNotFound ); @@ -2656,7 +2743,7 @@ mod unbond { let member = PoolMember { pool_id: 2, points: 10, ..Default::default() }; PoolMembers::::insert(11, member); - let _ = Pools::fully_unbond(Origin::signed(11), 11); + let _ = Pools::fully_unbond(RuntimeOrigin::signed(11), 11); }); } @@ -2678,13 +2765,13 @@ mod unbond { } .put(); - let _ = Pools::fully_unbond(Origin::signed(11), 11); + let _ = Pools::fully_unbond(RuntimeOrigin::signed(11), 11); }); } #[test] fn partial_unbond_era_tracking() { - ExtBuilder::default().build_and_execute(|| { + ExtBuilder::default().ed(1).build_and_execute(|| { // to make the depositor capable of withdrawing. StakingMinBond::set(1); MinCreateBond::::set(1); @@ -2708,7 +2795,7 @@ mod unbond { unsafe_set_state(1, PoolState::Destroying); // when: casual unbond - assert_ok!(Pools::unbond(Origin::signed(10), 10, 1)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 1)); // then assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 9); @@ -2737,7 +2824,7 @@ mod unbond { ); // when: casual further unbond, same era. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 5)); // then assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 4); @@ -2763,7 +2850,7 @@ mod unbond { // when: casual further unbond, next era. CurrentEra::set(1); - assert_ok!(Pools::unbond(Origin::signed(10), 10, 1)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 1)); // then assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 3); @@ -2791,14 +2878,14 @@ mod unbond { // when: unbonding more than our active: error assert_noop!( frame_support::storage::with_storage_layer(|| Pools::unbond( - Origin::signed(10), + RuntimeOrigin::signed(10), 10, 5 )), Error::::MinimumBondNotMet ); // instead: - assert_ok!(Pools::unbond(Origin::signed(10), 10, 3)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 3)); // then assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 0); @@ -2831,9 +2918,9 @@ mod unbond { MaxUnbonding::set(2); // given - assert_ok!(Pools::unbond(Origin::signed(20), 20, 2)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 2)); CurrentEra::set(1); - assert_ok!(Pools::unbond(Origin::signed(20), 20, 3)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 3)); assert_eq!( PoolMembers::::get(20).unwrap().unbonding_eras, member_unbonding_eras!(3 => 2, 4 => 3) @@ -2843,7 +2930,7 @@ mod unbond { CurrentEra::set(2); assert_noop!( frame_support::storage::with_storage_layer(|| Pools::unbond( - Origin::signed(20), + RuntimeOrigin::signed(20), 20, 4 )), @@ -2852,7 +2939,7 @@ mod unbond { // when MaxUnbonding::set(3); - assert_ok!(Pools::unbond(Origin::signed(20), 20, 1)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 1)); assert_eq!( PoolMembers::::get(20).unwrap().unbonding_eras, @@ -2885,13 +2972,13 @@ mod unbond { assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 0); // can unbond a bit.. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 3)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 3)); assert_eq!(PoolMembers::::get(10).unwrap().active_points(), 7); assert_eq!(PoolMembers::::get(10).unwrap().unbonding_points(), 3); // but not less than 2 assert_noop!( - Pools::unbond(Origin::signed(10), 10, 6), + Pools::unbond(RuntimeOrigin::signed(10), 10, 6), Error::::MinimumBondNotMet ); @@ -2919,7 +3006,7 @@ mod unbond { // cannot unbond even 7, because the value of shares is now less. assert_noop!( - Pools::unbond(Origin::signed(10), 10, 7), + Pools::unbond(RuntimeOrigin::signed(10), 10, 7), Error::::MinimumBondNotMet ); }); @@ -2937,7 +3024,7 @@ mod unbond { 4 * Balances::minimum_balance(), ); - assert_ok!(Pools::unbond(Origin::signed(20), 20, 2)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 2)); assert_eq!( pool_events_since_last_call(), vec![ @@ -2956,7 +3043,7 @@ mod unbond { 4 * Balances::minimum_balance(), ); - assert_ok!(Pools::unbond(Origin::signed(20), 20, 3)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 3)); assert_eq!( pool_events_since_last_call(), vec![ @@ -2972,7 +3059,7 @@ mod unbond { 4 * Balances::minimum_balance(), ); - assert_ok!(Pools::unbond(Origin::signed(20), 20, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); assert_eq!( pool_events_since_last_call(), vec![ @@ -3003,7 +3090,7 @@ mod pool_withdraw_unbonded { assert_eq!(Balances::free_balance(&default_bonded_account()), 10); // When - assert_ok!(Pools::pool_withdraw_unbonded(Origin::signed(10), 1, 0)); + assert_ok!(Pools::pool_withdraw_unbonded(RuntimeOrigin::signed(10), 1, 0)); // Then there unbonding balance is no longer locked assert_eq!(StakingMock::active_stake(&default_bonded_account()), Some(5)); @@ -3027,8 +3114,8 @@ mod withdraw_unbonded { // Given assert_eq!(StakingMock::bonding_duration(), 3); - assert_ok!(Pools::fully_unbond(Origin::signed(550), 550)); - assert_ok!(Pools::fully_unbond(Origin::signed(40), 40)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(550), 550)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(40), 40)); assert_eq!(Balances::free_balance(&default_bonded_account()), 600); let mut current_era = 1; @@ -3103,7 +3190,7 @@ mod withdraw_unbonded { ); // When - assert_ok!(Pools::withdraw_unbonded(Origin::signed(550), 550, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(550), 550, 0)); // Then assert_eq!( @@ -3123,7 +3210,7 @@ mod withdraw_unbonded { ); // When - assert_ok!(Pools::withdraw_unbonded(Origin::signed(40), 40, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(40), 40, 0)); // Then assert_eq!( @@ -3151,7 +3238,7 @@ mod withdraw_unbonded { CurrentEra::set(current_era); // when - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); assert_eq!( pool_events_since_last_call(), vec![ @@ -3223,7 +3310,7 @@ mod withdraw_unbonded { CurrentEra::set(StakingMock::bonding_duration()); // When - assert_ok!(Pools::withdraw_unbonded(Origin::signed(40), 40, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(40), 40, 0)); // Then assert_eq!( @@ -3244,7 +3331,7 @@ mod withdraw_unbonded { ); // When - assert_ok!(Pools::withdraw_unbonded(Origin::signed(550), 550, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(550), 550, 0)); // Then assert_eq!( @@ -3273,11 +3360,11 @@ mod withdraw_unbonded { CurrentEra::set(CurrentEra::get() + 3); // set metadata to check that it's being removed on dissolve - assert_ok!(Pools::set_metadata(Origin::signed(900), 1, vec![1, 1])); + assert_ok!(Pools::set_metadata(RuntimeOrigin::signed(900), 1, vec![1, 1])); assert!(Metadata::::contains_key(1)); // when - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); // then assert_eq!(Balances::free_balance(&10), 10 + 35); @@ -3313,7 +3400,7 @@ mod withdraw_unbonded { assert_eq!(Balances::free_balance(&10), 35); assert_eq!(Balances::free_balance(&default_bonded_account()), 10); unsafe_set_state(1, PoolState::Destroying); - assert_ok!(Pools::fully_unbond(Origin::signed(10), 10)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(10), 10)); // Simulate a slash that is not accounted for in the sub pools. Balances::make_free_balance_be(&default_bonded_account(), 5); @@ -3326,7 +3413,7 @@ mod withdraw_unbonded { CurrentEra::set(0 + 3); // When - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); // Then assert_eq!(Balances::free_balance(10), 10 + 35); @@ -3345,7 +3432,7 @@ mod withdraw_unbonded { SubPoolsStorage::::insert(1, sub_pools.clone()); assert_noop!( - Pools::withdraw_unbonded(Origin::signed(11), 11, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(11), 11, 0), Error::::PoolMemberNotFound ); @@ -3358,7 +3445,7 @@ mod withdraw_unbonded { // We are still in the bonding duration assert_noop!( - Pools::withdraw_unbonded(Origin::signed(11), 11, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(11), 11, 0), Error::::CannotWithdrawAny ); @@ -3375,8 +3462,8 @@ mod withdraw_unbonded { .add_members(vec![(100, 100), (200, 200)]) .build_and_execute(|| { // Given - assert_ok!(Pools::fully_unbond(Origin::signed(100), 100)); - assert_ok!(Pools::fully_unbond(Origin::signed(200), 200)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(100), 100)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(200), 200)); assert_eq!( BondedPool::::get(1).unwrap(), BondedPool { @@ -3393,7 +3480,7 @@ mod withdraw_unbonded { // Cannot kick when pool is open assert_noop!( - Pools::withdraw_unbonded(Origin::signed(902), 100, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(902), 100, 0), Error::::NotKickerOrDestroying ); assert_eq!( @@ -3425,15 +3512,15 @@ mod withdraw_unbonded { // Cannot kick as a nominator assert_noop!( - Pools::withdraw_unbonded(Origin::signed(901), 100, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(901), 100, 0), Error::::NotKickerOrDestroying ); // Can kick as root - assert_ok!(Pools::withdraw_unbonded(Origin::signed(900), 100, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(900), 100, 0)); // Can kick as state toggler - assert_ok!(Pools::withdraw_unbonded(Origin::signed(900), 200, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(900), 200, 0)); assert_eq!(Balances::free_balance(100), 100 + 100); assert_eq!(Balances::free_balance(200), 200 + 200); @@ -3456,7 +3543,7 @@ mod withdraw_unbonded { fn withdraw_unbonded_destroying_permissionless() { ExtBuilder::default().add_members(vec![(100, 100)]).build_and_execute(|| { // Given - assert_ok!(Pools::fully_unbond(Origin::signed(100), 100)); + assert_ok!(Pools::fully_unbond(RuntimeOrigin::signed(100), 100)); assert_eq!( BondedPool::::get(1).unwrap(), BondedPool { @@ -3474,7 +3561,7 @@ mod withdraw_unbonded { // Cannot permissionlessly withdraw assert_noop!( - Pools::fully_unbond(Origin::signed(420), 100), + Pools::fully_unbond(RuntimeOrigin::signed(420), 100), Error::::NotKickerOrDestroying ); @@ -3482,7 +3569,7 @@ mod withdraw_unbonded { unsafe_set_state(1, PoolState::Destroying); // Can permissionlesly withdraw a member that is not the depositor - assert_ok!(Pools::withdraw_unbonded(Origin::signed(420), 100, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(420), 100, 0)); assert_eq!(SubPoolsStorage::::get(1).unwrap(), Default::default(),); assert_eq!(Balances::free_balance(100), 100 + 100); @@ -3504,13 +3591,13 @@ mod withdraw_unbonded { #[test] fn partial_withdraw_unbonded_depositor() { ExtBuilder::default().ed(1).build_and_execute(|| { - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); unsafe_set_state(1, PoolState::Destroying); // given - assert_ok!(Pools::unbond(Origin::signed(10), 10, 6)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 6)); CurrentEra::set(1); - assert_ok!(Pools::unbond(Origin::signed(10), 10, 1)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 1)); assert_eq!( PoolMembers::::get(10).unwrap().unbonding_eras, member_unbonding_eras!(3 => 6, 4 => 1) @@ -3541,13 +3628,13 @@ mod withdraw_unbonded { // when CurrentEra::set(2); assert_noop!( - Pools::withdraw_unbonded(Origin::signed(10), 10, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0), Error::::CannotWithdrawAny ); // when CurrentEra::set(3); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); // then assert_eq!( @@ -3570,7 +3657,7 @@ mod withdraw_unbonded { // when CurrentEra::set(4); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); // then assert_eq!( @@ -3585,7 +3672,7 @@ mod withdraw_unbonded { // when repeating: assert_noop!( - Pools::withdraw_unbonded(Origin::signed(10), 10, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0), Error::::CannotWithdrawAny ); }); @@ -3595,9 +3682,9 @@ mod withdraw_unbonded { fn partial_withdraw_unbonded_non_depositor() { ExtBuilder::default().add_members(vec![(11, 10)]).build_and_execute(|| { // given - assert_ok!(Pools::unbond(Origin::signed(11), 11, 6)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(11), 11, 6)); CurrentEra::set(1); - assert_ok!(Pools::unbond(Origin::signed(11), 11, 1)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(11), 11, 1)); assert_eq!( PoolMembers::::get(11).unwrap().unbonding_eras, member_unbonding_eras!(3 => 6, 4 => 1) @@ -3628,13 +3715,13 @@ mod withdraw_unbonded { // when CurrentEra::set(2); assert_noop!( - Pools::withdraw_unbonded(Origin::signed(11), 11, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(11), 11, 0), Error::::CannotWithdrawAny ); // when CurrentEra::set(3); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(11), 11, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(11), 11, 0)); // then assert_eq!( @@ -3657,7 +3744,7 @@ mod withdraw_unbonded { // when CurrentEra::set(4); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(11), 11, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(11), 11, 0)); // then assert_eq!( @@ -3672,7 +3759,7 @@ mod withdraw_unbonded { // when repeating: assert_noop!( - Pools::withdraw_unbonded(Origin::signed(11), 11, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(11), 11, 0), Error::::CannotWithdrawAny ); }); @@ -3682,7 +3769,7 @@ mod withdraw_unbonded { fn full_multi_step_withdrawing_non_depositor() { ExtBuilder::default().add_members(vec![(100, 100)]).build_and_execute(|| { // given - assert_ok!(Pools::unbond(Origin::signed(100), 100, 75)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(100), 100, 75)); assert_eq!( PoolMembers::::get(100).unwrap().unbonding_eras, member_unbonding_eras!(3 => 75) @@ -3690,20 +3777,20 @@ mod withdraw_unbonded { // progress one era and unbond the leftover. CurrentEra::set(1); - assert_ok!(Pools::unbond(Origin::signed(100), 100, 25)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(100), 100, 25)); assert_eq!( PoolMembers::::get(100).unwrap().unbonding_eras, member_unbonding_eras!(3 => 75, 4 => 25) ); assert_noop!( - Pools::withdraw_unbonded(Origin::signed(100), 100, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(100), 100, 0), Error::::CannotWithdrawAny ); // now the 75 should be free. CurrentEra::set(3); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(100), 100, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(100), 100, 0)); assert_eq!( pool_events_since_last_call(), vec![ @@ -3722,7 +3809,7 @@ mod withdraw_unbonded { // the 25 should be free now, and the member removed. CurrentEra::set(4); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(100), 100, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(100), 100, 0)); assert_eq!( pool_events_since_last_call(), vec![ @@ -3733,19 +3820,183 @@ mod withdraw_unbonded { }) } + #[test] + fn out_of_sync_unbonding_chunks() { + // the unbonding_eras in pool member are always fixed to the era at which they are unlocked, + // but the actual unbonding pools get pruned and might get combined in the no_era pool. + // Pools are only merged when one unbonds, so we unbond a little bit on every era to + // simulate this. + ExtBuilder::default() + .add_members(vec![(20, 100), (30, 100)]) + .build_and_execute(|| { + System::reset_events(); + + // when + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(30), 30, 5)); + + // then member-local unbonding is pretty much in sync with the global pools. + assert_eq!( + PoolMembers::::get(20).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 5) + ); + assert_eq!( + PoolMembers::::get(30).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 5) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 3 => UnbondPool { points: 10, balance: 10 } + } + } + ); + assert_eq!( + pool_events_since_last_call(), + vec![ + Event::Unbonded { member: 20, pool_id: 1, points: 5, balance: 5, era: 3 }, + Event::Unbonded { member: 30, pool_id: 1, points: 5, balance: 5, era: 3 }, + ] + ); + + // when + CurrentEra::set(1); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); + + // then still member-local unbonding is pretty much in sync with the global pools. + assert_eq!( + PoolMembers::::get(20).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 5, 4 => 5) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 3 => UnbondPool { points: 10, balance: 10 }, + 4 => UnbondPool { points: 5, balance: 5 } + } + } + ); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Unbonded { member: 20, pool_id: 1, points: 5, balance: 5, era: 4 }] + ); + + // when + CurrentEra::set(2); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); + + // then still member-local unbonding is pretty much in sync with the global pools. + assert_eq!( + PoolMembers::::get(20).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 5, 4 => 5, 5 => 5) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 3 => UnbondPool { points: 10, balance: 10 }, + 4 => UnbondPool { points: 5, balance: 5 }, + 5 => UnbondPool { points: 5, balance: 5 } + } + } + ); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Unbonded { member: 20, pool_id: 1, points: 5, balance: 5, era: 5 }] + ); + + // when + CurrentEra::set(5); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 5)); + + // then + assert_eq!( + PoolMembers::::get(20).unwrap().unbonding_eras, + member_unbonding_eras!(3 => 5, 4 => 5, 5 => 5, 8 => 5) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + // era 3 is merged into no_era. + no_era: UnbondPool { points: 10, balance: 10 }, + with_era: unbonding_pools_with_era! { + 4 => UnbondPool { points: 5, balance: 5 }, + 5 => UnbondPool { points: 5, balance: 5 }, + 8 => UnbondPool { points: 5, balance: 5 } + } + } + ); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Unbonded { member: 20, pool_id: 1, points: 5, balance: 5, era: 8 }] + ); + + // now we start withdrawing unlocked bonds. + + // when + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); + // then + assert_eq!( + PoolMembers::::get(20).unwrap().unbonding_eras, + member_unbonding_eras!(8 => 5) + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + // era 3 is merged into no_era. + no_era: UnbondPool { points: 5, balance: 5 }, + with_era: unbonding_pools_with_era! { + 8 => UnbondPool { points: 5, balance: 5 } + } + } + ); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Withdrawn { member: 20, pool_id: 1, points: 15, balance: 15 }] + ); + + // when + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(30), 30, 0)); + // then + assert_eq!( + PoolMembers::::get(30).unwrap().unbonding_eras, + member_unbonding_eras!() + ); + assert_eq!( + SubPoolsStorage::::get(1).unwrap(), + SubPools { + // era 3 is merged into no_era. + no_era: Default::default(), + with_era: unbonding_pools_with_era! { + 8 => UnbondPool { points: 5, balance: 5 } + } + } + ); + assert_eq!( + pool_events_since_last_call(), + vec![Event::Withdrawn { member: 30, pool_id: 1, points: 5, balance: 5 }] + ); + }) + } + #[test] fn full_multi_step_withdrawing_depositor() { ExtBuilder::default().ed(1).build_and_execute(|| { // depositor now has 20, they can unbond to 10. assert_eq!(Pools::depositor_min_bond(), 10); - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); // now they can. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 7)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 7)); // progress one era and unbond the leftover. CurrentEra::set(1); - assert_ok!(Pools::unbond(Origin::signed(10), 10, 3)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 3)); assert_eq!( PoolMembers::::get(10).unwrap().unbonding_eras, @@ -3754,27 +4005,27 @@ mod withdraw_unbonded { // they can't unbond to a value below 10 other than 0.. assert_noop!( - Pools::unbond(Origin::signed(10), 10, 5), + Pools::unbond(RuntimeOrigin::signed(10), 10, 5), Error::::MinimumBondNotMet ); // but not even full, because they pool is not yet destroying. assert_noop!( - Pools::unbond(Origin::signed(10), 10, 10), + Pools::unbond(RuntimeOrigin::signed(10), 10, 10), Error::::MinimumBondNotMet ); // but now they can. unsafe_set_state(1, PoolState::Destroying); assert_noop!( - Pools::unbond(Origin::signed(10), 10, 5), + Pools::unbond(RuntimeOrigin::signed(10), 10, 5), Error::::MinimumBondNotMet ); - assert_ok!(Pools::unbond(Origin::signed(10), 10, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10)); // now the 7 should be free. CurrentEra::set(3); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); assert_eq!( pool_events_since_last_call(), @@ -3795,7 +4046,7 @@ mod withdraw_unbonded { // the 13 should be free now, and the member removed. CurrentEra::set(4); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); assert_eq!( pool_events_since_last_call(), @@ -3827,7 +4078,7 @@ mod create { Balances::make_free_balance_be(&11, StakingMock::minimum_bond() + ed); assert_ok!(Pools::create( - Origin::signed(11), + RuntimeOrigin::signed(11), StakingMock::minimum_bond(), 123, 456, @@ -3885,7 +4136,7 @@ mod create { fn create_errors_correctly() { ExtBuilder::default().with_check(0).build_and_execute(|| { assert_noop!( - Pools::create(Origin::signed(10), 420, 123, 456, 789), + Pools::create(RuntimeOrigin::signed(10), 420, 123, 456, 789), Error::::AccountBelongsToOtherPool ); @@ -3895,7 +4146,7 @@ mod create { // Then assert_noop!( - Pools::create(Origin::signed(11), 9, 123, 456, 789), + Pools::create(RuntimeOrigin::signed(11), 9, 123, 456, 789), Error::::MinimumBondNotMet ); @@ -3904,7 +4155,7 @@ mod create { // Then assert_noop!( - Pools::create(Origin::signed(11), 19, 123, 456, 789), + Pools::create(RuntimeOrigin::signed(11), 19, 123, 456, 789), Error::::MinimumBondNotMet ); @@ -3924,7 +4175,7 @@ mod create { // Then assert_noop!( - Pools::create(Origin::signed(11), 20, 123, 456, 789), + Pools::create(RuntimeOrigin::signed(11), 20, 123, 456, 789), Error::::MaxPools ); @@ -3935,13 +4186,16 @@ mod create { Balances::make_free_balance_be(&11, 5 + 20); // Then - let create = Call::Pools(crate::Call::::create { + let create = RuntimeCall::Pools(crate::Call::::create { amount: 20, root: 11, nominator: 11, state_toggler: 11, }); - assert_noop!(create.dispatch(Origin::signed(11)), Error::::MaxPoolMembers); + assert_noop!( + create.dispatch(RuntimeOrigin::signed(11)), + Error::::MaxPoolMembers + ); }); } } @@ -3954,27 +4208,27 @@ mod nominate { ExtBuilder::default().build_and_execute(|| { // Depositor can't nominate assert_noop!( - Pools::nominate(Origin::signed(10), 1, vec![21]), + Pools::nominate(RuntimeOrigin::signed(10), 1, vec![21]), Error::::NotNominator ); // State toggler can't nominate assert_noop!( - Pools::nominate(Origin::signed(902), 1, vec![21]), + Pools::nominate(RuntimeOrigin::signed(902), 1, vec![21]), Error::::NotNominator ); // Root can nominate - assert_ok!(Pools::nominate(Origin::signed(900), 1, vec![21])); + assert_ok!(Pools::nominate(RuntimeOrigin::signed(900), 1, vec![21])); assert_eq!(Nominations::get().unwrap(), vec![21]); // Nominator can nominate - assert_ok!(Pools::nominate(Origin::signed(901), 1, vec![31])); + assert_ok!(Pools::nominate(RuntimeOrigin::signed(901), 1, vec![31])); assert_eq!(Nominations::get().unwrap(), vec![31]); // Can't nominate for a pool that doesn't exist assert_noop!( - Pools::nominate(Origin::signed(902), 123, vec![21]), + Pools::nominate(RuntimeOrigin::signed(902), 123, vec![21]), Error::::PoolNotFound ); }); @@ -3992,16 +4246,16 @@ mod set_state { // Only the root and state toggler can change the state when the pool is ok to be open. assert_noop!( - Pools::set_state(Origin::signed(10), 1, PoolState::Blocked), + Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Blocked), Error::::CanNotChangeState ); assert_noop!( - Pools::set_state(Origin::signed(901), 1, PoolState::Blocked), + Pools::set_state(RuntimeOrigin::signed(901), 1, PoolState::Blocked), Error::::CanNotChangeState ); // Root can change state - assert_ok!(Pools::set_state(Origin::signed(900), 1, PoolState::Blocked)); + assert_ok!(Pools::set_state(RuntimeOrigin::signed(900), 1, PoolState::Blocked)); assert_eq!( pool_events_since_last_call(), @@ -4015,16 +4269,16 @@ mod set_state { assert_eq!(BondedPool::::get(1).unwrap().state, PoolState::Blocked); // State toggler can change state - assert_ok!(Pools::set_state(Origin::signed(902), 1, PoolState::Destroying)); + assert_ok!(Pools::set_state(RuntimeOrigin::signed(902), 1, PoolState::Destroying)); assert_eq!(BondedPool::::get(1).unwrap().state, PoolState::Destroying); // If the pool is destroying, then no one can set state assert_noop!( - Pools::set_state(Origin::signed(900), 1, PoolState::Blocked), + Pools::set_state(RuntimeOrigin::signed(900), 1, PoolState::Blocked), Error::::CanNotChangeState ); assert_noop!( - Pools::set_state(Origin::signed(902), 1, PoolState::Blocked), + Pools::set_state(RuntimeOrigin::signed(902), 1, PoolState::Blocked), Error::::CanNotChangeState ); @@ -4036,7 +4290,7 @@ mod set_state { bonded_pool.points = 100; bonded_pool.put(); // When - assert_ok!(Pools::set_state(Origin::signed(11), 1, PoolState::Destroying)); + assert_ok!(Pools::set_state(RuntimeOrigin::signed(11), 1, PoolState::Destroying)); // Then assert_eq!(BondedPool::::get(1).unwrap().state, PoolState::Destroying); @@ -4044,7 +4298,7 @@ mod set_state { Balances::make_free_balance_be(&default_bonded_account(), Balance::max_value() / 10); unsafe_set_state(1, PoolState::Open); // When - assert_ok!(Pools::set_state(Origin::signed(11), 1, PoolState::Destroying)); + assert_ok!(Pools::set_state(RuntimeOrigin::signed(11), 1, PoolState::Destroying)); // Then assert_eq!(BondedPool::::get(1).unwrap().state, PoolState::Destroying); @@ -4052,7 +4306,7 @@ mod set_state { // isn't destroying unsafe_set_state(1, PoolState::Open); assert_noop!( - Pools::set_state(Origin::signed(11), 1, PoolState::Blocked), + Pools::set_state(RuntimeOrigin::signed(11), 1, PoolState::Blocked), Error::::CanNotChangeState ); @@ -4075,28 +4329,28 @@ mod set_metadata { fn set_metadata_works() { ExtBuilder::default().build_and_execute(|| { // Root can set metadata - assert_ok!(Pools::set_metadata(Origin::signed(900), 1, vec![1, 1])); + assert_ok!(Pools::set_metadata(RuntimeOrigin::signed(900), 1, vec![1, 1])); assert_eq!(Metadata::::get(1), vec![1, 1]); // State toggler can set metadata - assert_ok!(Pools::set_metadata(Origin::signed(902), 1, vec![2, 2])); + assert_ok!(Pools::set_metadata(RuntimeOrigin::signed(902), 1, vec![2, 2])); assert_eq!(Metadata::::get(1), vec![2, 2]); // Depositor can't set metadata assert_noop!( - Pools::set_metadata(Origin::signed(10), 1, vec![3, 3]), + Pools::set_metadata(RuntimeOrigin::signed(10), 1, vec![3, 3]), Error::::DoesNotHavePermission ); // Nominator can't set metadata assert_noop!( - Pools::set_metadata(Origin::signed(901), 1, vec![3, 3]), + Pools::set_metadata(RuntimeOrigin::signed(901), 1, vec![3, 3]), Error::::DoesNotHavePermission ); // Metadata cannot be longer than `MaxMetadataLen` assert_noop!( - Pools::set_metadata(Origin::signed(900), 1, vec![1, 1, 1]), + Pools::set_metadata(RuntimeOrigin::signed(900), 1, vec![1, 1, 1]), Error::::MetadataExceedsMaxLen ); }); @@ -4111,7 +4365,7 @@ mod set_configs { ExtBuilder::default().build_and_execute(|| { // Setting works assert_ok!(Pools::set_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Set(1 as Balance), ConfigOp::Set(2 as Balance), ConfigOp::Set(3u32), @@ -4126,7 +4380,7 @@ mod set_configs { // Noop does nothing assert_storage_noop!(assert_ok!(Pools::set_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Noop, @@ -4136,7 +4390,7 @@ mod set_configs { // Removing works assert_ok!(Pools::set_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Remove, ConfigOp::Remove, ConfigOp::Remove, @@ -4168,7 +4422,7 @@ mod bond_extra { assert_eq!(Balances::free_balance(10), 100); // when - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(10))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(10))); // then assert_eq!(Balances::free_balance(10), 90); @@ -4185,7 +4439,7 @@ mod bond_extra { ); // when - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::FreeBalance(20))); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::FreeBalance(20))); // then assert_eq!(Balances::free_balance(10), 70); @@ -4214,7 +4468,7 @@ mod bond_extra { assert_eq!(Balances::free_balance(10), 35); // when - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::Rewards)); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::Rewards)); // then assert_eq!(Balances::free_balance(10), 35); @@ -4257,7 +4511,7 @@ mod bond_extra { assert_eq!(Balances::free_balance(20), 20); // when - assert_ok!(Pools::bond_extra(Origin::signed(10), BondExtra::Rewards)); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(10), BondExtra::Rewards)); // then assert_eq!(Balances::free_balance(10), 35); @@ -4266,7 +4520,7 @@ mod bond_extra { assert_eq!(BondedPools::::get(1).unwrap().points, 30 + 1); // when - assert_ok!(Pools::bond_extra(Origin::signed(20), BondExtra::Rewards)); + assert_ok!(Pools::bond_extra(RuntimeOrigin::signed(20), BondExtra::Rewards)); // then assert_eq!(Balances::free_balance(20), 20); @@ -4310,7 +4564,7 @@ mod update_roles { // non-existent pools assert_noop!( Pools::update_roles( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, ConfigOp::Set(5), ConfigOp::Set(6), @@ -4322,7 +4576,7 @@ mod update_roles { // depositor cannot change roles. assert_noop!( Pools::update_roles( - Origin::signed(1), + RuntimeOrigin::signed(1), 1, ConfigOp::Set(5), ConfigOp::Set(6), @@ -4334,7 +4588,7 @@ mod update_roles { // nominator cannot change roles. assert_noop!( Pools::update_roles( - Origin::signed(901), + RuntimeOrigin::signed(901), 1, ConfigOp::Set(5), ConfigOp::Set(6), @@ -4345,7 +4599,7 @@ mod update_roles { // state-toggler assert_noop!( Pools::update_roles( - Origin::signed(902), + RuntimeOrigin::signed(902), 1, ConfigOp::Set(5), ConfigOp::Set(6), @@ -4356,7 +4610,7 @@ mod update_roles { // but root can assert_ok!(Pools::update_roles( - Origin::signed(900), + RuntimeOrigin::signed(900), 1, ConfigOp::Set(5), ConfigOp::Set(6), @@ -4387,7 +4641,7 @@ mod update_roles { // also root origin can assert_ok!(Pools::update_roles( - Origin::root(), + RuntimeOrigin::root(), 1, ConfigOp::Set(1), ConfigOp::Set(2), @@ -4414,7 +4668,7 @@ mod update_roles { // Noop works assert_ok!(Pools::update_roles( - Origin::root(), + RuntimeOrigin::root(), 1, ConfigOp::Set(11), ConfigOp::Noop, @@ -4442,7 +4696,7 @@ mod update_roles { // Remove works assert_ok!(Pools::update_roles( - Origin::root(), + RuntimeOrigin::root(), 1, ConfigOp::Set(69), ConfigOp::Remove, @@ -4518,7 +4772,7 @@ mod reward_counter_precision { // tad bit less. cannot be paid out. assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += expected_smallest_reward - 1)); - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_eq!(pool_events_since_last_call(), vec![]); // revert it. @@ -4528,7 +4782,7 @@ mod reward_counter_precision { // tad bit more. can be claimed. assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += expected_smallest_reward + 1)); - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_eq!( pool_events_since_last_call(), vec![Event::PaidOut { member: 10, pool_id: 1, payout: 1173 }] @@ -4564,7 +4818,7 @@ mod reward_counter_precision { // some whale now joins with the other half ot the total issuance. This will bloat all // the calculation regarding current reward counter. Balances::make_free_balance_be(&20, pool_bond * 2); - assert_ok!(Pools::join(Origin::signed(20), pool_bond, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), pool_bond, 1)); assert_eq!( pool_events_since_last_call(), @@ -4576,8 +4830,8 @@ mod reward_counter_precision { }] ); - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), @@ -4586,12 +4840,12 @@ mod reward_counter_precision { // now let a small member join with 10 DOTs. Balances::make_free_balance_be(&30, 20 * DOT); - assert_ok!(Pools::join(Origin::signed(30), 10 * DOT, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(30), 10 * DOT, 1)); // and give a reasonably small reward to the pool. assert_ok!(Balances::mutate_account(&default_reward_account(), |a| a.free += DOT)); - assert_ok!(Pools::claim_payout(Origin::signed(30))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(30))); assert_eq!( pool_events_since_last_call(), vec![ @@ -4629,7 +4883,10 @@ mod reward_counter_precision { // set to zero. In other tests that we want to assert a scenario won't fail, we should // also set the reward counters to some large value. Balances::make_free_balance_be(&20, pool_bond * 2); - assert_err!(Pools::join(Origin::signed(20), pool_bond, 1), Error::::OverflowRisk); + assert_err!( + Pools::join(RuntimeOrigin::signed(20), pool_bond, 1), + Error::::OverflowRisk + ); }) } @@ -4655,7 +4912,7 @@ mod reward_counter_precision { // and have a tiny fish join the pool as well.. Balances::make_free_balance_be(&20, 20 * DOT); - assert_ok!(Pools::join(Origin::signed(20), 10 * DOT, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10 * DOT, 1)); // earn some small rewards assert_ok!( @@ -4664,7 +4921,7 @@ mod reward_counter_precision { // no point in claiming for 20 (nonetheless, it should be harmless) assert!(pending_rewards(20).unwrap().is_zero()); - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_eq!( pool_events_since_last_call(), vec![ @@ -4684,7 +4941,7 @@ mod reward_counter_precision { Balances::mutate_account(&default_reward_account(), |a| a.free += DOT / 1000) ); assert!(pending_rewards(20).unwrap().is_zero()); - assert_ok!(Pools::claim_payout(Origin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); assert_eq!( pool_events_since_last_call(), vec![Event::PaidOut { member: 10, pool_id: 1, payout: 10000000 }] @@ -4695,8 +4952,8 @@ mod reward_counter_precision { Balances::mutate_account(&default_reward_account(), |a| a.free += DOT / 1000) ); assert_eq!(pending_rewards(20).unwrap(), 1); - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), vec![ @@ -4729,7 +4986,7 @@ mod reward_counter_precision { // and have a tiny fish join the pool as well.. Balances::make_free_balance_be(&20, 20 * DOT); - assert_ok!(Pools::join(Origin::signed(20), 10 * DOT, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10 * DOT, 1)); // earn some small rewards assert_ok!( @@ -4739,8 +4996,8 @@ mod reward_counter_precision { // if 20 claims now, their reward counter should stay the same, so that they have a // chance of claiming this if they let it accumulate. Also see // `if_small_member_waits_long_enough_they_will_earn_rewards` - assert_ok!(Pools::claim_payout(Origin::signed(10))); - assert_ok!(Pools::claim_payout(Origin::signed(20))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(10))); + assert_ok!(Pools::claim_payout(RuntimeOrigin::signed(20))); assert_eq!( pool_events_since_last_call(), vec![ @@ -4768,3 +5025,328 @@ mod reward_counter_precision { }); } } + +// NOTE: run this with debug_assertions, but in release mode. +#[cfg(feature = "fuzz-test")] +mod fuzz_test { + use super::*; + use crate::pallet::{Call as PoolsCall, Event as PoolsEvents}; + use frame_support::traits::UnfilteredDispatchable; + use rand::{seq::SliceRandom, thread_rng, Rng}; + use sp_runtime::{assert_eq_error_rate, Perquintill}; + + const ERA: BlockNumber = 1000; + const MAX_ED_MULTIPLE: Balance = 10_000; + const MIN_ED_MULTIPLE: Balance = 10; + + // not quite elegant, just to make it available in random_signed_origin. + const REWARD_AGENT_ACCOUNT: AccountId = 42; + + /// Grab random accounts, either known ones, or new ones. + fn random_signed_origin(rng: &mut R) -> (RuntimeOrigin, AccountId) { + let count = PoolMembers::::count(); + if rng.gen::() && count > 0 { + // take an existing account. + let skip = rng.gen_range(0..count as usize); + + // this is tricky: the account might be our reward agent, which we never want to be + // randomly chosen here. Try another one, or, if it is only our agent, return a random + // one nonetheless. + let candidate = PoolMembers::::iter_keys().skip(skip).take(1).next().unwrap(); + let acc = + if candidate == REWARD_AGENT_ACCOUNT { rng.gen::() } else { candidate }; + + (RuntimeOrigin::signed(acc), acc) + } else { + // create a new account + let acc = rng.gen::(); + (RuntimeOrigin::signed(acc), acc) + } + } + + fn random_ed_multiple(rng: &mut R) -> Balance { + let multiple = rng.gen_range(MIN_ED_MULTIPLE..MAX_ED_MULTIPLE); + ExistentialDeposit::get() * multiple + } + + fn fund_account(rng: &mut R, account: &AccountId) { + let target_amount = random_ed_multiple(rng); + if let Some(top_up) = target_amount.checked_sub(Balances::free_balance(account)) { + let _ = Balances::deposit_creating(account, top_up); + } + assert!(Balances::free_balance(account) >= target_amount); + } + + fn random_existing_pool(mut rng: &mut R) -> Option { + BondedPools::::iter_keys().collect::>().choose(&mut rng).map(|x| *x) + } + + fn random_call(mut rng: &mut R) -> (crate::pallet::Call, RuntimeOrigin) { + let op = rng.gen::(); + let mut op_count = + as frame_support::dispatch::GetCallName>::get_call_names() + .len(); + // Exclude set_state, set_metadata, set_configs, update_roles and chill. + op_count -= 5; + + match op % op_count { + 0 => { + // join + let pool_id = random_existing_pool(&mut rng).unwrap_or_default(); + let (origin, who) = random_signed_origin(&mut rng); + fund_account(&mut rng, &who); + let amount = random_ed_multiple(&mut rng); + (PoolsCall::::join { amount, pool_id }, origin) + }, + 1 => { + // bond_extra + let (origin, who) = random_signed_origin(&mut rng); + let extra = if rng.gen::() { + BondExtra::Rewards + } else { + fund_account(&mut rng, &who); + let amount = random_ed_multiple(&mut rng); + BondExtra::FreeBalance(amount) + }; + (PoolsCall::::bond_extra { extra }, origin) + }, + 2 => { + // claim_payout + let (origin, _) = random_signed_origin(&mut rng); + (PoolsCall::::claim_payout {}, origin) + }, + 3 => { + // unbond + let (origin, who) = random_signed_origin(&mut rng); + let amount = random_ed_multiple(&mut rng); + (PoolsCall::::unbond { member_account: who, unbonding_points: amount }, origin) + }, + 4 => { + // pool_withdraw_unbonded + let pool_id = random_existing_pool(&mut rng).unwrap_or_default(); + let (origin, _) = random_signed_origin(&mut rng); + (PoolsCall::::pool_withdraw_unbonded { pool_id, num_slashing_spans: 0 }, origin) + }, + 5 => { + // withdraw_unbonded + let (origin, who) = random_signed_origin(&mut rng); + ( + PoolsCall::::withdraw_unbonded { + member_account: who, + num_slashing_spans: 0, + }, + origin, + ) + }, + 6 => { + // create + let (origin, who) = random_signed_origin(&mut rng); + let amount = random_ed_multiple(&mut rng); + fund_account(&mut rng, &who); + let root = who.clone(); + let state_toggler = who.clone(); + let nominator = who.clone(); + (PoolsCall::::create { amount, root, state_toggler, nominator }, origin) + }, + 7 => { + // nominate + let (origin, _) = random_signed_origin(&mut rng); + let pool_id = random_existing_pool(&mut rng).unwrap_or_default(); + let validators = Default::default(); + (PoolsCall::::nominate { pool_id, validators }, origin) + }, + _ => unreachable!(), + } + } + + #[derive(Default)] + struct RewardAgent { + who: AccountId, + pool_id: Option, + expected_reward: Balance, + } + + // TODO: inject some slashes into the game. + impl RewardAgent { + fn new(who: AccountId) -> Self { + Self { who, ..Default::default() } + } + + fn join(&mut self) { + if self.pool_id.is_some() { + return + } + let pool_id = LastPoolId::::get(); + let amount = 10 * ExistentialDeposit::get(); + let origin = RuntimeOrigin::signed(self.who); + let _ = Balances::deposit_creating(&self.who, 10 * amount); + self.pool_id = Some(pool_id); + log::info!(target: "reward-agent", "🤖 reward agent joining in {} with {}", pool_id, amount); + assert_ok!(PoolsCall::join:: { amount, pool_id }.dispatch_bypass_filter(origin)); + } + + fn claim_payout(&mut self) { + // 10 era later, we claim our payout. We expect our income to be roughly what we + // calculated. + if !PoolMembers::::contains_key(&self.who) { + log!(warn, "reward agent is not in the pool yet, cannot claim"); + return + } + let pre = Balances::free_balance(&42); + let origin = RuntimeOrigin::signed(42); + assert_ok!(PoolsCall::::claim_payout {}.dispatch_bypass_filter(origin)); + let post = Balances::free_balance(&42); + + let income = post - pre; + log::info!( + target: "reward-agent", "🤖 CLAIM: actual: {}, expected: {}", + income, + self.expected_reward, + ); + assert_eq_error_rate!(income, self.expected_reward, 10); + self.expected_reward = 0; + } + } + + #[test] + fn fuzz_test() { + let mut reward_agent = RewardAgent::new(42); + sp_tracing::try_init_simple(); + // NOTE: use this to get predictable (non)randomness: + // use::{rngs::SmallRng, SeedableRng}; + // let mut rng = SmallRng::from_seed([0u8; 32]); + let mut rng = thread_rng(); + let mut ext = sp_io::TestExternalities::new_empty(); + // NOTE: sadly events don't fulfill the requirements of hashmap or btreemap. + let mut events_histogram = Vec::<(PoolsEvents, u32)>::default(); + let mut iteration = 0 as BlockNumber; + let mut ok = 0; + let mut err = 0; + + ext.execute_with(|| { + MaxPoolMembers::::set(Some(10_000)); + MaxPoolMembersPerPool::::set(Some(1000)); + MaxPools::::set(Some(1_000)); + + MinCreateBond::::set(10 * ExistentialDeposit::get()); + MinJoinBond::::set(5 * ExistentialDeposit::get()); + System::set_block_number(1); + }); + + ExistentialDeposit::set(10u128.pow(12u32)); + BondingDuration::set(8); + + loop { + ext.execute_with(|| { + iteration += 1; + let (call, origin) = random_call(&mut rng); + let outcome = call.clone().dispatch_bypass_filter(origin.clone()); + + match outcome { + Ok(_) => ok += 1, + Err(_) => err += 1, + }; + + log!( + debug, + "iteration {}, call {:?}, origin {:?}, outcome: {:?}, so far {} ok {} err", + iteration, + call, + origin, + outcome, + ok, + err, + ); + + // possibly join the reward_agent + if iteration > ERA / 2 && BondedPools::::count() > 0 { + reward_agent.join(); + } + // and possibly roughly every 4 era, trigger payout for the agent. Doing this more + // frequent is also harmless. + if rng.gen_range(0..(4 * ERA)) == 0 { + reward_agent.claim_payout(); + } + + // execute sanity checks at a fixed interval, possibly on every block. + if iteration % + (std::env::var("SANITY_CHECK_INTERVAL") + .ok() + .and_then(|x| x.parse::().ok())) + .unwrap_or(1) == 0 + { + log!(info, "running sanity checks at {}", iteration); + Pools::do_try_state(u8::MAX).unwrap(); + } + + // collect and reset events. + System::events() + .into_iter() + .map(|r| r.event) + .filter_map( + |e| if let mock::Event::Pools(inner) = e { Some(inner) } else { None }, + ) + .for_each(|e| { + if let Some((_, c)) = events_histogram + .iter_mut() + .find(|(x, _)| std::mem::discriminant(x) == std::mem::discriminant(&e)) + { + *c += 1; + } else { + events_histogram.push((e, 1)) + } + }); + System::reset_events(); + + // trigger an era change, and check the status of the reward agent. + if iteration % ERA == 0 { + CurrentEra::mutate(|c| *c += 1); + BondedPools::::iter().for_each(|(id, _)| { + let amount = random_ed_multiple(&mut rng); + let _ = + Balances::deposit_creating(&Pools::create_reward_account(id), amount); + // if we just paid out the reward agent, let's calculate how much we expect + // our reward agent to have earned. + if reward_agent.pool_id.map_or(false, |mid| mid == id) { + let all_points = BondedPool::::get(id).map(|p| p.points).unwrap(); + let member_points = + PoolMembers::::get(reward_agent.who).map(|m| m.points).unwrap(); + let agent_share = Perquintill::from_rational(member_points, all_points); + log::info!( + target: "reward-agent", + "🤖 REWARD = amount = {:?}, ratio: {:?}, share {:?}", + amount, + agent_share, + agent_share * amount, + ); + reward_agent.expected_reward += agent_share * amount; + } + }); + + log!( + info, + "iteration {}, {} pools, {} members, {} ok {} err, events = {:?}", + iteration, + BondedPools::::count(), + PoolMembers::::count(), + ok, + err, + events_histogram + .iter() + .map(|(x, c)| ( + format!("{:?}", x) + .split(" ") + .map(|x| x.to_string()) + .collect::>() + .first() + .cloned() + .unwrap(), + c, + )) + .collect::>(), + ); + } + }); + } + } +} diff --git a/frame/nomination-pools/test-staking/src/lib.rs b/frame/nomination-pools/test-staking/src/lib.rs index 8c6ecae937063..00e0e40ce33b0 100644 --- a/frame/nomination-pools/test-staking/src/lib.rs +++ b/frame/nomination-pools/test-staking/src/lib.rs @@ -35,13 +35,16 @@ fn pool_lifecycle_e2e() { assert_eq!(Staking::current_era(), None); // create the pool, we know this has id 1. - assert_ok!(Pools::create(Origin::signed(10), 50, 10, 10, 10)); + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 50, 10, 10, 10)); assert_eq!(LastPoolId::::get(), 1); // have the pool nominate. - assert_ok!(Pools::nominate(Origin::signed(10), 1, vec![1, 2, 3])); + assert_ok!(Pools::nominate(RuntimeOrigin::signed(10), 1, vec![1, 2, 3])); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 50),]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 50 }] + ); assert_eq!( pool_events_since_last_call(), vec![ @@ -51,12 +54,15 @@ fn pool_lifecycle_e2e() { ); // have two members join - assert_ok!(Pools::join(Origin::signed(20), 10, 1)); - assert_ok!(Pools::join(Origin::signed(21), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 10, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), 10, 1)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Bonded(POOL1_BONDED, 10), StakingEvent::Bonded(POOL1_BONDED, 10),] + vec![ + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 10 }, + ] ); assert_eq!( pool_events_since_last_call(), @@ -67,17 +73,17 @@ fn pool_lifecycle_e2e() { ); // pool goes into destroying - assert_ok!(Pools::set_state(Origin::signed(10), 1, PoolState::Destroying)); + assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); // depositor cannot unbond yet. assert_noop!( - Pools::unbond(Origin::signed(10), 10, 50), + Pools::unbond(RuntimeOrigin::signed(10), 10, 50), PoolsError::::MinimumBondNotMet, ); // now the members want to unbond. - assert_ok!(Pools::unbond(Origin::signed(20), 20, 10)); - assert_ok!(Pools::unbond(Origin::signed(21), 21, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); assert_eq!(PoolMembers::::get(20).unwrap().unbonding_eras.len(), 1); assert_eq!(PoolMembers::::get(20).unwrap().points, 0); @@ -87,8 +93,8 @@ fn pool_lifecycle_e2e() { assert_eq!( staking_events_since_last_call(), vec![ - StakingEvent::Unbonded(POOL1_BONDED, 10), - StakingEvent::Unbonded(POOL1_BONDED, 10), + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, ] ); assert_eq!( @@ -102,14 +108,14 @@ fn pool_lifecycle_e2e() { // depositor cannot still unbond assert_noop!( - Pools::unbond(Origin::signed(10), 10, 50), + Pools::unbond(RuntimeOrigin::signed(10), 10, 50), PoolsError::::MinimumBondNotMet, ); for e in 1..BondingDuration::get() { CurrentEra::::set(Some(e)); assert_noop!( - Pools::withdraw_unbonded(Origin::signed(20), 20, 0), + Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0), PoolsError::::CannotWithdrawAny ); } @@ -119,19 +125,19 @@ fn pool_lifecycle_e2e() { // depositor cannot still unbond assert_noop!( - Pools::unbond(Origin::signed(10), 10, 50), + Pools::unbond(RuntimeOrigin::signed(10), 10, 50), PoolsError::::MinimumBondNotMet, ); // but members can now withdraw. - assert_ok!(Pools::withdraw_unbonded(Origin::signed(20), 20, 0)); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(21), 21, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); assert!(PoolMembers::::get(20).is_none()); assert!(PoolMembers::::get(21).is_none()); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Withdrawn(POOL1_BONDED, 20),] + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 20 },] ); assert_eq!( pool_events_since_last_call(), @@ -146,16 +152,19 @@ fn pool_lifecycle_e2e() { // as soon as all members have left, the depositor can try to unbond, but since the // min-nominator intention is set, they must chill first. assert_noop!( - Pools::unbond(Origin::signed(10), 10, 50), + Pools::unbond(RuntimeOrigin::signed(10), 10, 50), pallet_staking::Error::::InsufficientBond ); - assert_ok!(Pools::chill(Origin::signed(10), 1)); - assert_ok!(Pools::unbond(Origin::signed(10), 10, 50)); + assert_ok!(Pools::chill(RuntimeOrigin::signed(10), 1)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 50)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Chilled(POOL1_BONDED), StakingEvent::Unbonded(POOL1_BONDED, 50),] + vec![ + StakingEvent::Chilled { stash: POOL1_BONDED }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 50 }, + ] ); assert_eq!( pool_events_since_last_call(), @@ -164,12 +173,12 @@ fn pool_lifecycle_e2e() { // waiting another bonding duration: CurrentEra::::set(Some(BondingDuration::get() * 2)); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 1)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 1)); // pools is fully destroyed now. assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Withdrawn(POOL1_BONDED, 50),] + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 50 },] ); assert_eq!( pool_events_since_last_call(), @@ -190,10 +199,13 @@ fn pool_slash_e2e() { assert_eq!(Staking::current_era(), None); // create the pool, we know this has id 1. - assert_ok!(Pools::create(Origin::signed(10), 40, 10, 10, 10)); + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); assert_eq!(LastPoolId::::get(), 1); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 40)]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] + ); assert_eq!( pool_events_since_last_call(), vec![ @@ -205,12 +217,15 @@ fn pool_slash_e2e() { assert_eq!(Payee::::get(POOL1_BONDED), RewardDestination::Account(POOL1_REWARD)); // have two members join - assert_ok!(Pools::join(Origin::signed(20), 20, 1)); - assert_ok!(Pools::join(Origin::signed(21), 20, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), 20, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), 20, 1)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Bonded(POOL1_BONDED, 20), StakingEvent::Bonded(POOL1_BONDED, 20)] + vec![ + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: 20 } + ] ); assert_eq!( pool_events_since_last_call(), @@ -224,14 +239,14 @@ fn pool_slash_e2e() { CurrentEra::::set(Some(1)); // 20 / 80 of the total funds are unlocked, and safe from any further slash. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 10)); - assert_ok!(Pools::unbond(Origin::signed(20), 20, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); assert_eq!( staking_events_since_last_call(), vec![ - StakingEvent::Unbonded(POOL1_BONDED, 10), - StakingEvent::Unbonded(POOL1_BONDED, 10) + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 } ] ); assert_eq!( @@ -246,16 +261,16 @@ fn pool_slash_e2e() { // note: depositor cannot fully unbond at this point. // these funds will still get slashed. - assert_ok!(Pools::unbond(Origin::signed(10), 10, 10)); - assert_ok!(Pools::unbond(Origin::signed(20), 20, 10)); - assert_ok!(Pools::unbond(Origin::signed(21), 21, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); assert_eq!( staking_events_since_last_call(), vec![ - StakingEvent::Unbonded(POOL1_BONDED, 10), - StakingEvent::Unbonded(POOL1_BONDED, 10), - StakingEvent::Unbonded(POOL1_BONDED, 10), + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, + StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }, ] ); @@ -278,7 +293,10 @@ fn pool_slash_e2e() { 2, // slash era 2, affects chunks at era 5 onwards. ); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Slashed(POOL1_BONDED, 30)]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }] + ); assert_eq!( pool_events_since_last_call(), vec![ @@ -290,7 +308,7 @@ fn pool_slash_e2e() { ); CurrentEra::::set(Some(3)); - assert_ok!(Pools::unbond(Origin::signed(21), 21, 10)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, 10)); assert_eq!( PoolMembers::::get(21).unwrap(), @@ -302,7 +320,10 @@ fn pool_slash_e2e() { unbonding_eras: bounded_btree_map!(5 => 10, 6 => 5) } ); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Unbonded(POOL1_BONDED, 5)]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 5 }] + ); assert_eq!( pool_events_since_last_call(), vec![PoolsEvent::Unbonded { member: 21, pool_id: 1, balance: 5, points: 5, era: 6 }] @@ -310,8 +331,8 @@ fn pool_slash_e2e() { // now we start withdrawing. we do it all at once, at era 6 where 20 and 21 are fully free. CurrentEra::::set(Some(6)); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(20), 20, 0)); - assert_ok!(Pools::withdraw_unbonded(Origin::signed(21), 21, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(20), 20, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(21), 21, 0)); assert_eq!( pool_events_since_last_call(), @@ -327,16 +348,16 @@ fn pool_slash_e2e() { assert_eq!( staking_events_since_last_call(), // a 10 (un-slashed) + 10/2 (slashed) balance from 10 has also been unlocked - vec![StakingEvent::Withdrawn(POOL1_BONDED, 15 + 10 + 15)] + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 15 + 10 + 15 }] ); // now, finally, we can unbond the depositor further than their current limit. - assert_ok!(Pools::set_state(Origin::signed(10), 1, PoolState::Destroying)); - assert_ok!(Pools::unbond(Origin::signed(10), 10, 20)); + assert_ok!(Pools::set_state(RuntimeOrigin::signed(10), 1, PoolState::Destroying)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(10), 10, 20)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Unbonded(POOL1_BONDED, 10)] + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: 10 }] ); assert_eq!( pool_events_since_last_call(), @@ -357,11 +378,11 @@ fn pool_slash_e2e() { } ); // withdraw the depositor, they should lose 12 balance in total due to slash. - assert_ok!(Pools::withdraw_unbonded(Origin::signed(10), 10, 0)); + assert_ok!(Pools::withdraw_unbonded(RuntimeOrigin::signed(10), 10, 0)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Withdrawn(POOL1_BONDED, 10)] + vec![StakingEvent::Withdrawn { stash: POOL1_BONDED, amount: 10 }] ); assert_eq!( pool_events_since_last_call(), @@ -385,10 +406,13 @@ fn pool_slash_proportional() { assert_eq!(Staking::current_era(), None); // create the pool, we know this has id 1. - assert_ok!(Pools::create(Origin::signed(10), 40, 10, 10, 10)); + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); assert_eq!(LastPoolId::::get(), 1); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 40)]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] + ); assert_eq!( pool_events_since_last_call(), vec![ @@ -399,16 +423,16 @@ fn pool_slash_proportional() { // have two members join let bond = 20; - assert_ok!(Pools::join(Origin::signed(20), bond, 1)); - assert_ok!(Pools::join(Origin::signed(21), bond, 1)); - assert_ok!(Pools::join(Origin::signed(22), bond, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(21), bond, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(22), bond, 1)); assert_eq!( staking_events_since_last_call(), vec![ - StakingEvent::Bonded(POOL1_BONDED, bond), - StakingEvent::Bonded(POOL1_BONDED, bond), - StakingEvent::Bonded(POOL1_BONDED, bond), + StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, + StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }, ] ); assert_eq!( @@ -424,11 +448,11 @@ fn pool_slash_proportional() { CurrentEra::::set(Some(99)); // and unbond - assert_ok!(Pools::unbond(Origin::signed(20), 20, bond)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Unbonded(POOL1_BONDED, bond),] + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] ); assert_eq!( pool_events_since_last_call(), @@ -442,10 +466,10 @@ fn pool_slash_proportional() { ); CurrentEra::::set(Some(100)); - assert_ok!(Pools::unbond(Origin::signed(21), 21, bond)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(21), 21, bond)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Unbonded(POOL1_BONDED, bond),] + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] ); assert_eq!( pool_events_since_last_call(), @@ -459,10 +483,10 @@ fn pool_slash_proportional() { ); CurrentEra::::set(Some(101)); - assert_ok!(Pools::unbond(Origin::signed(22), 22, bond)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(22), 22, bond)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Unbonded(POOL1_BONDED, bond),] + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond },] ); assert_eq!( pool_events_since_last_call(), @@ -486,7 +510,10 @@ fn pool_slash_proportional() { 100, ); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Slashed(POOL1_BONDED, 50)]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }] + ); assert_eq!( pool_events_since_last_call(), vec![ @@ -516,8 +543,11 @@ fn pool_slash_non_proportional_only_bonded_pool() { assert_eq!(Staking::current_era(), None); // create the pool, we know this has id 1. - assert_ok!(Pools::create(Origin::signed(10), 40, 10, 10, 10)); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 40)]); + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] + ); assert_eq!( pool_events_since_last_call(), vec![ @@ -528,10 +558,10 @@ fn pool_slash_non_proportional_only_bonded_pool() { // have two members join let bond = 20; - assert_ok!(Pools::join(Origin::signed(20), bond, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Bonded(POOL1_BONDED, bond)] + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }] ); assert_eq!( pool_events_since_last_call(), @@ -540,10 +570,10 @@ fn pool_slash_non_proportional_only_bonded_pool() { // progress and unbond. CurrentEra::::set(Some(99)); - assert_ok!(Pools::unbond(Origin::signed(20), 20, bond)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Unbonded(POOL1_BONDED, bond)] + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }] ); assert_eq!( pool_events_since_last_call(), @@ -567,7 +597,10 @@ fn pool_slash_non_proportional_only_bonded_pool() { 100, ); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Slashed(POOL1_BONDED, 30)]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 30 }] + ); assert_eq!( pool_events_since_last_call(), vec![PoolsEvent::PoolSlashed { pool_id: 1, balance: 10 }] @@ -589,8 +622,11 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { assert_eq!(Staking::current_era(), None); // create the pool, we know this has id 1. - assert_ok!(Pools::create(Origin::signed(10), 40, 10, 10, 10)); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Bonded(POOL1_BONDED, 40)]); + assert_ok!(Pools::create(RuntimeOrigin::signed(10), 40, 10, 10, 10)); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: 40 }] + ); assert_eq!( pool_events_since_last_call(), vec![ @@ -601,10 +637,10 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { // have two members join let bond = 20; - assert_ok!(Pools::join(Origin::signed(20), bond, 1)); + assert_ok!(Pools::join(RuntimeOrigin::signed(20), bond, 1)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Bonded(POOL1_BONDED, bond)] + vec![StakingEvent::Bonded { stash: POOL1_BONDED, amount: bond }] ); assert_eq!( pool_events_since_last_call(), @@ -613,10 +649,10 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { // progress and unbond. CurrentEra::::set(Some(99)); - assert_ok!(Pools::unbond(Origin::signed(20), 20, bond)); + assert_ok!(Pools::unbond(RuntimeOrigin::signed(20), 20, bond)); assert_eq!( staking_events_since_last_call(), - vec![StakingEvent::Unbonded(POOL1_BONDED, bond)] + vec![StakingEvent::Unbonded { stash: POOL1_BONDED, amount: bond }] ); assert_eq!( pool_events_since_last_call(), @@ -640,7 +676,10 @@ fn pool_slash_non_proportional_bonded_pool_and_chunks() { 100, ); - assert_eq!(staking_events_since_last_call(), vec![StakingEvent::Slashed(POOL1_BONDED, 50)]); + assert_eq!( + staking_events_since_last_call(), + vec![StakingEvent::Slashed { staker: POOL1_BONDED, amount: 50 }] + ); assert_eq!( pool_events_since_last_call(), vec![ diff --git a/frame/nomination-pools/test-staking/src/mock.rs b/frame/nomination-pools/test-staking/src/mock.rs index 055ba7b4b3c06..8c04e40d71df4 100644 --- a/frame/nomination-pools/test-staking/src/mock.rs +++ b/frame/nomination-pools/test-staking/src/mock.rs @@ -43,16 +43,16 @@ impl frame_system::Config for Runtime { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = AccountIndex; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_core::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type Version = (); type PalletInfo = PalletInfo; @@ -81,7 +81,7 @@ impl pallet_balances::Config for Runtime { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; @@ -111,7 +111,7 @@ impl pallet_staking::Config for Runtime { type UnixTime = pallet_timestamp::Pallet; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type RewardRemainder = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Slash = (); type Reward = (); type SessionsPerEra = (); @@ -126,8 +126,10 @@ impl pallet_staking::Config for Runtime { type ElectionProvider = frame_election_provider_support::NoElection<(AccountId, BlockNumber, Staking)>; type GenesisElectionProvider = Self::ElectionProvider; - type VoterList = pallet_bags_list::Pallet; + type VoterList = VoterList; + type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = ConstU32<84>; type OnStakerSlash = Pools; type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); @@ -137,8 +139,9 @@ parameter_types! { pub static BagThresholds: &'static [VoteWeight] = &[10, 20, 30, 40, 50, 60, 1_000, 2_000, 10_000]; } -impl pallet_bags_list::Config for Runtime { - type Event = Event; +type VoterBagsListInstance = pallet_bags_list::Instance1; +impl pallet_bags_list::Config for Runtime { + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type BagThresholds = BagThresholds; type ScoreProvider = Staking; @@ -165,7 +168,7 @@ parameter_types! { } impl pallet_nomination_pools::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type Currency = Balances; type CurrencyBalance = Balance; @@ -193,7 +196,7 @@ frame_support::construct_runtime!( Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, - BagsList: pallet_bags_list::{Pallet, Call, Storage, Event}, + VoterList: pallet_bags_list::::{Pallet, Call, Storage, Event}, Pools: pallet_nomination_pools::{Pallet, Call, Storage, Event}, } ); @@ -225,7 +228,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { // set some limit for nominations. assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), pallet_staking::ConfigOp::Set(10), // minimum nominator bond pallet_staking::ConfigOp::Noop, pallet_staking::ConfigOp::Noop, @@ -248,7 +251,7 @@ pub(crate) fn pool_events_since_last_call() -> Vec>(); let already_seen = ObservedEventsPools::get(); ObservedEventsPools::set(events.len()); @@ -259,7 +262,7 @@ pub(crate) fn staking_events_since_last_call() -> Vec>(); let already_seen = ObservedEventsStaking::get(); ObservedEventsStaking::set(events.len()); diff --git a/frame/offences/benchmarking/Cargo.toml b/frame/offences/benchmarking/Cargo.toml index 2b8e461b84192..3c7a43068af82 100644 --- a/frame/offences/benchmarking/Cargo.toml +++ b/frame/offences/benchmarking/Cargo.toml @@ -23,13 +23,9 @@ pallet-babe = { version = "4.0.0-dev", default-features = false, path = "../../b pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../balances" } pallet-grandpa = { version = "4.0.0-dev", default-features = false, path = "../../grandpa" } pallet-im-online = { version = "4.0.0-dev", default-features = false, path = "../../im-online" } -pallet-offences = { version = "4.0.0-dev", default-features = false, features = [ - "runtime-benchmarks", -], path = "../../offences" } +pallet-offences = { version = "4.0.0-dev", default-features = false, path = "../../offences" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../../session" } -pallet-staking = { version = "4.0.0-dev", default-features = false, features = [ - "runtime-benchmarks", -], path = "../../staking" } +pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../staking" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/staking" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } @@ -60,3 +56,7 @@ std = [ "sp-staking/std", "sp-std/std", ] + +runtime-benchmarks = [ + "pallet-staking/runtime-benchmarks", +] diff --git a/frame/offences/benchmarking/src/lib.rs b/frame/offences/benchmarking/src/lib.rs index 5d81a71d4c47c..555ec42882ee1 100644 --- a/frame/offences/benchmarking/src/lib.rs +++ b/frame/offences/benchmarking/src/lib.rs @@ -17,6 +17,7 @@ //! Offences pallet benchmarking. +#![cfg(feature = "runtime-benchmarks")] #![cfg_attr(not(feature = "std"), no_std)] mod mock; @@ -216,7 +217,7 @@ fn make_offenders_im_online( } #[cfg(test)] -fn check_events::Event>>(expected: I) { +fn check_events::RuntimeEvent>>(expected: I) { let events = System::::events() .into_iter() .map(|frame_system::EventRecord { event, .. }| event) @@ -308,16 +309,16 @@ benchmarks! { let reward_amount = slash_amount.saturating_mul(1 + n) / 2; let reward = reward_amount / r; let slash = |id| core::iter::once( - ::Event::from(StakingEvent::::Slashed(id, BalanceOf::::from(slash_amount))) + ::RuntimeEvent::from(StakingEvent::::Slashed{staker: id, amount: BalanceOf::::from(slash_amount)}) ); let balance_slash = |id| core::iter::once( - ::Event::from(pallet_balances::Event::::Slashed{who: id, amount: slash_amount.into()}) + ::RuntimeEvent::from(pallet_balances::Event::::Slashed{who: id, amount: slash_amount.into()}) ); let chill = |id| core::iter::once( - ::Event::from(StakingEvent::::Chilled(id)) + ::RuntimeEvent::from(StakingEvent::::Chilled{stash: id}) ); let balance_deposit = |id, amount: u32| - ::Event::from(pallet_balances::Event::::Deposit{who: id, amount: amount.into()}); + ::RuntimeEvent::from(pallet_balances::Event::::Deposit{who: id, amount: amount.into()}); let mut first = true; let slash_events = raw_offenders.into_iter() .flat_map(|offender| { @@ -339,7 +340,7 @@ benchmarks! { .flat_map(|reporter| vec![ balance_deposit(reporter.clone(), reward).into(), frame_system::Event::::NewAccount { account: reporter.clone() }.into(), - ::Event::from( + ::RuntimeEvent::from( pallet_balances::Event::::Endowed{account: reporter, free_balance: reward.into()} ).into(), ]) @@ -366,7 +367,7 @@ benchmarks! { check_events::( std::iter::empty() .chain(slash_events.into_iter().map(Into::into)) - .chain(std::iter::once(::Event::from( + .chain(std::iter::once(::RuntimeEvent::from( pallet_offences::Event::Offence{ kind: UnresponsivenessOffence::::ID, timeslot: 0_u32.to_le_bytes().to_vec(), diff --git a/frame/offences/benchmarking/src/mock.rs b/frame/offences/benchmarking/src/mock.rs index 6d66f5251c78c..c4c1d2aca8d07 100644 --- a/frame/offences/benchmarking/src/mock.rs +++ b/frame/offences/benchmarking/src/mock.rs @@ -50,16 +50,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = AccountIndex; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_core::H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type Version = (); type PalletInfo = PalletInfo; @@ -77,7 +77,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<10>; type AccountStore = System; @@ -128,7 +128,7 @@ impl pallet_session::Config for Test { type ShouldEndSession = pallet_session::PeriodicSessions; type NextSessionRotation = pallet_session::PeriodicSessions; type SessionHandler = TestSessionHandler; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = AccountId; type ValidatorIdOf = pallet_staking::StashOf; type WeightInfo = (); @@ -148,7 +148,7 @@ parameter_types! { pub const RewardCurve: &'static sp_runtime::curve::PiecewiseLinear<'static> = &I_NPOS; } -pub type Extrinsic = sp_runtime::testing::TestXt; +pub type Extrinsic = sp_runtime::testing::TestXt; pub struct OnChainSeqPhragmen; impl onchain::Config for OnChainSeqPhragmen { @@ -165,7 +165,7 @@ impl pallet_staking::Config for Test { type UnixTime = pallet_timestamp::Pallet; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type RewardRemainder = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Slash = (); type Reward = (); type SessionsPerEra = (); @@ -180,7 +180,9 @@ impl pallet_staking::Config for Test { type ElectionProvider = onchain::UnboundedExecution; type GenesisElectionProvider = Self::ElectionProvider; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; + type TargetList = pallet_staking::UseValidatorsMap; type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = ConstU32<84>; type OnStakerSlash = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); @@ -188,7 +190,7 @@ impl pallet_staking::Config for Test { impl pallet_im_online::Config for Test { type AuthorityId = UintAuthorityId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorSet = Historical; type NextSessionRotation = pallet_session::PeriodicSessions; type ReportUnresponsiveness = Offences; @@ -200,23 +202,23 @@ impl pallet_im_online::Config for Test { } impl pallet_offences::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type IdentificationTuple = pallet_session::historical::IdentificationTuple; type OnOffenceHandler = Staking; } impl frame_system::offchain::SendTransactionTypes for Test where - Call: From, + RuntimeCall: From, { type Extrinsic = Extrinsic; - type OverarchingCall = Call; + type OverarchingCall = RuntimeCall; } impl crate::Config for Test {} pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Test where diff --git a/frame/offences/src/lib.rs b/frame/offences/src/lib.rs index ae454d6b06740..7858b02719c4c 100644 --- a/frame/offences/src/lib.rs +++ b/frame/offences/src/lib.rs @@ -57,7 +57,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From + IsType<::Event>; + type RuntimeEvent: From + IsType<::RuntimeEvent>; /// Full identification of the validator. type IdentificationTuple: Parameter; /// A handler called for every offence report. diff --git a/frame/offences/src/mock.rs b/frame/offences/src/mock.rs index a578a6082cf3e..31dac8d51d3b1 100644 --- a/frame/offences/src/mock.rs +++ b/frame/offences/src/mock.rs @@ -40,13 +40,12 @@ use sp_staking::{ offence::{self, DisableStrategy, Kind, OffenceDetails}, SessionIndex, }; -use std::cell::RefCell; pub struct OnOffenceHandler; -thread_local! { - pub static ON_OFFENCE_PERBILL: RefCell> = RefCell::new(Default::default()); - pub static OFFENCE_WEIGHT: RefCell = RefCell::new(Default::default()); +parameter_types! { + pub static OnOffencePerbill: Vec = Default::default(); + pub static OffenceWeight: Weight = Default::default(); } impl offence::OnOffenceHandler @@ -58,16 +57,16 @@ impl offence::OnOffenceHandler _offence_session: SessionIndex, _disable_strategy: DisableStrategy, ) -> Weight { - ON_OFFENCE_PERBILL.with(|f| { - *f.borrow_mut() = slash_fraction.to_vec(); + OnOffencePerbill::mutate(|f| { + *f = slash_fraction.to_vec(); }); - OFFENCE_WEIGHT.with(|w| *w.borrow()) + OffenceWeight::get() } } pub fn with_on_offence_fractions) -> R>(f: F) -> R { - ON_OFFENCE_PERBILL.with(|fractions| f(&mut fractions.borrow_mut())) + OnOffencePerbill::mutate(|fractions| f(fractions)) } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; @@ -93,16 +92,16 @@ impl frame_system::Config for Runtime { type BlockWeights = (); type BlockLength = (); type DbWeight = RocksDbWeight; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -116,7 +115,7 @@ impl frame_system::Config for Runtime { } impl Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type IdentificationTuple = u64; type OnOffenceHandler = OnOffenceHandler; } diff --git a/frame/offences/src/tests.rs b/frame/offences/src/tests.rs index 49bd2fb5a6923..266e05debf050 100644 --- a/frame/offences/src/tests.rs +++ b/frame/offences/src/tests.rs @@ -21,8 +21,8 @@ use super::*; use crate::mock::{ - new_test_ext, offence_reports, report_id, with_on_offence_fractions, Event, Offence, Offences, - System, KIND, + new_test_ext, offence_reports, report_id, with_on_offence_fractions, Offence, Offences, + RuntimeEvent, System, KIND, }; use frame_system::{EventRecord, Phase}; use sp_runtime::Perbill; @@ -114,7 +114,7 @@ fn should_deposit_event() { System::events(), vec![EventRecord { phase: Phase::Initialization, - event: Event::Offences(crate::Event::Offence { + event: RuntimeEvent::Offences(crate::Event::Offence { kind: KIND, timeslot: time_slot.encode() }), @@ -148,7 +148,7 @@ fn doesnt_deposit_event_for_dups() { System::events(), vec![EventRecord { phase: Phase::Initialization, - event: Event::Offences(crate::Event::Offence { + event: RuntimeEvent::Offences(crate::Event::Offence { kind: KIND, timeslot: time_slot.encode() }), diff --git a/frame/preimage/Cargo.toml b/frame/preimage/Cargo.toml index 325e906c61a3c..77046f4fb58b6 100644 --- a/frame/preimage/Cargo.toml +++ b/frame/preimage/Cargo.toml @@ -19,6 +19,7 @@ sp-core = { version = "6.0.0", default-features = false, optional = true, path = sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } +log = { version = "0.4.17", default-features = false } [dev-dependencies] pallet-balances = { version = "4.0.0-dev", path = "../balances" } @@ -33,13 +34,16 @@ runtime-benchmarks = [ ] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", + "log/std", "scale-info/std", "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", ] -try-runtime = ["frame-support/try-runtime"] +try-runtime = [ + "frame-support/try-runtime", +] diff --git a/frame/preimage/src/benchmarking.rs b/frame/preimage/src/benchmarking.rs index e0d7e9614abbc..8a61d7d780bfd 100644 --- a/frame/preimage/src/benchmarking.rs +++ b/frame/preimage/src/benchmarking.rs @@ -35,7 +35,7 @@ fn funded_account(name: &'static str, index: u32) -> T::AccountId { } fn preimage_and_hash() -> (Vec, T::Hash) { - sized_preimage_and_hash::(T::MaxSize::get()) + sized_preimage_and_hash::(MAX_SIZE) } fn sized_preimage_and_hash(size: u32) -> (Vec, T::Hash) { @@ -48,7 +48,7 @@ fn sized_preimage_and_hash(size: u32) -> (Vec, T::Hash) { benchmarks! { // Expensive note - will reserve. note_preimage { - let s in 0 .. T::MaxSize::get(); + let s in 0 .. MAX_SIZE; let caller = funded_account::("caller", 0); whitelist_account!(caller); let (preimage, hash) = sized_preimage_and_hash::(s); @@ -58,7 +58,7 @@ benchmarks! { } // Cheap note - will not reserve since it was requested. note_requested_preimage { - let s in 0 .. T::MaxSize::get(); + let s in 0 .. MAX_SIZE; let caller = funded_account::("caller", 0); whitelist_account!(caller); let (preimage, hash) = sized_preimage_and_hash::(s); @@ -69,10 +69,10 @@ benchmarks! { } // Cheap note - will not reserve since it's the manager. note_no_deposit_preimage { - let s in 0 .. T::MaxSize::get(); + let s in 0 .. MAX_SIZE; let (preimage, hash) = sized_preimage_and_hash::(s); assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); - }: note_preimage(T::ManagerOrigin::successful_origin(), preimage) + }: note_preimage(T::ManagerOrigin::successful_origin(), preimage) verify { assert!(Preimage::::have_preimage(&hash)); } @@ -91,7 +91,7 @@ benchmarks! { unnote_no_deposit_preimage { let (preimage, hash) = preimage_and_hash::(); assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); - }: unnote_preimage(T::ManagerOrigin::successful_origin(), hash) + }: unnote_preimage(T::ManagerOrigin::successful_origin(), hash) verify { assert!(!Preimage::::have_preimage(&hash)); } @@ -101,33 +101,38 @@ benchmarks! { let (preimage, hash) = preimage_and_hash::(); let noter = funded_account::("noter", 0); whitelist_account!(noter); - assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(noter).into(), preimage)); - }: _(T::ManagerOrigin::successful_origin(), hash) + assert_ok!(Preimage::::note_preimage(RawOrigin::Signed(noter.clone()).into(), preimage)); + }: _(T::ManagerOrigin::successful_origin(), hash) verify { - assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); + let deposit = T::BaseDeposit::get() + T::ByteDeposit::get() * MAX_SIZE.into(); + let s = RequestStatus::Requested { deposit: Some((noter, deposit)), count: 1, len: Some(MAX_SIZE) }; + assert_eq!(StatusFor::::get(&hash), Some(s)); } // Cheap request - would unreserve the deposit but none was held. request_no_deposit_preimage { let (preimage, hash) = preimage_and_hash::(); assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); - }: request_preimage(T::ManagerOrigin::successful_origin(), hash) + }: request_preimage(T::ManagerOrigin::successful_origin(), hash) verify { - assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); + let s = RequestStatus::Requested { deposit: None, count: 2, len: Some(MAX_SIZE) }; + assert_eq!(StatusFor::::get(&hash), Some(s)); } // Cheap request - the preimage is not yet noted, so deposit to unreserve. request_unnoted_preimage { let (_, hash) = preimage_and_hash::(); - }: request_preimage(T::ManagerOrigin::successful_origin(), hash) + }: request_preimage(T::ManagerOrigin::successful_origin(), hash) verify { - assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); + let s = RequestStatus::Requested { deposit: None, count: 1, len: None }; + assert_eq!(StatusFor::::get(&hash), Some(s)); } // Cheap request - the preimage is already requested, so just a counter bump. request_requested_preimage { let (_, hash) = preimage_and_hash::(); assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); - }: request_preimage(T::ManagerOrigin::successful_origin(), hash) + }: request_preimage(T::ManagerOrigin::successful_origin(), hash) verify { - assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(2))); + let s = RequestStatus::Requested { deposit: None, count: 2, len: None }; + assert_eq!(StatusFor::::get(&hash), Some(s)); } // Expensive unrequest - last reference and it's noted, so will destroy the preimage. @@ -135,7 +140,7 @@ benchmarks! { let (preimage, hash) = preimage_and_hash::(); assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); assert_ok!(Preimage::::note_preimage(T::ManagerOrigin::successful_origin(), preimage)); - }: _(T::ManagerOrigin::successful_origin(), hash) + }: _(T::ManagerOrigin::successful_origin(), hash) verify { assert_eq!(StatusFor::::get(&hash), None); } @@ -143,7 +148,7 @@ benchmarks! { unrequest_unnoted_preimage { let (_, hash) = preimage_and_hash::(); assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); - }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash) + }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash) verify { assert_eq!(StatusFor::::get(&hash), None); } @@ -152,9 +157,10 @@ benchmarks! { let (_, hash) = preimage_and_hash::(); assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); assert_ok!(Preimage::::request_preimage(T::ManagerOrigin::successful_origin(), hash)); - }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash) + }: unrequest_preimage(T::ManagerOrigin::successful_origin(), hash) verify { - assert_eq!(StatusFor::::get(&hash), Some(RequestStatus::Requested(1))); + let s = RequestStatus::Requested { deposit: None, count: 1, len: None }; + assert_eq!(StatusFor::::get(&hash), Some(s)); } impl_benchmark_test_suite!(Preimage, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/frame/preimage/src/lib.rs b/frame/preimage/src/lib.rs index 09f6ecd52f9ad..e899d3643dbbf 100644 --- a/frame/preimage/src/lib.rs +++ b/frame/preimage/src/lib.rs @@ -30,6 +30,7 @@ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod migration; #[cfg(test)] mod mock; #[cfg(test)] @@ -37,15 +38,18 @@ mod tests; pub mod weights; use sp_runtime::traits::{BadOrigin, Hash, Saturating}; -use sp_std::prelude::*; +use sp_std::{borrow::Cow, prelude::*}; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ + dispatch::Pays, ensure, pallet_prelude::Get, - traits::{Currency, PreimageProvider, PreimageRecipient, ReservableCurrency}, - weights::Pays, - BoundedVec, + traits::{ + Currency, Defensive, FetchResult, Hash as PreimageHash, PreimageProvider, + PreimageRecipient, QueryPreimage, ReservableCurrency, StorePreimage, + }, + BoundedSlice, BoundedVec, }; use scale_info::TypeInfo; pub use weights::WeightInfo; @@ -59,24 +63,31 @@ pub use pallet::*; #[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug)] pub enum RequestStatus { /// The associated preimage has not yet been requested by the system. The given deposit (if - /// some) is being held until either it becomes requested or the user retracts the primage. - Unrequested(Option<(AccountId, Balance)>), + /// some) is being held until either it becomes requested or the user retracts the preimage. + Unrequested { deposit: (AccountId, Balance), len: u32 }, /// There are a non-zero number of outstanding requests for this hash by this chain. If there - /// is a preimage registered, then it may be removed iff this counter becomes zero. - Requested(u32), + /// is a preimage registered, then `len` is `Some` and it may be removed iff this counter + /// becomes zero. + Requested { deposit: Option<(AccountId, Balance)>, count: u32, len: Option }, } type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +/// Maximum size of preimage we can store is 4mb. +const MAX_SIZE: u32 = 4 * 1024 * 1024; + #[frame_support::pallet] pub mod pallet { use super::*; + /// The current storage version. + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The Weight information for this pallet. type WeightInfo: weights::WeightInfo; @@ -86,10 +97,7 @@ pub mod pallet { /// An origin that can request a preimage be placed on-chain without a deposit or fee, or /// manage existing preimages. - type ManagerOrigin: EnsureOrigin; - - /// Max size allowed for a preimage. - type MaxSize: Get; + type ManagerOrigin: EnsureOrigin; /// The base deposit for placing a preimage on chain. type BaseDeposit: Get>; @@ -100,6 +108,7 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(PhantomData); #[pallet::event] @@ -116,7 +125,7 @@ pub mod pallet { #[pallet::error] pub enum Error { /// Preimage is too large to store on-chain. - TooLarge, + TooBig, /// Preimage has already been noted on-chain. AlreadyNoted, /// The user is not authorized to perform this action. @@ -134,10 +143,9 @@ pub mod pallet { pub(super) type StatusFor = StorageMap<_, Identity, T::Hash, RequestStatus>>; - /// The preimages stored by this pallet. #[pallet::storage] pub(super) type PreimageFor = - StorageMap<_, Identity, T::Hash, BoundedVec>; + StorageMap<_, Identity, (T::Hash, u32), BoundedVec>>; #[pallet::call] impl Pallet { @@ -150,9 +158,7 @@ pub mod pallet { // We accept a signed origin which will pay a deposit, or a root origin where a deposit // is not taken. let maybe_sender = Self::ensure_signed_or_manager(origin)?; - let bounded_vec = - BoundedVec::::try_from(bytes).map_err(|()| Error::::TooLarge)?; - let system_requested = Self::note_bytes(bounded_vec, maybe_sender.as_ref())?; + let (system_requested, _) = Self::note_bytes(bytes.into(), maybe_sender.as_ref())?; if system_requested || maybe_sender.is_none() { Ok(Pays::No.into()) } else { @@ -161,6 +167,11 @@ pub mod pallet { } /// Clear an unrequested preimage from the runtime storage. + /// + /// If `len` is provided, then it will be a much cheaper operation. + /// + /// - `hash`: The hash of the preimage to be removed from the store. + /// - `len`: The length of the preimage of `hash`. #[pallet::weight(T::WeightInfo::unnote_preimage())] pub fn unnote_preimage(origin: OriginFor, hash: T::Hash) -> DispatchResult { let maybe_sender = Self::ensure_signed_or_manager(origin)?; @@ -191,7 +202,9 @@ pub mod pallet { impl Pallet { /// Ensure that the origin is either the `ManagerOrigin` or a signed origin. - fn ensure_signed_or_manager(origin: T::Origin) -> Result, BadOrigin> { + fn ensure_signed_or_manager( + origin: T::RuntimeOrigin, + ) -> Result, BadOrigin> { if T::ManagerOrigin::ensure_origin(origin.clone()).is_ok() { return Ok(None) } @@ -201,41 +214,46 @@ impl Pallet { /// Store some preimage on chain. /// + /// If `maybe_depositor` is `None` then it is also requested. If `Some`, then it is not. + /// /// We verify that the preimage is within the bounds of what the pallet supports. /// /// If the preimage was requested to be uploaded, then the user pays no deposits or tx fees. fn note_bytes( - preimage: BoundedVec, + preimage: Cow<[u8]>, maybe_depositor: Option<&T::AccountId>, - ) -> Result { + ) -> Result<(bool, T::Hash), DispatchError> { let hash = T::Hashing::hash(&preimage); - ensure!(!PreimageFor::::contains_key(hash), Error::::AlreadyNoted); + let len = preimage.len() as u32; + ensure!(len <= MAX_SIZE, Error::::TooBig); - // We take a deposit only if there is a provided depositor, and the preimage was not + // We take a deposit only if there is a provided depositor and the preimage was not // previously requested. This also allows the tx to pay no fee. - let was_requested = match (StatusFor::::get(hash), maybe_depositor) { - (Some(RequestStatus::Requested(..)), _) => true, - (Some(RequestStatus::Unrequested(..)), _) => + let status = match (StatusFor::::get(hash), maybe_depositor) { + (Some(RequestStatus::Requested { count, deposit, .. }), _) => + RequestStatus::Requested { count, deposit, len: Some(len) }, + (Some(RequestStatus::Unrequested { .. }), Some(_)) => return Err(Error::::AlreadyNoted.into()), - (None, None) => { - StatusFor::::insert(hash, RequestStatus::Unrequested(None)); - false - }, + (Some(RequestStatus::Unrequested { len, deposit }), None) => + RequestStatus::Requested { deposit: Some(deposit), count: 1, len: Some(len) }, + (None, None) => RequestStatus::Requested { count: 1, len: Some(len), deposit: None }, (None, Some(depositor)) => { let length = preimage.len() as u32; let deposit = T::BaseDeposit::get() .saturating_add(T::ByteDeposit::get().saturating_mul(length.into())); T::Currency::reserve(depositor, deposit)?; - let status = RequestStatus::Unrequested(Some((depositor.clone(), deposit))); - StatusFor::::insert(hash, status); - false + RequestStatus::Unrequested { deposit: (depositor.clone(), deposit), len } }, }; + let was_requested = matches!(status, RequestStatus::Requested { .. }); + StatusFor::::insert(hash, status); + + let _ = Self::insert(&hash, preimage) + .defensive_proof("Unable to insert. Logic error in `note_bytes`?"); - PreimageFor::::insert(hash, preimage); Self::deposit_event(Event::Noted { hash }); - Ok(was_requested) + Ok((was_requested, hash)) } // This function will add a hash to the list of requested preimages. @@ -243,19 +261,15 @@ impl Pallet { // If the preimage already exists before the request is made, the deposit for the preimage is // returned to the user, and removed from their management. fn do_request_preimage(hash: &T::Hash) { - let count = StatusFor::::get(hash).map_or(1, |x| match x { - RequestStatus::Requested(mut count) => { - count.saturating_inc(); - count - }, - RequestStatus::Unrequested(None) => 1, - RequestStatus::Unrequested(Some((owner, deposit))) => { - // Return the deposit - the preimage now has outstanding requests. - T::Currency::unreserve(&owner, deposit); - 1 - }, - }); - StatusFor::::insert(hash, RequestStatus::Requested(count)); + let (count, len, deposit) = + StatusFor::::get(hash).map_or((1, None, None), |x| match x { + RequestStatus::Requested { mut count, len, deposit } => { + count.saturating_inc(); + (count, len, deposit) + }, + RequestStatus::Unrequested { deposit, len } => (1, Some(len), Some(deposit)), + }); + StatusFor::::insert(hash, RequestStatus::Requested { count, len, deposit }); if count == 1 { Self::deposit_event(Event::Requested { hash: *hash }); } @@ -263,6 +277,8 @@ impl Pallet { // Clear a preimage from the storage of the chain, returning any deposit that may be reserved. // + // If `len` is provided, it will be a much cheaper operation. + // // If `maybe_owner` is provided, we verify that it is the correct owner before clearing the // data. fn do_unnote_preimage( @@ -270,51 +286,101 @@ impl Pallet { maybe_check_owner: Option, ) -> DispatchResult { match StatusFor::::get(hash).ok_or(Error::::NotNoted)? { - RequestStatus::Unrequested(Some((owner, deposit))) => { + RequestStatus::Requested { deposit: Some((owner, deposit)), count, len } => { ensure!(maybe_check_owner.map_or(true, |c| c == owner), Error::::NotAuthorized); T::Currency::unreserve(&owner, deposit); + StatusFor::::insert( + hash, + RequestStatus::Requested { deposit: None, count, len }, + ); + Ok(()) }, - RequestStatus::Unrequested(None) => { + RequestStatus::Requested { deposit: None, .. } => { ensure!(maybe_check_owner.is_none(), Error::::NotAuthorized); + Self::do_unrequest_preimage(hash) + }, + RequestStatus::Unrequested { deposit: (owner, deposit), len } => { + ensure!(maybe_check_owner.map_or(true, |c| c == owner), Error::::NotAuthorized); + T::Currency::unreserve(&owner, deposit); + StatusFor::::remove(hash); + + Self::remove(hash, len); + Self::deposit_event(Event::Cleared { hash: *hash }); + Ok(()) }, - RequestStatus::Requested(_) => return Err(Error::::Requested.into()), } - StatusFor::::remove(hash); - PreimageFor::::remove(hash); - Self::deposit_event(Event::Cleared { hash: *hash }); - Ok(()) } /// Clear a preimage request. fn do_unrequest_preimage(hash: &T::Hash) -> DispatchResult { match StatusFor::::get(hash).ok_or(Error::::NotRequested)? { - RequestStatus::Requested(mut count) if count > 1 => { + RequestStatus::Requested { mut count, len, deposit } if count > 1 => { count.saturating_dec(); - StatusFor::::insert(hash, RequestStatus::Requested(count)); + StatusFor::::insert(hash, RequestStatus::Requested { count, len, deposit }); }, - RequestStatus::Requested(count) => { + RequestStatus::Requested { count, len, deposit } => { debug_assert!(count == 1, "preimage request counter at zero?"); - PreimageFor::::remove(hash); - StatusFor::::remove(hash); - Self::deposit_event(Event::Cleared { hash: *hash }); + match (len, deposit) { + // Preimage was never noted. + (None, _) => StatusFor::::remove(hash), + // Preimage was noted without owner - just remove it. + (Some(len), None) => { + Self::remove(hash, len); + StatusFor::::remove(hash); + Self::deposit_event(Event::Cleared { hash: *hash }); + }, + // Preimage was noted with owner - move to unrequested so they can get refund. + (Some(len), Some(deposit)) => { + StatusFor::::insert(hash, RequestStatus::Unrequested { deposit, len }); + }, + } }, - RequestStatus::Unrequested(_) => return Err(Error::::NotRequested.into()), + RequestStatus::Unrequested { .. } => return Err(Error::::NotRequested.into()), } Ok(()) } + + fn insert(hash: &T::Hash, preimage: Cow<[u8]>) -> Result<(), ()> { + BoundedSlice::>::try_from(preimage.as_ref()) + .map(|s| PreimageFor::::insert((hash, s.len() as u32), s)) + } + + fn remove(hash: &T::Hash, len: u32) { + PreimageFor::::remove((hash, len)) + } + + fn have(hash: &T::Hash) -> bool { + Self::len(hash).is_some() + } + + fn len(hash: &T::Hash) -> Option { + use RequestStatus::*; + match StatusFor::::get(hash) { + Some(Requested { len: Some(len), .. }) | Some(Unrequested { len, .. }) => Some(len), + _ => None, + } + } + + fn fetch(hash: &T::Hash, len: Option) -> FetchResult { + let len = len.or_else(|| Self::len(hash)).ok_or(DispatchError::Unavailable)?; + PreimageFor::::get((hash, len)) + .map(|p| p.into_inner()) + .map(Into::into) + .ok_or(DispatchError::Unavailable) + } } impl PreimageProvider for Pallet { fn have_preimage(hash: &T::Hash) -> bool { - PreimageFor::::contains_key(hash) + Self::have(hash) } fn preimage_requested(hash: &T::Hash) -> bool { - matches!(StatusFor::::get(hash), Some(RequestStatus::Requested(..))) + matches!(StatusFor::::get(hash), Some(RequestStatus::Requested { .. })) } fn get_preimage(hash: &T::Hash) -> Option> { - PreimageFor::::get(hash).map(|preimage| preimage.to_vec()) + Self::fetch(hash, None).ok().map(Cow::into_owned) } fn request_preimage(hash: &T::Hash) { @@ -328,15 +394,60 @@ impl PreimageProvider for Pallet { } impl PreimageRecipient for Pallet { - type MaxSize = T::MaxSize; + type MaxSize = ConstU32; // 2**22 fn note_preimage(bytes: BoundedVec) { // We don't really care if this fails, since that's only the case if someone else has // already noted it. - let _ = Self::note_bytes(bytes, None); + let _ = Self::note_bytes(bytes.into_inner().into(), None); } fn unnote_preimage(hash: &T::Hash) { + // Should never fail if authorization check is skipped. + let res = Self::do_unrequest_preimage(hash); + debug_assert!(res.is_ok(), "unnote_preimage failed - request outstanding?"); + } +} + +impl> QueryPreimage for Pallet { + fn len(hash: &T::Hash) -> Option { + Pallet::::len(hash) + } + + fn fetch(hash: &T::Hash, len: Option) -> FetchResult { + Pallet::::fetch(hash, len) + } + + fn is_requested(hash: &T::Hash) -> bool { + matches!(StatusFor::::get(hash), Some(RequestStatus::Requested { .. })) + } + + fn request(hash: &T::Hash) { + Self::do_request_preimage(hash) + } + + fn unrequest(hash: &T::Hash) { + let res = Self::do_unrequest_preimage(hash); + debug_assert!(res.is_ok(), "do_unrequest_preimage failed - counter underflow?"); + } +} + +impl> StorePreimage for Pallet { + const MAX_LENGTH: usize = MAX_SIZE as usize; + + fn note(bytes: Cow<[u8]>) -> Result { + // We don't really care if this fails, since that's only the case if someone else has + // already noted it. + let maybe_hash = Self::note_bytes(bytes, None).map(|(_, h)| h); + // Map to the correct trait error. + if maybe_hash == Err(DispatchError::from(Error::::TooBig)) { + Err(DispatchError::Exhausted) + } else { + maybe_hash + } + } + + fn unnote(hash: &T::Hash) { // Should never fail if authorization check is skipped. let res = Self::do_unnote_preimage(hash, None); debug_assert!(res.is_ok(), "unnote_preimage failed - request outstanding?"); diff --git a/frame/preimage/src/migration.rs b/frame/preimage/src/migration.rs new file mode 100644 index 0000000000000..a5d15c23c758a --- /dev/null +++ b/frame/preimage/src/migration.rs @@ -0,0 +1,263 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Storage migrations for the preimage pallet. + +use super::*; +use frame_support::{ + storage_alias, + traits::{ConstU32, OnRuntimeUpgrade}, +}; +use sp_std::collections::btree_map::BTreeMap; + +/// The log target. +const TARGET: &'static str = "runtime::preimage::migration::v1"; + +/// The original data layout of the preimage pallet without a specific version number. +mod v0 { + use super::*; + + #[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen, RuntimeDebug)] + pub enum RequestStatus { + Unrequested(Option<(AccountId, Balance)>), + Requested(u32), + } + + #[storage_alias] + pub type PreimageFor = StorageMap< + Pallet, + Identity, + ::Hash, + BoundedVec>, + >; + + #[storage_alias] + pub type StatusFor = StorageMap< + Pallet, + Identity, + ::Hash, + RequestStatus<::AccountId, BalanceOf>, + >; + + /// Returns the number of images or `None` if the storage is corrupted. + #[cfg(feature = "try-runtime")] + pub fn image_count() -> Option { + let images = v0::PreimageFor::::iter_values().count() as u32; + let status = v0::StatusFor::::iter_values().count() as u32; + + if images == status { + Some(images) + } else { + None + } + } +} + +pub mod v1 { + use super::*; + + /// Migration for moving preimage from V0 to V1 storage. + /// + /// Note: This needs to be run with the same hashing algorithm as before + /// since it is not re-hashing the preimages. + pub struct Migration(sp_std::marker::PhantomData); + + impl OnRuntimeUpgrade for Migration { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + assert_eq!(StorageVersion::get::>(), 0, "can only upgrade from version 0"); + + let images = v0::image_count::().expect("v0 storage corrupted"); + log::info!(target: TARGET, "Migrating {} images", &images); + Ok((images as u32).encode()) + } + + fn on_runtime_upgrade() -> Weight { + let mut weight = T::DbWeight::get().reads(1); + if StorageVersion::get::>() != 0 { + log::warn!( + target: TARGET, + "skipping MovePreimagesIntoBuckets: executed on wrong storage version.\ + Expected version 0" + ); + return weight + } + + let status = v0::StatusFor::::drain().collect::>(); + weight.saturating_accrue(T::DbWeight::get().reads(status.len() as u64)); + + let preimages = v0::PreimageFor::::drain().collect::>(); + weight.saturating_accrue(T::DbWeight::get().reads(preimages.len() as u64)); + + for (hash, status) in status.into_iter() { + let preimage = if let Some(preimage) = preimages.get(&hash) { + preimage + } else { + log::error!(target: TARGET, "preimage not found for hash {:?}", &hash); + continue + }; + let len = preimage.len() as u32; + if len > MAX_SIZE { + log::error!( + target: TARGET, + "preimage too large for hash {:?}, len: {}", + &hash, + len + ); + continue + } + + let status = match status { + v0::RequestStatus::Unrequested(deposit) => match deposit { + Some(deposit) => RequestStatus::Unrequested { deposit, len }, + // `None` depositor becomes system-requested. + None => + RequestStatus::Requested { deposit: None, count: 1, len: Some(len) }, + }, + v0::RequestStatus::Requested(count) if count == 0 => { + log::error!(target: TARGET, "preimage has counter of zero: {:?}", hash); + continue + }, + v0::RequestStatus::Requested(count) => + RequestStatus::Requested { deposit: None, count, len: Some(len) }, + }; + log::trace!(target: TARGET, "Moving preimage {:?} with len {}", hash, len); + + crate::StatusFor::::insert(hash, status); + crate::PreimageFor::::insert(&(hash, len), preimage); + + weight.saturating_accrue(T::DbWeight::get().writes(2)); + } + StorageVersion::new(1).put::>(); + + weight.saturating_add(T::DbWeight::get().writes(1)) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + let old_images: u32 = + Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed"); + let new_images = image_count::().expect("V1 storage corrupted"); + + if new_images != old_images { + log::error!( + target: TARGET, + "migrated {} images, expected {}", + new_images, + old_images + ); + } + assert_eq!(StorageVersion::get::>(), 1, "must upgrade"); + Ok(()) + } + } + + /// Returns the number of images or `None` if the storage is corrupted. + #[cfg(feature = "try-runtime")] + pub fn image_count() -> Option { + // Use iter_values() to ensure that the values are decodable. + let images = crate::PreimageFor::::iter_values().count() as u32; + let status = crate::StatusFor::::iter_values().count() as u32; + + if images == status { + Some(images) + } else { + None + } + } +} + +#[cfg(test)] +#[cfg(feature = "try-runtime")] +mod test { + use super::*; + use crate::mock::{Test as T, *}; + + use frame_support::bounded_vec; + + #[test] + fn migration_works() { + new_test_ext().execute_with(|| { + assert_eq!(StorageVersion::get::>(), 0); + // Insert some preimages into the v0 storage: + + // Case 1: Unrequested without deposit + let (p, h) = preimage::(128); + v0::PreimageFor::::insert(h, p); + v0::StatusFor::::insert(h, v0::RequestStatus::Unrequested(None)); + // Case 2: Unrequested with deposit + let (p, h) = preimage::(1024); + v0::PreimageFor::::insert(h, p); + v0::StatusFor::::insert(h, v0::RequestStatus::Unrequested(Some((1, 1)))); + // Case 3: Requested by 0 (invalid) + let (p, h) = preimage::(8192); + v0::PreimageFor::::insert(h, p); + v0::StatusFor::::insert(h, v0::RequestStatus::Requested(0)); + // Case 4: Requested by 10 + let (p, h) = preimage::(65536); + v0::PreimageFor::::insert(h, p); + v0::StatusFor::::insert(h, v0::RequestStatus::Requested(10)); + + assert_eq!(v0::image_count::(), Some(4)); + assert_eq!(v1::image_count::(), None, "V1 storage should be corrupted"); + + let state = v1::Migration::::pre_upgrade().unwrap(); + let _w = v1::Migration::::on_runtime_upgrade(); + v1::Migration::::post_upgrade(state).unwrap(); + + // V0 and V1 share the same prefix, so `iter_values` still counts the same. + assert_eq!(v0::image_count::(), Some(3)); + assert_eq!(v1::image_count::(), Some(3)); // One gets skipped therefore 3. + assert_eq!(StorageVersion::get::>(), 1); + + // Case 1: Unrequested without deposit becomes system-requested + let (p, h) = preimage::(128); + assert_eq!(crate::PreimageFor::::get(&(h, 128)), Some(p)); + assert_eq!( + crate::StatusFor::::get(h), + Some(RequestStatus::Requested { deposit: None, count: 1, len: Some(128) }) + ); + // Case 2: Unrequested with deposit becomes unrequested + let (p, h) = preimage::(1024); + assert_eq!(crate::PreimageFor::::get(&(h, 1024)), Some(p)); + assert_eq!( + crate::StatusFor::::get(h), + Some(RequestStatus::Unrequested { deposit: (1, 1), len: 1024 }) + ); + // Case 3: Requested by 0 should be skipped + let (_, h) = preimage::(8192); + assert_eq!(crate::PreimageFor::::get(&(h, 8192)), None); + assert_eq!(crate::StatusFor::::get(h), None); + // Case 4: Requested by 10 becomes requested by 10 + let (p, h) = preimage::(65536); + assert_eq!(crate::PreimageFor::::get(&(h, 65536)), Some(p)); + assert_eq!( + crate::StatusFor::::get(h), + Some(RequestStatus::Requested { deposit: None, count: 10, len: Some(65536) }) + ); + }); + } + + /// Returns a preimage with a given size and its hash. + fn preimage( + len: usize, + ) -> (BoundedVec>, ::Hash) { + let p = bounded_vec![1; len]; + let h = ::Hashing::hash_of(&p); + (p, h) + } +} diff --git a/frame/preimage/src/mock.rs b/frame/preimage/src/mock.rs index 1a1f05cb9c088..ce74ea65bd8aa 100644 --- a/frame/preimage/src/mock.rs +++ b/frame/preimage/src/mock.rs @@ -57,8 +57,8 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = RocksDbWeight; - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -66,7 +66,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -81,7 +81,7 @@ impl frame_system::Config for Test { impl pallet_balances::Config for Test { type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<5>; type AccountStore = System; @@ -102,10 +102,9 @@ ord_parameter_types! { impl Config for Test { type WeightInfo = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureSignedBy; - type MaxSize = ConstU32<1024>; type BaseDeposit = ConstU64<2>; type ByteDeposit = ConstU64<1>; } diff --git a/frame/preimage/src/tests.rs b/frame/preimage/src/tests.rs index 721bb128de239..f480b9c36b670 100644 --- a/frame/preimage/src/tests.rs +++ b/frame/preimage/src/tests.rs @@ -17,16 +17,40 @@ //! # Scheduler tests. +#![cfg(test)] + use super::*; use crate::mock::*; -use frame_support::{assert_noop, assert_ok}; +use frame_support::{ + assert_err, assert_noop, assert_ok, assert_storage_noop, bounded_vec, + traits::{Bounded, BoundedInline, Hash as PreimageHash}, + StorageNoopGuard, +}; use pallet_balances::Error as BalancesError; +use sp_core::{blake2_256, H256}; + +/// Returns one `Inline`, `Lookup` and `Legacy` item each with different data and hash. +pub fn make_bounded_values() -> (Bounded>, Bounded>, Bounded>) { + let data: BoundedInline = bounded_vec![1]; + let inline = Bounded::>::Inline(data); + + let data = vec![1, 2]; + let hash: H256 = blake2_256(&data[..]).into(); + let len = data.len() as u32; + let lookup = Bounded::>::unrequested(hash, len); + + let data = vec![1, 2, 3]; + let hash: H256 = blake2_256(&data[..]).into(); + let legacy = Bounded::>::Legacy { hash, dummy: Default::default() }; + + (inline, lookup, legacy) +} #[test] fn user_note_preimage_works() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); assert_eq!(Balances::reserved_balance(2), 3); assert_eq!(Balances::free_balance(2), 97); @@ -35,11 +59,11 @@ fn user_note_preimage_works() { assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); assert_noop!( - Preimage::note_preimage(Origin::signed(2), vec![1]), + Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1]), Error::::AlreadyNoted ); assert_noop!( - Preimage::note_preimage(Origin::signed(0), vec![2]), + Preimage::note_preimage(RuntimeOrigin::signed(0), vec![2]), BalancesError::::InsufficientBalance ); }); @@ -48,7 +72,7 @@ fn user_note_preimage_works() { #[test] fn manager_note_preimage_works() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1])); assert_eq!(Balances::reserved_balance(1), 0); assert_eq!(Balances::free_balance(1), 100); @@ -56,29 +80,26 @@ fn manager_note_preimage_works() { assert!(Preimage::have_preimage(&h)); assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); - assert_noop!( - Preimage::note_preimage(Origin::signed(1), vec![1]), - Error::::AlreadyNoted - ); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1])); }); } #[test] fn user_unnote_preimage_works() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); assert_noop!( - Preimage::unnote_preimage(Origin::signed(3), hashed([1])), + Preimage::unnote_preimage(RuntimeOrigin::signed(3), hashed([1])), Error::::NotAuthorized ); assert_noop!( - Preimage::unnote_preimage(Origin::signed(2), hashed([2])), + Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([2])), Error::::NotNoted ); - assert_ok!(Preimage::unnote_preimage(Origin::signed(2), hashed([1]))); + assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1]))); assert_noop!( - Preimage::unnote_preimage(Origin::signed(2), hashed([1])), + Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1])), Error::::NotNoted ); @@ -91,10 +112,10 @@ fn user_unnote_preimage_works() { #[test] fn manager_unnote_preimage_works() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); - assert_ok!(Preimage::unnote_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1])); + assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1]))); assert_noop!( - Preimage::unnote_preimage(Origin::signed(1), hashed([1])), + Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1])), Error::::NotNoted ); @@ -107,17 +128,17 @@ fn manager_unnote_preimage_works() { #[test] fn manager_unnote_user_preimage_works() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); assert_noop!( - Preimage::unnote_preimage(Origin::signed(3), hashed([1])), + Preimage::unnote_preimage(RuntimeOrigin::signed(3), hashed([1])), Error::::NotAuthorized ); assert_noop!( - Preimage::unnote_preimage(Origin::signed(2), hashed([2])), + Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([2])), Error::::NotNoted ); - assert_ok!(Preimage::unnote_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1]))); let h = hashed([1]); assert!(!Preimage::have_preimage(&h)); @@ -128,32 +149,35 @@ fn manager_unnote_user_preimage_works() { #[test] fn requested_then_noted_preimage_cannot_be_unnoted() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); - assert_noop!( - Preimage::unnote_preimage(Origin::signed(1), hashed([1])), - Error::::Requested - ); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![1])); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(1), hashed([1]))); + // it's still here. let h = hashed([1]); assert!(Preimage::have_preimage(&h)); assert_eq!(Preimage::get_preimage(&h), Some(vec![1])); + + // now it's gone + assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert!(!Preimage::have_preimage(&hashed([1]))); }); } #[test] fn request_note_order_makes_no_difference() { let one_way = new_test_ext().execute_with(|| { - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); - assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); ( StatusFor::::iter().collect::>(), PreimageFor::::iter().collect::>(), ) }); new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(1), vec![1])); - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1]))); let other_way = ( StatusFor::::iter().collect::>(), PreimageFor::::iter().collect::>(), @@ -165,8 +189,8 @@ fn request_note_order_makes_no_difference() { #[test] fn requested_then_user_noted_preimage_is_free() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); assert_eq!(Balances::reserved_balance(2), 0); assert_eq!(Balances::free_balance(2), 100); @@ -179,16 +203,17 @@ fn requested_then_user_noted_preimage_is_free() { #[test] fn request_user_note_order_makes_no_difference() { let one_way = new_test_ext().execute_with(|| { - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); ( StatusFor::::iter().collect::>(), PreimageFor::::iter().collect::>(), ) }); new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1]))); let other_way = ( StatusFor::::iter().collect::>(), PreimageFor::::iter().collect::>(), @@ -200,20 +225,20 @@ fn request_user_note_order_makes_no_difference() { #[test] fn unrequest_preimage_works() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); assert_noop!( - Preimage::unrequest_preimage(Origin::signed(1), hashed([2])), + Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([2])), Error::::NotRequested ); - assert_ok!(Preimage::unrequest_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1]))); assert!(Preimage::have_preimage(&hashed([1]))); - assert_ok!(Preimage::unrequest_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1]))); assert_noop!( - Preimage::unrequest_preimage(Origin::signed(1), hashed([1])), + Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1])), Error::::NotRequested ); }); @@ -222,12 +247,244 @@ fn unrequest_preimage_works() { #[test] fn user_noted_then_requested_preimage_is_refunded_once_only() { new_test_ext().execute_with(|| { - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1; 3])); - assert_ok!(Preimage::note_preimage(Origin::signed(2), vec![1])); - assert_ok!(Preimage::request_preimage(Origin::signed(1), hashed([1]))); - assert_ok!(Preimage::unrequest_preimage(Origin::signed(1), hashed([1]))); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1; 3])); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(2), vec![1])); + assert_ok!(Preimage::request_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::unrequest_preimage(RuntimeOrigin::signed(1), hashed([1]))); + assert_ok!(Preimage::unnote_preimage(RuntimeOrigin::signed(2), hashed([1]))); // Still have reserve from `vec[1; 3]`. assert_eq!(Balances::reserved_balance(2), 5); assert_eq!(Balances::free_balance(2), 95); }); } + +#[test] +fn noted_preimage_use_correct_map() { + new_test_ext().execute_with(|| { + // Add one preimage per bucket... + for i in 0..7 { + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![0; 128 << (i * 2)])); + } + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(1), vec![0; MAX_SIZE as usize])); + assert_eq!(PreimageFor::::iter().count(), 8); + + // All are present + assert_eq!(StatusFor::::iter().count(), 8); + + // Now start removing them again... + for i in 0..7 { + assert_ok!(Preimage::unnote_preimage( + RuntimeOrigin::signed(1), + hashed(vec![0; 128 << (i * 2)]) + )); + } + assert_eq!(PreimageFor::::iter().count(), 1); + assert_ok!(Preimage::unnote_preimage( + RuntimeOrigin::signed(1), + hashed(vec![0; MAX_SIZE as usize]) + )); + assert_eq!(PreimageFor::::iter().count(), 0); + + // All are gone + assert_eq!(StatusFor::::iter().count(), 0); + }); +} + +/// The `StorePreimage` and `QueryPreimage` traits work together. +#[test] +fn query_and_store_preimage_workflow() { + new_test_ext().execute_with(|| { + let _guard = StorageNoopGuard::default(); + let data: Vec = vec![1; 512]; + let encoded = data.encode(); + + // Bound an unbound value. + let bound = Preimage::bound(data.clone()).unwrap(); + let (len, hash) = (bound.len().unwrap(), bound.hash()); + + assert_eq!(hash, blake2_256(&encoded).into()); + assert_eq!(bound.len(), Some(len)); + assert!(bound.lookup_needed(), "Should not be Inlined"); + assert_eq!(bound.lookup_len(), Some(len)); + + // The value is requested and available. + assert!(Preimage::is_requested(&hash)); + assert!(::have(&bound)); + assert_eq!(Preimage::len(&hash), Some(len)); + + // It can be fetched with length. + assert_eq!(Preimage::fetch(&hash, Some(len)).unwrap(), encoded); + // ... and without length. + assert_eq!(Preimage::fetch(&hash, None).unwrap(), encoded); + // ... but not with wrong length. + assert_err!(Preimage::fetch(&hash, Some(0)), DispatchError::Unavailable); + + // It can be peeked and decoded correctly. + assert_eq!(Preimage::peek::>(&bound).unwrap(), (data.clone(), Some(len))); + // Request it two more times. + assert_eq!(Preimage::pick::>(hash, len), bound); + Preimage::request(&hash); + // It is requested thrice. + assert!(matches!( + StatusFor::::get(&hash).unwrap(), + RequestStatus::Requested { count: 3, .. } + )); + + // It can be realized and decoded correctly. + assert_eq!(Preimage::realize::>(&bound).unwrap(), (data.clone(), Some(len))); + assert!(matches!( + StatusFor::::get(&hash).unwrap(), + RequestStatus::Requested { count: 2, .. } + )); + // Dropping should unrequest. + Preimage::drop(&bound); + assert!(matches!( + StatusFor::::get(&hash).unwrap(), + RequestStatus::Requested { count: 1, .. } + )); + + // Is still available. + assert!(::have(&bound)); + // Manually unnote it. + Preimage::unnote(&hash); + // Is not available anymore. + assert!(!::have(&bound)); + assert_err!(Preimage::fetch(&hash, Some(len)), DispatchError::Unavailable); + // And not requested since the traits assume permissioned origin. + assert!(!Preimage::is_requested(&hash)); + + // No storage changes remain. Checked by `StorageNoopGuard`. + }); +} + +/// The request function behaves as expected. +#[test] +fn query_preimage_request_works() { + new_test_ext().execute_with(|| { + let _guard = StorageNoopGuard::default(); + let data: Vec = vec![1; 10]; + let hash: PreimageHash = blake2_256(&data[..]).into(); + + // Request the preimage. + ::request(&hash); + + // The preimage is requested with unknown length and cannot be fetched. + assert!(::is_requested(&hash)); + assert!(::len(&hash).is_none()); + assert_noop!(::fetch(&hash, None), DispatchError::Unavailable); + + // Request again. + ::request(&hash); + // The preimage is still requested. + assert!(::is_requested(&hash)); + assert!(::len(&hash).is_none()); + assert_noop!(::fetch(&hash, None), DispatchError::Unavailable); + // But there is only one entry in the map. + assert_eq!(StatusFor::::iter().count(), 1); + + // Un-request the preimage. + ::unrequest(&hash); + // It is still requested. + assert!(::is_requested(&hash)); + // Un-request twice. + ::unrequest(&hash); + // It is not requested anymore. + assert!(!::is_requested(&hash)); + // And there is no entry in the map. + assert_eq!(StatusFor::::iter().count(), 0); + }); +} + +/// The `QueryPreimage` functions can be used together with `Bounded` values. +#[test] +fn query_preimage_hold_and_drop_work() { + new_test_ext().execute_with(|| { + let _guard = StorageNoopGuard::default(); + let (inline, lookup, legacy) = make_bounded_values(); + + // `hold` does nothing for `Inline` values. + assert_storage_noop!(::hold(&inline)); + // `hold` requests `Lookup` values. + ::hold(&lookup); + assert!(::is_requested(&lookup.hash())); + // `hold` requests `Legacy` values. + ::hold(&legacy); + assert!(::is_requested(&legacy.hash())); + + // There are two values requested in total. + assert_eq!(StatusFor::::iter().count(), 2); + + // Cleanup by dropping both. + ::drop(&lookup); + assert!(!::is_requested(&lookup.hash())); + ::drop(&legacy); + assert!(!::is_requested(&legacy.hash())); + + // There are no values requested anymore. + assert_eq!(StatusFor::::iter().count(), 0); + }); +} + +/// The `StorePreimage` trait works as expected. +#[test] +fn store_preimage_basic_works() { + new_test_ext().execute_with(|| { + let _guard = StorageNoopGuard::default(); + let data: Vec = vec![1; 512]; // Too large to inline. + let encoded = Cow::from(data.encode()); + + // Bound the data. + let bound = ::bound(data.clone()).unwrap(); + // The preimage can be peeked. + assert_ok!(::peek(&bound)); + // Un-note the preimage. + ::unnote(&bound.hash()); + // The preimage cannot be peeked anymore. + assert_err!(::peek(&bound), DispatchError::Unavailable); + // Noting the wrong pre-image does not make it peek-able. + assert_ok!(::note(Cow::Borrowed(&data))); + assert_err!(::peek(&bound), DispatchError::Unavailable); + + // Manually note the preimage makes it peek-able again. + assert_ok!(::note(encoded.clone())); + // Noting again works. + assert_ok!(::note(encoded)); + assert_ok!(::peek(&bound)); + + // Cleanup. + ::unnote(&bound.hash()); + let data_hash = blake2_256(&data); + ::unnote(&data_hash.into()); + + // No storage changes remain. Checked by `StorageNoopGuard`. + }); +} + +#[test] +fn store_preimage_note_too_large_errors() { + new_test_ext().execute_with(|| { + // Works with `MAX_LENGTH`. + let len = ::MAX_LENGTH; + let data = vec![0u8; len]; + assert_ok!(::note(data.into())); + + // Errors with `MAX_LENGTH+1`. + let data = vec![0u8; len + 1]; + assert_err!(::note(data.into()), DispatchError::Exhausted); + }); +} + +#[test] +fn store_preimage_bound_too_large_errors() { + new_test_ext().execute_with(|| { + // Using `MAX_LENGTH` number of bytes in a vector does not work + // since SCALE prepends the length. + let len = ::MAX_LENGTH; + let data: Vec = vec![0; len]; + assert_err!(::bound(data.clone()), DispatchError::Exhausted); + + // Works with `MAX_LENGTH-4`. + let data: Vec = vec![0; len - 4]; + assert_ok!(::bound(data.clone())); + }); +} diff --git a/frame/preimage/src/weights.rs b/frame/preimage/src/weights.rs index ad9e3e569e733..186c41b798c6b 100644 --- a/frame/preimage/src/weights.rs +++ b/frame/preimage/src/weights.rs @@ -18,22 +18,24 @@ //! Autogenerated weights for pallet_preimage //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-10-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_preimage // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --pallet=pallet_preimage +// --chain=dev // --output=./frame/preimage/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -61,88 +63,90 @@ pub trait WeightInfo { /// Weights for pallet_preimage using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) + Weight::from_ref_time(32_591_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) + .saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:0) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + /// The range of component `s` is `[0, 4194304]`. fn note_requested_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) + Weight::from_ref_time(23_350_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(Weight::from_ref_time(1_681 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:0) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + /// The range of component `s` is `[0, 4194304]`. fn note_no_deposit_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) + Weight::from_ref_time(21_436_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + .saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64)) + .saturating_add(T::DbWeight::get().reads(1 as u64)) + .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - Weight::from_ref_time(44_380_000 as u64) + Weight::from_ref_time(44_567_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - Weight::from_ref_time(30_280_000 as u64) + Weight::from_ref_time(30_065_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - Weight::from_ref_time(42_809_000 as u64) + Weight::from_ref_time(28_470_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - Weight::from_ref_time(28_964_000 as u64) + Weight::from_ref_time(14_601_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - Weight::from_ref_time(17_555_000 as u64) + Weight::from_ref_time(20_121_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - Weight::from_ref_time(7_745_000 as u64) + Weight::from_ref_time(9_440_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - Weight::from_ref_time(29_758_000 as u64) + Weight::from_ref_time(29_013_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - Weight::from_ref_time(18_360_000 as u64) + Weight::from_ref_time(9_223_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - Weight::from_ref_time(7_439_000 as u64) + Weight::from_ref_time(9_252_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -150,88 +154,90 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) + Weight::from_ref_time(32_591_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) + .saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:0) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + /// The range of component `s` is `[0, 4194304]`. fn note_requested_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) + Weight::from_ref_time(23_350_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(Weight::from_ref_time(1_681 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:0) + // Storage: Preimage StatusFor (r:1 w:1) + // Storage: Preimage PreimageFor (r:0 w:1) + /// The range of component `s` is `[0, 4194304]`. fn note_no_deposit_preimage(s: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) + Weight::from_ref_time(21_436_000 as u64) // Standard Error: 0 - .saturating_add(Weight::from_ref_time(2_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + .saturating_add(Weight::from_ref_time(1_680 as u64).saturating_mul(s as u64)) + .saturating_add(RocksDbWeight::get().reads(1 as u64)) + .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_preimage() -> Weight { - Weight::from_ref_time(44_380_000 as u64) + Weight::from_ref_time(44_567_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unnote_no_deposit_preimage() -> Weight { - Weight::from_ref_time(30_280_000 as u64) + Weight::from_ref_time(30_065_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_preimage() -> Weight { - Weight::from_ref_time(42_809_000 as u64) + Weight::from_ref_time(28_470_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_no_deposit_preimage() -> Weight { - Weight::from_ref_time(28_964_000 as u64) + Weight::from_ref_time(14_601_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_unnoted_preimage() -> Weight { - Weight::from_ref_time(17_555_000 as u64) + Weight::from_ref_time(20_121_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn request_requested_preimage() -> Weight { - Weight::from_ref_time(7_745_000 as u64) + Weight::from_ref_time(9_440_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_preimage() -> Weight { - Weight::from_ref_time(29_758_000 as u64) + Weight::from_ref_time(29_013_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Preimage PreimageFor (r:0 w:1) fn unrequest_unnoted_preimage() -> Weight { - Weight::from_ref_time(18_360_000 as u64) + Weight::from_ref_time(9_223_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Preimage StatusFor (r:1 w:1) fn unrequest_multi_referenced_preimage() -> Weight { - Weight::from_ref_time(7_439_000 as u64) + Weight::from_ref_time(9_252_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } diff --git a/frame/proxy/Cargo.toml b/frame/proxy/Cargo.toml index aaacaa23021e7..afec89ad40fb8 100644 --- a/frame/proxy/Cargo.toml +++ b/frame/proxy/Cargo.toml @@ -30,6 +30,7 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/proxy/src/benchmarking.rs b/frame/proxy/src/benchmarking.rs index c01a8da000c09..58c0cb73011df 100644 --- a/frame/proxy/src/benchmarking.rs +++ b/frame/proxy/src/benchmarking.rs @@ -27,7 +27,7 @@ use sp_runtime::traits::Bounded; const SEED: u32 = 0; -fn assert_last_event(generic_event: ::Event) { +fn assert_last_event(generic_event: ::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } @@ -88,7 +88,7 @@ benchmarks! { // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real); - let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); }: _(RawOrigin::Signed(caller), real_lookup, Some(T::ProxyType::default()), Box::new(call)) verify { assert_last_event::(Event::ProxyExecuted { result: Ok(()) }.into()) @@ -98,14 +98,14 @@ benchmarks! { let a in 0 .. T::MaxPending::get() - 1; let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; // In this case the caller is the "target" proxy - let caller: T::AccountId = account("anonymous", 0, SEED); + let caller: T::AccountId = account("pure", 0, SEED); let delegate: T::AccountId = account("target", p - 1, SEED); let delegate_lookup = T::Lookup::unlookup(delegate.clone()); T::Currency::make_free_balance_be(&delegate, BalanceOf::::max_value() / 2u32.into()); // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real); - let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::announce( RawOrigin::Signed(delegate.clone()).into(), real_lookup.clone(), @@ -126,7 +126,7 @@ benchmarks! { // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real); - let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::announce( RawOrigin::Signed(caller.clone()).into(), real_lookup.clone(), @@ -149,7 +149,7 @@ benchmarks! { // ... and "real" is the traditional caller. This is not a typo. let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real.clone()); - let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::announce( RawOrigin::Signed(caller.clone()).into(), real_lookup, @@ -172,7 +172,7 @@ benchmarks! { let real: T::AccountId = whitelisted_caller(); let real_lookup = T::Lookup::unlookup(real.clone()); add_announcements::(a, Some(caller.clone()), None)?; - let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); let call_hash = T::CallHasher::hash_of(&call); }: _(RawOrigin::Signed(caller.clone()), real_lookup, call_hash) verify { @@ -218,7 +218,7 @@ benchmarks! { assert_eq!(proxies.len() as u32, 0); } - anonymous { + create_pure { let p in 1 .. (T::MaxProxies::get() - 1) => add_proxies::(p, None)?; let caller: T::AccountId = whitelisted_caller(); }: _( @@ -228,22 +228,22 @@ benchmarks! { 0 ) verify { - let anon_account = Pallet::::anonymous_account(&caller, &T::ProxyType::default(), 0, None); - assert_last_event::(Event::AnonymousCreated { - anonymous: anon_account, + let pure_account = Pallet::::pure_account(&caller, &T::ProxyType::default(), 0, None); + assert_last_event::(Event::PureCreated { + pure: pure_account, who: caller, proxy_type: T::ProxyType::default(), disambiguation_index: 0, }.into()); } - kill_anonymous { + kill_pure { let p in 0 .. (T::MaxProxies::get() - 2); let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); - Pallet::::anonymous( + Pallet::::create_pure( RawOrigin::Signed(whitelisted_caller()).into(), T::ProxyType::default(), T::BlockNumber::zero(), @@ -251,13 +251,13 @@ benchmarks! { )?; let height = system::Pallet::::block_number(); let ext_index = system::Pallet::::extrinsic_index().unwrap_or(0); - let anon = Pallet::::anonymous_account(&caller, &T::ProxyType::default(), 0, None); + let pure_account = Pallet::::pure_account(&caller, &T::ProxyType::default(), 0, None); - add_proxies::(p, Some(anon.clone()))?; - ensure!(Proxies::::contains_key(&anon), "anon proxy not created"); - }: _(RawOrigin::Signed(anon.clone()), caller_lookup, T::ProxyType::default(), 0, height, ext_index) + add_proxies::(p, Some(pure_account.clone()))?; + ensure!(Proxies::::contains_key(&pure_account), "pure proxy not created"); + }: _(RawOrigin::Signed(pure_account.clone()), caller_lookup, T::ProxyType::default(), 0, height, ext_index) verify { - assert!(!Proxies::::contains_key(&anon)); + assert!(!Proxies::::contains_key(&pure_account)); } impl_benchmark_test_suite!(Proxy, crate::tests::new_test_ext(), crate::tests::Test); diff --git a/frame/proxy/src/lib.rs b/frame/proxy/src/lib.rs index 2d8dfc238bcd0..5c07a2b012243 100644 --- a/frame/proxy/src/lib.rs +++ b/frame/proxy/src/lib.rs @@ -35,10 +35,9 @@ pub mod weights; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - dispatch::DispatchError, + dispatch::{DispatchError, GetDispatchInfo}, ensure, traits::{Currency, Get, InstanceFilter, IsSubType, IsType, OriginTrait, ReservableCurrency}, - weights::GetDispatchInfo, RuntimeDebug, }; use frame_system::{self as system}; @@ -110,15 +109,15 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The overarching call type. - type Call: Parameter - + Dispatchable + type RuntimeCall: Parameter + + Dispatchable + GetDispatchInfo + From> + IsSubType> - + IsType<::Call>; + + IsType<::RuntimeCall>; /// The currency mechanism. type Currency: ReservableCurrency; @@ -131,7 +130,7 @@ pub mod pallet { + Member + Ord + PartialOrd - + InstanceFilter<::Call> + + InstanceFilter<::RuntimeCall> + Default + MaxEncodedLen; @@ -192,10 +191,6 @@ pub mod pallet { /// - `real`: The account that the proxy will make a call on behalf of. /// - `force_proxy_type`: Specify the exact proxy type to be used and checked for this call. /// - `call`: The call to be made by the `real` account. - /// - /// # - /// Weight is a function of the number of proxies the user has (P). - /// # #[pallet::weight({ let di = call.get_dispatch_info(); (T::WeightInfo::proxy(T::MaxProxies::get()) @@ -208,7 +203,7 @@ pub mod pallet { origin: OriginFor, real: AccountIdLookupOf, force_proxy_type: Option, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResult { let who = ensure_signed(origin)?; let real = T::Lookup::lookup(real)?; @@ -229,10 +224,6 @@ pub mod pallet { /// - `proxy_type`: The permissions allowed for this proxy account. /// - `delay`: The announcement period required of the initial proxy. Will generally be /// zero. - /// - /// # - /// Weight is a function of the number of proxies the user has (P). - /// # #[pallet::weight(T::WeightInfo::add_proxy(T::MaxProxies::get()))] pub fn add_proxy( origin: OriginFor, @@ -252,10 +243,6 @@ pub mod pallet { /// Parameters: /// - `proxy`: The account that the `caller` would like to remove as a proxy. /// - `proxy_type`: The permissions currently enabled for the removed proxy account. - /// - /// # - /// Weight is a function of the number of proxies the user has (P). - /// # #[pallet::weight(T::WeightInfo::remove_proxy(T::MaxProxies::get()))] pub fn remove_proxy( origin: OriginFor, @@ -272,12 +259,8 @@ pub mod pallet { /// /// The dispatch origin for this call must be _Signed_. /// - /// WARNING: This may be called on accounts created by `anonymous`, however if done, then + /// WARNING: This may be called on accounts created by `pure`, however if done, then /// the unreserved fees will be inaccessible. **All access to this account will be lost.** - /// - /// # - /// Weight is a function of the number of proxies the user has (P). - /// # #[pallet::weight(T::WeightInfo::remove_proxies(T::MaxProxies::get()))] pub fn remove_proxies(origin: OriginFor) -> DispatchResult { let who = ensure_signed(origin)?; @@ -305,13 +288,8 @@ pub mod pallet { /// same sender, with the same parameters. /// /// Fails if there are insufficient funds to pay for deposit. - /// - /// # - /// Weight is a function of the number of proxies the user has (P). - /// # - /// TODO: Might be over counting 1 read - #[pallet::weight(T::WeightInfo::anonymous(T::MaxProxies::get()))] - pub fn anonymous( + #[pallet::weight(T::WeightInfo::create_pure(T::MaxProxies::get()))] + pub fn create_pure( origin: OriginFor, proxy_type: T::ProxyType, delay: T::BlockNumber, @@ -319,8 +297,8 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin)?; - let anonymous = Self::anonymous_account(&who, &proxy_type, index, None); - ensure!(!Proxies::::contains_key(&anonymous), Error::::Duplicate); + let pure = Self::pure_account(&who, &proxy_type, index, None); + ensure!(!Proxies::::contains_key(&pure), Error::::Duplicate); let proxy_def = ProxyDefinition { delegate: who.clone(), proxy_type: proxy_type.clone(), delay }; @@ -330,9 +308,9 @@ pub mod pallet { let deposit = T::ProxyDepositBase::get() + T::ProxyDepositFactor::get(); T::Currency::reserve(&who, deposit)?; - Proxies::::insert(&anonymous, (bounded_proxies, deposit)); - Self::deposit_event(Event::AnonymousCreated { - anonymous, + Proxies::::insert(&pure, (bounded_proxies, deposit)); + Self::deposit_event(Event::PureCreated { + pure, who, proxy_type, disambiguation_index: index, @@ -341,28 +319,24 @@ pub mod pallet { Ok(()) } - /// Removes a previously spawned anonymous proxy. + /// Removes a previously spawned pure proxy. /// /// WARNING: **All access to this account will be lost.** Any funds held in it will be /// inaccessible. /// /// Requires a `Signed` origin, and the sender account must have been created by a call to - /// `anonymous` with corresponding parameters. - /// - /// - `spawner`: The account that originally called `anonymous` to create this account. - /// - `index`: The disambiguation index originally passed to `anonymous`. Probably `0`. - /// - `proxy_type`: The proxy type originally passed to `anonymous`. - /// - `height`: The height of the chain when the call to `anonymous` was processed. - /// - `ext_index`: The extrinsic index in which the call to `anonymous` was processed. - /// - /// Fails with `NoPermission` in case the caller is not a previously created anonymous - /// account whose `anonymous` call has corresponding parameters. - /// - /// # - /// Weight is a function of the number of proxies the user has (P). - /// # - #[pallet::weight(T::WeightInfo::kill_anonymous(T::MaxProxies::get()))] - pub fn kill_anonymous( + /// `pure` with corresponding parameters. + /// + /// - `spawner`: The account that originally called `pure` to create this account. + /// - `index`: The disambiguation index originally passed to `pure`. Probably `0`. + /// - `proxy_type`: The proxy type originally passed to `pure`. + /// - `height`: The height of the chain when the call to `pure` was processed. + /// - `ext_index`: The extrinsic index in which the call to `pure` was processed. + /// + /// Fails with `NoPermission` in case the caller is not a previously created pure + /// account whose `pure` call has corresponding parameters. + #[pallet::weight(T::WeightInfo::kill_pure(T::MaxProxies::get()))] + pub fn kill_pure( origin: OriginFor, spawner: AccountIdLookupOf, proxy_type: T::ProxyType, @@ -374,7 +348,7 @@ pub mod pallet { let spawner = T::Lookup::lookup(spawner)?; let when = (height, ext_index); - let proxy = Self::anonymous_account(&spawner, &proxy_type, index, Some(when)); + let proxy = Self::pure_account(&spawner, &proxy_type, index, Some(when)); ensure!(proxy == who, Error::::NoPermission); let (_, deposit) = Proxies::::take(&who); @@ -398,12 +372,6 @@ pub mod pallet { /// Parameters: /// - `real`: The account that the proxy will make a call on behalf of. /// - `call_hash`: The hash of the call to be made by the `real` account. - /// - /// # - /// Weight is a function of: - /// - A: the number of announcements made. - /// - P: the number of proxies the user has. - /// # #[pallet::weight(T::WeightInfo::announce(T::MaxPending::get(), T::MaxProxies::get()))] pub fn announce( origin: OriginFor, @@ -453,12 +421,6 @@ pub mod pallet { /// Parameters: /// - `real`: The account that the proxy will make a call on behalf of. /// - `call_hash`: The hash of the call to be made by the `real` account. - /// - /// # - /// Weight is a function of: - /// - A: the number of announcements made. - /// - P: the number of proxies the user has. - /// # #[pallet::weight(T::WeightInfo::remove_announcement( T::MaxPending::get(), T::MaxProxies::get() @@ -485,12 +447,6 @@ pub mod pallet { /// Parameters: /// - `delegate`: The account that previously announced the call. /// - `call_hash`: The hash of the call to be made. - /// - /// # - /// Weight is a function of: - /// - A: the number of announcements made. - /// - P: the number of proxies the user has. - /// # #[pallet::weight(T::WeightInfo::reject_announcement( T::MaxPending::get(), T::MaxProxies::get() @@ -520,12 +476,6 @@ pub mod pallet { /// - `real`: The account that the proxy will make a call on behalf of. /// - `force_proxy_type`: Specify the exact proxy type to be used and checked for this call. /// - `call`: The call to be made by the `real` account. - /// - /// # - /// Weight is a function of: - /// - A: the number of announcements made. - /// - P: the number of proxies the user has. - /// # #[pallet::weight({ let di = call.get_dispatch_info(); (T::WeightInfo::proxy_announced(T::MaxPending::get(), T::MaxProxies::get()) @@ -539,7 +489,7 @@ pub mod pallet { delegate: AccountIdLookupOf, real: AccountIdLookupOf, force_proxy_type: Option, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResult { ensure_signed(origin)?; let delegate = T::Lookup::lookup(delegate)?; @@ -566,10 +516,10 @@ pub mod pallet { pub enum Event { /// A proxy was executed correctly, with the given. ProxyExecuted { result: DispatchResult }, - /// Anonymous account has been created by new proxy with given + /// A pure account has been created by new proxy with given /// disambiguation index and proxy type. - AnonymousCreated { - anonymous: T::AccountId, + PureCreated { + pure: T::AccountId, who: T::AccountId, proxy_type: T::ProxyType, disambiguation_index: u16, @@ -643,7 +593,7 @@ pub mod pallet { } impl Pallet { - /// Calculate the address of an anonymous account. + /// Calculate the address of an pure account. /// /// - `who`: The spawner account. /// - `proxy_type`: The type of the proxy that the sender will be registered as over the @@ -652,9 +602,9 @@ impl Pallet { /// - `index`: A disambiguation index, in case this is called multiple times in the same /// transaction (e.g. with `utility::batch`). Unless you're using `batch` you probably just /// want to use `0`. - /// - `maybe_when`: The block height and extrinsic index of when the anonymous account was + /// - `maybe_when`: The block height and extrinsic index of when the pure account was /// created. None to use current block height and extrinsic index. - pub fn anonymous_account( + pub fn pure_account( who: &T::AccountId, proxy_type: &T::ProxyType, index: u16, @@ -817,12 +767,12 @@ impl Pallet { fn do_proxy( def: ProxyDefinition, real: T::AccountId, - call: ::Call, + call: ::RuntimeCall, ) { // This is a freshly authenticated new account, the origin restrictions doesn't apply. - let mut origin: T::Origin = frame_system::RawOrigin::Signed(real).into(); - origin.add_filter(move |c: &::Call| { - let c = ::Call::from_ref(c); + let mut origin: T::RuntimeOrigin = frame_system::RawOrigin::Signed(real).into(); + origin.add_filter(move |c: &::RuntimeCall| { + let c = ::RuntimeCall::from_ref(c); // We make sure the proxy call does access this pallet to change modify proxies. match c.is_sub_type() { // Proxy call cannot add or remove a proxy with more permissions than it already @@ -831,9 +781,9 @@ impl Pallet { Some(Call::remove_proxy { ref proxy_type, .. }) if !def.proxy_type.is_superset(proxy_type) => false, - // Proxy call cannot remove all proxies or kill anonymous proxies unless it has full + // Proxy call cannot remove all proxies or kill pure proxies unless it has full // permissions. - Some(Call::remove_proxies { .. }) | Some(Call::kill_anonymous { .. }) + Some(Call::remove_proxies { .. }) | Some(Call::kill_pure { .. }) if def.proxy_type != T::ProxyType::default() => false, _ => def.proxy_type.filter(c), diff --git a/frame/proxy/src/tests.rs b/frame/proxy/src/tests.rs index b8d5a55705efa..17bc7bcb92ee1 100644 --- a/frame/proxy/src/tests.rs +++ b/frame/proxy/src/tests.rs @@ -61,16 +61,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -88,15 +88,15 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } impl pallet_utility::Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; type WeightInfo = (); } @@ -124,14 +124,14 @@ impl Default for ProxyType { Self::Any } } -impl InstanceFilter for ProxyType { - fn filter(&self, c: &Call) -> bool { +impl InstanceFilter for ProxyType { + fn filter(&self, c: &RuntimeCall) -> bool { match self { ProxyType::Any => true, ProxyType::JustTransfer => { - matches!(c, Call::Balances(pallet_balances::Call::transfer { .. })) + matches!(c, RuntimeCall::Balances(pallet_balances::Call::transfer { .. })) }, - ProxyType::JustUtility => matches!(c, Call::Utility { .. }), + ProxyType::JustUtility => matches!(c, RuntimeCall::Utility { .. }), } } fn is_superset(&self, o: &Self) -> bool { @@ -139,19 +139,19 @@ impl InstanceFilter for ProxyType { } } pub struct BaseFilter; -impl Contains for BaseFilter { - fn contains(c: &Call) -> bool { +impl Contains for BaseFilter { + fn contains(c: &RuntimeCall) -> bool { match *c { // Remark is used as a no-op call in the benchmarking - Call::System(SystemCall::remark { .. }) => true, - Call::System(_) => false, + RuntimeCall::System(SystemCall::remark { .. }) => true, + RuntimeCall::System(_) => false, _ => true, } } } impl Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type Currency = Balances; type ProxyType = ProxyType; type ProxyDepositBase = ConstU64<1>; @@ -183,7 +183,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { ext } -fn last_events(n: usize) -> Vec { +fn last_events(n: usize) -> Vec { system::Pallet::::events() .into_iter() .rev() @@ -193,18 +193,18 @@ fn last_events(n: usize) -> Vec { .collect() } -fn expect_events(e: Vec) { +fn expect_events(e: Vec) { assert_eq!(last_events(e.len()), e); } -fn call_transfer(dest: u64, value: u64) -> Call { - Call::Balances(BalancesCall::transfer { dest, value }) +fn call_transfer(dest: u64, value: u64) -> RuntimeCall { + RuntimeCall::Balances(BalancesCall::transfer { dest, value }) } #[test] fn announcement_works() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(Origin::signed(1), 3, ProxyType::Any, 1)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 1)); System::assert_last_event( ProxyEvent::ProxyAdded { delegator: 1, @@ -214,10 +214,10 @@ fn announcement_works() { } .into(), ); - assert_ok!(Proxy::add_proxy(Origin::signed(2), 3, ProxyType::Any, 1)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(2), 3, ProxyType::Any, 1)); assert_eq!(Balances::reserved_balance(3), 0); - assert_ok!(Proxy::announce(Origin::signed(3), 1, [1; 32].into())); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 1, [1; 32].into())); let announcements = Announcements::::get(3); assert_eq!( announcements.0, @@ -225,7 +225,7 @@ fn announcement_works() { ); assert_eq!(Balances::reserved_balance(3), announcements.1); - assert_ok!(Proxy::announce(Origin::signed(3), 2, [2; 32].into())); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 2, [2; 32].into())); let announcements = Announcements::::get(3); assert_eq!( announcements.0, @@ -236,20 +236,23 @@ fn announcement_works() { ); assert_eq!(Balances::reserved_balance(3), announcements.1); - assert_noop!(Proxy::announce(Origin::signed(3), 2, [3; 32].into()), Error::::TooMany); + assert_noop!( + Proxy::announce(RuntimeOrigin::signed(3), 2, [3; 32].into()), + Error::::TooMany + ); }); } #[test] fn remove_announcement_works() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(Origin::signed(1), 3, ProxyType::Any, 1)); - assert_ok!(Proxy::add_proxy(Origin::signed(2), 3, ProxyType::Any, 1)); - assert_ok!(Proxy::announce(Origin::signed(3), 1, [1; 32].into())); - assert_ok!(Proxy::announce(Origin::signed(3), 2, [2; 32].into())); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 1)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(2), 3, ProxyType::Any, 1)); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 1, [1; 32].into())); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 2, [2; 32].into())); let e = Error::::NotFound; - assert_noop!(Proxy::remove_announcement(Origin::signed(3), 1, [0; 32].into()), e); - assert_ok!(Proxy::remove_announcement(Origin::signed(3), 1, [1; 32].into())); + assert_noop!(Proxy::remove_announcement(RuntimeOrigin::signed(3), 1, [0; 32].into()), e); + assert_ok!(Proxy::remove_announcement(RuntimeOrigin::signed(3), 1, [1; 32].into())); let announcements = Announcements::::get(3); assert_eq!( announcements.0, @@ -262,15 +265,15 @@ fn remove_announcement_works() { #[test] fn reject_announcement_works() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(Origin::signed(1), 3, ProxyType::Any, 1)); - assert_ok!(Proxy::add_proxy(Origin::signed(2), 3, ProxyType::Any, 1)); - assert_ok!(Proxy::announce(Origin::signed(3), 1, [1; 32].into())); - assert_ok!(Proxy::announce(Origin::signed(3), 2, [2; 32].into())); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 1)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(2), 3, ProxyType::Any, 1)); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 1, [1; 32].into())); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 2, [2; 32].into())); let e = Error::::NotFound; - assert_noop!(Proxy::reject_announcement(Origin::signed(1), 3, [0; 32].into()), e); + assert_noop!(Proxy::reject_announcement(RuntimeOrigin::signed(1), 3, [0; 32].into()), e); let e = Error::::NotFound; - assert_noop!(Proxy::reject_announcement(Origin::signed(4), 3, [1; 32].into()), e); - assert_ok!(Proxy::reject_announcement(Origin::signed(1), 3, [1; 32].into())); + assert_noop!(Proxy::reject_announcement(RuntimeOrigin::signed(4), 3, [1; 32].into()), e); + assert_ok!(Proxy::reject_announcement(RuntimeOrigin::signed(1), 3, [1; 32].into())); let announcements = Announcements::::get(3); assert_eq!( announcements.0, @@ -283,41 +286,44 @@ fn reject_announcement_works() { #[test] fn announcer_must_be_proxy() { new_test_ext().execute_with(|| { - assert_noop!(Proxy::announce(Origin::signed(2), 1, H256::zero()), Error::::NotProxy); + assert_noop!( + Proxy::announce(RuntimeOrigin::signed(2), 1, H256::zero()), + Error::::NotProxy + ); }); } #[test] fn delayed_requires_pre_announcement() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(Origin::signed(1), 2, ProxyType::Any, 1)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 1)); let call = Box::new(call_transfer(6, 1)); let e = Error::::Unannounced; - assert_noop!(Proxy::proxy(Origin::signed(2), 1, None, call.clone()), e); + assert_noop!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone()), e); let e = Error::::Unannounced; - assert_noop!(Proxy::proxy_announced(Origin::signed(0), 2, 1, None, call.clone()), e); + assert_noop!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 2, 1, None, call.clone()), e); let call_hash = BlakeTwo256::hash_of(&call); - assert_ok!(Proxy::announce(Origin::signed(2), 1, call_hash)); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(2), 1, call_hash)); system::Pallet::::set_block_number(2); - assert_ok!(Proxy::proxy_announced(Origin::signed(0), 2, 1, None, call.clone())); + assert_ok!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 2, 1, None, call.clone())); }); } #[test] fn proxy_announced_removes_announcement_and_returns_deposit() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(Origin::signed(1), 3, ProxyType::Any, 1)); - assert_ok!(Proxy::add_proxy(Origin::signed(2), 3, ProxyType::Any, 1)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 1)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(2), 3, ProxyType::Any, 1)); let call = Box::new(call_transfer(6, 1)); let call_hash = BlakeTwo256::hash_of(&call); - assert_ok!(Proxy::announce(Origin::signed(3), 1, call_hash)); - assert_ok!(Proxy::announce(Origin::signed(3), 2, call_hash)); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 1, call_hash)); + assert_ok!(Proxy::announce(RuntimeOrigin::signed(3), 2, call_hash)); // Too early to execute announced call let e = Error::::Unannounced; - assert_noop!(Proxy::proxy_announced(Origin::signed(0), 3, 1, None, call.clone()), e); + assert_noop!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 3, 1, None, call.clone()), e); system::Pallet::::set_block_number(2); - assert_ok!(Proxy::proxy_announced(Origin::signed(0), 3, 1, None, call.clone())); + assert_ok!(Proxy::proxy_announced(RuntimeOrigin::signed(0), 3, 1, None, call.clone())); let announcements = Announcements::::get(3); assert_eq!(announcements.0, vec![Announcement { real: 2, call_hash, height: 1 }]); assert_eq!(Balances::reserved_balance(3), announcements.1); @@ -328,16 +334,16 @@ fn proxy_announced_removes_announcement_and_returns_deposit() { fn filtering_works() { new_test_ext().execute_with(|| { assert!(Balances::mutate_account(&1, |a| a.free = 1000).is_ok()); - assert_ok!(Proxy::add_proxy(Origin::signed(1), 2, ProxyType::Any, 0)); - assert_ok!(Proxy::add_proxy(Origin::signed(1), 3, ProxyType::JustTransfer, 0)); - assert_ok!(Proxy::add_proxy(Origin::signed(1), 4, ProxyType::JustUtility, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::JustTransfer, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 4, ProxyType::JustUtility, 0)); let call = Box::new(call_transfer(6, 1)); - assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); - assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); - assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); @@ -346,65 +352,70 @@ fn filtering_works() { assert!(Balances::mutate_account(&derivative_id, |a| a.free = 1000).is_ok()); let inner = Box::new(call_transfer(6, 1)); - let call = - Box::new(Call::Utility(UtilityCall::as_derivative { index: 0, call: inner.clone() })); - assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); + let call = Box::new(RuntimeCall::Utility(UtilityCall::as_derivative { + index: 0, + call: inner.clone(), + })); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); - assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); - assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); - let call = Box::new(Call::Utility(UtilityCall::batch { calls: vec![*inner] })); - assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); + let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { calls: vec![*inner] })); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); expect_events(vec![ UtilityEvent::BatchCompleted.into(), ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), ]); - assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); - assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone())); expect_events(vec![ UtilityEvent::BatchInterrupted { index: 0, error: SystemError::CallFiltered.into() } .into(), ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), ]); - let inner = - Box::new(Call::Proxy(ProxyCall::new_call_variant_add_proxy(5, ProxyType::Any, 0))); - let call = Box::new(Call::Utility(UtilityCall::batch { calls: vec![*inner] })); - assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); + let inner = Box::new(RuntimeCall::Proxy(ProxyCall::new_call_variant_add_proxy( + 5, + ProxyType::Any, + 0, + ))); + let call = Box::new(RuntimeCall::Utility(UtilityCall::batch { calls: vec![*inner] })); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); expect_events(vec![ UtilityEvent::BatchCompleted.into(), ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), ]); - assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); - assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone())); expect_events(vec![ UtilityEvent::BatchInterrupted { index: 0, error: SystemError::CallFiltered.into() } .into(), ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), ]); - let call = Box::new(Call::Proxy(ProxyCall::remove_proxies {})); - assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); + let call = Box::new(RuntimeCall::Proxy(ProxyCall::remove_proxies {})); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); - assert_ok!(Proxy::proxy(Origin::signed(4), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); - assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); expect_events(vec![ BalancesEvent::::Unreserved { who: 1, amount: 5 }.into(), ProxyEvent::ProxyExecuted { result: Ok(()) }.into(), @@ -415,27 +426,27 @@ fn filtering_works() { #[test] fn add_remove_proxies_works() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(Origin::signed(1), 2, ProxyType::Any, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 0)); assert_noop!( - Proxy::add_proxy(Origin::signed(1), 2, ProxyType::Any, 0), + Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 0), Error::::Duplicate ); assert_eq!(Balances::reserved_balance(1), 2); - assert_ok!(Proxy::add_proxy(Origin::signed(1), 2, ProxyType::JustTransfer, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::JustTransfer, 0)); assert_eq!(Balances::reserved_balance(1), 3); - assert_ok!(Proxy::add_proxy(Origin::signed(1), 3, ProxyType::Any, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 0)); assert_eq!(Balances::reserved_balance(1), 4); - assert_ok!(Proxy::add_proxy(Origin::signed(1), 4, ProxyType::JustUtility, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 4, ProxyType::JustUtility, 0)); assert_eq!(Balances::reserved_balance(1), 5); assert_noop!( - Proxy::add_proxy(Origin::signed(1), 4, ProxyType::Any, 0), + Proxy::add_proxy(RuntimeOrigin::signed(1), 4, ProxyType::Any, 0), Error::::TooMany ); assert_noop!( - Proxy::remove_proxy(Origin::signed(1), 3, ProxyType::JustTransfer, 0), + Proxy::remove_proxy(RuntimeOrigin::signed(1), 3, ProxyType::JustTransfer, 0), Error::::NotFound ); - assert_ok!(Proxy::remove_proxy(Origin::signed(1), 4, ProxyType::JustUtility, 0)); + assert_ok!(Proxy::remove_proxy(RuntimeOrigin::signed(1), 4, ProxyType::JustUtility, 0)); System::assert_last_event( ProxyEvent::ProxyRemoved { delegator: 1, @@ -446,7 +457,7 @@ fn add_remove_proxies_works() { .into(), ); assert_eq!(Balances::reserved_balance(1), 4); - assert_ok!(Proxy::remove_proxy(Origin::signed(1), 3, ProxyType::Any, 0)); + assert_ok!(Proxy::remove_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 0)); assert_eq!(Balances::reserved_balance(1), 3); System::assert_last_event( ProxyEvent::ProxyRemoved { @@ -457,7 +468,7 @@ fn add_remove_proxies_works() { } .into(), ); - assert_ok!(Proxy::remove_proxy(Origin::signed(1), 2, ProxyType::Any, 0)); + assert_ok!(Proxy::remove_proxy(RuntimeOrigin::signed(1), 2, ProxyType::Any, 0)); assert_eq!(Balances::reserved_balance(1), 2); System::assert_last_event( ProxyEvent::ProxyRemoved { @@ -468,7 +479,7 @@ fn add_remove_proxies_works() { } .into(), ); - assert_ok!(Proxy::remove_proxy(Origin::signed(1), 2, ProxyType::JustTransfer, 0)); + assert_ok!(Proxy::remove_proxy(RuntimeOrigin::signed(1), 2, ProxyType::JustTransfer, 0)); assert_eq!(Balances::reserved_balance(1), 0); System::assert_last_event( ProxyEvent::ProxyRemoved { @@ -480,7 +491,7 @@ fn add_remove_proxies_works() { .into(), ); assert_noop!( - Proxy::add_proxy(Origin::signed(1), 1, ProxyType::Any, 0), + Proxy::add_proxy(RuntimeOrigin::signed(1), 1, ProxyType::Any, 0), Error::::NoSelfProxy ); }); @@ -489,10 +500,10 @@ fn add_remove_proxies_works() { #[test] fn cannot_add_proxy_without_balance() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(Origin::signed(5), 3, ProxyType::Any, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(5), 3, ProxyType::Any, 0)); assert_eq!(Balances::reserved_balance(5), 2); assert_noop!( - Proxy::add_proxy(Origin::signed(5), 4, ProxyType::Any, 0), + Proxy::add_proxy(RuntimeOrigin::signed(5), 4, ProxyType::Any, 0), BalancesError::::InsufficientBalance ); }); @@ -501,49 +512,51 @@ fn cannot_add_proxy_without_balance() { #[test] fn proxying_works() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::add_proxy(Origin::signed(1), 2, ProxyType::JustTransfer, 0)); - assert_ok!(Proxy::add_proxy(Origin::signed(1), 3, ProxyType::Any, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 2, ProxyType::JustTransfer, 0)); + assert_ok!(Proxy::add_proxy(RuntimeOrigin::signed(1), 3, ProxyType::Any, 0)); let call = Box::new(call_transfer(6, 1)); assert_noop!( - Proxy::proxy(Origin::signed(4), 1, None, call.clone()), + Proxy::proxy(RuntimeOrigin::signed(4), 1, None, call.clone()), Error::::NotProxy ); assert_noop!( - Proxy::proxy(Origin::signed(2), 1, Some(ProxyType::Any), call.clone()), + Proxy::proxy(RuntimeOrigin::signed(2), 1, Some(ProxyType::Any), call.clone()), Error::::NotProxy ); - assert_ok!(Proxy::proxy(Origin::signed(2), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), 1, None, call.clone())); System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); assert_eq!(Balances::free_balance(6), 1); - let call = Box::new(Call::System(SystemCall::set_code { code: vec![] })); - assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); + let call = Box::new(RuntimeCall::System(SystemCall::set_code { code: vec![] })); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); - let call = - Box::new(Call::Balances(BalancesCall::transfer_keep_alive { dest: 6, value: 1 })); - assert_ok!(Call::Proxy(super::Call::new_call_variant_proxy(1, None, call.clone())) - .dispatch(Origin::signed(2))); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer_keep_alive { + dest: 6, + value: 1, + })); + assert_ok!(RuntimeCall::Proxy(super::Call::new_call_variant_proxy(1, None, call.clone())) + .dispatch(RuntimeOrigin::signed(2))); System::assert_last_event( ProxyEvent::ProxyExecuted { result: Err(SystemError::CallFiltered.into()) }.into(), ); - assert_ok!(Proxy::proxy(Origin::signed(3), 1, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(3), 1, None, call.clone())); System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); assert_eq!(Balances::free_balance(6), 2); }); } #[test] -fn anonymous_works() { +fn pure_works() { new_test_ext().execute_with(|| { - assert_ok!(Proxy::anonymous(Origin::signed(1), ProxyType::Any, 0, 0)); - let anon = Proxy::anonymous_account(&1, &ProxyType::Any, 0, None); + assert_ok!(Proxy::create_pure(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0)); + let anon = Proxy::pure_account(&1, &ProxyType::Any, 0, None); System::assert_last_event( - ProxyEvent::AnonymousCreated { - anonymous: anon, + ProxyEvent::PureCreated { + pure: anon, who: 1, proxy_type: ProxyType::Any, disambiguation_index: 0, @@ -551,46 +564,46 @@ fn anonymous_works() { .into(), ); - // other calls to anonymous allowed as long as they're not exactly the same. - assert_ok!(Proxy::anonymous(Origin::signed(1), ProxyType::JustTransfer, 0, 0)); - assert_ok!(Proxy::anonymous(Origin::signed(1), ProxyType::Any, 0, 1)); - let anon2 = Proxy::anonymous_account(&2, &ProxyType::Any, 0, None); - assert_ok!(Proxy::anonymous(Origin::signed(2), ProxyType::Any, 0, 0)); + // other calls to pure allowed as long as they're not exactly the same. + assert_ok!(Proxy::create_pure(RuntimeOrigin::signed(1), ProxyType::JustTransfer, 0, 0)); + assert_ok!(Proxy::create_pure(RuntimeOrigin::signed(1), ProxyType::Any, 0, 1)); + let anon2 = Proxy::pure_account(&2, &ProxyType::Any, 0, None); + assert_ok!(Proxy::create_pure(RuntimeOrigin::signed(2), ProxyType::Any, 0, 0)); assert_noop!( - Proxy::anonymous(Origin::signed(1), ProxyType::Any, 0, 0), + Proxy::create_pure(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0), Error::::Duplicate ); System::set_extrinsic_index(1); - assert_ok!(Proxy::anonymous(Origin::signed(1), ProxyType::Any, 0, 0)); + assert_ok!(Proxy::create_pure(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0)); System::set_extrinsic_index(0); System::set_block_number(2); - assert_ok!(Proxy::anonymous(Origin::signed(1), ProxyType::Any, 0, 0)); + assert_ok!(Proxy::create_pure(RuntimeOrigin::signed(1), ProxyType::Any, 0, 0)); let call = Box::new(call_transfer(6, 1)); - assert_ok!(Balances::transfer(Origin::signed(3), anon, 5)); - assert_ok!(Proxy::proxy(Origin::signed(1), anon, None, call)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(3), anon, 5)); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(1), anon, None, call)); System::assert_last_event(ProxyEvent::ProxyExecuted { result: Ok(()) }.into()); assert_eq!(Balances::free_balance(6), 1); - let call = Box::new(Call::Proxy(ProxyCall::new_call_variant_kill_anonymous( + let call = Box::new(RuntimeCall::Proxy(ProxyCall::new_call_variant_kill_pure( 1, ProxyType::Any, 0, 1, 0, ))); - assert_ok!(Proxy::proxy(Origin::signed(2), anon2, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(2), anon2, None, call.clone())); let de = DispatchError::from(Error::::NoPermission).stripped(); System::assert_last_event(ProxyEvent::ProxyExecuted { result: Err(de) }.into()); assert_noop!( - Proxy::kill_anonymous(Origin::signed(1), 1, ProxyType::Any, 0, 1, 0), + Proxy::kill_pure(RuntimeOrigin::signed(1), 1, ProxyType::Any, 0, 1, 0), Error::::NoPermission ); assert_eq!(Balances::free_balance(1), 0); - assert_ok!(Proxy::proxy(Origin::signed(1), anon, None, call.clone())); + assert_ok!(Proxy::proxy(RuntimeOrigin::signed(1), anon, None, call.clone())); assert_eq!(Balances::free_balance(1), 2); assert_noop!( - Proxy::proxy(Origin::signed(1), anon, None, call.clone()), + Proxy::proxy(RuntimeOrigin::signed(1), anon, None, call.clone()), Error::::NotProxy ); }); diff --git a/frame/proxy/src/weights.rs b/frame/proxy/src/weights.rs index 2d409d977f875..25457d52f4391 100644 --- a/frame/proxy/src/weights.rs +++ b/frame/proxy/src/weights.rs @@ -52,8 +52,8 @@ pub trait WeightInfo { fn add_proxy(p: u32, ) -> Weight; fn remove_proxy(p: u32, ) -> Weight; fn remove_proxies(p: u32, ) -> Weight; - fn anonymous(p: u32, ) -> Weight; - fn kill_anonymous(p: u32, ) -> Weight; + fn create_pure(p: u32, ) -> Weight; + fn kill_pure(p: u32, ) -> Weight; } /// Weights for pallet_proxy using the Substrate node and recommended hardware. @@ -138,7 +138,7 @@ impl WeightInfo for SubstrateWeight { } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) - fn anonymous(p: u32, ) -> Weight { + fn create_pure(p: u32, ) -> Weight { Weight::from_ref_time(31_077_000 as u64) // Standard Error: 3_000 .saturating_add(Weight::from_ref_time(37_000 as u64).saturating_mul(p as u64)) @@ -146,7 +146,7 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Proxy Proxies (r:1 w:1) - fn kill_anonymous(p: u32, ) -> Weight { + fn kill_pure(p: u32, ) -> Weight { Weight::from_ref_time(24_657_000 as u64) // Standard Error: 2_000 .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(p as u64)) @@ -236,7 +236,7 @@ impl WeightInfo for () { } // Storage: unknown [0x3a65787472696e7369635f696e646578] (r:1 w:0) // Storage: Proxy Proxies (r:1 w:1) - fn anonymous(p: u32, ) -> Weight { + fn create_pure(p: u32, ) -> Weight { Weight::from_ref_time(31_077_000 as u64) // Standard Error: 3_000 .saturating_add(Weight::from_ref_time(37_000 as u64).saturating_mul(p as u64)) @@ -244,7 +244,7 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Proxy Proxies (r:1 w:1) - fn kill_anonymous(p: u32, ) -> Weight { + fn kill_pure(p: u32, ) -> Weight { Weight::from_ref_time(24_657_000 as u64) // Standard Error: 2_000 .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(p as u64)) diff --git a/frame/randomness-collective-flip/src/lib.rs b/frame/randomness-collective-flip/src/lib.rs index 467cae9728fae..be970ba2a8422 100644 --- a/frame/randomness-collective-flip/src/lib.rs +++ b/frame/randomness-collective-flip/src/lib.rs @@ -197,16 +197,16 @@ mod tests { type BlockWeights = (); type BlockLength = BlockLength; type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; diff --git a/frame/ranked-collective/Cargo.toml b/frame/ranked-collective/Cargo.toml index cb43b9ea4c831..c8cf671a97467 100644 --- a/frame/ranked-collective/Cargo.toml +++ b/frame/ranked-collective/Cargo.toml @@ -29,7 +29,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../primitives default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/ranked-collective/src/benchmarking.rs b/frame/ranked-collective/src/benchmarking.rs index 611a4ce7334a9..eb629b330abb2 100644 --- a/frame/ranked-collective/src/benchmarking.rs +++ b/frame/ranked-collective/src/benchmarking.rs @@ -27,7 +27,7 @@ use frame_system::RawOrigin as SystemOrigin; const SEED: u32 = 0; -fn assert_last_event, I: 'static>(generic_event: >::Event) { +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } @@ -138,7 +138,7 @@ benchmarks_instance_pallet! { } cleanup_poll { - let n in 1 .. 100; + let n in 0 .. 100; // Create a poll let class = T::Polls::classes().into_iter().next().unwrap(); diff --git a/frame/ranked-collective/src/lib.rs b/frame/ranked-collective/src/lib.rs index b8eaac9823634..111c5f70efdfa 100644 --- a/frame/ranked-collective/src/lib.rs +++ b/frame/ranked-collective/src/lib.rs @@ -52,10 +52,9 @@ use sp_std::{marker::PhantomData, prelude::*}; use frame_support::{ codec::{Decode, Encode, MaxEncodedLen}, - dispatch::{DispatchError, DispatchResultWithPostInfo}, + dispatch::{DispatchError, DispatchResultWithPostInfo, PostDispatchInfo}, ensure, traits::{EnsureOrigin, PollStatus, Polling, VoteTally}, - weights::PostDispatchInfo, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; @@ -200,11 +199,11 @@ impl Convert for Unit { /// Vote-weight scheme where all voters get one vote plus an additional vote for every excess rank /// they have. I.e.: /// -/// - Each member with no excess rank gets 1 vote; +/// - Each member with an excess rank of 0 gets 1 vote; /// - ...with an excess rank of 1 gets 2 votes; -/// - ...with an excess rank of 2 gets 2 votes; -/// - ...with an excess rank of 3 gets 3 votes; -/// - ...with an excess rank of 4 gets 4 votes. +/// - ...with an excess rank of 2 gets 3 votes; +/// - ...with an excess rank of 3 gets 4 votes; +/// - ...with an excess rank of 4 gets 5 votes. pub struct Linear; impl Convert for Linear { fn convert(r: Rank) -> Votes { @@ -215,11 +214,11 @@ impl Convert for Linear { /// Vote-weight scheme where all voters get one vote plus additional votes for every excess rank /// they have incrementing by one vote for each excess rank. I.e.: /// -/// - Each member with no excess rank gets 1 vote; -/// - ...with an excess rank of 1 gets 2 votes; -/// - ...with an excess rank of 2 gets 3 votes; -/// - ...with an excess rank of 3 gets 6 votes; -/// - ...with an excess rank of 4 gets 10 votes. +/// - Each member with an excess rank of 0 gets 1 vote; +/// - ...with an excess rank of 1 gets 3 votes; +/// - ...with an excess rank of 2 gets 6 votes; +/// - ...with an excess rank of 3 gets 10 votes; +/// - ...with an excess rank of 4 gets 15 votes. pub struct Geometric; impl Convert for Geometric { fn convert(r: Rank) -> Votes { @@ -242,12 +241,12 @@ impl, I: 'static> GetMaxVoters for Pallet { /// Guard to ensure that the given origin is a member of the collective. The rank of the member is /// the `Success` value. pub struct EnsureRanked(PhantomData<(T, I)>); -impl, I: 'static, const MIN_RANK: u16> EnsureOrigin +impl, I: 'static, const MIN_RANK: u16> EnsureOrigin for EnsureRanked { type Success = Rank; - fn try_origin(o: T::Origin) -> Result { + fn try_origin(o: T::RuntimeOrigin) -> Result { let who = frame_system::EnsureSigned::try_origin(o)?; match Members::::get(&who) { Some(MemberRecord { rank, .. }) if rank >= MIN_RANK => Ok(rank), @@ -256,13 +255,13 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin } #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { + fn try_successful_origin() -> Result { let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; Ok(frame_system::RawOrigin::Signed(who).into()) } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> T::Origin { + fn successful_origin() -> T::RuntimeOrigin { match Self::try_successful_origin() { Ok(o) => o, Err(()) => { @@ -278,12 +277,12 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin /// Guard to ensure that the given origin is a member of the collective. The account ID of the /// member is the `Success` value. pub struct EnsureMember(PhantomData<(T, I)>); -impl, I: 'static, const MIN_RANK: u16> EnsureOrigin +impl, I: 'static, const MIN_RANK: u16> EnsureOrigin for EnsureMember { type Success = T::AccountId; - fn try_origin(o: T::Origin) -> Result { + fn try_origin(o: T::RuntimeOrigin) -> Result { let who = frame_system::EnsureSigned::try_origin(o)?; match Members::::get(&who) { Some(MemberRecord { rank, .. }) if rank >= MIN_RANK => Ok(who), @@ -292,13 +291,13 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin } #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { + fn try_successful_origin() -> Result { let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; Ok(frame_system::RawOrigin::Signed(who).into()) } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> T::Origin { + fn successful_origin() -> T::RuntimeOrigin { match Self::try_successful_origin() { Ok(o) => o, Err(()) => { @@ -314,12 +313,12 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin /// Guard to ensure that the given origin is a member of the collective. The pair of including both /// the account ID and the rank of the member is the `Success` value. pub struct EnsureRankedMember(PhantomData<(T, I)>); -impl, I: 'static, const MIN_RANK: u16> EnsureOrigin +impl, I: 'static, const MIN_RANK: u16> EnsureOrigin for EnsureRankedMember { type Success = (T::AccountId, Rank); - fn try_origin(o: T::Origin) -> Result { + fn try_origin(o: T::RuntimeOrigin) -> Result { let who = frame_system::EnsureSigned::try_origin(o)?; match Members::::get(&who) { Some(MemberRecord { rank, .. }) if rank >= MIN_RANK => Ok((who, rank)), @@ -328,13 +327,13 @@ impl, I: 'static, const MIN_RANK: u16> EnsureOrigin } #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { + fn try_successful_origin() -> Result { let who = IndexToId::::get(MIN_RANK, 0).ok_or(())?; Ok(frame_system::RawOrigin::Signed(who).into()) } #[cfg(feature = "runtime-benchmarks")] - fn successful_origin() -> T::Origin { + fn successful_origin() -> T::RuntimeOrigin { match Self::try_successful_origin() { Ok(o) => o, Err(()) => { @@ -362,16 +361,17 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; - /// The outer event type. - type Event: From> + IsType<::Event>; + /// The runtime event type. + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// The origin required to add or promote a mmember. The success value indicates the /// maximum rank *to which* the promotion may be. - type PromoteOrigin: EnsureOrigin; + type PromoteOrigin: EnsureOrigin; /// The origin required to demote or remove a member. The success value indicates the /// maximum rank *from which* the demotion/removal may be. - type DemoteOrigin: EnsureOrigin; + type DemoteOrigin: EnsureOrigin; /// The polling system used for our voting. type Polls: Polling, Votes = Votes, Moment = Self::BlockNumber>; diff --git a/frame/ranked-collective/src/tests.rs b/frame/ranked-collective/src/tests.rs index b4173b30b0c2e..68bb79f3d07f7 100644 --- a/frame/ranked-collective/src/tests.rs +++ b/frame/ranked-collective/src/tests.rs @@ -58,16 +58,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -171,7 +171,7 @@ impl Polling> for TestPolls { impl Config for Test { type WeightInfo = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PromoteOrigin = EitherOf< // Root can promote arbitrarily. frame_system::EnsureRootWithSuccess>, @@ -239,10 +239,10 @@ fn basic_stuff() { #[test] fn member_lifecycle_works() { new_test_ext().execute_with(|| { - assert_ok!(Club::add_member(Origin::root(), 1)); - assert_ok!(Club::promote_member(Origin::root(), 1)); - assert_ok!(Club::demote_member(Origin::root(), 1)); - assert_ok!(Club::demote_member(Origin::root(), 1)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::demote_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::demote_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 0); assert_eq!(member_count(1), 0); }); @@ -251,29 +251,29 @@ fn member_lifecycle_works() { #[test] fn add_remove_works() { new_test_ext().execute_with(|| { - assert_noop!(Club::add_member(Origin::signed(1), 1), DispatchError::BadOrigin); - assert_ok!(Club::add_member(Origin::root(), 1)); + assert_noop!(Club::add_member(RuntimeOrigin::signed(1), 1), DispatchError::BadOrigin); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 1); - assert_ok!(Club::demote_member(Origin::root(), 1)); + assert_ok!(Club::demote_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 0); - assert_ok!(Club::add_member(Origin::root(), 1)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 1); - assert_ok!(Club::add_member(Origin::root(), 2)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 2)); assert_eq!(member_count(0), 2); - assert_ok!(Club::add_member(Origin::root(), 3)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 3)); assert_eq!(member_count(0), 3); - assert_ok!(Club::demote_member(Origin::root(), 3)); + assert_ok!(Club::demote_member(RuntimeOrigin::root(), 3)); assert_eq!(member_count(0), 2); - assert_ok!(Club::demote_member(Origin::root(), 1)); + assert_ok!(Club::demote_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 1); - assert_ok!(Club::demote_member(Origin::root(), 2)); + assert_ok!(Club::demote_member(RuntimeOrigin::root(), 2)); assert_eq!(member_count(0), 0); }); } @@ -281,29 +281,29 @@ fn add_remove_works() { #[test] fn promote_demote_works() { new_test_ext().execute_with(|| { - assert_noop!(Club::add_member(Origin::signed(1), 1), DispatchError::BadOrigin); - assert_ok!(Club::add_member(Origin::root(), 1)); + assert_noop!(Club::add_member(RuntimeOrigin::signed(1), 1), DispatchError::BadOrigin); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 1); assert_eq!(member_count(1), 0); - assert_ok!(Club::add_member(Origin::root(), 2)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 2)); assert_eq!(member_count(0), 2); assert_eq!(member_count(1), 0); - assert_ok!(Club::promote_member(Origin::root(), 1)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 2); assert_eq!(member_count(1), 1); - assert_ok!(Club::promote_member(Origin::root(), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 2)); assert_eq!(member_count(0), 2); assert_eq!(member_count(1), 2); - assert_ok!(Club::demote_member(Origin::root(), 1)); + assert_ok!(Club::demote_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 2); assert_eq!(member_count(1), 1); - assert_noop!(Club::demote_member(Origin::signed(1), 1), DispatchError::BadOrigin); - assert_ok!(Club::demote_member(Origin::root(), 1)); + assert_noop!(Club::demote_member(RuntimeOrigin::signed(1), 1), DispatchError::BadOrigin); + assert_ok!(Club::demote_member(RuntimeOrigin::root(), 1)); assert_eq!(member_count(0), 1); assert_eq!(member_count(1), 1); }); @@ -312,88 +312,100 @@ fn promote_demote_works() { #[test] fn promote_demote_by_rank_works() { new_test_ext().execute_with(|| { - assert_ok!(Club::add_member(Origin::root(), 1)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); for _ in 0..7 { - assert_ok!(Club::promote_member(Origin::root(), 1)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); } // #1 can add #2 and promote to rank 1 - assert_ok!(Club::add_member(Origin::signed(1), 2)); - assert_ok!(Club::promote_member(Origin::signed(1), 2)); + assert_ok!(Club::add_member(RuntimeOrigin::signed(1), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(1), 2)); // #2 as rank 1 cannot do anything privileged - assert_noop!(Club::add_member(Origin::signed(2), 3), BadOrigin); + assert_noop!(Club::add_member(RuntimeOrigin::signed(2), 3), BadOrigin); - assert_ok!(Club::promote_member(Origin::signed(1), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(1), 2)); // #2 as rank 2 can add #3. - assert_ok!(Club::add_member(Origin::signed(2), 3)); + assert_ok!(Club::add_member(RuntimeOrigin::signed(2), 3)); // #2 as rank 2 cannot promote #3 to rank 1 - assert_noop!(Club::promote_member(Origin::signed(2), 3), Error::::NoPermission); + assert_noop!( + Club::promote_member(RuntimeOrigin::signed(2), 3), + Error::::NoPermission + ); // #1 as rank 7 can promote #2 only up to rank 5 and once there cannot demote them. - assert_ok!(Club::promote_member(Origin::signed(1), 2)); - assert_ok!(Club::promote_member(Origin::signed(1), 2)); - assert_ok!(Club::promote_member(Origin::signed(1), 2)); - assert_noop!(Club::promote_member(Origin::signed(1), 2), Error::::NoPermission); - assert_noop!(Club::demote_member(Origin::signed(1), 2), Error::::NoPermission); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(1), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(1), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(1), 2)); + assert_noop!( + Club::promote_member(RuntimeOrigin::signed(1), 2), + Error::::NoPermission + ); + assert_noop!(Club::demote_member(RuntimeOrigin::signed(1), 2), Error::::NoPermission); // #2 as rank 5 can promote #3 only up to rank 3 and once there cannot demote them. - assert_ok!(Club::promote_member(Origin::signed(2), 3)); - assert_ok!(Club::promote_member(Origin::signed(2), 3)); - assert_ok!(Club::promote_member(Origin::signed(2), 3)); - assert_noop!(Club::promote_member(Origin::signed(2), 3), Error::::NoPermission); - assert_noop!(Club::demote_member(Origin::signed(2), 3), Error::::NoPermission); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(2), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(2), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(2), 3)); + assert_noop!( + Club::promote_member(RuntimeOrigin::signed(2), 3), + Error::::NoPermission + ); + assert_noop!(Club::demote_member(RuntimeOrigin::signed(2), 3), Error::::NoPermission); // #2 can add #4 & #5 as rank 0 and #6 & #7 as rank 1. - assert_ok!(Club::add_member(Origin::signed(2), 4)); - assert_ok!(Club::add_member(Origin::signed(2), 5)); - assert_ok!(Club::add_member(Origin::signed(2), 6)); - assert_ok!(Club::promote_member(Origin::signed(2), 6)); - assert_ok!(Club::add_member(Origin::signed(2), 7)); - assert_ok!(Club::promote_member(Origin::signed(2), 7)); + assert_ok!(Club::add_member(RuntimeOrigin::signed(2), 4)); + assert_ok!(Club::add_member(RuntimeOrigin::signed(2), 5)); + assert_ok!(Club::add_member(RuntimeOrigin::signed(2), 6)); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(2), 6)); + assert_ok!(Club::add_member(RuntimeOrigin::signed(2), 7)); + assert_ok!(Club::promote_member(RuntimeOrigin::signed(2), 7)); // #3 as rank 3 can demote/remove #4 & #5 but not #6 & #7 - assert_ok!(Club::demote_member(Origin::signed(3), 4)); - assert_ok!(Club::remove_member(Origin::signed(3), 5, 0)); - assert_noop!(Club::demote_member(Origin::signed(3), 6), Error::::NoPermission); - assert_noop!(Club::remove_member(Origin::signed(3), 7, 1), Error::::NoPermission); + assert_ok!(Club::demote_member(RuntimeOrigin::signed(3), 4)); + assert_ok!(Club::remove_member(RuntimeOrigin::signed(3), 5, 0)); + assert_noop!(Club::demote_member(RuntimeOrigin::signed(3), 6), Error::::NoPermission); + assert_noop!( + Club::remove_member(RuntimeOrigin::signed(3), 7, 1), + Error::::NoPermission + ); // #2 as rank 5 can demote/remove #6 & #7 - assert_ok!(Club::demote_member(Origin::signed(2), 6)); - assert_ok!(Club::remove_member(Origin::signed(2), 7, 1)); + assert_ok!(Club::demote_member(RuntimeOrigin::signed(2), 6)); + assert_ok!(Club::remove_member(RuntimeOrigin::signed(2), 7, 1)); }); } #[test] fn voting_works() { new_test_ext().execute_with(|| { - assert_ok!(Club::add_member(Origin::root(), 0)); - assert_ok!(Club::add_member(Origin::root(), 1)); - assert_ok!(Club::promote_member(Origin::root(), 1)); - assert_ok!(Club::add_member(Origin::root(), 2)); - assert_ok!(Club::promote_member(Origin::root(), 2)); - assert_ok!(Club::promote_member(Origin::root(), 2)); - assert_ok!(Club::add_member(Origin::root(), 3)); - assert_ok!(Club::promote_member(Origin::root(), 3)); - assert_ok!(Club::promote_member(Origin::root(), 3)); - assert_ok!(Club::promote_member(Origin::root(), 3)); - - assert_noop!(Club::vote(Origin::signed(0), 3, true), Error::::RankTooLow); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 0)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 2)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 3)); + + assert_noop!(Club::vote(RuntimeOrigin::signed(0), 3, true), Error::::RankTooLow); assert_eq!(tally(3), Tally::from_parts(0, 0, 0)); - assert_ok!(Club::vote(Origin::signed(1), 3, true)); + assert_ok!(Club::vote(RuntimeOrigin::signed(1), 3, true)); assert_eq!(tally(3), Tally::from_parts(1, 1, 0)); - assert_ok!(Club::vote(Origin::signed(1), 3, false)); + assert_ok!(Club::vote(RuntimeOrigin::signed(1), 3, false)); assert_eq!(tally(3), Tally::from_parts(0, 0, 1)); - assert_ok!(Club::vote(Origin::signed(2), 3, true)); + assert_ok!(Club::vote(RuntimeOrigin::signed(2), 3, true)); assert_eq!(tally(3), Tally::from_parts(1, 3, 1)); - assert_ok!(Club::vote(Origin::signed(2), 3, false)); + assert_ok!(Club::vote(RuntimeOrigin::signed(2), 3, false)); assert_eq!(tally(3), Tally::from_parts(0, 0, 4)); - assert_ok!(Club::vote(Origin::signed(3), 3, true)); + assert_ok!(Club::vote(RuntimeOrigin::signed(3), 3, true)); assert_eq!(tally(3), Tally::from_parts(1, 6, 4)); - assert_ok!(Club::vote(Origin::signed(3), 3, false)); + assert_ok!(Club::vote(RuntimeOrigin::signed(3), 3, false)); assert_eq!(tally(3), Tally::from_parts(0, 0, 10)); }); } @@ -401,59 +413,78 @@ fn voting_works() { #[test] fn cleanup_works() { new_test_ext().execute_with(|| { - assert_ok!(Club::add_member(Origin::root(), 1)); - assert_ok!(Club::promote_member(Origin::root(), 1)); - assert_ok!(Club::add_member(Origin::root(), 2)); - assert_ok!(Club::promote_member(Origin::root(), 2)); - assert_ok!(Club::add_member(Origin::root(), 3)); - assert_ok!(Club::promote_member(Origin::root(), 3)); - - assert_ok!(Club::vote(Origin::signed(1), 3, true)); - assert_ok!(Club::vote(Origin::signed(2), 3, false)); - assert_ok!(Club::vote(Origin::signed(3), 3, true)); - - assert_noop!(Club::cleanup_poll(Origin::signed(4), 3, 10), Error::::Ongoing); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 2)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 3)); + + assert_ok!(Club::vote(RuntimeOrigin::signed(1), 3, true)); + assert_ok!(Club::vote(RuntimeOrigin::signed(2), 3, false)); + assert_ok!(Club::vote(RuntimeOrigin::signed(3), 3, true)); + + assert_noop!(Club::cleanup_poll(RuntimeOrigin::signed(4), 3, 10), Error::::Ongoing); Polls::set( vec![(1, Completed(1, true)), (2, Completed(2, false)), (3, Completed(3, true))] .into_iter() .collect(), ); - assert_ok!(Club::cleanup_poll(Origin::signed(4), 3, 10)); + assert_ok!(Club::cleanup_poll(RuntimeOrigin::signed(4), 3, 10)); // NOTE: This will fail until #10016 is merged. - // assert_noop!(Club::cleanup_poll(Origin::signed(4), 3, 10), Error::::NoneRemaining); + // assert_noop!(Club::cleanup_poll(RuntimeOrigin::signed(4), 3, 10), + // Error::::NoneRemaining); }); } #[test] fn ensure_ranked_works() { new_test_ext().execute_with(|| { - assert_ok!(Club::add_member(Origin::root(), 1)); - assert_ok!(Club::promote_member(Origin::root(), 1)); - assert_ok!(Club::add_member(Origin::root(), 2)); - assert_ok!(Club::promote_member(Origin::root(), 2)); - assert_ok!(Club::promote_member(Origin::root(), 2)); - assert_ok!(Club::add_member(Origin::root(), 3)); - assert_ok!(Club::promote_member(Origin::root(), 3)); - assert_ok!(Club::promote_member(Origin::root(), 3)); - assert_ok!(Club::promote_member(Origin::root(), 3)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 1)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 2)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 2)); + assert_ok!(Club::add_member(RuntimeOrigin::root(), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 3)); + assert_ok!(Club::promote_member(RuntimeOrigin::root(), 3)); use frame_support::traits::OriginTrait; type Rank1 = EnsureRanked; type Rank2 = EnsureRanked; type Rank3 = EnsureRanked; type Rank4 = EnsureRanked; - assert_eq!(Rank1::try_origin(Origin::signed(1)).unwrap(), 1); - assert_eq!(Rank1::try_origin(Origin::signed(2)).unwrap(), 2); - assert_eq!(Rank1::try_origin(Origin::signed(3)).unwrap(), 3); - assert_eq!(Rank2::try_origin(Origin::signed(1)).unwrap_err().as_signed().unwrap(), 1); - assert_eq!(Rank2::try_origin(Origin::signed(2)).unwrap(), 2); - assert_eq!(Rank2::try_origin(Origin::signed(3)).unwrap(), 3); - assert_eq!(Rank3::try_origin(Origin::signed(1)).unwrap_err().as_signed().unwrap(), 1); - assert_eq!(Rank3::try_origin(Origin::signed(2)).unwrap_err().as_signed().unwrap(), 2); - assert_eq!(Rank3::try_origin(Origin::signed(3)).unwrap(), 3); - assert_eq!(Rank4::try_origin(Origin::signed(1)).unwrap_err().as_signed().unwrap(), 1); - assert_eq!(Rank4::try_origin(Origin::signed(2)).unwrap_err().as_signed().unwrap(), 2); - assert_eq!(Rank4::try_origin(Origin::signed(3)).unwrap_err().as_signed().unwrap(), 3); + assert_eq!(Rank1::try_origin(RuntimeOrigin::signed(1)).unwrap(), 1); + assert_eq!(Rank1::try_origin(RuntimeOrigin::signed(2)).unwrap(), 2); + assert_eq!(Rank1::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3); + assert_eq!( + Rank2::try_origin(RuntimeOrigin::signed(1)).unwrap_err().as_signed().unwrap(), + 1 + ); + assert_eq!(Rank2::try_origin(RuntimeOrigin::signed(2)).unwrap(), 2); + assert_eq!(Rank2::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3); + assert_eq!( + Rank3::try_origin(RuntimeOrigin::signed(1)).unwrap_err().as_signed().unwrap(), + 1 + ); + assert_eq!( + Rank3::try_origin(RuntimeOrigin::signed(2)).unwrap_err().as_signed().unwrap(), + 2 + ); + assert_eq!(Rank3::try_origin(RuntimeOrigin::signed(3)).unwrap(), 3); + assert_eq!( + Rank4::try_origin(RuntimeOrigin::signed(1)).unwrap_err().as_signed().unwrap(), + 1 + ); + assert_eq!( + Rank4::try_origin(RuntimeOrigin::signed(2)).unwrap_err().as_signed().unwrap(), + 2 + ); + assert_eq!( + Rank4::try_origin(RuntimeOrigin::signed(3)).unwrap_err().as_signed().unwrap(), + 3 + ); }); } diff --git a/frame/recovery/Cargo.toml b/frame/recovery/Cargo.toml index 396555b3e2758..fb33b88d2dfab 100644 --- a/frame/recovery/Cargo.toml +++ b/frame/recovery/Cargo.toml @@ -36,7 +36,7 @@ runtime-benchmarks = [ ] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "scale-info/std", diff --git a/frame/recovery/src/benchmarking.rs b/frame/recovery/src/benchmarking.rs index 56d5df22d49c5..870543d9bd290 100644 --- a/frame/recovery/src/benchmarking.rs +++ b/frame/recovery/src/benchmarking.rs @@ -28,7 +28,7 @@ use sp_runtime::traits::Bounded; const SEED: u32 = 0; const DEFAULT_DELAY: u32 = 0; -fn assert_last_event(generic_event: ::Event) { +fn assert_last_event(generic_event: ::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } @@ -107,7 +107,7 @@ benchmarks! { let caller: T::AccountId = whitelisted_caller(); let recovered_account: T::AccountId = account("recovered_account", 0, SEED); let recovered_account_lookup = T::Lookup::unlookup(recovered_account.clone()); - let call: ::Call = frame_system::Call::::remark { remark: vec![] }.into(); + let call: ::RuntimeCall = frame_system::Call::::remark { remark: vec![] }.into(); Proxy::::insert(&caller, &recovered_account); }: _( diff --git a/frame/recovery/src/lib.rs b/frame/recovery/src/lib.rs index 45260b577f700..18d3d48dc024c 100644 --- a/frame/recovery/src/lib.rs +++ b/frame/recovery/src/lib.rs @@ -160,9 +160,8 @@ use sp_runtime::traits::{CheckedAdd, CheckedMul, Dispatchable, SaturatedConversi use sp_std::prelude::*; use frame_support::{ - dispatch::PostDispatchInfo, + dispatch::{GetDispatchInfo, PostDispatchInfo}, traits::{BalanceStatus, Currency, ReservableCurrency}, - weights::GetDispatchInfo, BoundedVec, RuntimeDebug, }; @@ -226,14 +225,14 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; /// The overarching call type. - type Call: Parameter - + Dispatchable + type RuntimeCall: Parameter + + Dispatchable + GetDispatchInfo + From>; @@ -384,7 +383,7 @@ pub mod pallet { pub fn as_recovered( origin: OriginFor, account: AccountIdLookupOf, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResult { let who = ensure_signed(origin)?; let account = T::Lookup::lookup(account)?; @@ -453,7 +452,7 @@ pub mod pallet { ensure!(!friends.is_empty(), Error::::NotEnoughFriends); ensure!(threshold as usize <= friends.len(), Error::::NotEnoughFriends); let bounded_friends: FriendsOf = - friends.try_into().map_err(|()| Error::::MaxFriends)?; + friends.try_into().map_err(|_| Error::::MaxFriends)?; ensure!(Self::is_sorted_and_unique(&bounded_friends), Error::::NotSorted); // Total deposit is base fee + number of friends * factor fee let friend_deposit = T::FriendDepositFactor::get() @@ -555,7 +554,7 @@ pub mod pallet { Err(pos) => active_recovery .friends .try_insert(pos, who.clone()) - .map_err(|()| Error::::MaxFriends)?, + .map_err(|_| Error::::MaxFriends)?, } // Update storage with the latest details >::insert(&lost, &rescuer, active_recovery); diff --git a/frame/recovery/src/mock.rs b/frame/recovery/src/mock.rs index 5dc49fff09b32..2a29390fdd20f 100644 --- a/frame/recovery/src/mock.rs +++ b/frame/recovery/src/mock.rs @@ -55,8 +55,8 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -64,7 +64,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -87,7 +87,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type Balance = u128; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; type WeightInfo = (); @@ -102,9 +102,9 @@ parameter_types! { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); - type Call = Call; + type RuntimeCall = RuntimeCall; type Currency = Balances; type ConfigDepositBase = ConfigDepositBase; type FriendDepositFactor = FriendDepositFactor; diff --git a/frame/recovery/src/tests.rs b/frame/recovery/src/tests.rs index a900a5b6bfa2a..b037a8110147d 100644 --- a/frame/recovery/src/tests.rs +++ b/frame/recovery/src/tests.rs @@ -20,8 +20,8 @@ use super::*; use frame_support::{assert_noop, assert_ok, bounded_vec, traits::Currency}; use mock::{ - new_test_ext, run_to_block, Balances, BalancesCall, Call, MaxFriends, Origin, Recovery, - RecoveryCall, Test, + new_test_ext, run_to_block, Balances, BalancesCall, MaxFriends, Recovery, RecoveryCall, + RuntimeCall, RuntimeOrigin, Test, }; use sp_runtime::traits::BadOrigin; @@ -41,12 +41,12 @@ fn basic_setup_works() { fn set_recovered_works() { new_test_ext().execute_with(|| { // Not accessible by a normal user - assert_noop!(Recovery::set_recovered(Origin::signed(1), 5, 1), BadOrigin); + assert_noop!(Recovery::set_recovered(RuntimeOrigin::signed(1), 5, 1), BadOrigin); // Root can set a recovered account though - assert_ok!(Recovery::set_recovered(Origin::root(), 5, 1)); + assert_ok!(Recovery::set_recovered(RuntimeOrigin::root(), 5, 1)); // Account 1 should now be able to make a call through account 5 - let call = Box::new(Call::Balances(BalancesCall::transfer { dest: 1, value: 100 })); - assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 1, value: 100 })); + assert_ok!(Recovery::as_recovered(RuntimeOrigin::signed(1), 5, call)); // Account 1 has successfully drained the funds from account 5 assert_eq!(Balances::free_balance(1), 200); assert_eq!(Balances::free_balance(5), 0); @@ -60,38 +60,46 @@ fn recovery_life_cycle_works() { let threshold = 3; let delay_period = 10; // Account 5 sets up a recovery configuration on their account - assert_ok!(Recovery::create_recovery(Origin::signed(5), friends, threshold, delay_period)); + assert_ok!(Recovery::create_recovery( + RuntimeOrigin::signed(5), + friends, + threshold, + delay_period + )); // Some time has passed, and the user lost their keys! run_to_block(10); // Using account 1, the user begins the recovery process to recover the lost account - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); // Off chain, the user contacts their friends and asks them to vouch for the recovery // attempt - assert_ok!(Recovery::vouch_recovery(Origin::signed(2), 5, 1)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(3), 5, 1)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(4), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(3), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(4), 5, 1)); // We met the threshold, lets try to recover the account...? - assert_noop!(Recovery::claim_recovery(Origin::signed(1), 5), Error::::DelayPeriod); + assert_noop!( + Recovery::claim_recovery(RuntimeOrigin::signed(1), 5), + Error::::DelayPeriod + ); // We need to wait at least the delay_period number of blocks before we can recover run_to_block(20); - assert_ok!(Recovery::claim_recovery(Origin::signed(1), 5)); + assert_ok!(Recovery::claim_recovery(RuntimeOrigin::signed(1), 5)); // Account 1 can use account 5 to close the active recovery process, claiming the deposited // funds used to initiate the recovery process into account 5. - let call = Box::new(Call::Recovery(RecoveryCall::close_recovery { rescuer: 1 })); - assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); + let call = Box::new(RuntimeCall::Recovery(RecoveryCall::close_recovery { rescuer: 1 })); + assert_ok!(Recovery::as_recovered(RuntimeOrigin::signed(1), 5, call)); // Account 1 can then use account 5 to remove the recovery configuration, claiming the // deposited funds used to create the recovery configuration into account 5. - let call = Box::new(Call::Recovery(RecoveryCall::remove_recovery {})); - assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); + let call = Box::new(RuntimeCall::Recovery(RecoveryCall::remove_recovery {})); + assert_ok!(Recovery::as_recovered(RuntimeOrigin::signed(1), 5, call)); // Account 1 should now be able to make a call through account 5 to get all of their funds assert_eq!(Balances::free_balance(5), 110); - let call = Box::new(Call::Balances(BalancesCall::transfer { dest: 1, value: 110 })); - assert_ok!(Recovery::as_recovered(Origin::signed(1), 5, call)); + let call = Box::new(RuntimeCall::Balances(BalancesCall::transfer { dest: 1, value: 110 })); + assert_ok!(Recovery::as_recovered(RuntimeOrigin::signed(1), 5, call)); // All funds have been fully recovered! assert_eq!(Balances::free_balance(1), 200); assert_eq!(Balances::free_balance(5), 0); // Remove the proxy link. - assert_ok!(Recovery::cancel_recovered(Origin::signed(1), 5)); + assert_ok!(Recovery::cancel_recovered(RuntimeOrigin::signed(1), 5)); // All storage items are removed from the module assert!(!>::contains_key(&5, &1)); @@ -107,38 +115,52 @@ fn malicious_recovery_fails() { let threshold = 3; let delay_period = 10; // Account 5 sets up a recovery configuration on their account - assert_ok!(Recovery::create_recovery(Origin::signed(5), friends, threshold, delay_period)); + assert_ok!(Recovery::create_recovery( + RuntimeOrigin::signed(5), + friends, + threshold, + delay_period + )); // Some time has passed, and account 1 wants to try and attack this account! run_to_block(10); // Using account 1, the malicious user begins the recovery process on account 5 - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); // Off chain, the user **tricks** their friends and asks them to vouch for the recovery - assert_ok!(Recovery::vouch_recovery(Origin::signed(2), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1)); // shame on you - assert_ok!(Recovery::vouch_recovery(Origin::signed(3), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(3), 5, 1)); // shame on you - assert_ok!(Recovery::vouch_recovery(Origin::signed(4), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(4), 5, 1)); // shame on you // We met the threshold, lets try to recover the account...? - assert_noop!(Recovery::claim_recovery(Origin::signed(1), 5), Error::::DelayPeriod); + assert_noop!( + Recovery::claim_recovery(RuntimeOrigin::signed(1), 5), + Error::::DelayPeriod + ); // Account 1 needs to wait... run_to_block(19); // One more block to wait! - assert_noop!(Recovery::claim_recovery(Origin::signed(1), 5), Error::::DelayPeriod); + assert_noop!( + Recovery::claim_recovery(RuntimeOrigin::signed(1), 5), + Error::::DelayPeriod + ); // Account 5 checks their account every `delay_period` and notices the malicious attack! // Account 5 can close the recovery process before account 1 can claim it - assert_ok!(Recovery::close_recovery(Origin::signed(5), 1)); + assert_ok!(Recovery::close_recovery(RuntimeOrigin::signed(5), 1)); // By doing so, account 5 has now claimed the deposit originally reserved by account 1 assert_eq!(Balances::total_balance(&1), 90); // Thanks for the free money! assert_eq!(Balances::total_balance(&5), 110); // The recovery process has been closed, so account 1 can't make the claim run_to_block(20); - assert_noop!(Recovery::claim_recovery(Origin::signed(1), 5), Error::::NotStarted); + assert_noop!( + Recovery::claim_recovery(RuntimeOrigin::signed(1), 5), + Error::::NotStarted + ); // Account 5 can remove their recovery config and pick some better friends - assert_ok!(Recovery::remove_recovery(Origin::signed(5))); + assert_ok!(Recovery::remove_recovery(RuntimeOrigin::signed(5))); assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), vec![22, 33, 44], threshold, delay_period @@ -151,23 +173,23 @@ fn create_recovery_handles_basic_errors() { new_test_ext().execute_with(|| { // No friends assert_noop!( - Recovery::create_recovery(Origin::signed(5), vec![], 1, 0), + Recovery::create_recovery(RuntimeOrigin::signed(5), vec![], 1, 0), Error::::NotEnoughFriends ); // Zero threshold assert_noop!( - Recovery::create_recovery(Origin::signed(5), vec![2], 0, 0), + Recovery::create_recovery(RuntimeOrigin::signed(5), vec![2], 0, 0), Error::::ZeroThreshold ); // Threshold greater than friends length assert_noop!( - Recovery::create_recovery(Origin::signed(5), vec![2, 3, 4], 4, 0), + Recovery::create_recovery(RuntimeOrigin::signed(5), vec![2, 3, 4], 4, 0), Error::::NotEnoughFriends ); // Too many friends assert_noop!( Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), vec![1; (MaxFriends::get() + 1) as usize], 1, 0 @@ -176,18 +198,18 @@ fn create_recovery_handles_basic_errors() { ); // Unsorted friends assert_noop!( - Recovery::create_recovery(Origin::signed(5), vec![3, 2, 4], 3, 0), + Recovery::create_recovery(RuntimeOrigin::signed(5), vec![3, 2, 4], 3, 0), Error::::NotSorted ); // Duplicate friends assert_noop!( - Recovery::create_recovery(Origin::signed(5), vec![2, 2, 4], 3, 0), + Recovery::create_recovery(RuntimeOrigin::signed(5), vec![2, 2, 4], 3, 0), Error::::NotSorted ); // Already configured - assert_ok!(Recovery::create_recovery(Origin::signed(5), vec![2, 3, 4], 3, 10)); + assert_ok!(Recovery::create_recovery(RuntimeOrigin::signed(5), vec![2, 3, 4], 3, 10)); assert_noop!( - Recovery::create_recovery(Origin::signed(5), vec![2, 3, 4], 3, 10), + Recovery::create_recovery(RuntimeOrigin::signed(5), vec![2, 3, 4], 3, 10), Error::::AlreadyRecoverable ); }); @@ -201,7 +223,7 @@ fn create_recovery_works() { let delay_period = 10; // Account 5 sets up a recovery configuration on their account assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), friends.clone(), threshold, delay_period @@ -225,7 +247,7 @@ fn initiate_recovery_handles_basic_errors() { new_test_ext().execute_with(|| { // No recovery process set up for the account assert_noop!( - Recovery::initiate_recovery(Origin::signed(1), 5), + Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5), Error::::NotRecoverable ); // Create a recovery process for next test @@ -233,15 +255,15 @@ fn initiate_recovery_handles_basic_errors() { let threshold = 3; let delay_period = 10; assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), friends.clone(), threshold, delay_period )); // Same user cannot recover same account twice - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); assert_noop!( - Recovery::initiate_recovery(Origin::signed(1), 5), + Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5), Error::::AlreadyStarted ); // No double deposit @@ -257,13 +279,13 @@ fn initiate_recovery_works() { let threshold = 3; let delay_period = 10; assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), friends.clone(), threshold, delay_period )); // Recovery can be initiated - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); // Deposit is reserved assert_eq!(Balances::reserved_balance(1), 10); // Recovery status object is created correctly @@ -271,7 +293,7 @@ fn initiate_recovery_works() { ActiveRecovery { created: 0, deposit: 10, friends: Default::default() }; assert_eq!(>::get(&5, &1), Some(recovery_status)); // Multiple users can attempt to recover the same account - assert_ok!(Recovery::initiate_recovery(Origin::signed(2), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(2), 5)); }); } @@ -280,7 +302,7 @@ fn vouch_recovery_handles_basic_errors() { new_test_ext().execute_with(|| { // Cannot vouch for non-recoverable account assert_noop!( - Recovery::vouch_recovery(Origin::signed(2), 5, 1), + Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1), Error::::NotRecoverable ); // Create a recovery process for next tests @@ -288,21 +310,27 @@ fn vouch_recovery_handles_basic_errors() { let threshold = 3; let delay_period = 10; assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), friends.clone(), threshold, delay_period )); // Cannot vouch a recovery process that has not started - assert_noop!(Recovery::vouch_recovery(Origin::signed(2), 5, 1), Error::::NotStarted); + assert_noop!( + Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1), + Error::::NotStarted + ); // Initiate a recovery process - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); // Cannot vouch if you are not a friend - assert_noop!(Recovery::vouch_recovery(Origin::signed(22), 5, 1), Error::::NotFriend); + assert_noop!( + Recovery::vouch_recovery(RuntimeOrigin::signed(22), 5, 1), + Error::::NotFriend + ); // Cannot vouch twice - assert_ok!(Recovery::vouch_recovery(Origin::signed(2), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1)); assert_noop!( - Recovery::vouch_recovery(Origin::signed(2), 5, 1), + Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1), Error::::AlreadyVouched ); }); @@ -316,17 +344,17 @@ fn vouch_recovery_works() { let threshold = 3; let delay_period = 10; assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), friends.clone(), threshold, delay_period )); - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); // Vouching works - assert_ok!(Recovery::vouch_recovery(Origin::signed(2), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1)); // Handles out of order vouches - assert_ok!(Recovery::vouch_recovery(Origin::signed(4), 5, 1)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(3), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(4), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(3), 5, 1)); // Final recovery status object is updated correctly let recovery_status = ActiveRecovery { created: 0, deposit: 10, friends: bounded_vec![2, 3, 4] }; @@ -338,28 +366,40 @@ fn vouch_recovery_works() { fn claim_recovery_handles_basic_errors() { new_test_ext().execute_with(|| { // Cannot claim a non-recoverable account - assert_noop!(Recovery::claim_recovery(Origin::signed(1), 5), Error::::NotRecoverable); + assert_noop!( + Recovery::claim_recovery(RuntimeOrigin::signed(1), 5), + Error::::NotRecoverable + ); // Create a recovery process for the test let friends = vec![2, 3, 4]; let threshold = 3; let delay_period = 10; assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), friends.clone(), threshold, delay_period )); // Cannot claim an account which has not started the recovery process - assert_noop!(Recovery::claim_recovery(Origin::signed(1), 5), Error::::NotStarted); - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); + assert_noop!( + Recovery::claim_recovery(RuntimeOrigin::signed(1), 5), + Error::::NotStarted + ); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); // Cannot claim an account which has not passed the delay period - assert_noop!(Recovery::claim_recovery(Origin::signed(1), 5), Error::::DelayPeriod); + assert_noop!( + Recovery::claim_recovery(RuntimeOrigin::signed(1), 5), + Error::::DelayPeriod + ); run_to_block(11); // Cannot claim an account which has not passed the threshold number of votes - assert_ok!(Recovery::vouch_recovery(Origin::signed(2), 5, 1)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(3), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(3), 5, 1)); // Only 2/3 is not good enough - assert_noop!(Recovery::claim_recovery(Origin::signed(1), 5), Error::::Threshold); + assert_noop!( + Recovery::claim_recovery(RuntimeOrigin::signed(1), 5), + Error::::Threshold + ); }); } @@ -371,32 +411,32 @@ fn claim_recovery_works() { let threshold = 3; let delay_period = 10; assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), friends.clone(), threshold, delay_period )); - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(2), 5, 1)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(3), 5, 1)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(4), 5, 1)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(3), 5, 1)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(4), 5, 1)); run_to_block(11); // Account can be recovered. - assert_ok!(Recovery::claim_recovery(Origin::signed(1), 5)); + assert_ok!(Recovery::claim_recovery(RuntimeOrigin::signed(1), 5)); // Recovered storage item is correctly created assert_eq!(>::get(&1), Some(5)); // Account could be re-recovered in the case that the recoverer account also gets lost. - assert_ok!(Recovery::initiate_recovery(Origin::signed(4), 5)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(2), 5, 4)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(3), 5, 4)); - assert_ok!(Recovery::vouch_recovery(Origin::signed(4), 5, 4)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(4), 5)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(2), 5, 4)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(3), 5, 4)); + assert_ok!(Recovery::vouch_recovery(RuntimeOrigin::signed(4), 5, 4)); run_to_block(21); // Account is re-recovered. - assert_ok!(Recovery::claim_recovery(Origin::signed(4), 5)); + assert_ok!(Recovery::claim_recovery(RuntimeOrigin::signed(4), 5)); // Recovered storage item is correctly updated assert_eq!(>::get(&4), Some(5)); }); @@ -406,7 +446,10 @@ fn claim_recovery_works() { fn close_recovery_handles_basic_errors() { new_test_ext().execute_with(|| { // Cannot close a non-active recovery - assert_noop!(Recovery::close_recovery(Origin::signed(5), 1), Error::::NotStarted); + assert_noop!( + Recovery::close_recovery(RuntimeOrigin::signed(5), 1), + Error::::NotStarted + ); }); } @@ -414,26 +457,35 @@ fn close_recovery_handles_basic_errors() { fn remove_recovery_works() { new_test_ext().execute_with(|| { // Cannot remove an unrecoverable account - assert_noop!(Recovery::remove_recovery(Origin::signed(5)), Error::::NotRecoverable); + assert_noop!( + Recovery::remove_recovery(RuntimeOrigin::signed(5)), + Error::::NotRecoverable + ); // Create and initiate a recovery process for the test let friends = vec![2, 3, 4]; let threshold = 3; let delay_period = 10; assert_ok!(Recovery::create_recovery( - Origin::signed(5), + RuntimeOrigin::signed(5), friends.clone(), threshold, delay_period )); - assert_ok!(Recovery::initiate_recovery(Origin::signed(1), 5)); - assert_ok!(Recovery::initiate_recovery(Origin::signed(2), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(1), 5)); + assert_ok!(Recovery::initiate_recovery(RuntimeOrigin::signed(2), 5)); // Cannot remove a recovery when there are active recoveries. - assert_noop!(Recovery::remove_recovery(Origin::signed(5)), Error::::StillActive); - assert_ok!(Recovery::close_recovery(Origin::signed(5), 1)); + assert_noop!( + Recovery::remove_recovery(RuntimeOrigin::signed(5)), + Error::::StillActive + ); + assert_ok!(Recovery::close_recovery(RuntimeOrigin::signed(5), 1)); // Still need to remove one more! - assert_noop!(Recovery::remove_recovery(Origin::signed(5)), Error::::StillActive); - assert_ok!(Recovery::close_recovery(Origin::signed(5), 2)); + assert_noop!( + Recovery::remove_recovery(RuntimeOrigin::signed(5)), + Error::::StillActive + ); + assert_ok!(Recovery::close_recovery(RuntimeOrigin::signed(5), 2)); // Finally removed - assert_ok!(Recovery::remove_recovery(Origin::signed(5))); + assert_ok!(Recovery::remove_recovery(RuntimeOrigin::signed(5))); }); } diff --git a/frame/referenda/Cargo.toml b/frame/referenda/Cargo.toml index 508f5a5ef8688..4e68d7528ad8a 100644 --- a/frame/referenda/Cargo.toml +++ b/frame/referenda/Cargo.toml @@ -38,7 +38,7 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "sp-runtime/std", "sp-arithmetic/std", diff --git a/frame/referenda/src/benchmarking.rs b/frame/referenda/src/benchmarking.rs index 4a64a9aa03b77..bc6fb31bf1127 100644 --- a/frame/referenda/src/benchmarking.rs +++ b/frame/referenda/src/benchmarking.rs @@ -24,15 +24,15 @@ use frame_benchmarking::{account, benchmarks_instance_pallet, whitelist_account} use frame_support::{ assert_ok, dispatch::UnfilteredDispatchable, - traits::{Currency, EnsureOrigin}, + traits::{Bounded, Currency, EnsureOrigin}, }; use frame_system::RawOrigin; -use sp_runtime::traits::{Bounded, Hash}; +use sp_runtime::traits::Bounded as ArithBounded; const SEED: u32 = 0; #[allow(dead_code)] -fn assert_last_event, I: 'static>(generic_event: >::Event) { +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } @@ -42,17 +42,23 @@ fn funded_account, I: 'static>(name: &'static str, index: u32) -> T caller } -fn create_referendum, I: 'static>() -> (T::Origin, ReferendumIndex) { - let origin: T::Origin = T::SubmitOrigin::successful_origin(); +fn dummy_call, I: 'static>() -> Bounded<>::RuntimeCall> { + let inner = frame_system::Call::remark { remark: vec![] }; + let call = >::RuntimeCall::from(inner); + T::Preimages::bound(call).unwrap() +} + +fn create_referendum, I: 'static>() -> (T::RuntimeOrigin, ReferendumIndex) { + let origin: T::RuntimeOrigin = T::SubmitOrigin::successful_origin(); if let Ok(caller) = frame_system::ensure_signed(origin.clone()) { T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); whitelist_account!(caller); } let proposal_origin = Box::new(RawOrigin::Root.into()); - let proposal_hash = T::Hashing::hash_of(&0); + let proposal = dummy_call::(); let enactment_moment = DispatchTime::After(0u32.into()); - let call = Call::::submit { proposal_origin, proposal_hash, enactment_moment }; + let call = crate::Call::::submit { proposal_origin, proposal, enactment_moment }; assert_ok!(call.dispatch_bypass_filter(origin.clone())); let index = ReferendumCount::::get() - 1; (origin, index) @@ -188,15 +194,15 @@ fn is_not_confirming, I: 'static>(index: ReferendumIndex) -> bool { benchmarks_instance_pallet! { submit { - let origin: T::Origin = T::SubmitOrigin::successful_origin(); + let origin: T::RuntimeOrigin = T::SubmitOrigin::successful_origin(); if let Ok(caller) = frame_system::ensure_signed(origin.clone()) { T::Currency::make_free_balance_be(&caller, BalanceOf::::max_value()); whitelist_account!(caller); } - }: _( + }: _( origin, Box::new(RawOrigin::Root.into()), - T::Hashing::hash_of(&0), + dummy_call::(), DispatchTime::After(0u32.into()) ) verify { let index = ReferendumCount::::get().checked_sub(1).unwrap(); @@ -205,7 +211,7 @@ benchmarks_instance_pallet! { place_decision_deposit_preparing { let (origin, index) = create_referendum::(); - }: place_decision_deposit(origin, index) + }: place_decision_deposit(origin, index) verify { assert!(Referenda::::ensure_ongoing(index).unwrap().decision_deposit.is_some()); } @@ -213,7 +219,7 @@ benchmarks_instance_pallet! { place_decision_deposit_queued { let (origin, index) = create_referendum::(); fill_queue::(index, 1, 90); - }: place_decision_deposit(origin, index) + }: place_decision_deposit(origin, index) verify { let track = Referenda::::ensure_ongoing(index).unwrap().track; assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); @@ -226,7 +232,7 @@ benchmarks_instance_pallet! { let track = Referenda::::ensure_ongoing(index).unwrap().track; assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); assert!(TrackQueue::::get(&track).into_iter().all(|(i, _)| i != index)); - }: place_decision_deposit(origin, index) + }: place_decision_deposit(origin, index) verify { assert_eq!(TrackQueue::::get(&track).len() as u32, T::MaxQueued::get()); assert!(TrackQueue::::get(&track).into_iter().all(|(i, _)| i != index)); @@ -236,7 +242,7 @@ benchmarks_instance_pallet! { let (origin, index) = create_referendum::(); skip_prepare_period::(index); make_passing::(index); - }: place_decision_deposit(origin, index) + }: place_decision_deposit(origin, index) verify { assert!(is_confirming::(index)); } @@ -244,7 +250,7 @@ benchmarks_instance_pallet! { place_decision_deposit_failing { let (origin, index) = create_referendum::(); skip_prepare_period::(index); - }: place_decision_deposit(origin, index) + }: place_decision_deposit(origin, index) verify { assert!(is_not_confirming::(index)); } @@ -253,7 +259,7 @@ benchmarks_instance_pallet! { let (origin, index) = create_referendum::(); place_deposit::(index); assert_ok!(Referenda::::cancel(T::CancelOrigin::successful_origin(), index)); - }: _(origin, index) + }: _(origin, index) verify { assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(_, _, None))); } @@ -261,7 +267,7 @@ benchmarks_instance_pallet! { cancel { let (_origin, index) = create_referendum::(); place_deposit::(index); - }: _(T::CancelOrigin::successful_origin(), index) + }: _(T::CancelOrigin::successful_origin(), index) verify { assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Cancelled(..))); } @@ -269,7 +275,7 @@ benchmarks_instance_pallet! { kill { let (_origin, index) = create_referendum::(); place_deposit::(index); - }: _(T::KillOrigin::successful_origin(), index) + }: _(T::KillOrigin::successful_origin(), index) verify { assert_matches!(ReferendumInfoFor::::get(index), Some(ReferendumInfo::Killed(..))); } diff --git a/frame/referenda/src/lib.rs b/frame/referenda/src/lib.rs index e9e14e1d4a96a..1bdc19d49c414 100644 --- a/frame/referenda/src/lib.rs +++ b/frame/referenda/src/lib.rs @@ -69,11 +69,11 @@ use frame_support::{ ensure, traits::{ schedule::{ - v2::{Anon as ScheduleAnon, Named as ScheduleNamed}, - DispatchTime, MaybeHashed, + v3::{Anon as ScheduleAnon, Named as ScheduleNamed}, + DispatchTime, }, - Currency, Get, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling, - ReservableCurrency, VoteTally, + Currency, LockIdentifier, OnUnbalanced, OriginTrait, PollStatus, Polling, QueryPreimage, + ReservableCurrency, StorePreimage, VoteTally, }, BoundedVec, }; @@ -92,10 +92,10 @@ use self::branch::{BeginDecidingBranch, OneFewerDecidingBranch, ServiceBranch}; pub use self::{ pallet::*, types::{ - BalanceOf, CallOf, Curve, DecidingStatus, DecidingStatusOf, Deposit, InsertSorted, - NegativeImbalanceOf, PalletsOriginOf, ReferendumIndex, ReferendumInfo, ReferendumInfoOf, - ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf, TallyOf, TrackIdOf, TrackInfo, - TrackInfoOf, TracksInfo, VotesOf, + BalanceOf, BoundedCallOf, CallOf, Curve, DecidingStatus, DecidingStatusOf, Deposit, + InsertSorted, NegativeImbalanceOf, PalletsOriginOf, ReferendumIndex, ReferendumInfo, + ReferendumInfoOf, ReferendumStatus, ReferendumStatusOf, ScheduleAddressOf, TallyOf, + TrackIdOf, TrackInfo, TrackInfoOf, TracksInfo, VotesOf, }, weights::WeightInfo, }; @@ -108,6 +108,30 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] pub mod benchmarking; +pub use frame_support::traits::Get; +pub use sp_std::vec::Vec; + +#[macro_export] +macro_rules! impl_tracksinfo_get { + ($tracksinfo:ty, $balance:ty, $blocknumber:ty) => { + impl + $crate::Get< + $crate::Vec<( + <$tracksinfo as $crate::TracksInfo<$balance, $blocknumber>>::Id, + $crate::TrackInfo<$balance, $blocknumber>, + )>, + > for $tracksinfo + { + fn get() -> $crate::Vec<( + <$tracksinfo as $crate::TracksInfo<$balance, $blocknumber>>::Id, + $crate::TrackInfo<$balance, $blocknumber>, + )> { + <$tracksinfo as $crate::TracksInfo<$balance, $blocknumber>>::tracks().to_vec() + } + } + }; +} + const ASSEMBLY_ID: LockIdentifier = *b"assembly"; #[frame_support::pallet] @@ -123,31 +147,27 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + Sized { // System level stuff. - type Call: Parameter + Dispatchable + From>; - type Event: From> + IsType<::Event>; + type RuntimeCall: Parameter + + Dispatchable + + From> + + IsType<::RuntimeCall> + + From>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; /// The Scheduler. - type Scheduler: ScheduleAnon< - Self::BlockNumber, - CallOf, - PalletsOriginOf, - Hash = Self::Hash, - > + ScheduleNamed< - Self::BlockNumber, - CallOf, - PalletsOriginOf, - Hash = Self::Hash, - >; + type Scheduler: ScheduleAnon, PalletsOriginOf> + + ScheduleNamed, PalletsOriginOf>; /// Currency type for this pallet. type Currency: ReservableCurrency; // Origins and unbalances. /// Origin from which proposals may be submitted. - type SubmitOrigin: EnsureOrigin; + type SubmitOrigin: EnsureOrigin; /// Origin from which any vote may be cancelled. - type CancelOrigin: EnsureOrigin; + type CancelOrigin: EnsureOrigin; /// Origin from which any vote may be killed. - type KillOrigin: EnsureOrigin; + type KillOrigin: EnsureOrigin; /// Handler for the unbalanced reduction when slashing a preimage deposit. type Slash: OnUnbalanced>; /// The counting type for votes. Usually just balance. @@ -183,11 +203,20 @@ pub mod pallet { // The other stuff. /// Information concerning the different referendum tracks. - type Tracks: TracksInfo< - BalanceOf, - Self::BlockNumber, - Origin = ::PalletsOrigin, - >; + #[pallet::constant] + type Tracks: Get< + Vec<( + , Self::BlockNumber>>::Id, + TrackInfo, Self::BlockNumber>, + )>, + > + TracksInfo< + BalanceOf, + Self::BlockNumber, + RuntimeOrigin = ::PalletsOrigin, + >; + + /// The preimage provider. + type Preimages: QueryPreimage + StorePreimage; } /// The next free referendum index, aka the number of referenda started so far. @@ -226,8 +255,8 @@ pub mod pallet { index: ReferendumIndex, /// The track (and by extension proposal dispatch origin) of this referendum. track: TrackIdOf, - /// The hash of the proposal up for referendum. - proposal_hash: T::Hash, + /// The proposal for the referendum. + proposal: BoundedCallOf, }, /// The decision deposit has been placed. DecisionDepositPlaced { @@ -260,8 +289,8 @@ pub mod pallet { index: ReferendumIndex, /// The track (and by extension proposal dispatch origin) of this referendum. track: TrackIdOf, - /// The hash of the proposal up for referendum. - proposal_hash: T::Hash, + /// The proposal for the referendum. + proposal: BoundedCallOf, /// The current tally of votes in this referendum. tally: T::Tally, }, @@ -348,7 +377,7 @@ pub mod pallet { /// - `origin`: must be `SubmitOrigin` and the account must have `SubmissionDeposit` funds /// available. /// - `proposal_origin`: The origin from which the proposal should be executed. - /// - `proposal_hash`: The hash of the proposal preimage. + /// - `proposal`: The proposal. /// - `enactment_moment`: The moment that the proposal should be enacted. /// /// Emits `Submitted`. @@ -356,7 +385,7 @@ pub mod pallet { pub fn submit( origin: OriginFor, proposal_origin: Box>, - proposal_hash: T::Hash, + proposal: BoundedCallOf, enactment_moment: DispatchTime, ) -> DispatchResult { let who = T::SubmitOrigin::ensure_origin(origin)?; @@ -370,11 +399,12 @@ pub mod pallet { r }); let now = frame_system::Pallet::::block_number(); - let nudge_call = Call::nudge_referendum { index }; + let nudge_call = + T::Preimages::bound(CallOf::::from(Call::nudge_referendum { index }))?; let status = ReferendumStatus { track, origin: *proposal_origin, - proposal_hash, + proposal: proposal.clone(), enactment: enactment_moment, submitted: now, submission_deposit, @@ -386,7 +416,7 @@ pub mod pallet { }; ReferendumInfoFor::::insert(index, ReferendumInfo::Ongoing(status)); - Self::deposit_event(Event::::Submitted { index, track, proposal_hash }); + Self::deposit_event(Event::::Submitted { index, track, proposal }); Ok(()) } @@ -618,7 +648,8 @@ impl, I: 'static> Polling for Pallet { let mut status = ReferendumStatusOf:: { track: class, origin: frame_support::dispatch::RawOrigin::Root.into(), - proposal_hash: ::hash_of(&index), + proposal: T::Preimages::bound(CallOf::::from(Call::nudge_referendum { index })) + .map_err(|_| ())?, enactment: DispatchTime::After(Zero::zero()), submitted: now, submission_deposit: Deposit { who: dummy_account_id, amount: Zero::zero() }, @@ -676,18 +707,18 @@ impl, I: 'static> Pallet { track: &TrackInfoOf, desired: DispatchTime, origin: PalletsOriginOf, - call_hash: T::Hash, + call: BoundedCallOf, ) { let now = frame_system::Pallet::::block_number(); let earliest_allowed = now.saturating_add(track.min_enactment_period); let desired = desired.evaluate(now); let ok = T::Scheduler::schedule_named( - (ASSEMBLY_ID, "enactment", index).encode(), + (ASSEMBLY_ID, "enactment", index).using_encoded(sp_io::hashing::blake2_256), DispatchTime::At(desired.max(earliest_allowed)), None, 63, origin, - MaybeHashed::Hash(call_hash), + call, ) .is_ok(); debug_assert!(ok, "LOGIC ERROR: bake_referendum/schedule_named failed"); @@ -695,7 +726,7 @@ impl, I: 'static> Pallet { /// Set an alarm to dispatch `call` at block number `when`. fn set_alarm( - call: impl Into>, + call: BoundedCallOf, when: T::BlockNumber, ) -> Option<(T::BlockNumber, ScheduleAddressOf)> { let alarm_interval = T::AlarmInterval::get().max(One::one()); @@ -706,7 +737,7 @@ impl, I: 'static> Pallet { None, 128u8, frame_system::RawOrigin::Root.into(), - MaybeHashed::Value(call.into()), + call, ) .ok() .map(|x| (when, x)); @@ -743,7 +774,7 @@ impl, I: 'static> Pallet { Self::deposit_event(Event::::DecisionStarted { index, tally: status.tally.clone(), - proposal_hash: status.proposal_hash, + proposal: status.proposal.clone(), track: status.track, }); let confirming = if is_passing { @@ -810,12 +841,21 @@ impl, I: 'static> Pallet { let alarm_interval = T::AlarmInterval::get().max(One::one()); let when = (next_block + alarm_interval - One::one()) / alarm_interval * alarm_interval; + let call = match T::Preimages::bound(CallOf::::from(Call::one_fewer_deciding { + track, + })) { + Ok(c) => c, + Err(_) => { + debug_assert!(false, "Unable to create a bounded call from `one_fewer_deciding`??",); + return + }, + }; let maybe_result = T::Scheduler::schedule( DispatchTime::At(when), None, 128u8, frame_system::RawOrigin::Root.into(), - MaybeHashed::Value(Call::one_fewer_deciding { track }.into()), + call, ); debug_assert!( maybe_result.is_ok(), @@ -838,7 +878,18 @@ impl, I: 'static> Pallet { if status.alarm.as_ref().map_or(true, |&(when, _)| when != alarm) { // Either no alarm or one that was different Self::ensure_no_alarm(status); - status.alarm = Self::set_alarm(Call::nudge_referendum { index }, alarm); + let call = + match T::Preimages::bound(CallOf::::from(Call::nudge_referendum { index })) { + Ok(c) => c, + Err(_) => { + debug_assert!( + false, + "Unable to create a bounded call from `nudge_referendum`??", + ); + return false + }, + }; + status.alarm = Self::set_alarm(call, alarm); true } else { false @@ -954,14 +1005,8 @@ impl, I: 'static> Pallet { // Passed! Self::ensure_no_alarm(&mut status); Self::note_one_fewer_deciding(status.track); - let (desired, call_hash) = (status.enactment, status.proposal_hash); - Self::schedule_enactment( - index, - track, - desired, - status.origin, - call_hash, - ); + let (desired, call) = (status.enactment, status.proposal); + Self::schedule_enactment(index, track, desired, status.origin, call); Self::deposit_event(Event::::Confirmed { index, tally: status.tally, diff --git a/frame/referenda/src/mock.rs b/frame/referenda/src/mock.rs index 698bea8cc9f67..c98fbf9a676b1 100644 --- a/frame/referenda/src/mock.rs +++ b/frame/referenda/src/mock.rs @@ -24,7 +24,7 @@ use frame_support::{ assert_ok, ord_parameter_types, parameter_types, traits::{ ConstU32, ConstU64, Contains, EqualPrivilegeOnly, OnInitialize, OriginTrait, Polling, - PreimageRecipient, SortedMembers, + SortedMembers, }, weights::Weight, }; @@ -32,7 +32,7 @@ use frame_system::{EnsureRoot, EnsureSignedBy}; use sp_core::H256; use sp_runtime::{ testing::Header, - traits::{BlakeTwo256, Hash, IdentityLookup}, + traits::{BlakeTwo256, IdentityLookup}, DispatchResult, Perbill, }; @@ -55,9 +55,9 @@ frame_support::construct_runtime!( // Test that a fitlered call can be dispatched. pub struct BaseFilter; -impl Contains for BaseFilter { - fn contains(call: &Call) -> bool { - !matches!(call, &Call::Balances(pallet_balances::Call::set_balance { .. })) +impl Contains for BaseFilter { + fn contains(call: &RuntimeCall) -> bool { + !matches!(call, &RuntimeCall::Balances(pallet_balances::Call::set_balance { .. })) } } @@ -71,16 +71,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -93,33 +93,31 @@ impl frame_system::Config for Test { type MaxConsumers = ConstU32<16>; } impl pallet_preimage::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type Currency = Balances; type ManagerOrigin = EnsureRoot; - type MaxSize = ConstU32<4096>; type BaseDeposit = (); type ByteDeposit = (); } impl pallet_scheduler::Config for Test { - type Event = Event; - type Origin = Origin; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; type PalletsOrigin = OriginCaller; - type Call = Call; + type RuntimeCall = RuntimeCall; type MaximumWeight = MaxWeight; type ScheduleOrigin = EnsureRoot; type MaxScheduledPerBlock = ConstU32<100>; type WeightInfo = (); type OriginPrivilegeCmp = EqualPrivilegeOnly; - type PreimageProvider = Preimage; - type NoPreimagePostponement = ConstU64<10>; + type Preimages = Preimage; } impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type MaxLocks = ConstU32<10>; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -148,7 +146,7 @@ impl SortedMembers for OneToFive { pub struct TestTracksInfo; impl TracksInfo for TestTracksInfo { type Id = u8; - type Origin = ::PalletsOrigin; + type RuntimeOrigin = ::PalletsOrigin; fn tracks() -> &'static [(Self::Id, TrackInfo)] { static DATA: [(u8, TrackInfo); 2] = [ ( @@ -198,7 +196,7 @@ impl TracksInfo for TestTracksInfo { ]; &DATA[..] } - fn track_for(id: &Self::Origin) -> Result { + fn track_for(id: &Self::RuntimeOrigin) -> Result { if let Ok(system_origin) = frame_system::RawOrigin::try_from(id.clone()) { match system_origin { frame_system::RawOrigin::Root => Ok(0), @@ -210,11 +208,12 @@ impl TracksInfo for TestTracksInfo { } } } +impl_tracksinfo_get!(TestTracksInfo, u64, u64); impl Config for Test { type WeightInfo = (); - type Call = Call; - type Event = Event; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type Scheduler = Scheduler; type Currency = pallet_balances::Pallet; type SubmitOrigin = frame_system::EnsureSigned; @@ -228,6 +227,7 @@ impl Config for Test { type UndecidingTimeout = ConstU64<20>; type AlarmInterval = AlarmInterval; type Tracks = TestTracksInfo; + type Preimages = Preimage; } pub fn new_test_ext() -> sp_io::TestExternalities { @@ -297,26 +297,29 @@ impl VoteTally for Tally { } pub fn set_balance_proposal(value: u64) -> Vec { - Call::Balances(pallet_balances::Call::set_balance { who: 42, new_free: value, new_reserved: 0 }) - .encode() + RuntimeCall::Balances(pallet_balances::Call::set_balance { + who: 42, + new_free: value, + new_reserved: 0, + }) + .encode() } -pub fn set_balance_proposal_hash(value: u64) -> H256 { - let c = Call::Balances(pallet_balances::Call::set_balance { +pub fn set_balance_proposal_bounded(value: u64) -> BoundedCallOf { + let c = RuntimeCall::Balances(pallet_balances::Call::set_balance { who: 42, new_free: value, new_reserved: 0, }); - >::note_preimage(c.encode().try_into().unwrap()); - BlakeTwo256::hash_of(&c) + ::bound(c).unwrap() } #[allow(dead_code)] pub fn propose_set_balance(who: u64, value: u64, delay: u64) -> DispatchResult { Referenda::submit( - Origin::signed(who), + RuntimeOrigin::signed(who), Box::new(frame_system::RawOrigin::Root.into()), - set_balance_proposal_hash(value), + set_balance_proposal_bounded(value), DispatchTime::After(delay), ) } @@ -442,12 +445,12 @@ pub enum RefState { impl RefState { pub fn create(self) -> ReferendumIndex { assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(frame_support::dispatch::RawOrigin::Root.into()), - set_balance_proposal_hash(1), + set_balance_proposal_bounded(1), DispatchTime::At(10), )); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0)); if matches!(self, RefState::Confirming { immediate: true }) { set_tally(0, 100, 0); } diff --git a/frame/referenda/src/tests.rs b/frame/referenda/src/tests.rs index d5435daf185bd..355ce3021b87f 100644 --- a/frame/referenda/src/tests.rs +++ b/frame/referenda/src/tests.rs @@ -42,14 +42,14 @@ fn basic_happy_path_works() { new_test_ext().execute_with(|| { // #1: submit assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), - set_balance_proposal_hash(1), + set_balance_proposal_bounded(1), DispatchTime::At(10), )); assert_eq!(Balances::reserved_balance(&1), 2); assert_eq!(ReferendumCount::::get(), 1); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0)); run_to(4); assert_eq!(DecidingCount::::get(0), 0); run_to(5); @@ -63,7 +63,7 @@ fn basic_happy_path_works() { run_to(9); // #8: Should be confirmed & ended. assert_eq!(approved_since(0), 9); - assert_ok!(Referenda::refund_decision_deposit(Origin::signed(2), 0)); + assert_ok!(Referenda::refund_decision_deposit(RuntimeOrigin::signed(2), 0)); run_to(12); // #9: Should not yet be enacted. assert_eq!(Balances::free_balance(&42), 0); @@ -78,7 +78,7 @@ fn insta_confirm_then_kill_works() { new_test_ext().execute_with(|| { let r = Confirming { immediate: true }.create(); run_to(6); - assert_ok!(Referenda::kill(Origin::root(), r)); + assert_ok!(Referenda::kill(RuntimeOrigin::root(), r)); assert_eq!(killed_since(r), 6); }); } @@ -173,24 +173,24 @@ fn queueing_works() { new_test_ext().execute_with(|| { // Submit a proposal into a track with a queue len of 1. assert_ok!(Referenda::submit( - Origin::signed(5), + RuntimeOrigin::signed(5), Box::new(RawOrigin::Root.into()), - set_balance_proposal_hash(0), + set_balance_proposal_bounded(0), DispatchTime::After(0), )); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(5), 0)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(5), 0)); run_to(2); // Submit 3 more proposals into the same queue. for i in 1..=4 { assert_ok!(Referenda::submit( - Origin::signed(i), + RuntimeOrigin::signed(i), Box::new(RawOrigin::Root.into()), - set_balance_proposal_hash(i), + set_balance_proposal_bounded(i), DispatchTime::After(0), )); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(i), i as u32)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(i), i as u32)); // TODO: decision deposit after some initial votes with a non-highest voted coming // first. } @@ -214,7 +214,7 @@ fn queueing_works() { println!("{:?}", Vec::<_>::from(TrackQueue::::get(0))); // Cancel the first. - assert_ok!(Referenda::cancel(Origin::signed(4), 0)); + assert_ok!(Referenda::cancel(RuntimeOrigin::signed(4), 0)); assert_eq!(cancelled_since(0), 6); // The other with the most approvals (#4) should be being decided. @@ -270,9 +270,9 @@ fn auto_timeout_should_happen_with_nothing_but_submit() { new_test_ext().execute_with(|| { // #1: submit assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), - set_balance_proposal_hash(1), + set_balance_proposal_bounded(1), DispatchTime::At(20), )); run_to(20); @@ -290,20 +290,20 @@ fn auto_timeout_should_happen_with_nothing_but_submit() { fn tracks_are_distinguished() { new_test_ext().execute_with(|| { assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), - set_balance_proposal_hash(1), + set_balance_proposal_bounded(1), DispatchTime::At(10), )); assert_ok!(Referenda::submit( - Origin::signed(2), + RuntimeOrigin::signed(2), Box::new(RawOrigin::None.into()), - set_balance_proposal_hash(2), + set_balance_proposal_bounded(2), DispatchTime::At(20), )); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(3), 0)); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(4), 1)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(3), 0)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(4), 1)); let mut i = ReferendumInfoFor::::iter().collect::>(); i.sort_by_key(|x| x.0); @@ -315,7 +315,7 @@ fn tracks_are_distinguished() { ReferendumInfo::Ongoing(ReferendumStatus { track: 0, origin: OriginCaller::system(RawOrigin::Root), - proposal_hash: set_balance_proposal_hash(1), + proposal: set_balance_proposal_bounded(1), enactment: DispatchTime::At(10), submitted: 1, submission_deposit: Deposit { who: 1, amount: 2 }, @@ -331,7 +331,7 @@ fn tracks_are_distinguished() { ReferendumInfo::Ongoing(ReferendumStatus { track: 1, origin: OriginCaller::system(RawOrigin::None), - proposal_hash: set_balance_proposal_hash(2), + proposal: set_balance_proposal_bounded(2), enactment: DispatchTime::At(20), submitted: 1, submission_deposit: Deposit { who: 2, amount: 2 }, @@ -350,13 +350,13 @@ fn tracks_are_distinguished() { #[test] fn submit_errors_work() { new_test_ext().execute_with(|| { - let h = set_balance_proposal_hash(1); + let h = set_balance_proposal_bounded(1); // No track for Signed origins. assert_noop!( Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Signed(2).into()), - h, + h.clone(), DispatchTime::At(10), ), Error::::NoTrack @@ -365,7 +365,7 @@ fn submit_errors_work() { // No funds for deposit assert_noop!( Referenda::submit( - Origin::signed(10), + RuntimeOrigin::signed(10), Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), @@ -379,21 +379,21 @@ fn submit_errors_work() { fn decision_deposit_errors_work() { new_test_ext().execute_with(|| { let e = Error::::NotOngoing; - assert_noop!(Referenda::place_decision_deposit(Origin::signed(2), 0), e); + assert_noop!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0), e); - let h = set_balance_proposal_hash(1); + let h = set_balance_proposal_bounded(1); assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); let e = BalancesError::::InsufficientBalance; - assert_noop!(Referenda::place_decision_deposit(Origin::signed(10), 0), e); + assert_noop!(Referenda::place_decision_deposit(RuntimeOrigin::signed(10), 0), e); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0)); let e = Error::::HasDeposit; - assert_noop!(Referenda::place_decision_deposit(Origin::signed(2), 0), e); + assert_noop!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0), e); }); } @@ -401,42 +401,42 @@ fn decision_deposit_errors_work() { fn refund_deposit_works() { new_test_ext().execute_with(|| { let e = Error::::BadReferendum; - assert_noop!(Referenda::refund_decision_deposit(Origin::signed(1), 0), e); + assert_noop!(Referenda::refund_decision_deposit(RuntimeOrigin::signed(1), 0), e); - let h = set_balance_proposal_hash(1); + let h = set_balance_proposal_bounded(1); assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); let e = Error::::NoDeposit; - assert_noop!(Referenda::refund_decision_deposit(Origin::signed(2), 0), e); + assert_noop!(Referenda::refund_decision_deposit(RuntimeOrigin::signed(2), 0), e); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0)); let e = Error::::Unfinished; - assert_noop!(Referenda::refund_decision_deposit(Origin::signed(3), 0), e); + assert_noop!(Referenda::refund_decision_deposit(RuntimeOrigin::signed(3), 0), e); run_to(11); - assert_ok!(Referenda::refund_decision_deposit(Origin::signed(3), 0)); + assert_ok!(Referenda::refund_decision_deposit(RuntimeOrigin::signed(3), 0)); }); } #[test] fn cancel_works() { new_test_ext().execute_with(|| { - let h = set_balance_proposal_hash(1); + let h = set_balance_proposal_bounded(1); assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0)); run_to(8); - assert_ok!(Referenda::cancel(Origin::signed(4), 0)); - assert_ok!(Referenda::refund_decision_deposit(Origin::signed(3), 0)); + assert_ok!(Referenda::cancel(RuntimeOrigin::signed(4), 0)); + assert_ok!(Referenda::refund_decision_deposit(RuntimeOrigin::signed(3), 0)); assert_eq!(cancelled_since(0), 8); }); } @@ -444,37 +444,37 @@ fn cancel_works() { #[test] fn cancel_errors_works() { new_test_ext().execute_with(|| { - let h = set_balance_proposal_hash(1); + let h = set_balance_proposal_bounded(1); assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); - assert_noop!(Referenda::cancel(Origin::signed(1), 0), BadOrigin); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0)); + assert_noop!(Referenda::cancel(RuntimeOrigin::signed(1), 0), BadOrigin); run_to(11); - assert_noop!(Referenda::cancel(Origin::signed(4), 0), Error::::NotOngoing); + assert_noop!(Referenda::cancel(RuntimeOrigin::signed(4), 0), Error::::NotOngoing); }); } #[test] fn kill_works() { new_test_ext().execute_with(|| { - let h = set_balance_proposal_hash(1); + let h = set_balance_proposal_bounded(1); assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0)); run_to(8); - assert_ok!(Referenda::kill(Origin::root(), 0)); + assert_ok!(Referenda::kill(RuntimeOrigin::root(), 0)); let e = Error::::NoDeposit; - assert_noop!(Referenda::refund_decision_deposit(Origin::signed(3), 0), e); + assert_noop!(Referenda::refund_decision_deposit(RuntimeOrigin::signed(3), 0), e); assert_eq!(killed_since(0), 8); }); } @@ -482,25 +482,25 @@ fn kill_works() { #[test] fn kill_errors_works() { new_test_ext().execute_with(|| { - let h = set_balance_proposal_hash(1); + let h = set_balance_proposal_bounded(1); assert_ok!(Referenda::submit( - Origin::signed(1), + RuntimeOrigin::signed(1), Box::new(RawOrigin::Root.into()), h, DispatchTime::At(10), )); - assert_ok!(Referenda::place_decision_deposit(Origin::signed(2), 0)); - assert_noop!(Referenda::kill(Origin::signed(4), 0), BadOrigin); + assert_ok!(Referenda::place_decision_deposit(RuntimeOrigin::signed(2), 0)); + assert_noop!(Referenda::kill(RuntimeOrigin::signed(4), 0), BadOrigin); run_to(11); - assert_noop!(Referenda::kill(Origin::root(), 0), Error::::NotOngoing); + assert_noop!(Referenda::kill(RuntimeOrigin::root(), 0), Error::::NotOngoing); }); } #[test] fn set_balance_proposal_is_correctly_filtered_out() { for i in 0..10 { - let call = crate::mock::Call::decode(&mut &set_balance_proposal(i)[..]).unwrap(); + let call = crate::mock::RuntimeCall::decode(&mut &set_balance_proposal(i)[..]).unwrap(); assert!(!::BaseCallFilter::contains(&call)); } } diff --git a/frame/referenda/src/types.rs b/frame/referenda/src/types.rs index 3eba783246e10..2ce93cb6adc3c 100644 --- a/frame/referenda/src/types.rs +++ b/frame/referenda/src/types.rs @@ -19,7 +19,10 @@ use super::*; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; -use frame_support::{traits::schedule::Anon, Parameter}; +use frame_support::{ + traits::{schedule::v3::Anon, Bounded}, + Parameter, +}; use scale_info::TypeInfo; use sp_arithmetic::{Rounding::*, SignedRounding::*}; use sp_runtime::{FixedI64, PerThing, RuntimeDebug}; @@ -30,15 +33,17 @@ pub type BalanceOf = pub type NegativeImbalanceOf = <>::Currency as Currency< ::AccountId, >>::NegativeImbalance; -pub type CallOf = >::Call; +pub type CallOf = >::RuntimeCall; +pub type BoundedCallOf = Bounded<>::RuntimeCall>; pub type VotesOf = >::Votes; pub type TallyOf = >::Tally; -pub type PalletsOriginOf = <::Origin as OriginTrait>::PalletsOrigin; +pub type PalletsOriginOf = + <::RuntimeOrigin as OriginTrait>::PalletsOrigin; pub type ReferendumInfoOf = ReferendumInfo< TrackIdOf, PalletsOriginOf, ::BlockNumber, - ::Hash, + BoundedCallOf, BalanceOf, TallyOf, ::AccountId, @@ -48,7 +53,7 @@ pub type ReferendumStatusOf = ReferendumStatus< TrackIdOf, PalletsOriginOf, ::BlockNumber, - ::Hash, + BoundedCallOf, BalanceOf, TallyOf, ::AccountId, @@ -139,13 +144,13 @@ pub trait TracksInfo { type Id: Copy + Parameter + Ord + PartialOrd + Send + Sync + 'static + MaxEncodedLen; /// The origin type from which a track is implied. - type Origin; + type RuntimeOrigin; /// Return the array of known tracks and their information. fn tracks() -> &'static [(Self::Id, TrackInfo)]; /// Determine the voting track for the given `origin`. - fn track_for(origin: &Self::Origin) -> Result; + fn track_for(origin: &Self::RuntimeOrigin) -> Result; /// Return the track info for track `id`, by default this just looks it up in `Self::tracks()`. fn info(id: Self::Id) -> Option<&'static TrackInfo> { @@ -157,9 +162,9 @@ pub trait TracksInfo { #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ReferendumStatus< TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, - Origin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + RuntimeOrigin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Moment: Parameter + Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike, - Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Call: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, @@ -168,9 +173,9 @@ pub struct ReferendumStatus< /// The track of this referendum. pub(crate) track: TrackId, /// The origin for this referendum. - pub(crate) origin: Origin, + pub(crate) origin: RuntimeOrigin, /// The hash of the proposal up for referendum. - pub(crate) proposal_hash: Hash, + pub(crate) proposal: Call, /// The time the proposal should be scheduled for enactment. pub(crate) enactment: DispatchTime, /// The time of submission. Once `UndecidingTimeout` passes, it may be closed by anyone if it @@ -194,9 +199,9 @@ pub struct ReferendumStatus< #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum ReferendumInfo< TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, - Origin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + RuntimeOrigin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Moment: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike, - Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Call: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, @@ -204,7 +209,16 @@ pub enum ReferendumInfo< > { /// Referendum has been submitted and is being voted on. Ongoing( - ReferendumStatus, + ReferendumStatus< + TrackId, + RuntimeOrigin, + Moment, + Call, + Balance, + Tally, + AccountId, + ScheduleAddress, + >, ), /// Referendum finished with approval. Submission deposit is held. Approved(Moment, Deposit, Option>), @@ -220,14 +234,14 @@ pub enum ReferendumInfo< impl< TrackId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, - Origin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + RuntimeOrigin: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Moment: Parameter + Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone + EncodeLike, - Hash: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, + Call: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Balance: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, Tally: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, AccountId: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, ScheduleAddress: Eq + PartialEq + Debug + Encode + Decode + TypeInfo + Clone, - > ReferendumInfo + > ReferendumInfo { /// Take the Decision Deposit from `self`, if there is one. Returns an `Err` if `self` is not /// in a valid state for the Decision Deposit to be refunded. diff --git a/frame/remark/Cargo.toml b/frame/remark/Cargo.toml index fe20365b7c904..f644ea723b59f 100644 --- a/frame/remark/Cargo.toml +++ b/frame/remark/Cargo.toml @@ -31,6 +31,7 @@ sp-core = { version = "6.0.0", default-features = false, path = "../../primitive default = ["std"] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/remark/src/benchmarking.rs b/frame/remark/src/benchmarking.rs index d30a8aa5df07d..c0db8d5d3d59b 100644 --- a/frame/remark/src/benchmarking.rs +++ b/frame/remark/src/benchmarking.rs @@ -27,9 +27,9 @@ use sp_std::*; #[cfg(test)] use crate::Pallet as Remark; -fn assert_last_event(generic_event: ::Event) { +fn assert_last_event(generic_event: ::RuntimeEvent) { let events = System::::events(); - let system_event: ::Event = generic_event.into(); + let system_event: ::RuntimeEvent = generic_event.into(); let EventRecord { event, .. } = &events[events.len() - 1]; assert_eq!(event, &system_event); } diff --git a/frame/remark/src/lib.rs b/frame/remark/src/lib.rs index c69f95907019f..b61c79f7f273d 100644 --- a/frame/remark/src/lib.rs +++ b/frame/remark/src/lib.rs @@ -43,7 +43,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; } diff --git a/frame/remark/src/mock.rs b/frame/remark/src/mock.rs index 67a0399e9c386..22467796cf37b 100644 --- a/frame/remark/src/mock.rs +++ b/frame/remark/src/mock.rs @@ -45,8 +45,8 @@ impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -54,7 +54,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); @@ -69,7 +69,7 @@ impl frame_system::Config for Test { } impl pallet_remark::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } diff --git a/frame/remark/src/tests.rs b/frame/remark/src/tests.rs index 580b64cc64997..2278e3817b48a 100644 --- a/frame/remark/src/tests.rs +++ b/frame/remark/src/tests.rs @@ -31,7 +31,7 @@ fn generates_event() { assert_ok!(Remark::::store(RawOrigin::Signed(caller).into(), data.clone(),)); let events = System::events(); // this one we create as we expect it - let system_event: ::Event = Event::Stored { + let system_event: ::RuntimeEvent = Event::Stored { content_hash: sp_io::hashing::blake2_256(&data).into(), sender: caller, } diff --git a/frame/root-offences/Cargo.toml b/frame/root-offences/Cargo.toml new file mode 100644 index 0000000000000..ea6a6527848aa --- /dev/null +++ b/frame/root-offences/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "pallet-root-offences" +version = "1.0.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "FRAME root offences pallet" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } + +pallet-session = { version = "4.0.0-dev", features = [ "historical" ], path = "../../frame/session", default-features = false } +pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../frame/staking" } +pallet-offences = { version = "4.0.0-dev", default-features = false, path = "../../frame/offences" } + +frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } +frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } +sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" } +sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } + +[dev-dependencies] +pallet-balances = { version = "4.0.0-dev", path = "../balances" } +pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } +pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } + +sp-core = { version = "6.0.0", path = "../../primitives/core" } +sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } +sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } + +frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } + +[features] +runtime-benchmarks = [] +try-runtime = ["frame-support/try-runtime"] +default = ["std"] +std = [ + "codec/std", + "frame-support/std", + "frame-system/std", + "pallet-session/std", + "pallet-staking/std", + "pallet-offences/std", + "scale-info/std", + "sp-runtime/std", +] diff --git a/frame/root-offences/README.md b/frame/root-offences/README.md new file mode 100644 index 0000000000000..a2c5261b6985a --- /dev/null +++ b/frame/root-offences/README.md @@ -0,0 +1,5 @@ +# Sudo Offences Pallet + +Pallet that allows the root to create an offence. + +NOTE: This pallet should only be used for testing purposes. \ No newline at end of file diff --git a/frame/root-offences/src/lib.rs b/frame/root-offences/src/lib.rs new file mode 100644 index 0000000000000..b4b549627f3fa --- /dev/null +++ b/frame/root-offences/src/lib.rs @@ -0,0 +1,131 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Sudo Offences Pallet +//! Pallet that allows the root to create an offence. +//! +//! NOTE: This pallet should be used for testing purposes. + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +use pallet_session::historical::IdentificationTuple; +use pallet_staking::{BalanceOf, Exposure, ExposureOf, Pallet as Staking}; +use sp_runtime::Perbill; +use sp_staking::offence::{DisableStrategy, OnOffenceHandler}; + +pub use pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: + frame_system::Config + + pallet_staking::Config + + pallet_session::Config::AccountId> + + pallet_session::historical::Config< + FullIdentification = Exposure< + ::AccountId, + BalanceOf, + >, + FullIdentificationOf = ExposureOf, + > + { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(_); + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// An offence was created by root. + OffenceCreated { offenders: Vec<(T::AccountId, Perbill)> }, + } + + #[pallet::error] + pub enum Error { + /// Failed to get the active era from the staking pallet. + FailedToGetActiveEra, + } + + type OffenceDetails = sp_staking::offence::OffenceDetails< + ::AccountId, + IdentificationTuple, + >; + + #[pallet::call] + impl Pallet { + /// Allows the `root`, for example sudo to create an offence. + #[pallet::weight(T::DbWeight::get().reads(2))] + pub fn create_offence( + origin: OriginFor, + offenders: Vec<(T::AccountId, Perbill)>, + ) -> DispatchResult { + ensure_root(origin)?; + + let slash_fraction = + offenders.clone().into_iter().map(|(_, fraction)| fraction).collect::>(); + let offence_details = Self::get_offence_details(offenders.clone())?; + + Self::submit_offence(&offence_details, &slash_fraction); + Self::deposit_event(Event::OffenceCreated { offenders }); + Ok(()) + } + } + + impl Pallet { + /// Returns a vector of offenders that are going to be slashed. + fn get_offence_details( + offenders: Vec<(T::AccountId, Perbill)>, + ) -> Result>, DispatchError> { + let now = Staking::::active_era() + .map(|e| e.index) + .ok_or(Error::::FailedToGetActiveEra)?; + + Ok(offenders + .clone() + .into_iter() + .map(|(o, _)| OffenceDetails:: { + offender: (o.clone(), Staking::::eras_stakers(now, o)), + reporters: vec![], + }) + .collect()) + } + + /// Submits the offence by calling the `on_offence` function. + fn submit_offence(offenders: &[OffenceDetails], slash_fraction: &[Perbill]) { + let session_index = as frame_support::traits::ValidatorSet>::session_index(); + + as OnOffenceHandler< + T::AccountId, + IdentificationTuple, + Weight, + >>::on_offence(&offenders, &slash_fraction, session_index, DisableStrategy::WhenSlashed); + } + } +} diff --git a/frame/root-offences/src/mock.rs b/frame/root-offences/src/mock.rs new file mode 100644 index 0000000000000..3f0a26afc1358 --- /dev/null +++ b/frame/root-offences/src/mock.rs @@ -0,0 +1,356 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use crate as root_offences; + +use frame_election_provider_support::{onchain, SequentialPhragmen}; +use frame_support::{ + parameter_types, + traits::{ConstU32, ConstU64, GenesisBuild, Hooks, OneSessionHandler}, +}; +use pallet_staking::StakerStatus; +use sp_core::H256; +use sp_runtime::{ + curve::PiecewiseLinear, + testing::{Header, UintAuthorityId}, + traits::{BlakeTwo256, IdentityLookup, Zero}, +}; +use sp_staking::{EraIndex, SessionIndex}; +use sp_std::collections::btree_map::BTreeMap; + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; +type AccountId = u64; +type Balance = u64; +type BlockNumber = u64; + +pub const INIT_TIMESTAMP: u64 = 30_000; +pub const BLOCK_TIME: u64 = 1000; + +frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, + Session: pallet_session::{Pallet, Call, Storage, Event, Config}, + RootOffences: root_offences::{Pallet, Call, Storage, Event}, + Historical: pallet_session::historical::{Pallet, Storage}, + } +); + +/// Another session handler struct to test on_disabled. +pub struct OtherSessionHandler; +impl OneSessionHandler for OtherSessionHandler { + type Key = UintAuthorityId; + + fn on_genesis_session<'a, I: 'a>(_: I) + where + I: Iterator, + AccountId: 'a, + { + } + + fn on_new_session<'a, I: 'a>(_: bool, _: I, _: I) + where + I: Iterator, + AccountId: 'a, + { + } + + fn on_disabled(_validator_index: u32) {} +} + +impl sp_runtime::BoundToRuntimeAppPublic for OtherSessionHandler { + type Public = UintAuthorityId; +} + +parameter_types! { + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(frame_support::weights::Weight::from_ref_time(1024)); +} + +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type RuntimeCall = RuntimeCall; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl pallet_balances::Config for Test { + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type Balance = Balance; + type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); + type ExistentialDeposit = ConstU64<1>; + type AccountStore = System; + type WeightInfo = (); +} + +pallet_staking_reward_curve::build! { + const REWARD_CURVE: PiecewiseLinear<'static> = curve!( + min_inflation: 0_025_000u64, + max_inflation: 0_100_000, + ideal_stake: 0_500_000, + falloff: 0_050_000, + max_piece_count: 40, + test_precision: 0_005_000, + ); +} + +pub struct OnChainSeqPhragmen; +impl onchain::Config for OnChainSeqPhragmen { + type System = Test; + type Solver = SequentialPhragmen; + type DataProvider = Staking; + type WeightInfo = (); +} + +pub struct OnStakerSlashMock(core::marker::PhantomData); +impl sp_staking::OnStakerSlash for OnStakerSlashMock { + fn on_slash( + _pool_account: &AccountId, + slashed_bonded: Balance, + slashed_chunks: &BTreeMap, + ) { + LedgerSlashPerEra::set((slashed_bonded, slashed_chunks.clone())); + } +} + +parameter_types! { + pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE; + pub static Offset: BlockNumber = 0; + pub const Period: BlockNumber = 1; + pub static SessionsPerEra: SessionIndex = 3; + pub static SlashDeferDuration: EraIndex = 0; + pub const BondingDuration: EraIndex = 3; + pub static LedgerSlashPerEra: (BalanceOf, BTreeMap>) = (Zero::zero(), BTreeMap::new()); + pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(75); +} + +impl pallet_staking::Config for Test { + type MaxNominations = ConstU32<16>; + type Currency = Balances; + type CurrencyBalance = ::Balance; + type UnixTime = Timestamp; + type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; + type RewardRemainder = (); + type RuntimeEvent = RuntimeEvent; + type Slash = (); + type Reward = (); + type SessionsPerEra = SessionsPerEra; + type SlashDeferDuration = SlashDeferDuration; + type SlashCancelOrigin = frame_system::EnsureRoot; + type BondingDuration = BondingDuration; + type SessionInterface = Self; + type EraPayout = pallet_staking::ConvertCurve; + type NextNewSession = Session; + type MaxNominatorRewardedPerValidator = ConstU32<64>; + type OffendingValidatorsThreshold = OffendingValidatorsThreshold; + type ElectionProvider = onchain::UnboundedExecution; + type GenesisElectionProvider = Self::ElectionProvider; + type TargetList = pallet_staking::UseValidatorsMap; + type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = ConstU32<84>; + type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; + type OnStakerSlash = OnStakerSlashMock; + type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; + type WeightInfo = (); +} + +impl pallet_session::historical::Config for Test { + type FullIdentification = pallet_staking::Exposure; + type FullIdentificationOf = pallet_staking::ExposureOf; +} + +sp_runtime::impl_opaque_keys! { + pub struct SessionKeys { + pub other: OtherSessionHandler, + } +} + +impl pallet_session::Config for Test { + type SessionManager = pallet_session::historical::NoteHistoricalRoot; + type Keys = SessionKeys; + type ShouldEndSession = pallet_session::PeriodicSessions; + type SessionHandler = (OtherSessionHandler,); + type RuntimeEvent = RuntimeEvent; + type ValidatorId = AccountId; + type ValidatorIdOf = pallet_staking::StashOf; + type NextSessionRotation = pallet_session::PeriodicSessions; + type WeightInfo = (); +} + +impl pallet_timestamp::Config for Test { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = ConstU64<5>; + type WeightInfo = (); +} + +impl Config for Test { + type RuntimeEvent = RuntimeEvent; +} + +pub struct ExtBuilder { + validator_count: u32, + minimum_validator_count: u32, + invulnerables: Vec, + balance_factor: Balance, +} + +impl Default for ExtBuilder { + fn default() -> Self { + Self { + validator_count: 2, + minimum_validator_count: 0, + invulnerables: vec![], + balance_factor: 1, + } + } +} + +impl ExtBuilder { + fn build(self) -> sp_io::TestExternalities { + let mut storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![ + //controllers + (10, self.balance_factor * 50), + (20, self.balance_factor * 50), + (30, self.balance_factor * 50), + (40, self.balance_factor * 50), + // stashes + (11, self.balance_factor * 1000), + (21, self.balance_factor * 1000), + (31, self.balance_factor * 500), + (41, self.balance_factor * 1000), + ], + } + .assimilate_storage(&mut storage) + .unwrap(); + + let stakers = vec![ + // (stash, ctrl, stake, status) + // these two will be elected in the default test where we elect 2. + (11, 10, 1000, StakerStatus::::Validator), + (21, 20, 1000, StakerStatus::::Validator), + // a loser validator + (31, 30, 500, StakerStatus::::Validator), + // an idle validator + (41, 40, 1000, StakerStatus::::Idle), + ]; + + let _ = pallet_staking::GenesisConfig:: { + stakers: stakers.clone(), + ..Default::default() + }; + + let _ = pallet_staking::GenesisConfig:: { + stakers: stakers.clone(), + validator_count: self.validator_count, + minimum_validator_count: self.minimum_validator_count, + invulnerables: self.invulnerables, + slash_reward_fraction: Perbill::from_percent(10), + ..Default::default() + } + .assimilate_storage(&mut storage); + + let _ = pallet_session::GenesisConfig:: { + keys: stakers + .into_iter() + .map(|(id, ..)| (id, id, SessionKeys { other: id.into() })) + .collect(), + } + .assimilate_storage(&mut storage); + + storage.into() + } + + pub fn build_and_execute(self, test: impl FnOnce() -> ()) { + let mut ext = self.build(); + ext.execute_with(test); + } +} + +/// Progresses from the current block number (whatever that may be) to the `P * session_index + 1`. +pub(crate) fn start_session(session_index: SessionIndex) { + let end: u64 = if Offset::get().is_zero() { + (session_index as u64) * Period::get() + } else { + Offset::get() + (session_index.saturating_sub(1) as u64) * Period::get() + }; + run_to_block(end); + // session must have progressed properly. + assert_eq!( + Session::current_index(), + session_index, + "current session index = {}, expected = {}", + Session::current_index(), + session_index, + ); +} + +/// Progress to the given block, triggering session and era changes as we progress. +/// +/// This will finalize the previous block, initialize up to the given block, essentially simulating +/// a block import/propose process where we first initialize the block, then execute some stuff (not +/// in the function), and then finalize the block. +pub(crate) fn run_to_block(n: BlockNumber) { + Staking::on_finalize(System::block_number()); + for b in (System::block_number() + 1)..=n { + System::set_block_number(b); + Session::on_initialize(b); + >::on_initialize(b); + Timestamp::set_timestamp(System::block_number() * BLOCK_TIME + INIT_TIMESTAMP); + if b != n { + Staking::on_finalize(System::block_number()); + } + } +} + +pub(crate) fn active_era() -> EraIndex { + Staking::active_era().unwrap().index +} diff --git a/frame/root-offences/src/tests.rs b/frame/root-offences/src/tests.rs new file mode 100644 index 0000000000000..a8b7d0a6d6aca --- /dev/null +++ b/frame/root-offences/src/tests.rs @@ -0,0 +1,94 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; +use frame_support::{assert_err, assert_ok}; +use mock::{active_era, start_session, Balances, ExtBuilder, RootOffences, RuntimeOrigin, System}; + +#[test] +fn create_offence_fails_given_signed_origin() { + use sp_runtime::traits::BadOrigin; + ExtBuilder::default().build_and_execute(|| { + let offenders = (&[]).to_vec(); + assert_err!(RootOffences::create_offence(RuntimeOrigin::signed(1), offenders), BadOrigin); + }) +} + +#[test] +fn create_offence_works_given_root_origin() { + ExtBuilder::default().build_and_execute(|| { + start_session(1); + + assert_eq!(active_era(), 0); + + assert_eq!(Balances::free_balance(11), 1000); + + let offenders = [(11, Perbill::from_percent(50))].to_vec(); + assert_ok!(RootOffences::create_offence(RuntimeOrigin::root(), offenders.clone())); + + System::assert_last_event(Event::OffenceCreated { offenders }.into()); + // the slash should be applied right away. + assert_eq!(Balances::free_balance(11), 500); + + // the other validator should keep his balance, because we only created + // an offences for the first validator. + assert_eq!(Balances::free_balance(21), 1000); + }) +} + +#[test] +fn create_offence_wont_slash_non_active_validators() { + ExtBuilder::default().build_and_execute(|| { + start_session(1); + + assert_eq!(active_era(), 0); + + // 31 is not an active validator. + assert_eq!(Balances::free_balance(31), 500); + + let offenders = [(31, Perbill::from_percent(20)), (11, Perbill::from_percent(20))].to_vec(); + assert_ok!(RootOffences::create_offence(RuntimeOrigin::root(), offenders.clone())); + + System::assert_last_event(Event::OffenceCreated { offenders }.into()); + + // so 31 didn't get slashed. + assert_eq!(Balances::free_balance(31), 500); + + // but 11 is an active validator so he got slashed. + assert_eq!(Balances::free_balance(11), 800); + }) +} + +#[test] +fn create_offence_wont_slash_idle() { + ExtBuilder::default().build_and_execute(|| { + start_session(1); + + assert_eq!(active_era(), 0); + + // 41 is idle. + assert_eq!(Balances::free_balance(41), 1000); + + let offenders = [(41, Perbill::from_percent(50))].to_vec(); + assert_ok!(RootOffences::create_offence(RuntimeOrigin::root(), offenders.clone())); + + System::assert_last_event(Event::OffenceCreated { offenders }.into()); + + // 41 didn't get slashed. + assert_eq!(Balances::free_balance(41), 1000); + }) +} diff --git a/frame/scheduler/Cargo.toml b/frame/scheduler/Cargo.toml index d92d0df0c8037..e78d8cd5061c1 100644 --- a/frame/scheduler/Cargo.toml +++ b/frame/scheduler/Cargo.toml @@ -34,7 +34,7 @@ runtime-benchmarks = [ ] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/scheduler/src/benchmarking.rs b/frame/scheduler/src/benchmarking.rs index a8e36b72814b7..aaa30fd88ffda 100644 --- a/frame/scheduler/src/benchmarking.rs +++ b/frame/scheduler/src/benchmarking.rs @@ -18,201 +18,219 @@ //! Scheduler pallet benchmarking. use super::*; -use frame_benchmarking::benchmarks; +use frame_benchmarking::{account, benchmarks}; use frame_support::{ ensure, - traits::{OnInitialize, PreimageProvider, PreimageRecipient}, + traits::{schedule::Priority, BoundedInline}, }; -use sp_runtime::traits::Hash; +use frame_system::RawOrigin; use sp_std::{prelude::*, vec}; use crate::Pallet as Scheduler; -use frame_system::Pallet as System; +use frame_system::Call as SystemCall; + +const SEED: u32 = 0; const BLOCK_NUMBER: u32 = 2; -type SystemOrigin = ::Origin; +type SystemOrigin = ::RuntimeOrigin; -/// Add `n` named items to the schedule. +/// Add `n` items to the schedule. /// /// For `resolved`: +/// - ` /// - `None`: aborted (hash without preimage) /// - `Some(true)`: hash resolves into call if possible, plain call otherwise /// - `Some(false)`: plain call -fn fill_schedule( - when: T::BlockNumber, - n: u32, +fn fill_schedule(when: T::BlockNumber, n: u32) -> Result<(), &'static str> { + let t = DispatchTime::At(when); + let origin: ::PalletsOrigin = frame_system::RawOrigin::Root.into(); + for i in 0..n { + let call = make_call::(None); + let period = Some(((i + 100).into(), 100)); + let name = u32_to_name(i); + Scheduler::::do_schedule_named(name, t, period, 0, origin.clone(), call)?; + } + ensure!(Agenda::::get(when).len() == n as usize, "didn't fill schedule"); + Ok(()) +} + +fn u32_to_name(i: u32) -> TaskName { + i.using_encoded(blake2_256) +} + +fn make_task( periodic: bool, named: bool, - resolved: Option, -) -> Result<(), &'static str> { - for i in 0..n { - // Named schedule is strictly heavier than anonymous - let (call, hash) = call_and_hash::(i); - let call_or_hash = match resolved { - Some(true) => { - T::PreimageProvider::note_preimage(call.encode().try_into().unwrap()); - if T::PreimageProvider::have_preimage(&hash) { - CallOrHashOf::::Hash(hash) - } else { - call.into() - } + signed: bool, + maybe_lookup_len: Option, + priority: Priority, +) -> ScheduledOf { + let call = make_call::(maybe_lookup_len); + let maybe_periodic = match periodic { + true => Some((100u32.into(), 100)), + false => None, + }; + let maybe_id = match named { + true => Some(u32_to_name(0)), + false => None, + }; + let origin = make_origin::(signed); + Scheduled { maybe_id, priority, call, maybe_periodic, origin, _phantom: PhantomData } +} + +fn bounded(len: u32) -> Option::RuntimeCall>> { + let call = + <::RuntimeCall>::from(SystemCall::remark { remark: vec![0; len as usize] }); + T::Preimages::bound(call).ok() +} + +fn make_call(maybe_lookup_len: Option) -> Bounded<::RuntimeCall> { + let bound = BoundedInline::bound() as u32; + let mut len = match maybe_lookup_len { + Some(len) => len.min(T::Preimages::MAX_LENGTH as u32 - 2).max(bound) - 3, + None => bound.saturating_sub(4), + }; + + loop { + let c = match bounded::(len) { + Some(x) => x, + None => { + len -= 1; + continue }, - Some(false) => call.into(), - None => CallOrHashOf::::Hash(hash), }; - let period = match periodic { - true => Some(((i + 100).into(), 100)), - false => None, - }; - let t = DispatchTime::At(when); - let origin = frame_system::RawOrigin::Root.into(); - if named { - Scheduler::::do_schedule_named(i.encode(), t, period, 0, origin, call_or_hash)?; + if c.lookup_needed() == maybe_lookup_len.is_some() { + break c + } + if maybe_lookup_len.is_some() { + len += 1; } else { - Scheduler::::do_schedule(t, period, 0, origin, call_or_hash)?; + if len > 0 { + len -= 1; + } else { + break c + } } } - ensure!(Agenda::::get(when).len() == n as usize, "didn't fill schedule"); - Ok(()) } -fn call_and_hash(i: u32) -> (::Call, T::Hash) { - // Essentially a no-op call. - let call: ::Call = frame_system::Call::remark { remark: i.encode() }.into(); - let hash = T::Hashing::hash_of(&call); - (call, hash) +fn make_origin(signed: bool) -> ::PalletsOrigin { + match signed { + true => frame_system::RawOrigin::Signed(account("origin", 0, SEED)).into(), + false => frame_system::RawOrigin::Root.into(), + } +} + +fn dummy_counter() -> WeightCounter { + WeightCounter { used: Weight::zero(), limit: Weight::MAX } } benchmarks! { - on_initialize_periodic_named_resolved { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, true, true, Some(true))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s * 2); - for i in 0..s { - assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); - } + // `service_agendas` when no work is done. + service_agendas_base { + let now = T::BlockNumber::from(BLOCK_NUMBER); + IncompleteSince::::put(now - One::one()); + }: { + Scheduler::::service_agendas(&mut dummy_counter(), now, 0); + } verify { + assert_eq!(IncompleteSince::::get(), Some(now - One::one())); } - on_initialize_named_resolved { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, true, Some(true))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s * 2); - assert!(Agenda::::iter().count() == 0); + // `service_agenda` when no work is done. + service_agenda_base { + let now = BLOCK_NUMBER.into(); + let s in 0 .. T::MaxScheduledPerBlock::get(); + fill_schedule::(now, s)?; + let mut executed = 0; + }: { + Scheduler::::service_agenda(&mut dummy_counter(), &mut executed, now, now, 0); + } verify { + assert_eq!(executed, 0); } - on_initialize_periodic_resolved { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, true, false, Some(true))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s * 2); - for i in 0..s { - assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); - } + // `service_task` when the task is a non-periodic, non-named, non-fetched call which is not + // dispatched (e.g. due to being overweight). + service_task_base { + let now = BLOCK_NUMBER.into(); + let task = make_task::(false, false, false, None, 0); + // prevent any tasks from actually being executed as we only want the surrounding weight. + let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() }; + }: { + let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); + } verify { + //assert_eq!(result, Ok(())); } - on_initialize_resolved { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, false, Some(true))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s * 2); - assert!(Agenda::::iter().count() == 0); + // `service_task` when the task is a non-periodic, non-named, fetched call (with a known + // preimage length) and which is not dispatched (e.g. due to being overweight). + service_task_fetched { + let s in (BoundedInline::bound() as u32) .. (T::Preimages::MAX_LENGTH as u32); + let now = BLOCK_NUMBER.into(); + let task = make_task::(false, false, false, Some(s), 0); + // prevent any tasks from actually being executed as we only want the surrounding weight. + let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() }; + }: { + let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); + } verify { } - on_initialize_named_aborted { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, true, None)?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), 0); - if let Some(delay) = T::NoPreimagePostponement::get() { - assert_eq!(Agenda::::get(when + delay).len(), s as usize); - } else { - assert!(Agenda::::iter().count() == 0); - } + // `service_task` when the task is a non-periodic, named, non-fetched call which is not + // dispatched (e.g. due to being overweight). + service_task_named { + let now = BLOCK_NUMBER.into(); + let task = make_task::(false, true, false, None, 0); + // prevent any tasks from actually being executed as we only want the surrounding weight. + let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() }; + }: { + let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); + } verify { } - on_initialize_aborted { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, false, None)?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), 0); - if let Some(delay) = T::NoPreimagePostponement::get() { - assert_eq!(Agenda::::get(when + delay).len(), s as usize); - } else { - assert!(Agenda::::iter().count() == 0); - } + // `service_task` when the task is a periodic, non-named, non-fetched call which is not + // dispatched (e.g. due to being overweight). + service_task_periodic { + let now = BLOCK_NUMBER.into(); + let task = make_task::(true, false, false, None, 0); + // prevent any tasks from actually being executed as we only want the surrounding weight. + let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() }; + }: { + let result = Scheduler::::service_task(&mut counter, now, now, 0, true, task); + } verify { } - on_initialize_periodic_named { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, true, true, Some(false))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s); - for i in 0..s { - assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); - } + // `execute_dispatch` when the origin is `Signed`, not counting the dispatable's weight. + execute_dispatch_signed { + let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX }; + let origin = make_origin::(true); + let call = T::Preimages::realize(&make_call::(None)).unwrap().0; + }: { + assert!(Scheduler::::execute_dispatch(&mut counter, origin, call).is_ok()); } - - on_initialize_periodic { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, true, false, Some(false))?; - }: { Scheduler::::on_initialize(when); } verify { - assert_eq!(System::::event_count(), s); - for i in 0..s { - assert_eq!(Agenda::::get(when + (i + 100).into()).len(), 1 as usize); - } } - on_initialize_named { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, true, Some(false))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } - verify { - assert_eq!(System::::event_count(), s); - assert!(Agenda::::iter().count() == 0); + // `execute_dispatch` when the origin is not `Signed`, not counting the dispatable's weight. + execute_dispatch_unsigned { + let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX }; + let origin = make_origin::(false); + let call = T::Preimages::realize(&make_call::(None)).unwrap().0; + }: { + assert!(Scheduler::::execute_dispatch(&mut counter, origin, call).is_ok()); } - - on_initialize { - let s in 1 .. T::MaxScheduledPerBlock::get(); - let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, false, false, Some(false))?; - }: { Scheduler::::on_initialize(BLOCK_NUMBER.into()); } verify { - assert_eq!(System::::event_count(), s); - assert!(Agenda::::iter().count() == 0); } schedule { - let s in 0 .. T::MaxScheduledPerBlock::get(); + let s in 0 .. (T::MaxScheduledPerBlock::get() - 1); let when = BLOCK_NUMBER.into(); let periodic = Some((T::BlockNumber::one(), 100)); let priority = 0; // Essentially a no-op call. - let inner_call = frame_system::Call::set_storage { items: vec![] }.into(); - let call = Box::new(CallOrHashOf::::Value(inner_call)); + let call = Box::new(SystemCall::set_storage { items: vec![] }.into()); - fill_schedule::(when, s, true, true, Some(false))?; - let schedule_origin = T::ScheduleOrigin::successful_origin(); - }: _>(schedule_origin, when, periodic, priority, call) + fill_schedule::(when, s)?; + }: _(RawOrigin::Root, when, periodic, priority, call) verify { ensure!( Agenda::::get(when).len() == (s + 1) as usize, @@ -224,13 +242,13 @@ benchmarks! { let s in 1 .. T::MaxScheduledPerBlock::get(); let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, true, true, Some(false))?; + fill_schedule::(when, s)?; assert_eq!(Agenda::::get(when).len(), s as usize); let schedule_origin = T::ScheduleOrigin::successful_origin(); }: _>(schedule_origin, when, 0) verify { ensure!( - Lookup::::get(0.encode()).is_none(), + Lookup::::get(u32_to_name(0)).is_none(), "didn't remove from lookup" ); // Removed schedule is NONE @@ -241,18 +259,16 @@ benchmarks! { } schedule_named { - let s in 0 .. T::MaxScheduledPerBlock::get(); - let id = s.encode(); + let s in 0 .. (T::MaxScheduledPerBlock::get() - 1); + let id = u32_to_name(s); let when = BLOCK_NUMBER.into(); let periodic = Some((T::BlockNumber::one(), 100)); let priority = 0; // Essentially a no-op call. - let inner_call = frame_system::Call::set_storage { items: vec![] }.into(); - let call = Box::new(CallOrHashOf::::Value(inner_call)); + let call = Box::new(SystemCall::set_storage { items: vec![] }.into()); - fill_schedule::(when, s, true, true, Some(false))?; - let schedule_origin = T::ScheduleOrigin::successful_origin(); - }: _>(schedule_origin, id, when, periodic, priority, call) + fill_schedule::(when, s)?; + }: _(RawOrigin::Root, id, when, periodic, priority, call) verify { ensure!( Agenda::::get(when).len() == (s + 1) as usize, @@ -264,12 +280,11 @@ benchmarks! { let s in 1 .. T::MaxScheduledPerBlock::get(); let when = BLOCK_NUMBER.into(); - fill_schedule::(when, s, true, true, Some(false))?; - let schedule_origin = T::ScheduleOrigin::successful_origin(); - }: _>(schedule_origin, 0.encode()) + fill_schedule::(when, s)?; + }: _(RawOrigin::Root, u32_to_name(0)) verify { ensure!( - Lookup::::get(0.encode()).is_none(), + Lookup::::get(u32_to_name(0)).is_none(), "didn't remove from lookup" ); // Removed schedule is NONE diff --git a/frame/scheduler/src/lib.rs b/frame/scheduler/src/lib.rs index a005c051a1abc..b5ea0deeba9a3 100644 --- a/frame/scheduler/src/lib.rs +++ b/frame/scheduler/src/lib.rs @@ -52,27 +52,33 @@ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod migration; #[cfg(test)] mod mock; #[cfg(test)] mod tests; pub mod weights; -use codec::{Codec, Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ - dispatch::{DispatchError, DispatchResult, Dispatchable, Parameter}, + dispatch::{ + DispatchError, DispatchResult, Dispatchable, GetDispatchInfo, Parameter, RawOrigin, + }, + ensure, traits::{ schedule::{self, DispatchTime, MaybeHashed}, - EnsureOrigin, Get, IsType, OriginTrait, PalletInfoAccess, PrivilegeCmp, StorageVersion, + Bounded, CallerTrait, EnsureOrigin, Get, Hash as PreimageHash, IsType, OriginTrait, + PalletInfoAccess, PrivilegeCmp, QueryPreimage, StorageVersion, StorePreimage, }, - weights::{GetDispatchInfo, Weight}, + weights::Weight, }; -use frame_system::{self as system, ensure_signed}; +use frame_system::{self as system}; pub use pallet::*; use scale_info::TypeInfo; +use sp_io::hashing::blake2_256; use sp_runtime::{ traits::{BadOrigin, One, Saturating, Zero}, - RuntimeDebug, + BoundedVec, RuntimeDebug, }; use sp_std::{borrow::Borrow, cmp::Ordering, marker::PhantomData, prelude::*}; pub use weights::WeightInfo; @@ -82,7 +88,8 @@ pub type PeriodicIndex = u32; /// The location of a scheduled task that can be used to remove it. pub type TaskAddress = (BlockNumber, u32); -pub type CallOrHashOf = MaybeHashed<::Call, ::Hash>; +pub type CallOrHashOf = + MaybeHashed<::RuntimeCall, ::Hash>; #[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))] #[derive(Clone, RuntimeDebug, Encode, Decode)] @@ -95,82 +102,80 @@ struct ScheduledV1 { /// Information regarding an item to be executed in the future. #[cfg_attr(any(feature = "std", test), derive(PartialEq, Eq))] -#[derive(Clone, RuntimeDebug, Encode, Decode, TypeInfo)] -pub struct ScheduledV3 { +#[derive(Clone, RuntimeDebug, Encode, Decode, MaxEncodedLen, TypeInfo)] +pub struct Scheduled { /// The unique identity for this task, if there is one. - maybe_id: Option>, + maybe_id: Option, /// This task's priority. priority: schedule::Priority, /// The call to be dispatched. call: Call, /// If the call is periodic, then this points to the information concerning that. maybe_periodic: Option>, - /// The origin to dispatch the call. + /// The origin with which to dispatch the call. origin: PalletsOrigin, _phantom: PhantomData, } -use crate::ScheduledV3 as ScheduledV2; +use crate::{Scheduled as ScheduledV3, Scheduled as ScheduledV2}; -pub type ScheduledV2Of = ScheduledV3< - ::Call, +pub type ScheduledV2Of = ScheduledV2< + Vec, + ::RuntimeCall, ::BlockNumber, ::PalletsOrigin, ::AccountId, >; pub type ScheduledV3Of = ScheduledV3< + Vec, CallOrHashOf, ::BlockNumber, ::PalletsOrigin, ::AccountId, >; -pub type ScheduledOf = ScheduledV3Of; - -/// The current version of Scheduled struct. -pub type Scheduled = - ScheduledV2; +pub type ScheduledOf = Scheduled< + TaskName, + Bounded<::RuntimeCall>, + ::BlockNumber, + ::PalletsOrigin, + ::AccountId, +>; -#[cfg(feature = "runtime-benchmarks")] -mod preimage_provider { - use frame_support::traits::PreimageRecipient; - pub trait PreimageProviderAndMaybeRecipient: PreimageRecipient {} - impl> PreimageProviderAndMaybeRecipient for T {} +struct WeightCounter { + used: Weight, + limit: Weight, } - -#[cfg(not(feature = "runtime-benchmarks"))] -mod preimage_provider { - use frame_support::traits::PreimageProvider; - pub trait PreimageProviderAndMaybeRecipient: PreimageProvider {} - impl> PreimageProviderAndMaybeRecipient for T {} +impl WeightCounter { + fn check_accrue(&mut self, w: Weight) -> bool { + let test = self.used.saturating_add(w); + if test.any_gt(self.limit) { + false + } else { + self.used = test; + true + } + } + fn can_accrue(&mut self, w: Weight) -> bool { + self.used.saturating_add(w).all_lte(self.limit) + } } -pub use preimage_provider::PreimageProviderAndMaybeRecipient; - pub(crate) trait MarginalWeightInfo: WeightInfo { - fn item(periodic: bool, named: bool, resolved: Option) -> Weight { - match (periodic, named, resolved) { - (_, false, None) => Self::on_initialize_aborted(2) - Self::on_initialize_aborted(1), - (_, true, None) => - Self::on_initialize_named_aborted(2) - Self::on_initialize_named_aborted(1), - (false, false, Some(false)) => Self::on_initialize(2) - Self::on_initialize(1), - (false, true, Some(false)) => - Self::on_initialize_named(2) - Self::on_initialize_named(1), - (true, false, Some(false)) => - Self::on_initialize_periodic(2) - Self::on_initialize_periodic(1), - (true, true, Some(false)) => - Self::on_initialize_periodic_named(2) - Self::on_initialize_periodic_named(1), - (false, false, Some(true)) => - Self::on_initialize_resolved(2) - Self::on_initialize_resolved(1), - (false, true, Some(true)) => - Self::on_initialize_named_resolved(2) - Self::on_initialize_named_resolved(1), - (true, false, Some(true)) => - Self::on_initialize_periodic_resolved(2) - Self::on_initialize_periodic_resolved(1), - (true, true, Some(true)) => - Self::on_initialize_periodic_named_resolved(2) - - Self::on_initialize_periodic_named_resolved(1), + fn service_task(maybe_lookup_len: Option, named: bool, periodic: bool) -> Weight { + let base = Self::service_task_base(); + let mut total = match maybe_lookup_len { + None => base, + Some(l) => Self::service_task_fetched(l as u32), + }; + if named { + total.saturating_accrue(Self::service_task_named().saturating_sub(base)); + } + if periodic { + total.saturating_accrue(Self::service_task_periodic().saturating_sub(base)); } + total } } impl MarginalWeightInfo for T {} @@ -178,11 +183,7 @@ impl MarginalWeightInfo for T {} #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::{ - dispatch::PostDispatchInfo, - pallet_prelude::*, - traits::{schedule::LookupError, PreimageProvider}, - }; + use frame_support::{dispatch::PostDispatchInfo, pallet_prelude::*}; use frame_system::pallet_prelude::*; /// The current storage version. @@ -191,36 +192,38 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] #[pallet::storage_version(STORAGE_VERSION)] - #[pallet::without_storage_info] pub struct Pallet(_); /// `system::Config` should always be included in our implied traits. #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The aggregated origin which the dispatch will take. - type Origin: OriginTrait + type RuntimeOrigin: OriginTrait + From - + IsType<::Origin>; + + IsType<::RuntimeOrigin>; /// The caller origin, overarching type of all pallets origins. - type PalletsOrigin: From> + Codec + Clone + Eq + TypeInfo; + type PalletsOrigin: From> + + CallerTrait + + MaxEncodedLen; /// The aggregated call type. - type Call: Parameter - + Dispatchable::Origin, PostInfo = PostDispatchInfo> - + GetDispatchInfo + type RuntimeCall: Parameter + + Dispatchable< + RuntimeOrigin = ::RuntimeOrigin, + PostInfo = PostDispatchInfo, + > + GetDispatchInfo + From>; - /// The maximum weight that may be scheduled per block for any dispatchables of less - /// priority than `schedule::HARD_DEADLINE`. + /// The maximum weight that may be scheduled per block for any dispatchables. #[pallet::constant] type MaximumWeight: Get; /// Required origin to schedule or cancel calls. - type ScheduleOrigin: EnsureOrigin<::Origin>; + type ScheduleOrigin: EnsureOrigin<::RuntimeOrigin>; /// Compare the privileges of origins. /// @@ -232,7 +235,6 @@ pub mod pallet { type OriginPrivilegeCmp: PrivilegeCmp; /// The maximum number of scheduled calls in the queue for a single block. - /// Not strictly enforced, but used for weight estimation. #[pallet::constant] type MaxScheduledPerBlock: Get; @@ -240,21 +242,29 @@ pub mod pallet { type WeightInfo: WeightInfo; /// The preimage provider with which we look up call hashes to get the call. - type PreimageProvider: PreimageProviderAndMaybeRecipient; - - /// If `Some` then the number of blocks to postpone execution for when the item is delayed. - type NoPreimagePostponement: Get>; + type Preimages: QueryPreimage + StorePreimage; } - /// Items to be executed, indexed by the block number that they should be executed on. #[pallet::storage] - pub type Agenda = - StorageMap<_, Twox64Concat, T::BlockNumber, Vec>>, ValueQuery>; + pub type IncompleteSince = StorageValue<_, T::BlockNumber>; - /// Lookup from identity to the block number and index of the task. + /// Items to be executed, indexed by the block number that they should be executed on. + #[pallet::storage] + pub type Agenda = StorageMap< + _, + Twox64Concat, + T::BlockNumber, + BoundedVec>, T::MaxScheduledPerBlock>, + ValueQuery, + >; + + /// Lookup from a name to the block number and index of the task. + /// + /// For v3 -> v4 the previously unbounded identities are Blake2-256 hashed to form the v4 + /// identities. #[pallet::storage] pub(crate) type Lookup = - StorageMap<_, Twox64Concat, Vec, TaskAddress>; + StorageMap<_, Twox64Concat, TaskName, TaskAddress>; /// Events type. #[pallet::event] @@ -267,15 +277,15 @@ pub mod pallet { /// Dispatched some task. Dispatched { task: TaskAddress, - id: Option>, + id: Option<[u8; 32]>, result: DispatchResult, }, /// The call for the provided hash was not found so the task has been aborted. - CallLookupFailed { - task: TaskAddress, - id: Option>, - error: LookupError, - }, + CallUnavailable { task: TaskAddress, id: Option<[u8; 32]> }, + /// The given task was unable to be renewed since the agenda is full at that block. + PeriodicFailed { task: TaskAddress, id: Option<[u8; 32]> }, + /// The given task can never be executed since it is overweight. + PermanentlyOverweight { task: TaskAddress, id: Option<[u8; 32]> }, } #[pallet::error] @@ -288,133 +298,18 @@ pub mod pallet { TargetBlockNumberInPast, /// Reschedule failed because it does not change scheduled time. RescheduleNoChange, + /// Attempt to use a non-named function on a named task. + Named, } #[pallet::hooks] impl Hooks> for Pallet { /// Execute the scheduled calls fn on_initialize(now: T::BlockNumber) -> Weight { - let limit = T::MaximumWeight::get(); - - let mut queued = Agenda::::take(now) - .into_iter() - .enumerate() - .filter_map(|(index, s)| Some((index as u32, s?))) - .collect::>(); - - if queued.len() as u32 > T::MaxScheduledPerBlock::get() { - log::warn!( - target: "runtime::scheduler", - "Warning: This block has more items queued in Scheduler than \ - expected from the runtime configuration. An update might be needed." - ); - } - - queued.sort_by_key(|(_, s)| s.priority); - - let next = now + One::one(); - - let mut total_weight: Weight = T::WeightInfo::on_initialize(0); - for (order, (index, mut s)) in queued.into_iter().enumerate() { - let named = if let Some(ref id) = s.maybe_id { - Lookup::::remove(id); - true - } else { - false - }; - - let (call, maybe_completed) = s.call.resolved::(); - s.call = call; - - let resolved = if let Some(completed) = maybe_completed { - T::PreimageProvider::unrequest_preimage(&completed); - true - } else { - false - }; - - let call = match s.call.as_value().cloned() { - Some(c) => c, - None => { - // Preimage not available - postpone until some block. - total_weight.saturating_accrue(T::WeightInfo::item(false, named, None)); - if let Some(delay) = T::NoPreimagePostponement::get() { - let until = now.saturating_add(delay); - if let Some(ref id) = s.maybe_id { - let index = Agenda::::decode_len(until).unwrap_or(0); - Lookup::::insert(id, (until, index as u32)); - } - Agenda::::append(until, Some(s)); - } - continue - }, - }; - - let periodic = s.maybe_periodic.is_some(); - let call_weight = call.get_dispatch_info().weight; - let mut item_weight = T::WeightInfo::item(periodic, named, Some(resolved)); - let origin = - <::Origin as From>::from(s.origin.clone()) - .into(); - if ensure_signed(origin).is_ok() { - // Weights of Signed dispatches expect their signing account to be whitelisted. - item_weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - } - - // We allow a scheduled call if any is true: - // - It's priority is `HARD_DEADLINE` - // - It does not push the weight past the limit. - // - It is the first item in the schedule - let hard_deadline = s.priority <= schedule::HARD_DEADLINE; - let test_weight = - total_weight.saturating_add(call_weight).saturating_add(item_weight); - if !hard_deadline && order > 0 && test_weight > limit { - // Cannot be scheduled this block - postpone until next. - total_weight.saturating_accrue(T::WeightInfo::item(false, named, None)); - if let Some(ref id) = s.maybe_id { - // NOTE: We could reasonably not do this (in which case there would be one - // block where the named and delayed item could not be referenced by name), - // but we will do it anyway since it should be mostly free in terms of - // weight and it is slightly cleaner. - let index = Agenda::::decode_len(next).unwrap_or(0); - Lookup::::insert(id, (next, index as u32)); - } - Agenda::::append(next, Some(s)); - continue - } - - let dispatch_origin = s.origin.clone().into(); - let (maybe_actual_call_weight, result) = match call.dispatch(dispatch_origin) { - Ok(post_info) => (post_info.actual_weight, Ok(())), - Err(error_and_info) => - (error_and_info.post_info.actual_weight, Err(error_and_info.error)), - }; - let actual_call_weight = maybe_actual_call_weight.unwrap_or(call_weight); - total_weight.saturating_accrue(item_weight); - total_weight.saturating_accrue(actual_call_weight); - - Self::deposit_event(Event::Dispatched { - task: (now, index), - id: s.maybe_id.clone(), - result, - }); - - if let &Some((period, count)) = &s.maybe_periodic { - if count > 1 { - s.maybe_periodic = Some((period, count - 1)); - } else { - s.maybe_periodic = None; - } - let wake = now + period; - // If scheduled is named, place its information in `Lookup` - if let Some(ref id) = s.maybe_id { - let wake_index = Agenda::::decode_len(wake).unwrap_or(0); - Lookup::::insert(id, (wake, wake_index as u32)); - } - Agenda::::append(wake, Some(s)); - } - } - total_weight + let mut weight_counter = + WeightCounter { used: Weight::zero(), limit: T::MaximumWeight::get() }; + Self::service_agendas(&mut weight_counter, now, u32::max_value()); + weight_counter.used } } @@ -427,16 +322,16 @@ pub mod pallet { when: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box>, + call: Box<::RuntimeCall>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::Origin::from(origin); + let origin = ::RuntimeOrigin::from(origin); Self::do_schedule( DispatchTime::At(when), maybe_periodic, priority, origin.caller().clone(), - *call, + T::Preimages::bound(*call)?, )?; Ok(()) } @@ -445,7 +340,7 @@ pub mod pallet { #[pallet::weight(::WeightInfo::cancel(T::MaxScheduledPerBlock::get()))] pub fn cancel(origin: OriginFor, when: T::BlockNumber, index: u32) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::Origin::from(origin); + let origin = ::RuntimeOrigin::from(origin); Self::do_cancel(Some(origin.caller().clone()), (when, index))?; Ok(()) } @@ -454,30 +349,30 @@ pub mod pallet { #[pallet::weight(::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))] pub fn schedule_named( origin: OriginFor, - id: Vec, + id: TaskName, when: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box>, + call: Box<::RuntimeCall>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::Origin::from(origin); + let origin = ::RuntimeOrigin::from(origin); Self::do_schedule_named( id, DispatchTime::At(when), maybe_periodic, priority, origin.caller().clone(), - *call, + T::Preimages::bound(*call)?, )?; Ok(()) } /// Cancel a named scheduled task. #[pallet::weight(::WeightInfo::cancel_named(T::MaxScheduledPerBlock::get()))] - pub fn cancel_named(origin: OriginFor, id: Vec) -> DispatchResult { + pub fn cancel_named(origin: OriginFor, id: TaskName) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::Origin::from(origin); + let origin = ::RuntimeOrigin::from(origin); Self::do_cancel_named(Some(origin.caller().clone()), id)?; Ok(()) } @@ -493,16 +388,16 @@ pub mod pallet { after: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box>, + call: Box<::RuntimeCall>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::Origin::from(origin); + let origin = ::RuntimeOrigin::from(origin); Self::do_schedule( DispatchTime::After(after), maybe_periodic, priority, origin.caller().clone(), - *call, + T::Preimages::bound(*call)?, )?; Ok(()) } @@ -515,55 +410,85 @@ pub mod pallet { #[pallet::weight(::WeightInfo::schedule_named(T::MaxScheduledPerBlock::get()))] pub fn schedule_named_after( origin: OriginFor, - id: Vec, + id: TaskName, after: T::BlockNumber, maybe_periodic: Option>, priority: schedule::Priority, - call: Box>, + call: Box<::RuntimeCall>, ) -> DispatchResult { T::ScheduleOrigin::ensure_origin(origin.clone())?; - let origin = ::Origin::from(origin); + let origin = ::RuntimeOrigin::from(origin); Self::do_schedule_named( id, DispatchTime::After(after), maybe_periodic, priority, origin.caller().clone(), - *call, + T::Preimages::bound(*call)?, )?; Ok(()) } } } -impl Pallet { - /// Migrate storage format from V1 to V3. +impl> Pallet { + /// Migrate storage format from V1 to V4. /// /// Returns the weight consumed by this migration. - pub fn migrate_v1_to_v3() -> Weight { + pub fn migrate_v1_to_v4() -> Weight { + use migration::v1 as old; let mut weight = T::DbWeight::get().reads_writes(1, 1); - Agenda::::translate::::Call, T::BlockNumber>>>, _>( - |_, agenda| { - Some( - agenda - .into_iter() - .map(|schedule| { - weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + // Delete all undecodable values. + // `StorageMap::translate` is not enough since it just skips them and leaves the keys in. + let keys = old::Agenda::::iter_keys().collect::>(); + for key in keys { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + if let Err(_) = old::Agenda::::try_get(&key) { + weight.saturating_accrue(T::DbWeight::get().writes(1)); + old::Agenda::::remove(&key); + log::warn!("Deleted undecodable agenda"); + } + } + + Agenda::::translate::< + Vec::RuntimeCall, T::BlockNumber>>>, + _, + >(|_, agenda| { + Some(BoundedVec::truncate_from( + agenda + .into_iter() + .map(|schedule| { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + + schedule.and_then(|schedule| { + if let Some(id) = schedule.maybe_id.as_ref() { + let name = blake2_256(id); + if let Some(item) = old::Lookup::::take(id) { + Lookup::::insert(name, item); + } + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + } + + let call = T::Preimages::bound(schedule.call).ok()?; - schedule.map(|schedule| ScheduledV3 { - maybe_id: schedule.maybe_id, + if call.lookup_needed() { + weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1)); + } + + Some(Scheduled { + maybe_id: schedule.maybe_id.map(|x| blake2_256(&x[..])), priority: schedule.priority, - call: schedule.call.into(), + call, maybe_periodic: schedule.maybe_periodic, origin: system::RawOrigin::Root.into(), _phantom: Default::default(), }) }) - .collect::>(), - ) - }, - ); + }) + .collect::>(), + )) + }); #[allow(deprecated)] frame_support::storage::migration::remove_storage_prefix( @@ -572,34 +497,62 @@ impl Pallet { &[], ); - StorageVersion::new(3).put::(); + StorageVersion::new(4).put::(); weight + T::DbWeight::get().writes(2) } - /// Migrate storage format from V2 to V3. + /// Migrate storage format from V2 to V4. /// /// Returns the weight consumed by this migration. - pub fn migrate_v2_to_v3() -> Weight { + pub fn migrate_v2_to_v4() -> Weight { + use migration::v2 as old; let mut weight = T::DbWeight::get().reads_writes(1, 1); + // Delete all undecodable values. + // `StorageMap::translate` is not enough since it just skips them and leaves the keys in. + let keys = old::Agenda::::iter_keys().collect::>(); + for key in keys { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + if let Err(_) = old::Agenda::::try_get(&key) { + weight.saturating_accrue(T::DbWeight::get().writes(1)); + old::Agenda::::remove(&key); + log::warn!("Deleted undecodable agenda"); + } + } + Agenda::::translate::>>, _>(|_, agenda| { - Some( + Some(BoundedVec::truncate_from( agenda .into_iter() .map(|schedule| { weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); - schedule.map(|schedule| ScheduledV3 { - maybe_id: schedule.maybe_id, - priority: schedule.priority, - call: schedule.call.into(), - maybe_periodic: schedule.maybe_periodic, - origin: schedule.origin, - _phantom: Default::default(), + schedule.and_then(|schedule| { + if let Some(id) = schedule.maybe_id.as_ref() { + let name = blake2_256(id); + if let Some(item) = old::Lookup::::take(id) { + Lookup::::insert(name, item); + } + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + } + + let call = T::Preimages::bound(schedule.call).ok()?; + if call.lookup_needed() { + weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1)); + } + + Some(Scheduled { + maybe_id: schedule.maybe_id.map(|x| blake2_256(&x[..])), + priority: schedule.priority, + call, + maybe_periodic: schedule.maybe_periodic, + origin: schedule.origin, + _phantom: Default::default(), + }) }) }) .collect::>(), - ) + )) }); #[allow(deprecated)] @@ -609,34 +562,140 @@ impl Pallet { &[], ); - StorageVersion::new(3).put::(); + StorageVersion::new(4).put::(); weight + T::DbWeight::get().writes(2) } - #[cfg(feature = "try-runtime")] - pub fn pre_migrate_to_v3() -> Result<(), &'static str> { - Ok(()) - } + /// Migrate storage format from V3 to V4. + /// + /// Returns the weight consumed by this migration. + #[allow(deprecated)] + pub fn migrate_v3_to_v4() -> Weight { + use migration::v3 as old; + let mut weight = T::DbWeight::get().reads_writes(2, 1); + + // Delete all undecodable values. + // `StorageMap::translate` is not enough since it just skips them and leaves the keys in. + let blocks = old::Agenda::::iter_keys().collect::>(); + for block in blocks { + weight.saturating_accrue(T::DbWeight::get().reads(1)); + if let Err(_) = old::Agenda::::try_get(&block) { + weight.saturating_accrue(T::DbWeight::get().writes(1)); + old::Agenda::::remove(&block); + log::warn!("Deleted undecodable agenda of block: {:?}", block); + } + } - #[cfg(feature = "try-runtime")] - pub fn post_migrate_to_v3() -> Result<(), &'static str> { - use frame_support::dispatch::GetStorageVersion; + Agenda::::translate::>>, _>(|block, agenda| { + log::info!("Migrating agenda of block: {:?}", &block); + Some(BoundedVec::truncate_from( + agenda + .into_iter() + .map(|schedule| { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + schedule + .and_then(|schedule| { + if let Some(id) = schedule.maybe_id.as_ref() { + let name = blake2_256(id); + if let Some(item) = old::Lookup::::take(id) { + Lookup::::insert(name, item); + log::info!("Migrated name for id: {:?}", id); + } else { + log::error!("No name in Lookup for id: {:?}", &id); + } + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + } else { + log::info!("Schedule is unnamed"); + } + + let call = match schedule.call { + MaybeHashed::Hash(h) => { + let bounded = Bounded::from_legacy_hash(h); + // Check that the call can be decoded in the new runtime. + if let Err(err) = T::Preimages::peek::< + ::RuntimeCall, + >(&bounded) + { + log::error!( + "Dropping undecodable call {}: {:?}", + &h, + &err + ); + return None + } + weight.saturating_accrue(T::DbWeight::get().reads(1)); + log::info!("Migrated call by hash, hash: {:?}", h); + bounded + }, + MaybeHashed::Value(v) => { + let call = T::Preimages::bound(v) + .map_err(|e| { + log::error!("Could not bound Call: {:?}", e) + }) + .ok()?; + if call.lookup_needed() { + weight.saturating_accrue( + T::DbWeight::get().reads_writes(0, 1), + ); + } + log::info!( + "Migrated call by value, hash: {:?}", + call.hash() + ); + call + }, + }; + + Some(Scheduled { + maybe_id: schedule.maybe_id.map(|x| blake2_256(&x[..])), + priority: schedule.priority, + call, + maybe_periodic: schedule.maybe_periodic, + origin: schedule.origin, + _phantom: Default::default(), + }) + }) + .or_else(|| { + log::info!("Schedule in agenda for block {:?} is empty - nothing to do here.", &block); + None + }) + }) + .collect::>(), + )) + }); - assert!(Self::current_storage_version() == 3); - for k in Agenda::::iter_keys() { - let _ = Agenda::::try_get(k).map_err(|()| "Invalid item in Agenda")?; - } - Ok(()) + #[allow(deprecated)] + frame_support::storage::migration::remove_storage_prefix( + Self::name().as_bytes(), + b"StorageVersion", + &[], + ); + + StorageVersion::new(4).put::(); + + weight + T::DbWeight::get().writes(2) } +} +impl Pallet { /// Helper to migrate scheduler when the pallet origin type has changed. pub fn migrate_origin + codec::Decode>() { Agenda::::translate::< - Vec, T::BlockNumber, OldOrigin, T::AccountId>>>, + Vec< + Option< + Scheduled< + TaskName, + Bounded<::RuntimeCall>, + T::BlockNumber, + OldOrigin, + T::AccountId, + >, + >, + >, _, >(|_, agenda| { - Some( + Some(BoundedVec::truncate_from( agenda .into_iter() .map(|schedule| { @@ -650,7 +709,7 @@ impl Pallet { }) }) .collect::>(), - ) + )) }); } @@ -671,34 +730,64 @@ impl Pallet { Ok(when) } + fn place_task( + when: T::BlockNumber, + what: ScheduledOf, + ) -> Result, (DispatchError, ScheduledOf)> { + let maybe_name = what.maybe_id; + let index = Self::push_to_agenda(when, what)?; + let address = (when, index); + if let Some(name) = maybe_name { + Lookup::::insert(name, address) + } + Self::deposit_event(Event::Scheduled { when: address.0, index: address.1 }); + Ok(address) + } + + fn push_to_agenda( + when: T::BlockNumber, + what: ScheduledOf, + ) -> Result)> { + let mut agenda = Agenda::::get(when); + let index = if (agenda.len() as u32) < T::MaxScheduledPerBlock::get() { + // will always succeed due to the above check. + let _ = agenda.try_push(Some(what)); + agenda.len() as u32 - 1 + } else { + if let Some(hole_index) = agenda.iter().position(|i| i.is_none()) { + agenda[hole_index] = Some(what); + hole_index as u32 + } else { + return Err((DispatchError::Exhausted, what)) + } + }; + Agenda::::insert(when, agenda); + Ok(index) + } + fn do_schedule( when: DispatchTime, maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: CallOrHashOf, + call: Bounded<::RuntimeCall>, ) -> Result, DispatchError> { let when = Self::resolve_time(when)?; - call.ensure_requested::(); // sanitize maybe_periodic let maybe_periodic = maybe_periodic .filter(|p| p.1 > 1 && !p.0.is_zero()) // Remove one from the number of repetitions since we will schedule one now. .map(|(p, c)| (p, c - 1)); - let s = Some(Scheduled { + let task = Scheduled { maybe_id: None, priority, call, maybe_periodic, origin, - _phantom: PhantomData::::default(), - }); - Agenda::::append(when, s); - let index = Agenda::::decode_len(when).unwrap_or(1) as u32 - 1; - Self::deposit_event(Event::Scheduled { when, index }); - - Ok((when, index)) + _phantom: PhantomData, + }; + Self::place_task(when, task).map_err(|x| x.0) } fn do_cancel( @@ -708,7 +797,7 @@ impl Pallet { let scheduled = Agenda::::try_mutate(when, |agenda| { agenda.get_mut(index as usize).map_or( Ok(None), - |s| -> Result>, DispatchError> { + |s| -> Result>, DispatchError> { if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) { if matches!( T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin), @@ -722,7 +811,7 @@ impl Pallet { ) })?; if let Some(s) = scheduled { - s.call.ensure_unrequested::(); + T::Preimages::drop(&s.call); if let Some(id) = s.maybe_id { Lookup::::remove(id); } @@ -743,27 +832,23 @@ impl Pallet { return Err(Error::::RescheduleNoChange.into()) } - Agenda::::try_mutate(when, |agenda| -> DispatchResult { + let task = Agenda::::try_mutate(when, |agenda| { let task = agenda.get_mut(index as usize).ok_or(Error::::NotFound)?; - let task = task.take().ok_or(Error::::NotFound)?; - Agenda::::append(new_time, Some(task)); - Ok(()) + ensure!(!matches!(task, Some(Scheduled { maybe_id: Some(_), .. })), Error::::Named); + task.take().ok_or(Error::::NotFound) })?; - - let new_index = Agenda::::decode_len(new_time).unwrap_or(1) as u32 - 1; Self::deposit_event(Event::Canceled { when, index }); - Self::deposit_event(Event::Scheduled { when: new_time, index: new_index }); - Ok((new_time, new_index)) + Self::place_task(new_time, task).map_err(|x| x.0) } fn do_schedule_named( - id: Vec, + id: TaskName, when: DispatchTime, maybe_periodic: Option>, priority: schedule::Priority, origin: T::PalletsOrigin, - call: CallOrHashOf, + call: Bounded<::RuntimeCall>, ) -> Result, DispatchError> { // ensure id it is unique if Lookup::::contains_key(&id) { @@ -772,32 +857,24 @@ impl Pallet { let when = Self::resolve_time(when)?; - call.ensure_requested::(); - // sanitize maybe_periodic let maybe_periodic = maybe_periodic .filter(|p| p.1 > 1 && !p.0.is_zero()) // Remove one from the number of repetitions since we will schedule one now. .map(|(p, c)| (p, c - 1)); - let s = Scheduled { - maybe_id: Some(id.clone()), + let task = Scheduled { + maybe_id: Some(id), priority, call, maybe_periodic, origin, _phantom: Default::default(), }; - Agenda::::append(when, Some(s)); - let index = Agenda::::decode_len(when).unwrap_or(1) as u32 - 1; - let address = (when, index); - Lookup::::insert(&id, &address); - Self::deposit_event(Event::Scheduled { when, index }); - - Ok(address) + Self::place_task(when, task).map_err(|x| x.0) } - fn do_cancel_named(origin: Option, id: Vec) -> DispatchResult { + fn do_cancel_named(origin: Option, id: TaskName) -> DispatchResult { Lookup::::try_mutate_exists(id, |lookup| -> DispatchResult { if let Some((when, index)) = lookup.take() { let i = index as usize; @@ -810,7 +887,7 @@ impl Pallet { ) { return Err(BadOrigin.into()) } - s.call.ensure_unrequested::(); + T::Preimages::drop(&s.call); } *s = None; } @@ -825,42 +902,245 @@ impl Pallet { } fn do_reschedule_named( - id: Vec, + id: TaskName, new_time: DispatchTime, ) -> Result, DispatchError> { let new_time = Self::resolve_time(new_time)?; - Lookup::::try_mutate_exists( - id, - |lookup| -> Result, DispatchError> { - let (when, index) = lookup.ok_or(Error::::NotFound)?; + let lookup = Lookup::::get(id); + let (when, index) = lookup.ok_or(Error::::NotFound)?; - if new_time == when { - return Err(Error::::RescheduleNoChange.into()) - } + if new_time == when { + return Err(Error::::RescheduleNoChange.into()) + } - Agenda::::try_mutate(when, |agenda| -> DispatchResult { - let task = agenda.get_mut(index as usize).ok_or(Error::::NotFound)?; - let task = task.take().ok_or(Error::::NotFound)?; - Agenda::::append(new_time, Some(task)); + let task = Agenda::::try_mutate(when, |agenda| { + let task = agenda.get_mut(index as usize).ok_or(Error::::NotFound)?; + task.take().ok_or(Error::::NotFound) + })?; + Self::deposit_event(Event::Canceled { when, index }); + Self::place_task(new_time, task).map_err(|x| x.0) + } +} - Ok(()) - })?; +enum ServiceTaskError { + /// Could not be executed due to missing preimage. + Unavailable, + /// Could not be executed due to weight limitations. + Overweight, +} +use ServiceTaskError::*; - let new_index = Agenda::::decode_len(new_time).unwrap_or(1) as u32 - 1; - Self::deposit_event(Event::Canceled { when, index }); - Self::deposit_event(Event::Scheduled { when: new_time, index: new_index }); +impl Pallet { + /// Service up to `max` agendas queue starting from earliest incompletely executed agenda. + fn service_agendas(weight: &mut WeightCounter, now: T::BlockNumber, max: u32) { + if !weight.check_accrue(T::WeightInfo::service_agendas_base()) { + return + } + + let mut incomplete_since = now + One::one(); + let mut when = IncompleteSince::::take().unwrap_or(now); + let mut executed = 0; - *lookup = Some((new_time, new_index)); + let max_items = T::MaxScheduledPerBlock::get(); + let mut count_down = max; + let service_agenda_base_weight = T::WeightInfo::service_agenda_base(max_items); + while count_down > 0 && when <= now && weight.can_accrue(service_agenda_base_weight) { + if !Self::service_agenda(weight, &mut executed, now, when, u32::max_value()) { + incomplete_since = incomplete_since.min(when); + } + when.saturating_inc(); + count_down.saturating_dec(); + } + incomplete_since = incomplete_since.min(when); + if incomplete_since <= now { + IncompleteSince::::put(incomplete_since); + } + } - Ok((new_time, new_index)) + /// Returns `true` if the agenda was fully completed, `false` if it should be revisited at a + /// later block. + fn service_agenda( + weight: &mut WeightCounter, + executed: &mut u32, + now: T::BlockNumber, + when: T::BlockNumber, + max: u32, + ) -> bool { + let mut agenda = Agenda::::get(when); + let mut ordered = agenda + .iter() + .enumerate() + .filter_map(|(index, maybe_item)| { + maybe_item.as_ref().map(|item| (index as u32, item.priority)) + }) + .collect::>(); + ordered.sort_by_key(|k| k.1); + let within_limit = + weight.check_accrue(T::WeightInfo::service_agenda_base(ordered.len() as u32)); + debug_assert!(within_limit, "weight limit should have been checked in advance"); + + // Items which we know can be executed and have postponed for execution in a later block. + let mut postponed = (ordered.len() as u32).saturating_sub(max); + // Items which we don't know can ever be executed. + let mut dropped = 0; + + for (agenda_index, _) in ordered.into_iter().take(max as usize) { + let task = match agenda[agenda_index as usize].take() { + None => continue, + Some(t) => t, + }; + let base_weight = T::WeightInfo::service_task( + task.call.lookup_len().map(|x| x as usize), + task.maybe_id.is_some(), + task.maybe_periodic.is_some(), + ); + if !weight.can_accrue(base_weight) { + postponed += 1; + break + } + let result = Self::service_task(weight, now, when, agenda_index, *executed == 0, task); + agenda[agenda_index as usize] = match result { + Err((Unavailable, slot)) => { + dropped += 1; + slot + }, + Err((Overweight, slot)) => { + postponed += 1; + slot + }, + Ok(()) => { + *executed += 1; + None + }, + }; + } + if postponed > 0 || dropped > 0 { + Agenda::::insert(when, agenda); + } else { + Agenda::::remove(when); + } + postponed == 0 + } + + /// Service (i.e. execute) the given task, being careful not to overflow the `weight` counter. + /// + /// This involves: + /// - removing and potentially replacing the `Lookup` entry for the task. + /// - realizing the task's call which can include a preimage lookup. + /// - Rescheduling the task for execution in a later agenda if periodic. + fn service_task( + weight: &mut WeightCounter, + now: T::BlockNumber, + when: T::BlockNumber, + agenda_index: u32, + is_first: bool, + mut task: ScheduledOf, + ) -> Result<(), (ServiceTaskError, Option>)> { + if let Some(ref id) = task.maybe_id { + Lookup::::remove(id); + } + + let (call, lookup_len) = match T::Preimages::peek(&task.call) { + Ok(c) => c, + Err(_) => return Err((Unavailable, Some(task))), + }; + + weight.check_accrue(T::WeightInfo::service_task( + lookup_len.map(|x| x as usize), + task.maybe_id.is_some(), + task.maybe_periodic.is_some(), + )); + + match Self::execute_dispatch(weight, task.origin.clone(), call) { + Err(Unavailable) => { + debug_assert!(false, "Checked to exist with `peek`"); + Self::deposit_event(Event::CallUnavailable { + task: (when, agenda_index), + id: task.maybe_id, + }); + Err((Unavailable, Some(task))) }, - ) + Err(Overweight) if is_first => { + T::Preimages::drop(&task.call); + Self::deposit_event(Event::PermanentlyOverweight { + task: (when, agenda_index), + id: task.maybe_id, + }); + Err((Unavailable, Some(task))) + }, + Err(Overweight) => Err((Overweight, Some(task))), + Ok(result) => { + Self::deposit_event(Event::Dispatched { + task: (when, agenda_index), + id: task.maybe_id, + result, + }); + if let &Some((period, count)) = &task.maybe_periodic { + if count > 1 { + task.maybe_periodic = Some((period, count - 1)); + } else { + task.maybe_periodic = None; + } + let wake = now.saturating_add(period); + match Self::place_task(wake, task) { + Ok(_) => {}, + Err((_, task)) => { + // TODO: Leave task in storage somewhere for it to be rescheduled + // manually. + T::Preimages::drop(&task.call); + Self::deposit_event(Event::PeriodicFailed { + task: (when, agenda_index), + id: task.maybe_id, + }); + }, + } + } else { + T::Preimages::drop(&task.call); + } + Ok(()) + }, + } + } + + /// Make a dispatch to the given `call` from the given `origin`, ensuring that the `weight` + /// counter does not exceed its limit and that it is counted accurately (e.g. accounted using + /// post info if available). + /// + /// NOTE: Only the weight for this function will be counted (origin lookup, dispatch and the + /// call itself). + fn execute_dispatch( + weight: &mut WeightCounter, + origin: T::PalletsOrigin, + call: ::RuntimeCall, + ) -> Result { + let base_weight = match origin.as_system_ref() { + Some(&RawOrigin::Signed(_)) => T::WeightInfo::execute_dispatch_signed(), + _ => T::WeightInfo::execute_dispatch_unsigned(), + }; + let call_weight = call.get_dispatch_info().weight; + // We only allow a scheduled call if it cannot push the weight past the limit. + let max_weight = base_weight.saturating_add(call_weight); + + if !weight.can_accrue(max_weight) { + return Err(Overweight) + } + + let dispatch_origin = origin.into(); + let (maybe_actual_call_weight, result) = match call.dispatch(dispatch_origin) { + Ok(post_info) => (post_info.actual_weight, Ok(())), + Err(error_and_info) => + (error_and_info.post_info.actual_weight, Err(error_and_info.error)), + }; + let call_weight = maybe_actual_call_weight.unwrap_or(call_weight); + weight.check_accrue(base_weight); + weight.check_accrue(call_weight); + Ok(result) } } -impl schedule::v2::Anon::Call, T::PalletsOrigin> - for Pallet +impl> + schedule::v2::Anon::RuntimeCall, T::PalletsOrigin> for Pallet { type Address = TaskAddress; type Hash = T::Hash; @@ -872,6 +1152,8 @@ impl schedule::v2::Anon::Call, T::Palle origin: T::PalletsOrigin, call: CallOrHashOf, ) -> Result { + let call = call.as_value().ok_or(DispatchError::CannotLookup)?; + let call = T::Preimages::bound(call)?.transmute(); Self::do_schedule(when, maybe_periodic, priority, origin, call) } @@ -891,8 +1173,8 @@ impl schedule::v2::Anon::Call, T::Palle } } -impl schedule::v2::Named::Call, T::PalletsOrigin> - for Pallet +impl> + schedule::v2::Named::RuntimeCall, T::PalletsOrigin> for Pallet { type Address = TaskAddress; type Hash = T::Hash; @@ -905,23 +1187,108 @@ impl schedule::v2::Named::Call, T::Pall origin: T::PalletsOrigin, call: CallOrHashOf, ) -> Result { - Self::do_schedule_named(id, when, maybe_periodic, priority, origin, call).map_err(|_| ()) + let call = call.as_value().ok_or(())?; + let call = T::Preimages::bound(call).map_err(|_| ())?.transmute(); + let name = blake2_256(&id[..]); + Self::do_schedule_named(name, when, maybe_periodic, priority, origin, call).map_err(|_| ()) } fn cancel_named(id: Vec) -> Result<(), ()> { - Self::do_cancel_named(None, id).map_err(|_| ()) + let name = blake2_256(&id[..]); + Self::do_cancel_named(None, name).map_err(|_| ()) } fn reschedule_named( id: Vec, when: DispatchTime, ) -> Result { - Self::do_reschedule_named(id, when) + let name = blake2_256(&id[..]); + Self::do_reschedule_named(name, when) } fn next_dispatch_time(id: Vec) -> Result { - Lookup::::get(id) + let name = blake2_256(&id[..]); + Lookup::::get(name) .and_then(|(when, index)| Agenda::::get(when).get(index as usize).map(|_| when)) .ok_or(()) } } + +impl schedule::v3::Anon::RuntimeCall, T::PalletsOrigin> + for Pallet +{ + type Address = TaskAddress; + + fn schedule( + when: DispatchTime, + maybe_periodic: Option>, + priority: schedule::Priority, + origin: T::PalletsOrigin, + call: Bounded<::RuntimeCall>, + ) -> Result { + Self::do_schedule(when, maybe_periodic, priority, origin, call) + } + + fn cancel((when, index): Self::Address) -> Result<(), DispatchError> { + Self::do_cancel(None, (when, index)).map_err(map_err_to_v3_err::) + } + + fn reschedule( + address: Self::Address, + when: DispatchTime, + ) -> Result { + Self::do_reschedule(address, when).map_err(map_err_to_v3_err::) + } + + fn next_dispatch_time((when, index): Self::Address) -> Result { + Agenda::::get(when) + .get(index as usize) + .ok_or(DispatchError::Unavailable) + .map(|_| when) + } +} + +use schedule::v3::TaskName; + +impl schedule::v3::Named::RuntimeCall, T::PalletsOrigin> + for Pallet +{ + type Address = TaskAddress; + + fn schedule_named( + id: TaskName, + when: DispatchTime, + maybe_periodic: Option>, + priority: schedule::Priority, + origin: T::PalletsOrigin, + call: Bounded<::RuntimeCall>, + ) -> Result { + Self::do_schedule_named(id, when, maybe_periodic, priority, origin, call) + } + + fn cancel_named(id: TaskName) -> Result<(), DispatchError> { + Self::do_cancel_named(None, id).map_err(map_err_to_v3_err::) + } + + fn reschedule_named( + id: TaskName, + when: DispatchTime, + ) -> Result { + Self::do_reschedule_named(id, when).map_err(map_err_to_v3_err::) + } + + fn next_dispatch_time(id: TaskName) -> Result { + Lookup::::get(id) + .and_then(|(when, index)| Agenda::::get(when).get(index as usize).map(|_| when)) + .ok_or(DispatchError::Unavailable) + } +} + +/// Maps a pallet error to an `schedule::v3` error. +fn map_err_to_v3_err(err: DispatchError) -> DispatchError { + if err == DispatchError::from(Error::::NotFound) { + DispatchError::Unavailable + } else { + err + } +} diff --git a/frame/scheduler/src/migration.rs b/frame/scheduler/src/migration.rs new file mode 100644 index 0000000000000..6769d20023196 --- /dev/null +++ b/frame/scheduler/src/migration.rs @@ -0,0 +1,402 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Migrations for the scheduler pallet. + +use super::*; +use frame_support::traits::OnRuntimeUpgrade; + +/// The log target. +const TARGET: &'static str = "runtime::scheduler::migration"; + +pub mod v1 { + use super::*; + use frame_support::pallet_prelude::*; + + #[frame_support::storage_alias] + pub(crate) type Agenda = StorageMap< + Pallet, + Twox64Concat, + ::BlockNumber, + Vec< + Option< + ScheduledV1<::RuntimeCall, ::BlockNumber>, + >, + >, + ValueQuery, + >; + + #[frame_support::storage_alias] + pub(crate) type Lookup = StorageMap< + Pallet, + Twox64Concat, + Vec, + TaskAddress<::BlockNumber>, + >; +} + +pub mod v2 { + use super::*; + use frame_support::pallet_prelude::*; + + #[frame_support::storage_alias] + pub(crate) type Agenda = StorageMap< + Pallet, + Twox64Concat, + ::BlockNumber, + Vec>>, + ValueQuery, + >; + + #[frame_support::storage_alias] + pub(crate) type Lookup = StorageMap< + Pallet, + Twox64Concat, + Vec, + TaskAddress<::BlockNumber>, + >; +} + +pub mod v3 { + use super::*; + use frame_support::pallet_prelude::*; + + #[frame_support::storage_alias] + pub(crate) type Agenda = StorageMap< + Pallet, + Twox64Concat, + ::BlockNumber, + Vec>>, + ValueQuery, + >; + + #[frame_support::storage_alias] + pub(crate) type Lookup = StorageMap< + Pallet, + Twox64Concat, + Vec, + TaskAddress<::BlockNumber>, + >; + + /// Migrate the scheduler pallet from V3 to V4. + pub struct MigrateToV4(sp_std::marker::PhantomData); + + impl> OnRuntimeUpgrade for MigrateToV4 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + assert_eq!(StorageVersion::get::>(), 3, "Can only upgrade from version 3"); + + let agendas = Agenda::::iter_keys().count() as u32; + let decodable_agendas = Agenda::::iter_values().count() as u32; + if agendas != decodable_agendas { + // This is not necessarily an error, but can happen when there are Calls + // in an Agenda that are not valid anymore with the new runtime. + log::error!( + target: TARGET, + "Can only decode {} of {} agendas - others will be dropped", + decodable_agendas, + agendas + ); + } + log::info!(target: TARGET, "Trying to migrate {} agendas...", decodable_agendas); + + // Check that no agenda overflows `MaxScheduledPerBlock`. + let max_scheduled_per_block = T::MaxScheduledPerBlock::get() as usize; + for (block_number, agenda) in Agenda::::iter() { + if agenda.iter().cloned().filter_map(|s| s).count() > max_scheduled_per_block { + log::error!( + target: TARGET, + "Would truncate agenda of block {:?} from {} items to {} items.", + block_number, + agenda.len(), + max_scheduled_per_block, + ); + return Err("Agenda would overflow `MaxScheduledPerBlock`.") + } + } + // Check that bounding the calls will not overflow `MAX_LENGTH`. + let max_length = T::Preimages::MAX_LENGTH as usize; + for (block_number, agenda) in Agenda::::iter() { + for schedule in agenda.iter().cloned().filter_map(|s| s) { + match schedule.call { + frame_support::traits::schedule::MaybeHashed::Value(call) => { + let l = call.using_encoded(|c| c.len()); + if l > max_length { + log::error!( + target: TARGET, + "Call in agenda of block {:?} is too large: {} byte", + block_number, + l, + ); + return Err("Call is too large.") + } + }, + _ => (), + } + } + } + + Ok((decodable_agendas as u32).encode()) + } + + fn on_runtime_upgrade() -> Weight { + let version = StorageVersion::get::>(); + if version != 3 { + log::warn!( + target: TARGET, + "skipping v3 to v4 migration: executed on wrong storage version.\ + Expected version 3, found {:?}", + version, + ); + return T::DbWeight::get().reads(1) + } + + crate::Pallet::::migrate_v3_to_v4() + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + assert_eq!(StorageVersion::get::>(), 4, "Must upgrade"); + + // Check that everything decoded fine. + for k in crate::Agenda::::iter_keys() { + assert!(crate::Agenda::::try_get(k).is_ok(), "Cannot decode V4 Agenda"); + } + + let old_agendas: u32 = + Decode::decode(&mut &state[..]).expect("pre_upgrade provides a valid state; qed"); + let new_agendas = crate::Agenda::::iter_keys().count() as u32; + if old_agendas != new_agendas { + // This is not necessarily an error, but can happen when there are Calls + // in an Agenda that are not valid anymore in the new runtime. + log::error!( + target: TARGET, + "Did not migrate all Agendas. Previous {}, Now {}", + old_agendas, + new_agendas, + ); + } else { + log::info!(target: TARGET, "Migrated {} agendas.", new_agendas); + } + + Ok(()) + } + } +} + +#[cfg(test)] +#[cfg(feature = "try-runtime")] +mod test { + use super::*; + use crate::mock::*; + use frame_support::Hashable; + use sp_std::borrow::Cow; + use substrate_test_utils::assert_eq_uvec; + + #[test] + #[allow(deprecated)] + fn migration_v3_to_v4_works() { + new_test_ext().execute_with(|| { + // Assume that we are at V3. + StorageVersion::new(3).put::(); + + // Call that will be bounded to a `Lookup`. + let large_call = + RuntimeCall::System(frame_system::Call::remark { remark: vec![0; 1024] }); + // Call that can be inlined. + let small_call = + RuntimeCall::System(frame_system::Call::remark { remark: vec![0; 10] }); + // Call that is already hashed and can will be converted to `Legacy`. + let hashed_call = + RuntimeCall::System(frame_system::Call::remark { remark: vec![0; 2048] }); + let bound_hashed_call = Preimage::bound(hashed_call.clone()).unwrap(); + assert!(bound_hashed_call.lookup_needed()); + // A Call by hash that will fail to decode becomes `None`. + let trash_data = vec![255u8; 1024]; + let undecodable_hash = Preimage::note(Cow::Borrowed(&trash_data)).unwrap(); + + for i in 0..2u64 { + let k = i.twox_64_concat(); + let old = vec![ + Some(ScheduledV3Of:: { + maybe_id: None, + priority: i as u8 + 10, + call: small_call.clone().into(), + maybe_periodic: None, // 1 + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledV3Of:: { + maybe_id: Some(vec![i as u8; 32]), + priority: 123, + call: large_call.clone().into(), + maybe_periodic: Some((4u64, 20)), + origin: signed(i), + _phantom: PhantomData::::default(), + }), + Some(ScheduledV3Of:: { + maybe_id: Some(vec![255 - i as u8; 320]), + priority: 123, + call: MaybeHashed::Hash(bound_hashed_call.hash()), + maybe_periodic: Some((8u64, 10)), + origin: signed(i), + _phantom: PhantomData::::default(), + }), + Some(ScheduledV3Of:: { + maybe_id: Some(vec![i as u8; 320]), + priority: 123, + call: MaybeHashed::Hash(undecodable_hash.clone()), + maybe_periodic: Some((4u64, 20)), + origin: root(), + _phantom: PhantomData::::default(), + }), + ]; + frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old); + } + + let state = v3::MigrateToV4::::pre_upgrade().unwrap(); + let _w = v3::MigrateToV4::::on_runtime_upgrade(); + v3::MigrateToV4::::post_upgrade(state).unwrap(); + + let mut x = Agenda::::iter().map(|x| (x.0, x.1.into_inner())).collect::>(); + x.sort_by_key(|x| x.0); + + let bound_large_call = Preimage::bound(large_call).unwrap(); + assert!(bound_large_call.lookup_needed()); + let bound_small_call = Preimage::bound(small_call).unwrap(); + assert!(!bound_small_call.lookup_needed()); + + let expected = vec![ + ( + 0, + vec![ + Some(ScheduledOf:: { + maybe_id: None, + priority: 10, + call: bound_small_call.clone(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledOf:: { + maybe_id: Some(blake2_256(&[0u8; 32])), + priority: 123, + call: bound_large_call.clone(), + maybe_periodic: Some((4u64, 20)), + origin: signed(0), + _phantom: PhantomData::::default(), + }), + Some(ScheduledOf:: { + maybe_id: Some(blake2_256(&[255u8; 320])), + priority: 123, + call: Bounded::from_legacy_hash(bound_hashed_call.hash()), + maybe_periodic: Some((8u64, 10)), + origin: signed(0), + _phantom: PhantomData::::default(), + }), + None, + ], + ), + ( + 1, + vec![ + Some(ScheduledOf:: { + maybe_id: None, + priority: 11, + call: bound_small_call.clone(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledOf:: { + maybe_id: Some(blake2_256(&[1u8; 32])), + priority: 123, + call: bound_large_call.clone(), + maybe_periodic: Some((4u64, 20)), + origin: signed(1), + _phantom: PhantomData::::default(), + }), + Some(ScheduledOf:: { + maybe_id: Some(blake2_256(&[254u8; 320])), + priority: 123, + call: Bounded::from_legacy_hash(bound_hashed_call.hash()), + maybe_periodic: Some((8u64, 10)), + origin: signed(1), + _phantom: PhantomData::::default(), + }), + None, + ], + ), + ]; + for (outer, (i, j)) in x.iter().zip(expected.iter()).enumerate() { + assert_eq!(i.0, j.0); + for (inner, (x, y)) in i.1.iter().zip(j.1.iter()).enumerate() { + assert_eq!(x, y, "at index: outer {} inner {}", outer, inner); + } + } + assert_eq_uvec!(x, expected); + + assert_eq!(StorageVersion::get::(), 4); + }); + } + + #[test] + #[allow(deprecated)] + fn migration_v3_to_v4_too_large_calls_are_ignored() { + new_test_ext().execute_with(|| { + // Assume that we are at V3. + StorageVersion::new(3).put::(); + + let too_large_call = RuntimeCall::System(frame_system::Call::remark { + remark: vec![0; ::Preimages::MAX_LENGTH + 1], + }); + + let i = 0u64; + let k = i.twox_64_concat(); + let old = vec![Some(ScheduledV3Of:: { + maybe_id: None, + priority: 1, + call: too_large_call.clone().into(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + })]; + frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old); + + // The pre_upgrade hook fails: + let err = v3::MigrateToV4::::pre_upgrade().unwrap_err(); + assert!(err.contains("Call is too large")); + // But the migration itself works: + let _w = v3::MigrateToV4::::on_runtime_upgrade(); + + let mut x = Agenda::::iter().map(|x| (x.0, x.1.into_inner())).collect::>(); + x.sort_by_key(|x| x.0); + // The call becomes `None`. + let expected = vec![(0, vec![None])]; + assert_eq_uvec!(x, expected); + + assert_eq!(StorageVersion::get::(), 4); + }); + } + + fn signed(i: u64) -> OriginCaller { + system::RawOrigin::Signed(i).into() + } +} diff --git a/frame/scheduler/src/mock.rs b/frame/scheduler/src/mock.rs index 7bbc628604bc6..61efdfb67b73e 100644 --- a/frame/scheduler/src/mock.rs +++ b/frame/scheduler/src/mock.rs @@ -39,15 +39,14 @@ use sp_runtime::{ #[frame_support::pallet] pub mod logger { use super::{OriginCaller, OriginTrait}; - use frame_support::pallet_prelude::*; + use frame_support::{pallet_prelude::*, parameter_types}; use frame_system::pallet_prelude::*; - use std::cell::RefCell; - thread_local! { - static LOG: RefCell> = RefCell::new(Vec::new()); + parameter_types! { + static Log: Vec<(OriginCaller, u32)> = Vec::new(); } pub fn log() -> Vec<(OriginCaller, u32)> { - LOG.with(|log| log.borrow().clone()) + Log::get().clone() } #[pallet::pallet] @@ -59,7 +58,7 @@ pub mod logger { #[pallet::config] pub trait Config: frame_system::Config { - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; } #[pallet::event] @@ -71,13 +70,13 @@ pub mod logger { #[pallet::call] impl Pallet where - ::Origin: OriginTrait, + ::RuntimeOrigin: OriginTrait, { #[pallet::weight(*weight)] pub fn log(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { Self::deposit_event(Event::Logged(i, weight)); - LOG.with(|log| { - log.borrow_mut().push((origin.caller().clone(), i)); + Log::mutate(|log| { + log.push((origin.caller().clone(), i)); }); Ok(()) } @@ -85,8 +84,8 @@ pub mod logger { #[pallet::weight(*weight)] pub fn log_without_filter(origin: OriginFor, i: u32, weight: Weight) -> DispatchResult { Self::deposit_event(Event::Logged(i, weight)); - LOG.with(|log| { - log.borrow_mut().push((origin.caller().clone(), i)); + Log::mutate(|log| { + log.push((origin.caller().clone(), i)); }); Ok(()) } @@ -111,23 +110,25 @@ frame_support::construct_runtime!( // Scheduler must dispatch with root and no filter, this tests base filter is indeed not used. pub struct BaseFilter; -impl Contains for BaseFilter { - fn contains(call: &Call) -> bool { - !matches!(call, Call::Logger(LoggerCall::log { .. })) +impl Contains for BaseFilter { + fn contains(call: &RuntimeCall) -> bool { + !matches!(call, RuntimeCall::Logger(LoggerCall::log { .. })) } } parameter_types! { pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::simple_max(Weight::from_ref_time(2_000_000_000_000)); + frame_system::limits::BlockWeights::simple_max( + Weight::from_ref_time(2_000_000_000_000).set_proof_size(u64::MAX), + ); } impl system::Config for Test { type BaseCallFilter = BaseFilter; - type BlockWeights = (); + type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = RocksDbWeight; - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -135,7 +136,7 @@ impl system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -148,38 +149,76 @@ impl system::Config for Test { type MaxConsumers = ConstU32<16>; } impl logger::Config for Test { - type Event = Event; -} -parameter_types! { - pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * BlockWeights::get().max_block; - pub const NoPreimagePostponement: Option = Some(2); + type RuntimeEvent = RuntimeEvent; } ord_parameter_types! { pub const One: u64 = 1; } impl pallet_preimage::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type Currency = (); type ManagerOrigin = EnsureRoot; - type MaxSize = ConstU32<1024>; type BaseDeposit = (); type ByteDeposit = (); } +pub struct TestWeightInfo; +impl WeightInfo for TestWeightInfo { + fn service_agendas_base() -> Weight { + Weight::from_ref_time(0b0000_0001) + } + fn service_agenda_base(i: u32) -> Weight { + Weight::from_ref_time((i << 8) as u64 + 0b0000_0010) + } + fn service_task_base() -> Weight { + Weight::from_ref_time(0b0000_0100) + } + fn service_task_periodic() -> Weight { + Weight::from_ref_time(0b0000_1100) + } + fn service_task_named() -> Weight { + Weight::from_ref_time(0b0001_0100) + } + fn service_task_fetched(s: u32) -> Weight { + Weight::from_ref_time((s << 8) as u64 + 0b0010_0100) + } + fn execute_dispatch_signed() -> Weight { + Weight::from_ref_time(0b0100_0000) + } + fn execute_dispatch_unsigned() -> Weight { + Weight::from_ref_time(0b1000_0000) + } + fn schedule(_s: u32) -> Weight { + Weight::from_ref_time(50) + } + fn cancel(_s: u32) -> Weight { + Weight::from_ref_time(50) + } + fn schedule_named(_s: u32) -> Weight { + Weight::from_ref_time(50) + } + fn cancel_named(_s: u32) -> Weight { + Weight::from_ref_time(50) + } +} +parameter_types! { + pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * + BlockWeights::get().max_block; +} + impl Config for Test { - type Event = Event; - type Origin = Origin; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; type PalletsOrigin = OriginCaller; - type Call = Call; + type RuntimeCall = RuntimeCall; type MaximumWeight = MaximumSchedulerWeight; type ScheduleOrigin = EitherOfDiverse, EnsureSignedBy>; type MaxScheduledPerBlock = ConstU32<10>; - type WeightInfo = (); + type WeightInfo = TestWeightInfo; type OriginPrivilegeCmp = EqualPrivilegeOnly; - type PreimageProvider = Preimage; - type NoPreimagePostponement = NoPreimagePostponement; + type Preimages = Preimage; } pub type LoggerCall = logger::Call; diff --git a/frame/scheduler/src/tests.rs b/frame/scheduler/src/tests.rs index 999a810d3b7c1..033d787946709 100644 --- a/frame/scheduler/src/tests.rs +++ b/frame/scheduler/src/tests.rs @@ -18,10 +18,12 @@ //! # Scheduler tests. use super::*; -use crate::mock::{logger, new_test_ext, root, run_to_block, Call, LoggerCall, Scheduler, Test, *}; +use crate::mock::{ + logger, new_test_ext, root, run_to_block, LoggerCall, RuntimeCall, Scheduler, Test, *, +}; use frame_support::{ assert_err, assert_noop, assert_ok, - traits::{Contains, GetStorageVersion, OnInitialize, PreimageProvider}, + traits::{Contains, GetStorageVersion, OnInitialize, QueryPreimage, StorePreimage}, Hashable, }; use sp_runtime::traits::Hash; @@ -30,9 +32,16 @@ use substrate_test_utils::assert_eq_uvec; #[test] fn basic_scheduling_works() { new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); assert!(!::BaseCallFilter::contains(&call)); - assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into())); + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call).unwrap() + )); run_to_block(3); assert!(logger::log().is_empty()); run_to_block(4); @@ -45,50 +54,20 @@ fn basic_scheduling_works() { #[test] fn scheduling_with_preimages_works() { new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); let hash = ::Hashing::hash_of(&call); - let hashed = MaybeHashed::Hash(hash); - assert_ok!(Preimage::note_preimage(Origin::signed(0), call.encode())); + let len = call.using_encoded(|x| x.len()) as u32; + let hashed = Preimage::pick(hash, len); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::signed(0), call.encode())); assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), hashed)); - assert!(Preimage::preimage_requested(&hash)); + assert!(Preimage::is_requested(&hash)); run_to_block(3); assert!(logger::log().is_empty()); run_to_block(4); - assert!(!Preimage::have_preimage(&hash)); - assert!(!Preimage::preimage_requested(&hash)); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - run_to_block(100); - assert_eq!(logger::log(), vec![(root(), 42u32)]); - }); -} - -#[test] -fn scheduling_with_preimage_postpones_correctly() { - new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); - let hash = ::Hashing::hash_of(&call); - let hashed = MaybeHashed::Hash(hash); - - assert_ok!(Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), hashed)); - assert!(Preimage::preimage_requested(&hash)); - - run_to_block(4); - // #4 empty due to no preimage - assert!(logger::log().is_empty()); - - // Register preimage. - assert_ok!(Preimage::note_preimage(Origin::signed(0), call.encode())); - - run_to_block(5); - // #5 empty since postponement is 2 blocks. - assert!(logger::log().is_empty()); - - run_to_block(6); - // #6 is good. + assert!(!Preimage::len(&hash).is_some()); + assert!(!Preimage::is_requested(&hash)); assert_eq!(logger::log(), vec![(root(), 42u32)]); - assert!(!Preimage::have_preimage(&hash)); - assert!(!Preimage::preimage_requested(&hash)); - run_to_block(100); assert_eq!(logger::log(), vec![(root(), 42u32)]); }); @@ -98,10 +77,17 @@ fn scheduling_with_preimage_postpones_correctly() { fn schedule_after_works() { new_test_ext().execute_with(|| { run_to_block(2); - let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); assert!(!::BaseCallFilter::contains(&call)); // This will schedule the call 3 blocks after the next block... so block 3 + 3 = 6 - assert_ok!(Scheduler::do_schedule(DispatchTime::After(3), None, 127, root(), call.into())); + assert_ok!(Scheduler::do_schedule( + DispatchTime::After(3), + None, + 127, + root(), + Preimage::bound(call).unwrap() + )); run_to_block(5); assert!(logger::log().is_empty()); run_to_block(6); @@ -115,9 +101,16 @@ fn schedule_after_works() { fn schedule_after_zero_works() { new_test_ext().execute_with(|| { run_to_block(2); - let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); assert!(!::BaseCallFilter::contains(&call)); - assert_ok!(Scheduler::do_schedule(DispatchTime::After(0), None, 127, root(), call.into())); + assert_ok!(Scheduler::do_schedule( + DispatchTime::After(0), + None, + 127, + root(), + Preimage::bound(call).unwrap() + )); // Will trigger on the next block. run_to_block(3); assert_eq!(logger::log(), vec![(root(), 42u32)]); @@ -135,7 +128,11 @@ fn periodic_scheduling_works() { Some((3, 3)), 127, root(), - Call::Logger(logger::Call::log { i: 42, weight: Weight::from_ref_time(1000) }).into() + Preimage::bound(RuntimeCall::Logger(logger::Call::log { + i: 42, + weight: Weight::from_ref_time(10) + })) + .unwrap() )); run_to_block(3); assert!(logger::log().is_empty()); @@ -157,10 +154,18 @@ fn periodic_scheduling_works() { #[test] fn reschedule_works() { new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); assert!(!::BaseCallFilter::contains(&call)); assert_eq!( - Scheduler::do_schedule(DispatchTime::At(4), None, 127, root(), call.into()).unwrap(), + Scheduler::do_schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call).unwrap() + ) + .unwrap(), (4, 0) ); @@ -188,16 +193,17 @@ fn reschedule_works() { #[test] fn reschedule_named_works() { new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); assert!(!::BaseCallFilter::contains(&call)); assert_eq!( Scheduler::do_schedule_named( - 1u32.encode(), + [1u8; 32], DispatchTime::At(4), None, 127, root(), - call.into(), + Preimage::bound(call).unwrap(), ) .unwrap(), (4, 0) @@ -206,13 +212,10 @@ fn reschedule_named_works() { run_to_block(3); assert!(logger::log().is_empty()); - assert_eq!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(), - (6, 0) - ); + assert_eq!(Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(6)).unwrap(), (6, 0)); assert_noop!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)), + Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(6)), Error::::RescheduleNoChange ); @@ -230,16 +233,17 @@ fn reschedule_named_works() { #[test] fn reschedule_named_perodic_works() { new_test_ext().execute_with(|| { - let call = Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); assert!(!::BaseCallFilter::contains(&call)); assert_eq!( Scheduler::do_schedule_named( - 1u32.encode(), + [1u8; 32], DispatchTime::At(4), Some((3, 3)), 127, root(), - call.into(), + Preimage::bound(call).unwrap(), ) .unwrap(), (4, 0) @@ -248,14 +252,8 @@ fn reschedule_named_perodic_works() { run_to_block(3); assert!(logger::log().is_empty()); - assert_eq!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(5)).unwrap(), - (5, 0) - ); - assert_eq!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(6)).unwrap(), - (6, 0) - ); + assert_eq!(Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(5)).unwrap(), (5, 0)); + assert_eq!(Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(6)).unwrap(), (6, 0)); run_to_block(5); assert!(logger::log().is_empty()); @@ -264,7 +262,7 @@ fn reschedule_named_perodic_works() { assert_eq!(logger::log(), vec![(root(), 42u32)]); assert_eq!( - Scheduler::do_reschedule_named(1u32.encode(), DispatchTime::At(10)).unwrap(), + Scheduler::do_reschedule_named([1u8; 32], DispatchTime::At(10)).unwrap(), (10, 0) ); @@ -287,12 +285,16 @@ fn cancel_named_scheduling_works_with_normal_cancel() { new_test_ext().execute_with(|| { // at #4. Scheduler::do_schedule_named( - 1u32.encode(), + [1u8; 32], DispatchTime::At(4), None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), + Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })) + .unwrap(), ) .unwrap(); let i = Scheduler::do_schedule( @@ -300,12 +302,16 @@ fn cancel_named_scheduling_works_with_normal_cancel() { None, 127, root(), - Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), + Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })) + .unwrap(), ) .unwrap(); run_to_block(3); assert!(logger::log().is_empty()); - assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode())); + assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32])); assert_ok!(Scheduler::do_cancel(None, i)); run_to_block(100); assert!(logger::log().is_empty()); @@ -317,32 +323,44 @@ fn cancel_named_periodic_scheduling_works() { new_test_ext().execute_with(|| { // at #4, every 3 blocks, 3 times. Scheduler::do_schedule_named( - 1u32.encode(), + [1u8; 32], DispatchTime::At(4), Some((3, 3)), 127, root(), - Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), + Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })) + .unwrap(), ) .unwrap(); // same id results in error. assert!(Scheduler::do_schedule_named( - 1u32.encode(), + [1u8; 32], DispatchTime::At(4), None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), + Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10) + })) + .unwrap(), ) .is_err()); // different id is ok. Scheduler::do_schedule_named( - 2u32.encode(), + [2u8; 32], DispatchTime::At(8), None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), + Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })) + .unwrap(), ) .unwrap(); run_to_block(3); @@ -350,7 +368,7 @@ fn cancel_named_periodic_scheduling_works() { run_to_block(4); assert_eq!(logger::log(), vec![(root(), 42u32)]); run_to_block(6); - assert_ok!(Scheduler::do_cancel_named(None, 1u32.encode())); + assert_ok!(Scheduler::do_cancel_named(None, [1u8; 32])); run_to_block(100); assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); }); @@ -358,22 +376,23 @@ fn cancel_named_periodic_scheduling_works() { #[test] fn scheduler_respects_weight_limits() { + let max_weight: Weight = ::MaximumWeight::get(); new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 3 * 2 }); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 127, root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) - .into(), + Preimage::bound(call).unwrap(), )); + let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 3 * 2 }); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) - .into(), + Preimage::bound(call).unwrap(), )); // 69 and 42 do not fit together run_to_block(4); @@ -383,50 +402,128 @@ fn scheduler_respects_weight_limits() { }); } +/// Permanently overweight calls are not deleted but also not executed. #[test] -fn scheduler_respects_hard_deadlines_more() { +fn scheduler_does_not_delete_permanently_overweight_call() { + let max_weight: Weight = ::MaximumWeight::get(); new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight }); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, - 0, + 127, root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) - .into(), + Preimage::bound(call).unwrap(), )); + // Never executes. + run_to_block(100); + assert_eq!(logger::log(), vec![]); + + // Assert the `PermanentlyOverweight` event. + assert_eq!( + System::events().last().unwrap().event, + crate::Event::PermanentlyOverweight { task: (4, 0), id: None }.into(), + ); + // The call is still in the agenda. + assert!(Agenda::::get(4)[0].is_some()); + }); +} + +#[test] +fn scheduler_handles_periodic_failure() { + let max_weight: Weight = ::MaximumWeight::get(); + let max_per_block = ::MaxScheduledPerBlock::get(); + + new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: (max_weight / 3) * 2 }); + let bound = Preimage::bound(call).unwrap(); + assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), - None, - 0, + Some((4, u32::MAX)), + 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) - .into(), + bound.clone(), )); - // With base weights, 69 and 42 should not fit together, but do because of hard - // deadlines + // Executes 5 times till block 20. + run_to_block(20); + assert_eq!(logger::log().len(), 5); + + // Block 28 will already be full. + for _ in 0..max_per_block { + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(28), + None, + 120, + root(), + bound.clone(), + )); + } + + // Going to block 24 will emit a `PeriodicFailed` event. + run_to_block(24); + assert_eq!(logger::log().len(), 6); + + assert_eq!( + System::events().last().unwrap().event, + crate::Event::PeriodicFailed { task: (24, 0), id: None }.into(), + ); + }); +} + +#[test] +fn scheduler_handles_periodic_unavailable_preimage() { + let max_weight: Weight = ::MaximumWeight::get(); + + new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: (max_weight / 3) * 2 }); + let hash = ::Hashing::hash_of(&call); + let len = call.using_encoded(|x| x.len()) as u32; + let bound = Preimage::pick(hash, len); + assert_ok!(Preimage::note(call.encode().into())); + + assert_ok!(Scheduler::do_schedule( + DispatchTime::At(4), + Some((4, u32::MAX)), + 127, + root(), + bound.clone(), + )); + // Executes 1 times till block 4. run_to_block(4); - assert_eq!(logger::log(), vec![(root(), 42u32), (root(), 69u32)]); + assert_eq!(logger::log().len(), 1); + + // Unnote the preimage. + Preimage::unnote(&hash); + + // Does not ever execute again. + run_to_block(100); + assert_eq!(logger::log().len(), 1); + + // The preimage is not requested anymore. + assert!(!Preimage::is_requested(&hash)); }); } #[test] fn scheduler_respects_priority_ordering() { + let max_weight: Weight = ::MaximumWeight::get(); new_test_ext().execute_with(|| { + let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 3 }); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 1, root(), - Call::Logger(LoggerCall::log { i: 42, weight: MaximumSchedulerWeight::get() / 2 }) - .into(), + Preimage::bound(call).unwrap(), )); + let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 3 }); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 0, root(), - Call::Logger(LoggerCall::log { i: 69, weight: MaximumSchedulerWeight::get() / 2 }) - .into(), + Preimage::bound(call).unwrap(), )); run_to_block(4); assert_eq!(logger::log(), vec![(root(), 69u32), (root(), 42u32)]); @@ -436,33 +533,30 @@ fn scheduler_respects_priority_ordering() { #[test] fn scheduler_respects_priority_ordering_with_soft_deadlines() { new_test_ext().execute_with(|| { - let max_weight = MaximumSchedulerWeight::get() - <() as WeightInfo>::on_initialize(0); - let item_weight = - <() as WeightInfo>::on_initialize(1) - <() as WeightInfo>::on_initialize(0); + let max_weight: Weight = ::MaximumWeight::get(); + let call = RuntimeCall::Logger(LoggerCall::log { i: 42, weight: max_weight / 5 * 2 }); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 255, root(), - Call::Logger(LoggerCall::log { i: 42, weight: max_weight / 2 - item_weight }).into(), + Preimage::bound(call).unwrap(), )); + let call = RuntimeCall::Logger(LoggerCall::log { i: 69, weight: max_weight / 5 * 2 }); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: max_weight / 2 - item_weight }).into(), + Preimage::bound(call).unwrap(), )); + let call = RuntimeCall::Logger(LoggerCall::log { i: 2600, weight: max_weight / 5 * 4 }); assert_ok!(Scheduler::do_schedule( DispatchTime::At(4), None, 126, root(), - Call::Logger(LoggerCall::log { - i: 2600, - weight: max_weight / 2 - item_weight + Weight::from_ref_time(1) - }) - .into(), + Preimage::bound(call).unwrap(), )); // 2600 does not fit with 69 or 42, but has higher priority, so will go through @@ -477,81 +571,96 @@ fn scheduler_respects_priority_ordering_with_soft_deadlines() { #[test] fn on_initialize_weight_is_correct() { new_test_ext().execute_with(|| { - let base_weight = <() as WeightInfo>::on_initialize(0); - let call_weight = MaximumSchedulerWeight::get() / 4; + let call_weight = Weight::from_ref_time(25); // Named + let call = RuntimeCall::Logger(LoggerCall::log { + i: 3, + weight: call_weight + Weight::from_ref_time(1), + }); assert_ok!(Scheduler::do_schedule_named( - 1u32.encode(), + [1u8; 32], DispatchTime::At(3), None, 255, root(), - Call::Logger(LoggerCall::log { i: 3, weight: call_weight + Weight::from_ref_time(1) }) - .into(), + Preimage::bound(call).unwrap(), )); + let call = RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: call_weight + Weight::from_ref_time(2), + }); // Anon Periodic assert_ok!(Scheduler::do_schedule( DispatchTime::At(2), Some((1000, 3)), 128, root(), - Call::Logger(LoggerCall::log { i: 42, weight: call_weight + Weight::from_ref_time(2) }) - .into(), + Preimage::bound(call).unwrap(), )); + let call = RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: call_weight + Weight::from_ref_time(3), + }); // Anon assert_ok!(Scheduler::do_schedule( DispatchTime::At(2), None, 127, root(), - Call::Logger(LoggerCall::log { i: 69, weight: call_weight + Weight::from_ref_time(3) }) - .into(), + Preimage::bound(call).unwrap(), )); // Named Periodic + let call = RuntimeCall::Logger(LoggerCall::log { + i: 2600, + weight: call_weight + Weight::from_ref_time(4), + }); assert_ok!(Scheduler::do_schedule_named( - 2u32.encode(), + [2u8; 32], DispatchTime::At(1), Some((1000, 3)), 126, root(), - Call::Logger(LoggerCall::log { - i: 2600, - weight: call_weight + Weight::from_ref_time(4) - }) - .into(), + Preimage::bound(call).unwrap(), )); // Will include the named periodic only - let actual_weight = Scheduler::on_initialize(1); assert_eq!( - actual_weight, - base_weight + - call_weight + Weight::from_ref_time(4) + - <() as MarginalWeightInfo>::item(true, true, Some(false)) + Scheduler::on_initialize(1), + TestWeightInfo::service_agendas_base() + + TestWeightInfo::service_agenda_base(1) + + ::service_task(None, true, true) + + TestWeightInfo::execute_dispatch_unsigned() + + call_weight + Weight::from_ref_time(4) ); + assert_eq!(IncompleteSince::::get(), None); assert_eq!(logger::log(), vec![(root(), 2600u32)]); // Will include anon and anon periodic - let actual_weight = Scheduler::on_initialize(2); assert_eq!( - actual_weight, - base_weight + - call_weight + Weight::from_ref_time(2) + - <() as MarginalWeightInfo>::item(false, false, Some(false)) + + Scheduler::on_initialize(2), + TestWeightInfo::service_agendas_base() + + TestWeightInfo::service_agenda_base(2) + + ::service_task(None, false, true) + + TestWeightInfo::execute_dispatch_unsigned() + call_weight + Weight::from_ref_time(3) + - <() as MarginalWeightInfo>::item(true, false, Some(false)) + ::service_task(None, false, false) + + TestWeightInfo::execute_dispatch_unsigned() + + call_weight + Weight::from_ref_time(2) ); + assert_eq!(IncompleteSince::::get(), None); assert_eq!(logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32)]); // Will include named only - let actual_weight = Scheduler::on_initialize(3); assert_eq!( - actual_weight, - base_weight + - call_weight + Weight::from_ref_time(1) + - <() as MarginalWeightInfo>::item(false, true, Some(false)) + Scheduler::on_initialize(3), + TestWeightInfo::service_agendas_base() + + TestWeightInfo::service_agenda_base(1) + + ::service_task(None, true, false) + + TestWeightInfo::execute_dispatch_unsigned() + + call_weight + Weight::from_ref_time(1) ); + assert_eq!(IncompleteSince::::get(), None); assert_eq!( logger::log(), vec![(root(), 2600u32), (root(), 69u32), (root(), 42u32), (root(), 3u32)] @@ -559,27 +668,34 @@ fn on_initialize_weight_is_correct() { // Will contain none let actual_weight = Scheduler::on_initialize(4); - assert_eq!(actual_weight, base_weight); + assert_eq!( + actual_weight, + TestWeightInfo::service_agendas_base() + TestWeightInfo::service_agenda_base(0) + ); }); } #[test] fn root_calls_works() { new_test_ext().execute_with(|| { - let call = Box::new( - Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), + let call = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })); + let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })); + assert_ok!( + Scheduler::schedule_named(RuntimeOrigin::root(), [1u8; 32], 4, None, 127, call,) ); - let call2 = Box::new( - Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), - ); - assert_ok!(Scheduler::schedule_named(Origin::root(), 1u32.encode(), 4, None, 127, call,)); - assert_ok!(Scheduler::schedule(Origin::root(), 4, None, 127, call2)); + assert_ok!(Scheduler::schedule(RuntimeOrigin::root(), 4, None, 127, call2)); run_to_block(3); // Scheduled calls are in the agenda. assert_eq!(Agenda::::get(4).len(), 2); assert!(logger::log().is_empty()); - assert_ok!(Scheduler::cancel_named(Origin::root(), 1u32.encode())); - assert_ok!(Scheduler::cancel(Origin::root(), 4, 1)); + assert_ok!(Scheduler::cancel_named(RuntimeOrigin::root(), [1u8; 32])); + assert_ok!(Scheduler::cancel(RuntimeOrigin::root(), 4, 1)); // Scheduled calls are made NONE, so should not effect state run_to_block(100); assert!(logger::log().is_empty()); @@ -591,45 +707,50 @@ fn fails_to_schedule_task_in_the_past() { new_test_ext().execute_with(|| { run_to_block(3); - let call1 = Box::new( - Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), - ); - let call2 = Box::new( - Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), - ); - let call3 = Box::new( - Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), - ); + let call1 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })); + let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })); + let call3 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })); - assert_err!( - Scheduler::schedule_named(Origin::root(), 1u32.encode(), 2, None, 127, call1), + assert_noop!( + Scheduler::schedule_named(RuntimeOrigin::root(), [1u8; 32], 2, None, 127, call1), Error::::TargetBlockNumberInPast, ); - assert_err!( - Scheduler::schedule(Origin::root(), 2, None, 127, call2), + assert_noop!( + Scheduler::schedule(RuntimeOrigin::root(), 2, None, 127, call2), Error::::TargetBlockNumberInPast, ); - assert_err!( - Scheduler::schedule(Origin::root(), 3, None, 127, call3), + assert_noop!( + Scheduler::schedule(RuntimeOrigin::root(), 3, None, 127, call3), Error::::TargetBlockNumberInPast, ); }); } #[test] -fn should_use_orign() { +fn should_use_origin() { new_test_ext().execute_with(|| { - let call = Box::new( - Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), - ); - let call2 = Box::new( - Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), - ); + let call = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })); + let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })); assert_ok!(Scheduler::schedule_named( system::RawOrigin::Signed(1).into(), - 1u32.encode(), + [1u8; 32], 4, None, 127, @@ -640,7 +761,7 @@ fn should_use_orign() { // Scheduled calls are in the agenda. assert_eq!(Agenda::::get(4).len(), 2); assert!(logger::log().is_empty()); - assert_ok!(Scheduler::cancel_named(system::RawOrigin::Signed(1).into(), 1u32.encode())); + assert_ok!(Scheduler::cancel_named(system::RawOrigin::Signed(1).into(), [1u8; 32])); assert_ok!(Scheduler::cancel(system::RawOrigin::Signed(1).into(), 4, 1)); // Scheduled calls are made NONE, so should not effect state run_to_block(100); @@ -649,18 +770,20 @@ fn should_use_orign() { } #[test] -fn should_check_orign() { +fn should_check_origin() { new_test_ext().execute_with(|| { - let call = Box::new( - Call::Logger(LoggerCall::log { i: 69, weight: Weight::from_ref_time(1000) }).into(), - ); - let call2 = Box::new( - Call::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }).into(), - ); + let call = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })); + let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log { + i: 42, + weight: Weight::from_ref_time(10), + })); assert_noop!( Scheduler::schedule_named( system::RawOrigin::Signed(2).into(), - 1u32.encode(), + [1u8; 32], 4, None, 127, @@ -676,25 +799,19 @@ fn should_check_orign() { } #[test] -fn should_check_orign_for_cancel() { +fn should_check_origin_for_cancel() { new_test_ext().execute_with(|| { - let call = Box::new( - Call::Logger(LoggerCall::log_without_filter { - i: 69, - weight: Weight::from_ref_time(1000), - }) - .into(), - ); - let call2 = Box::new( - Call::Logger(LoggerCall::log_without_filter { - i: 42, - weight: Weight::from_ref_time(1000), - }) - .into(), - ); + let call = Box::new(RuntimeCall::Logger(LoggerCall::log_without_filter { + i: 69, + weight: Weight::from_ref_time(10), + })); + let call2 = Box::new(RuntimeCall::Logger(LoggerCall::log_without_filter { + i: 42, + weight: Weight::from_ref_time(10), + })); assert_ok!(Scheduler::schedule_named( system::RawOrigin::Signed(1).into(), - 1u32.encode(), + [1u8; 32], 4, None, 127, @@ -706,14 +823,11 @@ fn should_check_orign_for_cancel() { assert_eq!(Agenda::::get(4).len(), 2); assert!(logger::log().is_empty()); assert_noop!( - Scheduler::cancel_named(system::RawOrigin::Signed(2).into(), 1u32.encode()), + Scheduler::cancel_named(system::RawOrigin::Signed(2).into(), [1u8; 32]), BadOrigin ); assert_noop!(Scheduler::cancel(system::RawOrigin::Signed(2).into(), 4, 1), BadOrigin); - assert_noop!( - Scheduler::cancel_named(system::RawOrigin::Root.into(), 1u32.encode()), - BadOrigin - ); + assert_noop!(Scheduler::cancel_named(system::RawOrigin::Root.into(), [1u8; 32]), BadOrigin); assert_noop!(Scheduler::cancel(system::RawOrigin::Root.into(), 4, 1), BadOrigin); run_to_block(5); assert_eq!( @@ -727,7 +841,7 @@ fn should_check_orign_for_cancel() { } #[test] -fn migration_to_v3_works() { +fn migration_to_v4_works() { new_test_ext().execute_with(|| { for i in 0..3u64 { let k = i.twox_64_concat(); @@ -735,7 +849,7 @@ fn migration_to_v3_works() { Some(ScheduledV1 { maybe_id: None, priority: i as u8 + 10, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 96, weight: Weight::from_ref_time(100), }), @@ -745,9 +859,9 @@ fn migration_to_v3_works() { Some(ScheduledV1 { maybe_id: Some(b"test".to_vec()), priority: 123, - call: Call::Logger(LoggerCall::log { + call: RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(1000), + weight: Weight::from_ref_time(10), }), maybe_periodic: Some((456u64, 10)), }), @@ -755,103 +869,109 @@ fn migration_to_v3_works() { frame_support::migration::put_storage_value(b"Scheduler", b"Agenda", &k, old); } - Scheduler::migrate_v1_to_v3(); - - assert_eq_uvec!( - Agenda::::iter().collect::>(), - vec![ - ( - 0, - vec![ - Some(ScheduledV3Of:: { - maybe_id: None, - priority: 10, - call: Call::Logger(LoggerCall::log { - i: 96, - weight: Weight::from_ref_time(100) - }) - .into(), - maybe_periodic: None, - origin: root(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV3Of:: { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: Call::Logger(LoggerCall::log { - i: 69, - weight: Weight::from_ref_time(1000) - }) - .into(), - maybe_periodic: Some((456u64, 10)), - origin: root(), - _phantom: PhantomData::::default(), - }), - ] - ), - ( - 1, - vec![ - Some(ScheduledV3Of:: { - maybe_id: None, - priority: 11, - call: Call::Logger(LoggerCall::log { - i: 96, - weight: Weight::from_ref_time(100) - }) - .into(), - maybe_periodic: None, - origin: root(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV3Of:: { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: Call::Logger(LoggerCall::log { - i: 69, - weight: Weight::from_ref_time(1000) - }) - .into(), - maybe_periodic: Some((456u64, 10)), - origin: root(), - _phantom: PhantomData::::default(), - }), - ] - ), - ( - 2, - vec![ - Some(ScheduledV3Of:: { - maybe_id: None, - priority: 12, - call: Call::Logger(LoggerCall::log { - i: 96, - weight: Weight::from_ref_time(100) - }) - .into(), - maybe_periodic: None, - origin: root(), - _phantom: PhantomData::::default(), - }), - None, - Some(ScheduledV3Of:: { - maybe_id: Some(b"test".to_vec()), - priority: 123, - call: Call::Logger(LoggerCall::log { - i: 69, - weight: Weight::from_ref_time(1000) - }) - .into(), - maybe_periodic: Some((456u64, 10)), - origin: root(), - _phantom: PhantomData::::default(), - }), - ] - ) - ] - ); + Scheduler::migrate_v1_to_v4(); + + let mut x = Agenda::::iter().map(|x| (x.0, x.1.into_inner())).collect::>(); + x.sort_by_key(|x| x.0); + let expected = vec![ + ( + 0, + vec![ + Some(ScheduledOf:: { + maybe_id: None, + priority: 10, + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 96, + weight: Weight::from_ref_time(100), + })) + .unwrap(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledOf:: { + maybe_id: Some(blake2_256(&b"test"[..])), + priority: 123, + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })) + .unwrap(), + maybe_periodic: Some((456u64, 10)), + origin: root(), + _phantom: PhantomData::::default(), + }), + ], + ), + ( + 1, + vec![ + Some(ScheduledOf:: { + maybe_id: None, + priority: 11, + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 96, + weight: Weight::from_ref_time(100), + })) + .unwrap(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledOf:: { + maybe_id: Some(blake2_256(&b"test"[..])), + priority: 123, + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })) + .unwrap(), + maybe_periodic: Some((456u64, 10)), + origin: root(), + _phantom: PhantomData::::default(), + }), + ], + ), + ( + 2, + vec![ + Some(ScheduledOf:: { + maybe_id: None, + priority: 12, + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 96, + weight: Weight::from_ref_time(100), + })) + .unwrap(), + maybe_periodic: None, + origin: root(), + _phantom: PhantomData::::default(), + }), + None, + Some(ScheduledOf:: { + maybe_id: Some(blake2_256(&b"test"[..])), + priority: 123, + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { + i: 69, + weight: Weight::from_ref_time(10), + })) + .unwrap(), + maybe_periodic: Some((456u64, 10)), + origin: root(), + _phantom: PhantomData::::default(), + }), + ], + ), + ]; + for (i, j) in x.iter().zip(expected.iter()) { + assert_eq!(i.0, j.0); + for (x, y) in i.1.iter().zip(j.1.iter()) { + assert_eq!(x, y); + } + } + assert_eq_uvec!(x, expected); assert_eq!(Scheduler::current_storage_version(), 3); }); @@ -862,29 +982,29 @@ fn test_migrate_origin() { new_test_ext().execute_with(|| { for i in 0..3u64 { let k = i.twox_64_concat(); - let old: Vec, u64, u32, u64>>> = vec![ + let old: Vec, u64, u32, u64>>> = vec![ Some(Scheduled { maybe_id: None, priority: i as u8 + 10, - call: Call::Logger(LoggerCall::log { + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 96, weight: Weight::from_ref_time(100), - }) - .into(), + })) + .unwrap(), origin: 3u32, maybe_periodic: None, _phantom: Default::default(), }), None, Some(Scheduled { - maybe_id: Some(b"test".to_vec()), + maybe_id: Some(blake2_256(&b"test"[..])), priority: 123, origin: 2u32, - call: Call::Logger(LoggerCall::log { + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(1000), - }) - .into(), + weight: Weight::from_ref_time(10), + })) + .unwrap(), maybe_periodic: Some((456u64, 10)), _phantom: Default::default(), }), @@ -905,32 +1025,32 @@ fn test_migrate_origin() { Scheduler::migrate_origin::(); assert_eq_uvec!( - Agenda::::iter().collect::>(), + Agenda::::iter().map(|x| (x.0, x.1.into_inner())).collect::>(), vec![ ( 0, vec![ - Some(ScheduledV2::, u64, OriginCaller, u64> { + Some(ScheduledOf:: { maybe_id: None, priority: 10, - call: Call::Logger(LoggerCall::log { + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 96, weight: Weight::from_ref_time(100) - }) - .into(), + })) + .unwrap(), maybe_periodic: None, origin: system::RawOrigin::Root.into(), _phantom: PhantomData::::default(), }), None, - Some(ScheduledV2 { - maybe_id: Some(b"test".to_vec()), + Some(Scheduled { + maybe_id: Some(blake2_256(&b"test"[..])), priority: 123, - call: Call::Logger(LoggerCall::log { + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(1000) - }) - .into(), + weight: Weight::from_ref_time(10) + })) + .unwrap(), maybe_periodic: Some((456u64, 10)), origin: system::RawOrigin::None.into(), _phantom: PhantomData::::default(), @@ -940,27 +1060,27 @@ fn test_migrate_origin() { ( 1, vec![ - Some(ScheduledV2 { + Some(Scheduled { maybe_id: None, priority: 11, - call: Call::Logger(LoggerCall::log { + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 96, weight: Weight::from_ref_time(100) - }) - .into(), + })) + .unwrap(), maybe_periodic: None, origin: system::RawOrigin::Root.into(), _phantom: PhantomData::::default(), }), None, - Some(ScheduledV2 { - maybe_id: Some(b"test".to_vec()), + Some(Scheduled { + maybe_id: Some(blake2_256(&b"test"[..])), priority: 123, - call: Call::Logger(LoggerCall::log { + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(1000) - }) - .into(), + weight: Weight::from_ref_time(10) + })) + .unwrap(), maybe_periodic: Some((456u64, 10)), origin: system::RawOrigin::None.into(), _phantom: PhantomData::::default(), @@ -970,27 +1090,27 @@ fn test_migrate_origin() { ( 2, vec![ - Some(ScheduledV2 { + Some(Scheduled { maybe_id: None, priority: 12, - call: Call::Logger(LoggerCall::log { + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 96, weight: Weight::from_ref_time(100) - }) - .into(), + })) + .unwrap(), maybe_periodic: None, origin: system::RawOrigin::Root.into(), _phantom: PhantomData::::default(), }), None, - Some(ScheduledV2 { - maybe_id: Some(b"test".to_vec()), + Some(Scheduled { + maybe_id: Some(blake2_256(&b"test"[..])), priority: 123, - call: Call::Logger(LoggerCall::log { + call: Preimage::bound(RuntimeCall::Logger(LoggerCall::log { i: 69, - weight: Weight::from_ref_time(1000) - }) - .into(), + weight: Weight::from_ref_time(10) + })) + .unwrap(), maybe_periodic: Some((456u64, 10)), origin: system::RawOrigin::None.into(), _phantom: PhantomData::::default(), @@ -1001,3 +1121,649 @@ fn test_migrate_origin() { ); }); } + +#[test] +fn postponed_named_task_cannot_be_rescheduled() { + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(1000) }); + let hash = ::Hashing::hash_of(&call); + let len = call.using_encoded(|x| x.len()) as u32; + let hashed = Preimage::pick(hash, len); + let name: [u8; 32] = hash.as_ref().try_into().unwrap(); + + let address = Scheduler::do_schedule_named( + name, + DispatchTime::At(4), + None, + 127, + root(), + hashed.clone(), + ) + .unwrap(); + assert!(Preimage::is_requested(&hash)); + assert!(Lookup::::contains_key(name)); + + // Run to a very large block. + run_to_block(10); + // It was not executed. + assert!(logger::log().is_empty()); + assert!(Preimage::is_requested(&hash)); + // Postponing removes the lookup. + assert!(!Lookup::::contains_key(name)); + + // The agenda still contains the call. + let agenda = Agenda::::iter().collect::>(); + assert_eq!(agenda.len(), 1); + assert_eq!( + agenda[0].1, + vec![Some(Scheduled { + maybe_id: Some(name), + priority: 127, + call: hashed, + maybe_periodic: None, + origin: root().into(), + _phantom: Default::default(), + })] + ); + + // Finally add the preimage. + assert_ok!(Preimage::note(call.encode().into())); + run_to_block(1000); + // It did not execute. + assert!(logger::log().is_empty()); + assert!(Preimage::is_requested(&hash)); + + // Manually re-schedule the call by name does not work. + assert_err!( + Scheduler::do_reschedule_named(name, DispatchTime::At(1001)), + Error::::NotFound + ); + // Manually re-scheduling the call by address errors. + assert_err!( + Scheduler::do_reschedule(address, DispatchTime::At(1001)), + Error::::Named + ); + }); +} + +/// Using the scheduler as `v3::Anon` works. +#[test] +fn scheduler_v3_anon_basic_works() { + use frame_support::traits::schedule::v3::Anon; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + + // Schedule a call. + let _address = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + ) + .unwrap(); + + run_to_block(3); + // Did not execute till block 3. + assert!(logger::log().is_empty()); + // Executes in block 4. + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + // ... but not again. + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +#[test] +fn scheduler_v3_anon_cancel_works() { + use frame_support::traits::schedule::v3::Anon; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + + // Schedule a call. + let address = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(); + // Cancel the call. + assert_ok!(>::cancel(address)); + // It did not get executed. + run_to_block(100); + assert!(logger::log().is_empty()); + // Cannot cancel again. + assert_err!(>::cancel(address), DispatchError::Unavailable); + }); +} + +#[test] +fn scheduler_v3_anon_reschedule_works() { + use frame_support::traits::schedule::v3::Anon; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + + // Schedule a call. + let address = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + ) + .unwrap(); + + run_to_block(3); + // Did not execute till block 3. + assert!(logger::log().is_empty()); + + // Cannot re-schedule into the same block. + assert_noop!( + >::reschedule(address, DispatchTime::At(4)), + Error::::RescheduleNoChange + ); + // Cannot re-schedule into the past. + assert_noop!( + >::reschedule(address, DispatchTime::At(3)), + Error::::TargetBlockNumberInPast + ); + // Re-schedule to block 5. + assert_ok!(>::reschedule(address, DispatchTime::At(5))); + // Scheduled for block 5. + run_to_block(4); + assert!(logger::log().is_empty()); + run_to_block(5); + // Does execute in block 5. + assert_eq!(logger::log(), vec![(root(), 42)]); + // Cannot re-schedule executed task. + assert_noop!( + >::reschedule(address, DispatchTime::At(10)), + DispatchError::Unavailable + ); + }); +} + +/// Cancelling a call and then scheduling a second call for the same +/// block results in different addresses. +#[test] +fn scheduler_v3_anon_schedule_does_not_resuse_addr() { + use frame_support::traits::schedule::v3::Anon; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + + // Schedule both calls. + let addr_1 = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call.clone()).unwrap(), + ) + .unwrap(); + // Cancel the call. + assert_ok!(>::cancel(addr_1)); + let addr_2 = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + ) + .unwrap(); + + // Should not re-use the address. + assert!(addr_1 != addr_2); + }); +} + +#[test] +fn scheduler_v3_anon_next_schedule_time_works() { + use frame_support::traits::schedule::v3::Anon; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + + // Schedule a call. + let address = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(); + + run_to_block(3); + // Did not execute till block 3. + assert!(logger::log().is_empty()); + + // Scheduled for block 4. + assert_eq!(>::next_dispatch_time(address), Ok(4)); + // Block 4 executes it. + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42)]); + + // It has no dispatch time anymore. + assert_noop!( + >::next_dispatch_time(address), + DispatchError::Unavailable + ); + }); +} + +/// Re-scheduling a task changes its next dispatch time. +#[test] +fn scheduler_v3_anon_reschedule_and_next_schedule_time_work() { + use frame_support::traits::schedule::v3::Anon; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + + // Schedule a call. + let old_address = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(); + + run_to_block(3); + // Did not execute till block 3. + assert!(logger::log().is_empty()); + + // Scheduled for block 4. + assert_eq!(>::next_dispatch_time(old_address), Ok(4)); + // Re-schedule to block 5. + let address = + >::reschedule(old_address, DispatchTime::At(5)).unwrap(); + assert!(address != old_address); + // Scheduled for block 5. + assert_eq!(>::next_dispatch_time(address), Ok(5)); + + // Block 4 does nothing. + run_to_block(4); + assert!(logger::log().is_empty()); + // Block 5 executes it. + run_to_block(5); + assert_eq!(logger::log(), vec![(root(), 42)]); + }); +} + +#[test] +fn scheduler_v3_anon_schedule_agenda_overflows() { + use frame_support::traits::schedule::v3::Anon; + let max: u32 = ::MaxScheduledPerBlock::get(); + + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + + // Schedule the maximal number allowed per block. + for _ in 0..max { + >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(); + } + + // One more time and it errors. + assert_noop!( + >::schedule(DispatchTime::At(4), None, 127, root(), bound,), + DispatchError::Exhausted + ); + + run_to_block(4); + // All scheduled calls are executed. + assert_eq!(logger::log().len() as u32, max); + }); +} + +/// Cancelling and scheduling does not overflow the agenda but fills holes. +#[test] +fn scheduler_v3_anon_cancel_and_schedule_fills_holes() { + use frame_support::traits::schedule::v3::Anon; + let max: u32 = ::MaxScheduledPerBlock::get(); + assert!(max > 3, "This test only makes sense for MaxScheduledPerBlock > 3"); + + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + let mut addrs = Vec::<_>::default(); + + // Schedule the maximal number allowed per block. + for _ in 0..max { + addrs.push( + >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(), + ); + } + // Cancel three of them. + for addr in addrs.into_iter().take(3) { + >::cancel(addr).unwrap(); + } + // Schedule three new ones. + for i in 0..3 { + let (_block, index) = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(); + assert_eq!(i, index); + } + + run_to_block(4); + // Maximum number of calls are executed. + assert_eq!(logger::log().len() as u32, max); + }); +} + +/// Re-scheduling does not overflow the agenda but fills holes. +#[test] +fn scheduler_v3_anon_reschedule_fills_holes() { + use frame_support::traits::schedule::v3::Anon; + let max: u32 = ::MaxScheduledPerBlock::get(); + assert!(max > 3, "pre-condition: This test only makes sense for MaxScheduledPerBlock > 3"); + + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + let mut addrs = Vec::<_>::default(); + + // Schedule the maximal number allowed per block. + for _ in 0..max { + addrs.push( + >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(), + ); + } + let mut new_addrs = Vec::<_>::default(); + // Reversed last three elements of block 4. + let last_three = addrs.into_iter().rev().take(3).collect::>(); + // Re-schedule three of them to block 5. + for addr in last_three.iter().cloned() { + new_addrs + .push(>::reschedule(addr, DispatchTime::At(5)).unwrap()); + } + // Re-scheduling them back into block 3 should result in the same addrs. + for (old, want) in new_addrs.into_iter().zip(last_three.into_iter().rev()) { + let new = >::reschedule(old, DispatchTime::At(4)).unwrap(); + assert_eq!(new, want); + } + + run_to_block(4); + // Maximum number of calls are executed. + assert_eq!(logger::log().len() as u32, max); + }); +} + +/// Re-scheduling into the same block produces a different address +/// if there is still space in the agenda. +#[test] +fn scheduler_v3_anon_reschedule_does_not_resuse_addr_if_agenda_not_full() { + use frame_support::traits::schedule::v3::Anon; + let max: u32 = ::MaxScheduledPerBlock::get(); + assert!(max > 1, "This test only makes sense for MaxScheduledPerBlock > 1"); + + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + + // Schedule both calls. + let addr_1 = >::schedule( + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call.clone()).unwrap(), + ) + .unwrap(); + // Cancel the call. + assert_ok!(>::cancel(addr_1)); + let addr_2 = >::schedule( + DispatchTime::At(5), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + ) + .unwrap(); + // Re-schedule `call` to block 4. + let addr_3 = >::reschedule(addr_2, DispatchTime::At(4)).unwrap(); + + // Should not re-use the address. + assert!(addr_1 != addr_3); + }); +} + +/// The scheduler can be used as `v3::Named` trait. +#[test] +fn scheduler_v3_named_basic_works() { + use frame_support::traits::schedule::v3::Named; + + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let name = [1u8; 32]; + + // Schedule a call. + let _address = >::schedule_named( + name, + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + ) + .unwrap(); + + run_to_block(3); + // Did not execute till block 3. + assert!(logger::log().is_empty()); + // Executes in block 4. + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + // ... but not again. + run_to_block(100); + assert_eq!(logger::log(), vec![(root(), 42u32)]); + }); +} + +/// A named task can be cancelled by its name. +#[test] +fn scheduler_v3_named_cancel_named_works() { + use frame_support::traits::schedule::v3::Named; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + let name = [1u8; 32]; + + // Schedule a call. + >::schedule_named( + name, + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(); + // Cancel the call by name. + assert_ok!(>::cancel_named(name)); + // It did not get executed. + run_to_block(100); + assert!(logger::log().is_empty()); + // Cannot cancel again. + assert_noop!(>::cancel_named(name), DispatchError::Unavailable); + }); +} + +/// A named task can also be cancelled by its address. +#[test] +fn scheduler_v3_named_cancel_without_name_works() { + use frame_support::traits::schedule::v3::{Anon, Named}; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + let name = [1u8; 32]; + + // Schedule a call. + let address = >::schedule_named( + name, + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(); + // Cancel the call by address. + assert_ok!(>::cancel(address)); + // It did not get executed. + run_to_block(100); + assert!(logger::log().is_empty()); + // Cannot cancel again. + assert_err!(>::cancel(address), DispatchError::Unavailable); + }); +} + +/// A named task can be re-scheduled by its name but not by its address. +#[test] +fn scheduler_v3_named_reschedule_named_works() { + use frame_support::traits::schedule::v3::{Anon, Named}; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let name = [1u8; 32]; + + // Schedule a call. + let address = >::schedule_named( + name, + DispatchTime::At(4), + None, + 127, + root(), + Preimage::bound(call).unwrap(), + ) + .unwrap(); + + run_to_block(3); + // Did not execute till block 3. + assert!(logger::log().is_empty()); + + // Cannot re-schedule by address. + assert_noop!( + >::reschedule(address, DispatchTime::At(10)), + Error::::Named, + ); + // Cannot re-schedule into the same block. + assert_noop!( + >::reschedule_named(name, DispatchTime::At(4)), + Error::::RescheduleNoChange + ); + // Cannot re-schedule into the past. + assert_noop!( + >::reschedule_named(name, DispatchTime::At(3)), + Error::::TargetBlockNumberInPast + ); + // Re-schedule to block 5. + assert_ok!(>::reschedule_named(name, DispatchTime::At(5))); + // Scheduled for block 5. + run_to_block(4); + assert!(logger::log().is_empty()); + run_to_block(5); + // Does execute in block 5. + assert_eq!(logger::log(), vec![(root(), 42)]); + // Cannot re-schedule executed task. + assert_noop!( + >::reschedule_named(name, DispatchTime::At(10)), + DispatchError::Unavailable + ); + // Also not by address. + assert_noop!( + >::reschedule(address, DispatchTime::At(10)), + DispatchError::Unavailable + ); + }); +} + +#[test] +fn scheduler_v3_named_next_schedule_time_works() { + use frame_support::traits::schedule::v3::{Anon, Named}; + new_test_ext().execute_with(|| { + let call = + RuntimeCall::Logger(LoggerCall::log { i: 42, weight: Weight::from_ref_time(10) }); + let bound = Preimage::bound(call).unwrap(); + let name = [1u8; 32]; + + // Schedule a call. + let address = >::schedule_named( + name, + DispatchTime::At(4), + None, + 127, + root(), + bound.clone(), + ) + .unwrap(); + + run_to_block(3); + // Did not execute till block 3. + assert!(logger::log().is_empty()); + + // Scheduled for block 4. + assert_eq!(>::next_dispatch_time(name), Ok(4)); + // Also works by address. + assert_eq!(>::next_dispatch_time(address), Ok(4)); + // Block 4 executes it. + run_to_block(4); + assert_eq!(logger::log(), vec![(root(), 42)]); + + // It has no dispatch time anymore. + assert_noop!( + >::next_dispatch_time(name), + DispatchError::Unavailable + ); + // Also not by address. + assert_noop!( + >::next_dispatch_time(address), + DispatchError::Unavailable + ); + }); +} diff --git a/frame/scheduler/src/weights.rs b/frame/scheduler/src/weights.rs index afbcf9373b2de..cb72fe3e2fdda 100644 --- a/frame/scheduler/src/weights.rs +++ b/frame/scheduler/src/weights.rs @@ -18,22 +18,24 @@ //! Autogenerated weights for pallet_scheduler //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-23, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-10-03, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_scheduler // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --pallet=pallet_scheduler +// --chain=dev // --output=./frame/scheduler/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -44,16 +46,14 @@ use sp_std::marker::PhantomData; /// Weight functions needed for pallet_scheduler. pub trait WeightInfo { - fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight; - fn on_initialize_named_resolved(s: u32, ) -> Weight; - fn on_initialize_periodic_resolved(s: u32, ) -> Weight; - fn on_initialize_resolved(s: u32, ) -> Weight; - fn on_initialize_named_aborted(s: u32, ) -> Weight; - fn on_initialize_aborted(s: u32, ) -> Weight; - fn on_initialize_periodic_named(s: u32, ) -> Weight; - fn on_initialize_periodic(s: u32, ) -> Weight; - fn on_initialize_named(s: u32, ) -> Weight; - fn on_initialize(s: u32, ) -> Weight; + fn service_agendas_base() -> Weight; + fn service_agenda_base(s: u32, ) -> Weight; + fn service_task_base() -> Weight; + fn service_task_fetched(s: u32, ) -> Weight; + fn service_task_named() -> Weight; + fn service_task_periodic() -> Weight; + fn execute_dispatch_signed() -> Weight; + fn execute_dispatch_unsigned() -> Weight; fn schedule(s: u32, ) -> Weight; fn cancel(s: u32, ) -> Weight; fn schedule_named(s: u32, ) -> Weight; @@ -63,149 +63,84 @@ pub trait WeightInfo { /// Weights for pallet_scheduler using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(9_994_000 as u64) - // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(19_843_000 as u64).saturating_mul(s as u64)) + // Storage: Scheduler IncompleteSince (r:1 w:1) + fn service_agendas_base() -> Weight { + Weight::from_ref_time(4_992_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(s as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((4 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:1 w:1) - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(10_318_000 as u64) - // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(15_451_000 as u64).saturating_mul(s as u64)) + /// The range of component `s` is `[0, 512]`. + fn service_agenda_base(s: u32, ) -> Weight { + Weight::from_ref_time(4_320_000 as u64) + // Standard Error: 619 + .saturating_add(Weight::from_ref_time(336_713 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(s as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(s as u64))) } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) - fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(11_675_000 as u64) - // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(17_019_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(s as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(s as u64))) + fn service_task_base() -> Weight { + Weight::from_ref_time(10_864_000 as u64) } - // Storage: Scheduler Agenda (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) - fn on_initialize_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(11_934_000 as u64) - // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(14_134_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(s as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Preimage PreimageFor (r:1 w:0) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named_aborted(s: u32, ) -> Weight { - Weight::from_ref_time(7_279_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(5_388_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Preimage PreimageFor (r:1 w:0) - fn on_initialize_aborted(s: u32, ) -> Weight { - Weight::from_ref_time(8_619_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_969_000 as u64).saturating_mul(s as u64)) + /// The range of component `s` is `[128, 4194304]`. + fn service_task_fetched(s: u32, ) -> Weight { + Weight::from_ref_time(24_586_000 as u64) + // Standard Error: 1 + .saturating_add(Weight::from_ref_time(1_138 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) .saturating_add(T::DbWeight::get().writes(2 as u64)) } - // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_periodic_named(s: u32, ) -> Weight { - Weight::from_ref_time(16_129_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(9_772_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + fn service_task_named() -> Weight { + Weight::from_ref_time(13_127_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((2 as u64).saturating_mul(s as u64))) } - // Storage: Scheduler Agenda (r:2 w:2) - fn on_initialize_periodic(s: u32, ) -> Weight { - Weight::from_ref_time(15_785_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(7_208_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) + fn service_task_periodic() -> Weight { + Weight::from_ref_time(11_053_000 as u64) } - // Storage: Scheduler Agenda (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named(s: u32, ) -> Weight { - Weight::from_ref_time(15_778_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(5_597_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) + fn execute_dispatch_signed() -> Weight { + Weight::from_ref_time(4_158_000 as u64) } - // Storage: Scheduler Agenda (r:1 w:1) - fn on_initialize(s: u32, ) -> Weight { - Weight::from_ref_time(15_912_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(4_530_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) + fn execute_dispatch_unsigned() -> Weight { + Weight::from_ref_time(4_104_000 as u64) } // Storage: Scheduler Agenda (r:1 w:1) + /// The range of component `s` is `[0, 511]`. fn schedule(s: u32, ) -> Weight { - Weight::from_ref_time(18_013_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(20_074_000 as u64) + // Standard Error: 765 + .saturating_add(Weight::from_ref_time(343_285 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) + /// The range of component `s` is `[1, 512]`. fn cancel(s: u32, ) -> Weight { - Weight::from_ref_time(18_131_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(21_509_000 as u64) + // Standard Error: 708 + .saturating_add(Weight::from_ref_time(323_013 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) + /// The range of component `s` is `[0, 511]`. fn schedule_named(s: u32, ) -> Weight { - Weight::from_ref_time(21_230_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(98_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(22_427_000 as u64) + // Standard Error: 850 + .saturating_add(Weight::from_ref_time(357_265 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) + /// The range of component `s` is `[1, 512]`. fn cancel_named(s: u32, ) -> Weight { - Weight::from_ref_time(20_139_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(22_875_000 as u64) + // Standard Error: 693 + .saturating_add(Weight::from_ref_time(336_643 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -213,149 +148,84 @@ impl WeightInfo for SubstrateWeight { // For backwards compatibility and tests impl WeightInfo for () { - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_periodic_named_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(9_994_000 as u64) - // Standard Error: 20_000 - .saturating_add(Weight::from_ref_time(19_843_000 as u64).saturating_mul(s as u64)) + // Storage: Scheduler IncompleteSince (r:1 w:1) + fn service_agendas_base() -> Weight { + Weight::from_ref_time(4_992_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(s as u64))) .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((4 as u64).saturating_mul(s as u64))) } // Storage: Scheduler Agenda (r:1 w:1) - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(10_318_000 as u64) - // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(15_451_000 as u64).saturating_mul(s as u64)) + /// The range of component `s` is `[0, 512]`. + fn service_agenda_base(s: u32, ) -> Weight { + Weight::from_ref_time(4_320_000 as u64) + // Standard Error: 619 + .saturating_add(Weight::from_ref_time(336_713 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(s as u64))) .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(s as u64))) } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Preimage PreimageFor (r:1 w:1) - // Storage: Preimage StatusFor (r:1 w:1) - fn on_initialize_periodic_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(11_675_000 as u64) - // Standard Error: 17_000 - .saturating_add(Weight::from_ref_time(17_019_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(s as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(s as u64))) + fn service_task_base() -> Weight { + Weight::from_ref_time(10_864_000 as u64) } - // Storage: Scheduler Agenda (r:1 w:1) // Storage: Preimage PreimageFor (r:1 w:1) // Storage: Preimage StatusFor (r:1 w:1) - fn on_initialize_resolved(s: u32, ) -> Weight { - Weight::from_ref_time(11_934_000 as u64) - // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(14_134_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(s as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Preimage PreimageFor (r:1 w:0) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named_aborted(s: u32, ) -> Weight { - Weight::from_ref_time(7_279_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(5_388_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) - } - // Storage: Scheduler Agenda (r:2 w:2) - // Storage: Preimage PreimageFor (r:1 w:0) - fn on_initialize_aborted(s: u32, ) -> Weight { - Weight::from_ref_time(8_619_000 as u64) - // Standard Error: 4_000 - .saturating_add(Weight::from_ref_time(2_969_000 as u64).saturating_mul(s as u64)) + /// The range of component `s` is `[128, 4194304]`. + fn service_task_fetched(s: u32, ) -> Weight { + Weight::from_ref_time(24_586_000 as u64) + // Standard Error: 1 + .saturating_add(Weight::from_ref_time(1_138 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } - // Storage: Scheduler Agenda (r:2 w:2) // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_periodic_named(s: u32, ) -> Weight { - Weight::from_ref_time(16_129_000 as u64) - // Standard Error: 7_000 - .saturating_add(Weight::from_ref_time(9_772_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + fn service_task_named() -> Weight { + Weight::from_ref_time(13_127_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((2 as u64).saturating_mul(s as u64))) } - // Storage: Scheduler Agenda (r:2 w:2) - fn on_initialize_periodic(s: u32, ) -> Weight { - Weight::from_ref_time(15_785_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(7_208_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) + fn service_task_periodic() -> Weight { + Weight::from_ref_time(11_053_000 as u64) } - // Storage: Scheduler Agenda (r:1 w:1) - // Storage: Scheduler Lookup (r:0 w:1) - fn on_initialize_named(s: u32, ) -> Weight { - Weight::from_ref_time(15_778_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(5_597_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) + fn execute_dispatch_signed() -> Weight { + Weight::from_ref_time(4_158_000 as u64) } - // Storage: Scheduler Agenda (r:1 w:1) - fn on_initialize(s: u32, ) -> Weight { - Weight::from_ref_time(15_912_000 as u64) - // Standard Error: 5_000 - .saturating_add(Weight::from_ref_time(4_530_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) + fn execute_dispatch_unsigned() -> Weight { + Weight::from_ref_time(4_104_000 as u64) } // Storage: Scheduler Agenda (r:1 w:1) + /// The range of component `s` is `[0, 511]`. fn schedule(s: u32, ) -> Weight { - Weight::from_ref_time(18_013_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(87_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(20_074_000 as u64) + // Standard Error: 765 + .saturating_add(Weight::from_ref_time(343_285 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Scheduler Agenda (r:1 w:1) // Storage: Scheduler Lookup (r:0 w:1) + /// The range of component `s` is `[1, 512]`. fn cancel(s: u32, ) -> Weight { - Weight::from_ref_time(18_131_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(21_509_000 as u64) + // Standard Error: 708 + .saturating_add(Weight::from_ref_time(323_013 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) + /// The range of component `s` is `[0, 511]`. fn schedule_named(s: u32, ) -> Weight { - Weight::from_ref_time(21_230_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(98_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(22_427_000 as u64) + // Standard Error: 850 + .saturating_add(Weight::from_ref_time(357_265 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Scheduler Lookup (r:1 w:1) // Storage: Scheduler Agenda (r:1 w:1) + /// The range of component `s` is `[1, 512]`. fn cancel_named(s: u32, ) -> Weight { - Weight::from_ref_time(20_139_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(595_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(22_875_000 as u64) + // Standard Error: 693 + .saturating_add(Weight::from_ref_time(336_643 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } diff --git a/frame/scored-pool/README.md b/frame/scored-pool/README.md index 56c6af916ecd0..455bae24e7951 100644 --- a/frame/scored-pool/README.md +++ b/frame/scored-pool/README.md @@ -58,7 +58,7 @@ pub mod pallet { let who = ensure_signed(origin)?; let _ = >::submit_candidacy( - T::Origin::from(Some(who.clone()).into()) + T::RuntimeOrigin::from(Some(who.clone()).into()) ); Ok(()) } diff --git a/frame/scored-pool/src/lib.rs b/frame/scored-pool/src/lib.rs index dd96a5df2baf9..a015c1c568153 100644 --- a/frame/scored-pool/src/lib.rs +++ b/frame/scored-pool/src/lib.rs @@ -75,7 +75,7 @@ //! let who = ensure_signed(origin)?; //! //! let _ = >::submit_candidacy( -//! T::Origin::from(Some(who.clone()).into()) +//! T::RuntimeOrigin::from(Some(who.clone()).into()) //! ); //! Ok(()) //! } @@ -98,10 +98,11 @@ mod mock; #[cfg(test)] mod tests; -use codec::FullCodec; +use codec::{FullCodec, MaxEncodedLen}; use frame_support::{ ensure, traits::{ChangeMembers, Currency, Get, InitializeMembers, ReservableCurrency}, + BoundedVec, }; pub use pallet::*; use sp_runtime::traits::{AtLeast32Bit, StaticLookup, Zero}; @@ -109,7 +110,12 @@ use sp_std::{fmt::Debug, prelude::*}; type BalanceOf = <>::Currency as Currency<::AccountId>>::Balance; -type PoolT = Vec<(::AccountId, Option<>::Score>)>; +type PoolT = BoundedVec< + (::AccountId, Option<>::Score>), + >::MaximumMembers, +>; +type MembersT = + BoundedVec<::AccountId, >::MaximumMembers>; type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; /// The enum is supplied when refreshing the members set. @@ -130,7 +136,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); #[pallet::config] @@ -138,6 +143,10 @@ pub mod pallet { /// The currency used for deposits. type Currency: Currency + ReservableCurrency; + /// Maximum members length allowed. + #[pallet::constant] + type MaximumMembers: Get; + /// The score attributed to a member or candidate. type Score: AtLeast32Bit + Clone @@ -146,10 +155,12 @@ pub mod pallet { + FullCodec + MaybeSerializeDeserialize + Debug - + scale_info::TypeInfo; + + scale_info::TypeInfo + + MaxEncodedLen; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; // The deposit which is reserved from candidates if they want to // start a candidacy. The deposit gets returned when the candidacy is @@ -172,13 +183,13 @@ pub mod pallet { type MembershipChanged: ChangeMembers; /// Allows a configurable origin type to set a score to a candidate in the pool. - type ScoreOrigin: EnsureOrigin; + type ScoreOrigin: EnsureOrigin; /// Required origin for removing a member (though can always be Root). /// Configurable origin which enables removing an entity. If the entity /// is part of the `Members` it is immediately replaced by the next /// highest scoring candidate, if available. - type KickOrigin: EnsureOrigin; + type KickOrigin: EnsureOrigin; } #[pallet::event] @@ -207,9 +218,11 @@ pub mod pallet { InvalidIndex, /// Index does not match requested account. WrongAccountIndex, + /// Number of members exceeds `MaximumMembers`. + TooManyMembers, } - /// The current pool of candidates, stored as an ordered Vec + /// The current pool of candidates, stored as an ordered Bounded Vec /// (ordered descending by score, `None` last, highest first). #[pallet::storage] #[pallet::getter(fn pool)] @@ -229,7 +242,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn members)] pub(crate) type Members, I: 'static = ()> = - StorageValue<_, Vec, ValueQuery>; + StorageValue<_, MembersT, ValueQuery>; /// Size of the `Members` set. #[pallet::storage] @@ -263,10 +276,10 @@ pub mod pallet { }); // Sorts the `Pool` by score in a descending order. Entities which - // have a score of `None` are sorted to the beginning of the vec. + // have a score of `None` are sorted to the end of the bounded vec. pool.sort_by_key(|(_, maybe_score)| Reverse(maybe_score.unwrap_or_default())); - - >::put(self.member_count); + >::update_member_count(self.member_count) + .expect("Number of allowed members exceeded"); >::put(&pool); >::refresh_members(pool, ChangeReceiver::MembershipInitialized); } @@ -308,7 +321,8 @@ pub mod pallet { // can be inserted as last element in pool, since entities with // `None` are always sorted to the end. - >::append((who.clone(), Option::<>::Score>::None)); + >::try_append((who.clone(), Option::<>::Score>::None)) + .map_err(|_| Error::::TooManyMembers)?; >::insert(&who, true); @@ -394,7 +408,7 @@ pub mod pallet { Reverse(maybe_score.unwrap_or_default()) }) .unwrap_or_else(|l| l); - pool.insert(location, item); + pool.try_insert(location, item).map_err(|_| Error::::TooManyMembers)?; >::put(&pool); Self::deposit_event(Event::::CandidateScored); @@ -410,8 +424,7 @@ pub mod pallet { #[pallet::weight(0)] pub fn change_member_count(origin: OriginFor, count: u32) -> DispatchResult { ensure_root(origin)?; - MemberCount::::put(&count); - Ok(()) + Self::update_member_count(count).map_err(Into::into) } } } @@ -424,23 +437,28 @@ impl, I: 'static> Pallet { /// type function to invoke at the end of the method. fn refresh_members(pool: PoolT, notify: ChangeReceiver) { let count = MemberCount::::get(); + let old_members = >::get(); - let mut new_members: Vec = pool + let new_members: Vec = pool .into_iter() .filter(|(_, score)| score.is_some()) .take(count as usize) .map(|(account_id, _)| account_id) .collect(); - new_members.sort(); - let old_members = >::get(); - >::put(&new_members); + // It's safe to truncate_from at this point since MemberCount + // is verified that it does not exceed the MaximumMembers value + let mut new_members_bounded: MembersT = BoundedVec::truncate_from(new_members); + + new_members_bounded.sort(); + + >::put(&new_members_bounded); match notify { ChangeReceiver::MembershipInitialized => - T::MembershipInitialized::initialize_members(&new_members), + T::MembershipInitialized::initialize_members(&new_members_bounded), ChangeReceiver::MembershipChanged => - T::MembershipChanged::set_members_sorted(&new_members[..], &old_members[..]), + T::MembershipChanged::set_members_sorted(&new_members_bounded[..], &old_members[..]), } } @@ -486,4 +504,11 @@ impl, I: 'static> Pallet { Ok(()) } + + /// Make sure the new member count value does not exceed the MaximumMembers + fn update_member_count(new_member_count: u32) -> Result<(), Error> { + ensure!(new_member_count <= T::MaximumMembers::get(), Error::::TooManyMembers); + >::put(new_member_count); + Ok(()) + } } diff --git a/frame/scored-pool/src/mock.rs b/frame/scored-pool/src/mock.rs index e38e0a18b99c8..d6f653b32ad2d 100644 --- a/frame/scored-pool/src/mock.rs +++ b/frame/scored-pool/src/mock.rs @@ -21,7 +21,7 @@ use super::*; use crate as pallet_scored_pool; use frame_support::{ - ord_parameter_types, parameter_types, + bounded_vec, construct_runtime, ord_parameter_types, parameter_types, traits::{ConstU32, ConstU64, GenesisBuild}, }; use frame_system::EnsureSignedBy; @@ -30,12 +30,11 @@ use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, }; -use std::cell::RefCell; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; -frame_support::construct_runtime!( +construct_runtime!( pub enum Test where Block = Block, NodeBlock = Block, @@ -62,16 +61,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -89,21 +88,21 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } -thread_local! { - pub static MEMBERS: RefCell> = RefCell::new(vec![]); +parameter_types! { + pub static MembersTestValue: BoundedVec> = bounded_vec![0,10]; } pub struct TestChangeMembers; impl ChangeMembers for TestChangeMembers { fn change_members_sorted(incoming: &[u64], outgoing: &[u64], new: &[u64]) { - let mut old_plus_incoming = MEMBERS.with(|m| m.borrow().to_vec()); + let mut old_plus_incoming = MembersTestValue::get().into_inner(); old_plus_incoming.extend_from_slice(incoming); old_plus_incoming.sort(); @@ -113,18 +112,20 @@ impl ChangeMembers for TestChangeMembers { assert_eq!(old_plus_incoming, new_plus_outgoing); - MEMBERS.with(|m| *m.borrow_mut() = new.to_vec()); + MembersTestValue::set(>>::truncate_from(new.to_vec())); } } impl InitializeMembers for TestChangeMembers { fn initialize_members(new_members: &[u64]) { - MEMBERS.with(|m| *m.borrow_mut() = new_members.to_vec()); + MembersTestValue::set(>>::truncate_from( + new_members.to_vec(), + )); } } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type KickOrigin = EnsureSignedBy; type MembershipInitialized = TestChangeMembers; type MembershipChanged = TestChangeMembers; @@ -133,25 +134,24 @@ impl Config for Test { type Period = ConstU64<4>; type Score = u64; type ScoreOrigin = EnsureSignedBy; + type MaximumMembers = ConstU32<10>; } pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - pallet_balances::GenesisConfig:: { - balances: vec![ - (5, 500_000), - (10, 500_000), - (15, 500_000), - (20, 500_000), - (31, 500_000), - (40, 500_000), - (99, 1), - ], + let mut balances = vec![]; + for i in 1..31 { + balances.push((i, 500_000)); } - .assimilate_storage(&mut t) - .unwrap(); + balances.push((31, 500_000)); + balances.push((40, 500_000)); + balances.push((99, 1)); + + pallet_balances::GenesisConfig:: { balances } + .assimilate_storage(&mut t) + .unwrap(); pallet_scored_pool::GenesisConfig:: { - pool: vec![(5, None), (10, Some(1)), (20, Some(2)), (31, Some(2)), (40, Some(3))], + pool: bounded_vec![(10, Some(1)), (20, Some(2)), (31, Some(2)), (40, Some(3)), (5, None)], member_count: 2, } .assimilate_storage(&mut t) diff --git a/frame/scored-pool/src/tests.rs b/frame/scored-pool/src/tests.rs index 7b431160ddfe5..8f4daff47cc44 100644 --- a/frame/scored-pool/src/tests.rs +++ b/frame/scored-pool/src/tests.rs @@ -33,7 +33,7 @@ fn query_membership_works() { assert_eq!(ScoredPool::members(), vec![20, 40]); assert_eq!(Balances::reserved_balance(31), CandidateDeposit::get()); assert_eq!(Balances::reserved_balance(40), CandidateDeposit::get()); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), vec![20, 40]); + assert_eq!(MembersTestValue::get().clone(), vec![20, 40]); }); } @@ -41,11 +41,11 @@ fn query_membership_works() { fn submit_candidacy_must_not_work() { new_test_ext().execute_with(|| { assert_noop!( - ScoredPool::submit_candidacy(Origin::signed(99)), + ScoredPool::submit_candidacy(RuntimeOrigin::signed(99)), pallet_balances::Error::::InsufficientBalance, ); assert_noop!( - ScoredPool::submit_candidacy(Origin::signed(40)), + ScoredPool::submit_candidacy(RuntimeOrigin::signed(40)), Error::::AlreadyInPool ); }); @@ -58,7 +58,7 @@ fn submit_candidacy_works() { let who = 15; // when - assert_ok!(ScoredPool::submit_candidacy(Origin::signed(who))); + assert_ok!(ScoredPool::submit_candidacy(RuntimeOrigin::signed(who))); assert_eq!(fetch_from_pool(15), Some((who, None))); // then @@ -72,11 +72,11 @@ fn scoring_works() { // given let who = 15; let score = 99; - assert_ok!(ScoredPool::submit_candidacy(Origin::signed(who))); + assert_ok!(ScoredPool::submit_candidacy(RuntimeOrigin::signed(who))); // when let index = find_in_pool(who).expect("entity must be in pool") as u32; - assert_ok!(ScoredPool::score(Origin::signed(ScoreOrigin::get()), who, index, score)); + assert_ok!(ScoredPool::score(RuntimeOrigin::signed(ScoreOrigin::get()), who, index, score)); // then assert_eq!(fetch_from_pool(who), Some((who, Some(score)))); @@ -93,7 +93,7 @@ fn scoring_same_element_with_same_score_works() { let score = 2; // when - assert_ok!(ScoredPool::score(Origin::signed(ScoreOrigin::get()), who, index, score)); + assert_ok!(ScoredPool::score(RuntimeOrigin::signed(ScoreOrigin::get()), who, index, score)); // then assert_eq!(fetch_from_pool(who), Some((who, Some(score)))); @@ -109,7 +109,7 @@ fn kicking_works_only_for_authorized() { new_test_ext().execute_with(|| { let who = 40; let index = find_in_pool(who).expect("entity must be in pool") as u32; - assert_noop!(ScoredPool::kick(Origin::signed(99), who, index), BadOrigin); + assert_noop!(ScoredPool::kick(RuntimeOrigin::signed(99), who, index), BadOrigin); }); } @@ -123,12 +123,12 @@ fn kicking_works() { // when let index = find_in_pool(who).expect("entity must be in pool") as u32; - assert_ok!(ScoredPool::kick(Origin::signed(KickOrigin::get()), who, index)); + assert_ok!(ScoredPool::kick(RuntimeOrigin::signed(KickOrigin::get()), who, index)); // then assert_eq!(find_in_pool(who), None); assert_eq!(ScoredPool::members(), vec![20, 31]); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), ScoredPool::members()); + assert_eq!(MembersTestValue::get().clone(), ScoredPool::members()); assert_eq!(Balances::reserved_balance(who), 0); // deposit must have been returned }); } @@ -138,21 +138,21 @@ fn unscored_entities_must_not_be_used_for_filling_members() { new_test_ext().execute_with(|| { // given // we submit a candidacy, score will be `None` - assert_ok!(ScoredPool::submit_candidacy(Origin::signed(15))); + assert_ok!(ScoredPool::submit_candidacy(RuntimeOrigin::signed(15))); // when // we remove every scored member ScoredPool::pool().into_iter().for_each(|(who, score)| { if let Some(_) = score { let index = find_in_pool(who).expect("entity must be in pool") as u32; - assert_ok!(ScoredPool::kick(Origin::signed(KickOrigin::get()), who, index)); + assert_ok!(ScoredPool::kick(RuntimeOrigin::signed(KickOrigin::get()), who, index)); } }); // then // the `None` candidates should not have been filled in assert!(ScoredPool::members().is_empty()); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), ScoredPool::members()); + assert_eq!(MembersTestValue::get().clone(), ScoredPool::members()); }); } @@ -161,16 +161,16 @@ fn refreshing_works() { new_test_ext().execute_with(|| { // given let who = 15; - assert_ok!(ScoredPool::submit_candidacy(Origin::signed(who))); + assert_ok!(ScoredPool::submit_candidacy(RuntimeOrigin::signed(who))); let index = find_in_pool(who).expect("entity must be in pool") as u32; - assert_ok!(ScoredPool::score(Origin::signed(ScoreOrigin::get()), who, index, 99)); + assert_ok!(ScoredPool::score(RuntimeOrigin::signed(ScoreOrigin::get()), who, index, 99)); // when ScoredPool::refresh_members(ScoredPool::pool(), ChangeReceiver::MembershipChanged); // then assert_eq!(ScoredPool::members(), vec![15, 40]); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), ScoredPool::members()); + assert_eq!(MembersTestValue::get().clone(), ScoredPool::members()); }); } @@ -179,9 +179,9 @@ fn refreshing_happens_every_period() { new_test_ext().execute_with(|| { // given System::set_block_number(1); - assert_ok!(ScoredPool::submit_candidacy(Origin::signed(15))); + assert_ok!(ScoredPool::submit_candidacy(RuntimeOrigin::signed(15))); let index = find_in_pool(15).expect("entity must be in pool") as u32; - assert_ok!(ScoredPool::score(Origin::signed(ScoreOrigin::get()), 15, index, 99)); + assert_ok!(ScoredPool::score(RuntimeOrigin::signed(ScoreOrigin::get()), 15, index, 99)); assert_eq!(ScoredPool::members(), vec![20, 40]); // when @@ -190,7 +190,7 @@ fn refreshing_happens_every_period() { // then assert_eq!(ScoredPool::members(), vec![15, 40]); - assert_eq!(MEMBERS.with(|m| m.borrow().clone()), ScoredPool::members()); + assert_eq!(MembersTestValue::get().clone(), ScoredPool::members()); }); } @@ -200,7 +200,7 @@ fn withdraw_candidacy_must_only_work_for_members() { let who = 77; let index = 0; assert_noop!( - ScoredPool::withdraw_candidacy(Origin::signed(who), index), + ScoredPool::withdraw_candidacy(RuntimeOrigin::signed(who), index), Error::::WrongAccountIndex ); }); @@ -212,15 +212,15 @@ fn oob_index_should_abort() { let who = 40; let oob_index = ScoredPool::pool().len() as u32; assert_noop!( - ScoredPool::withdraw_candidacy(Origin::signed(who), oob_index), + ScoredPool::withdraw_candidacy(RuntimeOrigin::signed(who), oob_index), Error::::InvalidIndex ); assert_noop!( - ScoredPool::score(Origin::signed(ScoreOrigin::get()), who, oob_index, 99), + ScoredPool::score(RuntimeOrigin::signed(ScoreOrigin::get()), who, oob_index, 99), Error::::InvalidIndex ); assert_noop!( - ScoredPool::kick(Origin::signed(KickOrigin::get()), who, oob_index), + ScoredPool::kick(RuntimeOrigin::signed(KickOrigin::get()), who, oob_index), Error::::InvalidIndex ); }); @@ -232,15 +232,15 @@ fn index_mismatches_should_abort() { let who = 40; let index = 3; assert_noop!( - ScoredPool::withdraw_candidacy(Origin::signed(who), index), + ScoredPool::withdraw_candidacy(RuntimeOrigin::signed(who), index), Error::::WrongAccountIndex ); assert_noop!( - ScoredPool::score(Origin::signed(ScoreOrigin::get()), who, index, 99), + ScoredPool::score(RuntimeOrigin::signed(ScoreOrigin::get()), who, index, 99), Error::::WrongAccountIndex ); assert_noop!( - ScoredPool::kick(Origin::signed(KickOrigin::get()), who, index), + ScoredPool::kick(RuntimeOrigin::signed(KickOrigin::get()), who, index), Error::::WrongAccountIndex ); }); @@ -254,7 +254,7 @@ fn withdraw_unscored_candidacy_must_work() { // when let index = find_in_pool(who).expect("entity must be in pool") as u32; - assert_ok!(ScoredPool::withdraw_candidacy(Origin::signed(who), index)); + assert_ok!(ScoredPool::withdraw_candidacy(RuntimeOrigin::signed(who), index)); // then assert_eq!(fetch_from_pool(5), None); @@ -270,7 +270,7 @@ fn withdraw_scored_candidacy_must_work() { // when let index = find_in_pool(who).expect("entity must be in pool") as u32; - assert_ok!(ScoredPool::withdraw_candidacy(Origin::signed(who), index)); + assert_ok!(ScoredPool::withdraw_candidacy(RuntimeOrigin::signed(who), index)); // then assert_eq!(fetch_from_pool(who), None); @@ -286,14 +286,36 @@ fn candidacy_resubmitting_works() { let who = 15; // when - assert_ok!(ScoredPool::submit_candidacy(Origin::signed(who))); + assert_ok!(ScoredPool::submit_candidacy(RuntimeOrigin::signed(who))); assert_eq!(ScoredPool::candidate_exists(who), true); let index = find_in_pool(who).expect("entity must be in pool") as u32; - assert_ok!(ScoredPool::withdraw_candidacy(Origin::signed(who), index)); + assert_ok!(ScoredPool::withdraw_candidacy(RuntimeOrigin::signed(who), index)); assert_eq!(ScoredPool::candidate_exists(who), false); - assert_ok!(ScoredPool::submit_candidacy(Origin::signed(who))); + assert_ok!(ScoredPool::submit_candidacy(RuntimeOrigin::signed(who))); // then assert_eq!(ScoredPool::candidate_exists(who), true); }); } + +#[test] +fn pool_candidates_exceeded() { + new_test_ext().execute_with(|| { + for i in [1, 2, 3, 4, 6] { + let who = i as u64; + assert_ok!(ScoredPool::submit_candidacy(RuntimeOrigin::signed(who))); + let index = find_in_pool(who).expect("entity must be in pool") as u32; + assert_ok!(ScoredPool::score( + RuntimeOrigin::signed(ScoreOrigin::get()), + who, + index, + 99 + )); + } + + assert_noop!( + ScoredPool::submit_candidacy(RuntimeOrigin::signed(8)), + Error::::TooManyMembers + ); + }); +} diff --git a/frame/session/benchmarking/Cargo.toml b/frame/session/benchmarking/Cargo.toml index 930ddb0ce7057..5b2fc0c9e1ebf 100644 --- a/frame/session/benchmarking/Cargo.toml +++ b/frame/session/benchmarking/Cargo.toml @@ -18,7 +18,7 @@ frame-benchmarking = { version = "4.0.0-dev", default-features = false, path = " frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../../session" } -pallet-staking = { version = "4.0.0-dev", default-features = false, features = ["runtime-benchmarks"], path = "../../staking" } +pallet-staking = { version = "4.0.0-dev", default-features = false, path = "../../staking" } sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } sp-session = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/session" } sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } @@ -46,3 +46,7 @@ std = [ "sp-session/std", "sp-std/std", ] + +runtime-benchmarks = [ + "pallet-staking/runtime-benchmarks", +] diff --git a/frame/session/benchmarking/src/lib.rs b/frame/session/benchmarking/src/lib.rs index 265c35cbe4908..9e478ada53cf2 100644 --- a/frame/session/benchmarking/src/lib.rs +++ b/frame/session/benchmarking/src/lib.rs @@ -18,6 +18,7 @@ //! Benchmarks for the Session Pallet. // This is separated into its own crate due to cyclic dependency issues. +#![cfg(feature = "runtime-benchmarks")] #![cfg_attr(not(feature = "std"), no_std)] mod mock; diff --git a/frame/session/benchmarking/src/mock.rs b/frame/session/benchmarking/src/mock.rs index 2181493f72947..f86ddfeedc08b 100644 --- a/frame/session/benchmarking/src/mock.rs +++ b/frame/session/benchmarking/src/mock.rs @@ -52,16 +52,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = AccountIndex; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_core::H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type Version = (); type PalletInfo = PalletInfo; @@ -79,7 +79,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<10>; type AccountStore = System; @@ -125,7 +125,7 @@ impl pallet_session::Config for Test { type ShouldEndSession = pallet_session::PeriodicSessions<(), ()>; type NextSessionRotation = pallet_session::PeriodicSessions<(), ()>; type SessionHandler = TestSessionHandler; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = AccountId; type ValidatorIdOf = pallet_staking::StashOf; type WeightInfo = (); @@ -159,7 +159,7 @@ impl pallet_staking::Config for Test { type UnixTime = pallet_timestamp::Pallet; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type RewardRemainder = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Slash = (); type Reward = (); type SessionsPerEra = (); @@ -174,7 +174,9 @@ impl pallet_staking::Config for Test { type ElectionProvider = onchain::UnboundedExecution; type GenesisElectionProvider = Self::ElectionProvider; type MaxUnlockingChunks = ConstU32<32>; + type HistoryDepth = ConstU32<84>; type VoterList = pallet_staking::UseNominatorsAndValidatorsMap; + type TargetList = pallet_staking::UseValidatorsMap; type OnStakerSlash = (); type BenchmarkingConfig = pallet_staking::TestBenchmarkingConfig; type WeightInfo = (); diff --git a/frame/session/src/historical/mod.rs b/frame/session/src/historical/mod.rs index c72ab8c210d69..45b4ba3c0a799 100644 --- a/frame/session/src/historical/mod.rs +++ b/frame/session/src/historical/mod.rs @@ -375,7 +375,7 @@ impl> KeyOwnerProofSystem<(KeyTypeId, D)> for Pallet sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - let keys: Vec<_> = NEXT_VALIDATORS.with(|l| { - l.borrow().iter().cloned().map(|i| (i, i, UintAuthorityId(i).into())).collect() - }); + let keys: Vec<_> = NextValidators::get() + .iter() + .cloned() + .map(|i| (i, i, UintAuthorityId(i).into())) + .collect(); BasicExternalities::execute_with_storage(&mut t, || { for (ref k, ..) in &keys { frame_system::Pallet::::inc_providers(k); diff --git a/frame/session/src/historical/offchain.rs b/frame/session/src/historical/offchain.rs index 95813d0a70272..ececb8af5ad58 100644 --- a/frame/session/src/historical/offchain.rs +++ b/frame/session/src/historical/offchain.rs @@ -141,7 +141,7 @@ mod tests { use super::*; use crate::{ historical::{onchain, Pallet}, - mock::{force_new_session, set_next_validators, Session, System, Test, NEXT_VALIDATORS}, + mock::{force_new_session, set_next_validators, NextValidators, Session, System, Test}, }; use codec::Encode; @@ -163,9 +163,12 @@ mod tests { .build_storage::() .expect("Failed to create test externalities."); - let keys: Vec<_> = NEXT_VALIDATORS.with(|l| { - l.borrow().iter().cloned().map(|i| (i, i, UintAuthorityId(i).into())).collect() - }); + let keys: Vec<_> = NextValidators::get() + .iter() + .cloned() + .map(|i| (i, i, UintAuthorityId(i).into())) + .collect(); + BasicExternalities::execute_with_storage(&mut t, || { for (ref k, ..) in &keys { frame_system::Pallet::::inc_providers(k); diff --git a/frame/session/src/lib.rs b/frame/session/src/lib.rs index 34c560984661d..7b97a20860175 100644 --- a/frame/session/src/lib.rs +++ b/frame/session/src/lib.rs @@ -379,7 +379,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From + IsType<::Event>; + type RuntimeEvent: From + IsType<::RuntimeEvent>; /// A stable ID for a validator. type ValidatorId: Member diff --git a/frame/session/src/mock.rs b/frame/session/src/mock.rs index 3044d6558e33e..aa13eacba9564 100644 --- a/frame/session/src/mock.rs +++ b/frame/session/src/mock.rs @@ -22,7 +22,7 @@ use crate as pallet_session; #[cfg(feature = "historical")] use crate::historical as pallet_session_historical; -use std::{cell::RefCell, collections::BTreeMap}; +use std::collections::BTreeMap; use sp_core::{crypto::key_types::DUMMY, H256}; use sp_runtime::{ @@ -103,29 +103,29 @@ frame_support::construct_runtime!( } ); -thread_local! { - pub static VALIDATORS: RefCell> = RefCell::new(vec![1, 2, 3]); - pub static NEXT_VALIDATORS: RefCell> = RefCell::new(vec![1, 2, 3]); - pub static AUTHORITIES: RefCell> = - RefCell::new(vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); - pub static FORCE_SESSION_END: RefCell = RefCell::new(false); - pub static SESSION_LENGTH: RefCell = RefCell::new(2); - pub static SESSION_CHANGED: RefCell = RefCell::new(false); - pub static TEST_SESSION_CHANGED: RefCell = RefCell::new(false); - pub static DISABLED: RefCell = RefCell::new(false); +parameter_types! { + pub static Validators: Vec = vec![1, 2, 3]; + pub static NextValidators: Vec = vec![1, 2, 3]; + pub static Authorities: Vec = + vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]; + pub static ForceSessionEnd: bool = false; + pub static SessionLength: u64 = 2; + pub static SessionChanged: bool = false; + pub static TestSessionChanged: bool = false; + pub static Disabled: bool = false; // Stores if `on_before_session_end` was called - pub static BEFORE_SESSION_END_CALLED: RefCell = RefCell::new(false); - pub static VALIDATOR_ACCOUNTS: RefCell> = RefCell::new(BTreeMap::new()); + pub static BeforeSessionEndCalled: bool = false; + pub static ValidatorAccounts: BTreeMap = BTreeMap::new(); } pub struct TestShouldEndSession; impl ShouldEndSession for TestShouldEndSession { fn should_end_session(now: u64) -> bool { - let l = SESSION_LENGTH.with(|l| *l.borrow()); + let l = SessionLength::get(); now % l == 0 || - FORCE_SESSION_END.with(|l| { - let r = *l.borrow(); - *l.borrow_mut() = false; + ForceSessionEnd::mutate(|l| { + let r = *l; + *l = false; r }) } @@ -140,19 +140,19 @@ impl SessionHandler for TestSessionHandler { validators: &[(u64, T)], _queued_validators: &[(u64, T)], ) { - SESSION_CHANGED.with(|l| *l.borrow_mut() = changed); - AUTHORITIES.with(|l| { - *l.borrow_mut() = validators + SessionChanged::mutate(|l| *l = changed); + Authorities::mutate(|l| { + *l = validators .iter() .map(|(_, id)| id.get::(DUMMY).unwrap_or_default()) .collect() }); } fn on_disabled(_validator_index: u32) { - DISABLED.with(|l| *l.borrow_mut() = true) + Disabled::mutate(|l| *l = true) } fn on_before_session_ending() { - BEFORE_SESSION_END_CALLED.with(|b| *b.borrow_mut() = true); + BeforeSessionEndCalled::mutate(|b| *b = true); } } @@ -161,16 +161,15 @@ impl SessionManager for TestSessionManager { fn end_session(_: SessionIndex) {} fn start_session(_: SessionIndex) {} fn new_session(_: SessionIndex) -> Option> { - if !TEST_SESSION_CHANGED.with(|l| *l.borrow()) { - VALIDATORS.with(|v| { - let mut v = v.borrow_mut(); - *v = NEXT_VALIDATORS.with(|l| l.borrow().clone()); + if !TestSessionChanged::get() { + Validators::mutate(|v| { + *v = NextValidators::get().clone(); Some(v.clone()) }) - } else if DISABLED.with(|l| std::mem::replace(&mut *l.borrow_mut(), false)) { + } else if Disabled::mutate(|l| std::mem::replace(&mut *l, false)) { // If there was a disabled validator, underlying conditions have changed // so we return `Some`. - Some(VALIDATORS.with(|v| v.borrow().clone())) + Some(Validators::get().clone()) } else { None } @@ -188,37 +187,40 @@ impl crate::historical::SessionManager for TestSessionManager { } pub fn authorities() -> Vec { - AUTHORITIES.with(|l| l.borrow().to_vec()) + Authorities::get().to_vec() } pub fn force_new_session() { - FORCE_SESSION_END.with(|l| *l.borrow_mut() = true) + ForceSessionEnd::mutate(|l| *l = true) } pub fn set_session_length(x: u64) { - SESSION_LENGTH.with(|l| *l.borrow_mut() = x) + SessionLength::mutate(|l| *l = x) } pub fn session_changed() -> bool { - SESSION_CHANGED.with(|l| *l.borrow()) + SessionChanged::get() } pub fn set_next_validators(next: Vec) { - NEXT_VALIDATORS.with(|v| *v.borrow_mut() = next); + NextValidators::mutate(|v| *v = next); } pub fn before_session_end_called() -> bool { - BEFORE_SESSION_END_CALLED.with(|b| *b.borrow()) + BeforeSessionEndCalled::get() } pub fn reset_before_session_end_called() { - BEFORE_SESSION_END_CALLED.with(|b| *b.borrow_mut() = false); + BeforeSessionEndCalled::mutate(|b| *b = false); } pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - let keys: Vec<_> = NEXT_VALIDATORS - .with(|l| l.borrow().iter().cloned().map(|i| (i, i, UintAuthorityId(i).into())).collect()); + let keys: Vec<_> = NextValidators::get() + .iter() + .cloned() + .map(|i| (i, i, UintAuthorityId(i).into())) + .collect(); BasicExternalities::execute_with_storage(&mut t, || { for (ref k, ..) in &keys { frame_system::Pallet::::inc_providers(k); @@ -230,10 +232,9 @@ pub fn new_test_ext() -> sp_io::TestExternalities { pallet_session::GenesisConfig:: { keys } .assimilate_storage(&mut t) .unwrap(); - NEXT_VALIDATORS.with(|l| { - let v = l.borrow().iter().map(|&i| (i, i)).collect(); - VALIDATOR_ACCOUNTS.with(|m| *m.borrow_mut() = v); - }); + + let v = NextValidators::get().iter().map(|&i| (i, i)).collect(); + ValidatorAccounts::mutate(|m| *m = v); sp_io::TestExternalities::new(t) } @@ -247,16 +248,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -279,12 +280,12 @@ impl pallet_timestamp::Config for Test { pub struct TestValidatorIdOf; impl TestValidatorIdOf { pub fn set(v: BTreeMap) { - VALIDATOR_ACCOUNTS.with(|m| *m.borrow_mut() = v); + ValidatorAccounts::mutate(|m| *m = v); } } impl Convert> for TestValidatorIdOf { fn convert(x: u64) -> Option { - VALIDATOR_ACCOUNTS.with(|m| m.borrow().get(&x).cloned()) + ValidatorAccounts::get().get(&x).cloned() } } @@ -298,7 +299,7 @@ impl Config for Test { type ValidatorId = u64; type ValidatorIdOf = TestValidatorIdOf; type Keys = MockSessionKeys; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type NextSessionRotation = (); type WeightInfo = (); } diff --git a/frame/session/src/tests.rs b/frame/session/src/tests.rs index c9d2dbb53d9ba..43809cc3a9de0 100644 --- a/frame/session/src/tests.rs +++ b/frame/session/src/tests.rs @@ -21,8 +21,8 @@ use super::*; use crate::mock::{ authorities, before_session_end_called, force_new_session, new_test_ext, reset_before_session_end_called, session_changed, set_next_validators, set_session_length, - Origin, PreUpgradeMockSessionKeys, Session, System, Test, TestValidatorIdOf, SESSION_CHANGED, - TEST_SESSION_CHANGED, + PreUpgradeMockSessionKeys, RuntimeOrigin, Session, SessionChanged, System, Test, + TestSessionChanged, TestValidatorIdOf, }; use codec::Decode; @@ -35,7 +35,7 @@ use frame_support::{ }; fn initialize_block(block: u64) { - SESSION_CHANGED.with(|l| *l.borrow_mut() = false); + SessionChanged::mutate(|l| *l = false); System::set_block_number(block); Session::on_initialize(block); } @@ -67,7 +67,7 @@ fn keys_cleared_on_kill() { assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), Some(1)); assert!(System::is_provider_required(&1)); - assert_ok!(Session::purge_keys(Origin::signed(1))); + assert_ok!(Session::purge_keys(RuntimeOrigin::signed(1))); assert!(!System::is_provider_required(&1)); assert_eq!(Session::load_keys(&1), None); @@ -87,8 +87,8 @@ fn purge_keys_works_for_stash_id() { let id = DUMMY; assert_eq!(Session::key_owner(id, UintAuthorityId(1).get_raw(id)), Some(1)); - assert_ok!(Session::purge_keys(Origin::signed(10))); - assert_ok!(Session::purge_keys(Origin::signed(2))); + assert_ok!(Session::purge_keys(RuntimeOrigin::signed(10))); + assert_ok!(Session::purge_keys(RuntimeOrigin::signed(2))); assert_eq!(Session::load_keys(&10), None); assert_eq!(Session::load_keys(&20), None); @@ -128,7 +128,7 @@ fn authorities_should_track_validators() { reset_before_session_end_called(); set_next_validators(vec![1, 2, 4]); - assert_ok!(Session::set_keys(Origin::signed(4), UintAuthorityId(4).into(), vec![])); + assert_ok!(Session::set_keys(RuntimeOrigin::signed(4), UintAuthorityId(4).into(), vec![])); force_new_session(); initialize_block(3); assert_eq!( @@ -194,7 +194,7 @@ fn session_change_should_work() { // Block 3: Set new key for validator 2; no visible change. initialize_block(3); - assert_ok!(Session::set_keys(Origin::signed(2), UintAuthorityId(5).into(), vec![])); + assert_ok!(Session::set_keys(RuntimeOrigin::signed(2), UintAuthorityId(5).into(), vec![])); assert_eq!(authorities(), vec![UintAuthorityId(1), UintAuthorityId(2), UintAuthorityId(3)]); // Block 4: Session rollover; no visible change. @@ -219,13 +219,13 @@ fn duplicates_are_not_allowed() { System::set_block_number(1); Session::on_initialize(1); assert_noop!( - Session::set_keys(Origin::signed(4), UintAuthorityId(1).into(), vec![]), + Session::set_keys(RuntimeOrigin::signed(4), UintAuthorityId(1).into(), vec![]), Error::::DuplicatedKey, ); - assert_ok!(Session::set_keys(Origin::signed(1), UintAuthorityId(10).into(), vec![])); + assert_ok!(Session::set_keys(RuntimeOrigin::signed(1), UintAuthorityId(10).into(), vec![])); // is fine now that 1 has migrated off. - assert_ok!(Session::set_keys(Origin::signed(4), UintAuthorityId(1).into(), vec![])); + assert_ok!(Session::set_keys(RuntimeOrigin::signed(4), UintAuthorityId(1).into(), vec![])); }); } @@ -235,7 +235,7 @@ fn session_changed_flag_works() { new_test_ext().execute_with(|| { TestValidatorIdOf::set(vec![(1, 1), (2, 2), (3, 3), (69, 69)].into_iter().collect()); - TEST_SESSION_CHANGED.with(|l| *l.borrow_mut() = true); + TestSessionChanged::mutate(|l| *l = true); force_new_session(); initialize_block(1); @@ -268,7 +268,7 @@ fn session_changed_flag_works() { assert!(before_session_end_called()); reset_before_session_end_called(); - assert_ok!(Session::set_keys(Origin::signed(2), UintAuthorityId(5).into(), vec![])); + assert_ok!(Session::set_keys(RuntimeOrigin::signed(2), UintAuthorityId(5).into(), vec![])); force_new_session(); initialize_block(6); assert!(!session_changed()); @@ -276,7 +276,11 @@ fn session_changed_flag_works() { reset_before_session_end_called(); // changing the keys of a validator leads to change. - assert_ok!(Session::set_keys(Origin::signed(69), UintAuthorityId(69).into(), vec![])); + assert_ok!(Session::set_keys( + RuntimeOrigin::signed(69), + UintAuthorityId(69).into(), + vec![] + )); force_new_session(); initialize_block(7); assert!(session_changed()); @@ -355,7 +359,7 @@ fn session_keys_generate_output_works_as_set_keys_input() { new_test_ext().execute_with(|| { let new_keys = mock::MockSessionKeys::generate(None); assert_ok!(Session::set_keys( - Origin::signed(2), + RuntimeOrigin::signed(2), ::Keys::decode(&mut &new_keys[..]).expect("Decode keys"), vec![], )); @@ -384,8 +388,8 @@ fn upgrade_keys() { use sp_core::crypto::key_types::DUMMY; // This test assumes certain mocks. - assert_eq!(mock::NEXT_VALIDATORS.with(|l| l.borrow().clone()), vec![1, 2, 3]); - assert_eq!(mock::VALIDATORS.with(|l| l.borrow().clone()), vec![1, 2, 3]); + assert_eq!(mock::NextValidators::get().clone(), vec![1, 2, 3]); + assert_eq!(mock::Validators::get().clone(), vec![1, 2, 3]); new_test_ext().execute_with(|| { let pre_one = PreUpgradeMockSessionKeys { a: [1u8; 32], b: [1u8; 64] }; diff --git a/frame/society/src/lib.rs b/frame/society/src/lib.rs index 9717486644761..73a09490ea579 100644 --- a/frame/society/src/lib.rs +++ b/frame/society/src/lib.rs @@ -378,7 +378,8 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// The societies's pallet id #[pallet::constant] @@ -420,10 +421,10 @@ pub mod pallet { type MaxLockDuration: Get; /// The origin that is allowed to call `found`. - type FounderSetOrigin: EnsureOrigin; + type FounderSetOrigin: EnsureOrigin; /// The origin that is allowed to make suspension judgements. - type SuspensionJudgementOrigin: EnsureOrigin; + type SuspensionJudgementOrigin: EnsureOrigin; /// The number of blocks between membership challenges. #[pallet::constant] @@ -1267,19 +1268,19 @@ pub mod pallet { /// Simple ensure origin struct to filter for the founder account. pub struct EnsureFounder(sp_std::marker::PhantomData); -impl EnsureOrigin for EnsureFounder { +impl EnsureOrigin for EnsureFounder { type Success = T::AccountId; - fn try_origin(o: T::Origin) -> Result { + fn try_origin(o: T::RuntimeOrigin) -> Result { o.into().and_then(|o| match (o, Founder::::get()) { (frame_system::RawOrigin::Signed(ref who), Some(ref f)) if who == f => Ok(who.clone()), - (r, _) => Err(T::Origin::from(r)), + (r, _) => Err(T::RuntimeOrigin::from(r)), }) } #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { + fn try_successful_origin() -> Result { let founder = Founder::::get().ok_or(())?; - Ok(T::Origin::from(frame_system::RawOrigin::Signed(founder))) + Ok(T::RuntimeOrigin::from(frame_system::RawOrigin::Signed(founder))) } } diff --git a/frame/society/src/mock.rs b/frame/society/src/mock.rs index ed668e79269fd..0b1b93aeae761 100644 --- a/frame/society/src/mock.rs +++ b/frame/society/src/mock.rs @@ -63,16 +63,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u128; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -90,7 +90,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -98,7 +98,7 @@ impl pallet_balances::Config for Test { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = pallet_balances::Pallet; type Randomness = TestRandomness; type CandidateDeposit = ConstU64<25>; diff --git a/frame/society/src/tests.rs b/frame/society/src/tests.rs index d394ddc9011b0..864735aa10cca 100644 --- a/frame/society/src/tests.rs +++ b/frame/society/src/tests.rs @@ -33,9 +33,9 @@ fn founding_works() { assert_eq!(Society::pot(), 0); // Account 1 is set as the founder origin // Account 5 cannot start a society - assert_noop!(Society::found(Origin::signed(5), 20, 100, vec![]), BadOrigin); + assert_noop!(Society::found(RuntimeOrigin::signed(5), 20, 100, vec![]), BadOrigin); // Account 1 can start a society, where 10 is the founding member - assert_ok!(Society::found(Origin::signed(1), 10, 100, b"be cool".to_vec())); + assert_ok!(Society::found(RuntimeOrigin::signed(1), 10, 100, b"be cool".to_vec())); // Society members only include 10 assert_eq!(Society::members(), vec![10]); // 10 is the head of the society @@ -51,7 +51,7 @@ fn founding_works() { assert_eq!(Society::pot(), 1000); // Cannot start another society assert_noop!( - Society::found(Origin::signed(1), 20, 100, vec![]), + Society::found(RuntimeOrigin::signed(1), 20, 100, vec![]), Error::::AlreadyFounded ); }); @@ -61,22 +61,22 @@ fn founding_works() { fn unfounding_works() { EnvBuilder::new().with_max_members(0).with_members(vec![]).execute(|| { // Account 1 sets the founder... - assert_ok!(Society::found(Origin::signed(1), 10, 100, vec![])); + assert_ok!(Society::found(RuntimeOrigin::signed(1), 10, 100, vec![])); // Account 2 cannot unfound it as it's not the founder. - assert_noop!(Society::unfound(Origin::signed(2)), Error::::NotFounder); + assert_noop!(Society::unfound(RuntimeOrigin::signed(2)), Error::::NotFounder); // Account 10 can, though. - assert_ok!(Society::unfound(Origin::signed(10))); + assert_ok!(Society::unfound(RuntimeOrigin::signed(10))); // 1 sets the founder to 20 this time - assert_ok!(Society::found(Origin::signed(1), 20, 100, vec![])); + assert_ok!(Society::found(RuntimeOrigin::signed(1), 20, 100, vec![])); // Bring in a new member... - assert_ok!(Society::bid(Origin::signed(10), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(10), 0)); run_to_block(4); - assert_ok!(Society::vote(Origin::signed(20), 10, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(20), 10, true)); run_to_block(8); // Unfounding won't work now, even though it's from 20. - assert_noop!(Society::unfound(Origin::signed(20)), Error::::NotHead); + assert_noop!(Society::unfound(RuntimeOrigin::signed(20)), Error::::NotHead); }); } @@ -85,7 +85,7 @@ fn basic_new_member_works() { EnvBuilder::new().execute(|| { assert_eq!(Balances::free_balance(20), 50); // Bid causes Candidate Deposit to be reserved. - assert_ok!(Society::bid(Origin::signed(20), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 0)); assert_eq!(Balances::free_balance(20), 25); assert_eq!(Balances::reserved_balance(20), 25); // Rotate period every 4 blocks @@ -93,7 +93,7 @@ fn basic_new_member_works() { // 20 is now a candidate assert_eq!(Society::candidates(), vec![create_bid(0, 20, BidKind::Deposit(25))]); // 10 (a member) can vote for the candidate - assert_ok!(Society::vote(Origin::signed(10), 20, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 20, true)); // Rotate period every 4 blocks run_to_block(8); // 20 is now a member of the society @@ -108,10 +108,10 @@ fn basic_new_member_works() { fn bidding_works() { EnvBuilder::new().execute(|| { // Users make bids of various amounts - assert_ok!(Society::bid(Origin::signed(60), 1900)); - assert_ok!(Society::bid(Origin::signed(50), 500)); - assert_ok!(Society::bid(Origin::signed(40), 400)); - assert_ok!(Society::bid(Origin::signed(30), 300)); + assert_ok!(Society::bid(RuntimeOrigin::signed(60), 1900)); + assert_ok!(Society::bid(RuntimeOrigin::signed(50), 500)); + assert_ok!(Society::bid(RuntimeOrigin::signed(40), 400)); + assert_ok!(Society::bid(RuntimeOrigin::signed(30), 300)); // Rotate period run_to_block(4); // Pot is 1000 after "PeriodSpend" @@ -126,8 +126,8 @@ fn bidding_works() { ] ); // A member votes for these candidates to join the society - assert_ok!(Society::vote(Origin::signed(10), 30, true)); - assert_ok!(Society::vote(Origin::signed(10), 40, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 30, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 40, true)); run_to_block(8); // Candidates become members after a period rotation assert_eq!(Society::members(), vec![10, 30, 40]); @@ -137,7 +137,7 @@ fn bidding_works() { // Left over from the original bids is 50 who satisfies the condition of bid less than pot. assert_eq!(Society::candidates(), vec![create_bid(500, 50, BidKind::Deposit(25))]); // 40, now a member, can vote for 50 - assert_ok!(Society::vote(Origin::signed(40), 50, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(40), 50, true)); run_to_block(12); // 50 is now a member assert_eq!(Society::members(), vec![10, 30, 40, 50]); @@ -146,8 +146,8 @@ fn bidding_works() { assert_eq!(Balances::free_balance(Society::account_id()), 8_800); // No more candidates satisfy the requirements assert_eq!(Society::candidates(), vec![]); - assert_ok!(Society::defender_vote(Origin::signed(10), true)); // Keep defender around - // Next period + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(10), true)); // Keep defender around + // Next period run_to_block(16); // Same members assert_eq!(Society::members(), vec![10, 30, 40, 50]); @@ -158,7 +158,7 @@ fn bidding_works() { // Candidate 60 now qualifies based on the increased pot size. assert_eq!(Society::candidates(), vec![create_bid(1900, 60, BidKind::Deposit(25))]); // Candidate 60 is voted in. - assert_ok!(Society::vote(Origin::signed(50), 60, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(50), 60, true)); run_to_block(20); // 60 joins as a member assert_eq!(Society::members(), vec![10, 30, 40, 50, 60]); @@ -172,15 +172,15 @@ fn bidding_works() { fn unbidding_works() { EnvBuilder::new().execute(|| { // 20 and 30 make bids - assert_ok!(Society::bid(Origin::signed(20), 1000)); - assert_ok!(Society::bid(Origin::signed(30), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 1000)); + assert_ok!(Society::bid(RuntimeOrigin::signed(30), 0)); // Balances are reserved assert_eq!(Balances::free_balance(30), 25); assert_eq!(Balances::reserved_balance(30), 25); // Must know right position to unbid + cannot unbid someone else - assert_noop!(Society::unbid(Origin::signed(30), 1), Error::::BadPosition); + assert_noop!(Society::unbid(RuntimeOrigin::signed(30), 1), Error::::BadPosition); // Can unbid themselves with the right position - assert_ok!(Society::unbid(Origin::signed(30), 0)); + assert_ok!(Society::unbid(RuntimeOrigin::signed(30), 0)); // Balance is returned assert_eq!(Balances::free_balance(30), 50); assert_eq!(Balances::reserved_balance(30), 0); @@ -195,15 +195,15 @@ fn payout_works() { EnvBuilder::new().execute(|| { // Original balance of 50 assert_eq!(Balances::free_balance(20), 50); - assert_ok!(Society::bid(Origin::signed(20), 1000)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 1000)); run_to_block(4); - assert_ok!(Society::vote(Origin::signed(10), 20, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 20, true)); run_to_block(8); // payout not ready - assert_noop!(Society::payout(Origin::signed(20)), Error::::NoPayout); + assert_noop!(Society::payout(RuntimeOrigin::signed(20)), Error::::NoPayout); run_to_block(9); // payout should be here - assert_ok!(Society::payout(Origin::signed(20))); + assert_ok!(Society::payout(RuntimeOrigin::signed(20))); assert_eq!(Balances::free_balance(20), 1050); }); } @@ -212,7 +212,7 @@ fn payout_works() { fn basic_new_member_skeptic_works() { EnvBuilder::new().execute(|| { assert_eq!(Strikes::::get(10), 0); - assert_ok!(Society::bid(Origin::signed(20), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 0)); run_to_block(4); assert_eq!(Society::candidates(), vec![create_bid(0, 20, BidKind::Deposit(25))]); run_to_block(8); @@ -227,14 +227,14 @@ fn basic_new_member_reject_works() { // Starting Balance assert_eq!(Balances::free_balance(20), 50); // 20 makes a bid - assert_ok!(Society::bid(Origin::signed(20), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 0)); assert_eq!(Balances::free_balance(20), 25); assert_eq!(Balances::reserved_balance(20), 25); // Rotation Period run_to_block(4); assert_eq!(Society::candidates(), vec![create_bid(0, 20, BidKind::Deposit(25))]); // We say no - assert_ok!(Society::vote(Origin::signed(10), 20, false)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 20, false)); run_to_block(8); // User is not added as member assert_eq!(Society::members(), vec![10]); @@ -248,19 +248,19 @@ fn basic_new_member_reject_works() { fn slash_payout_works() { EnvBuilder::new().execute(|| { assert_eq!(Balances::free_balance(20), 50); - assert_ok!(Society::bid(Origin::signed(20), 1000)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 1000)); run_to_block(4); - assert_ok!(Society::vote(Origin::signed(10), 20, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 20, true)); run_to_block(8); // payout in queue assert_eq!(Payouts::::get(20), vec![(9, 1000)]); - assert_noop!(Society::payout(Origin::signed(20)), Error::::NoPayout); + assert_noop!(Society::payout(RuntimeOrigin::signed(20)), Error::::NoPayout); // slash payout assert_eq!(Society::slash_payout(&20, 500), 500); assert_eq!(Payouts::::get(20), vec![(9, 500)]); run_to_block(9); // payout should be here, but 500 less - assert_ok!(Society::payout(Origin::signed(20))); + assert_ok!(Society::payout(RuntimeOrigin::signed(20))); assert_eq!(Balances::free_balance(20), 550); }); } @@ -295,10 +295,10 @@ fn suspended_member_life_cycle_works() { assert_eq!(>::get(20), false); // Let's suspend account 20 by giving them 2 strikes by not voting - assert_ok!(Society::bid(Origin::signed(30), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(30), 0)); run_to_block(8); assert_eq!(Strikes::::get(20), 1); - assert_ok!(Society::bid(Origin::signed(40), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(40), 0)); run_to_block(16); // Strike 2 is accumulated, and 20 is suspended :( @@ -307,14 +307,17 @@ fn suspended_member_life_cycle_works() { // Suspended members cannot get payout Society::bump_payout(&20, 10, 100); - assert_noop!(Society::payout(Origin::signed(20)), Error::::NotMember); + assert_noop!(Society::payout(RuntimeOrigin::signed(20)), Error::::NotMember); // Normal people cannot make judgement - assert_noop!(Society::judge_suspended_member(Origin::signed(20), 20, true), BadOrigin); + assert_noop!( + Society::judge_suspended_member(RuntimeOrigin::signed(20), 20, true), + BadOrigin + ); // Suspension judgment origin can judge thee // Suspension judgement origin forgives the suspended member - assert_ok!(Society::judge_suspended_member(Origin::signed(2), 20, true)); + assert_ok!(Society::judge_suspended_member(RuntimeOrigin::signed(2), 20, true)); assert_eq!(>::get(20), false); assert_eq!(>::get(), vec![10, 20]); @@ -322,7 +325,7 @@ fn suspended_member_life_cycle_works() { Society::suspend_member(&20); assert_eq!(>::get(20), true); // Suspension judgement origin does not forgive the suspended member - assert_ok!(Society::judge_suspended_member(Origin::signed(2), 20, false)); + assert_ok!(Society::judge_suspended_member(RuntimeOrigin::signed(2), 20, false)); // Cleaned up assert_eq!(>::get(20), false); assert_eq!(>::get(), vec![10]); @@ -337,14 +340,14 @@ fn suspended_candidate_rejected_works() { assert_eq!(Balances::free_balance(20), 50); assert_eq!(Balances::free_balance(Society::account_id()), 10000); // 20 makes a bid - assert_ok!(Society::bid(Origin::signed(20), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 0)); assert_eq!(Balances::free_balance(20), 25); assert_eq!(Balances::reserved_balance(20), 25); // Rotation Period run_to_block(4); assert_eq!(Society::candidates(), vec![create_bid(0, 20, BidKind::Deposit(25))]); // We say no - assert_ok!(Society::vote(Origin::signed(10), 20, false)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 20, false)); run_to_block(8); // User is not added as member assert_eq!(Society::members(), vec![10]); @@ -354,18 +357,22 @@ fn suspended_candidate_rejected_works() { // Normal user cannot make judgement on suspended candidate assert_noop!( - Society::judge_suspended_candidate(Origin::signed(20), 20, Judgement::Approve), + Society::judge_suspended_candidate(RuntimeOrigin::signed(20), 20, Judgement::Approve), BadOrigin ); // Suspension judgement origin makes no direct judgement - assert_ok!(Society::judge_suspended_candidate(Origin::signed(2), 20, Judgement::Rebid)); + assert_ok!(Society::judge_suspended_candidate( + RuntimeOrigin::signed(2), + 20, + Judgement::Rebid + )); // They are placed back in bid pool, repeat suspension process // Rotation Period run_to_block(12); assert_eq!(Society::candidates(), vec![create_bid(0, 20, BidKind::Deposit(25))]); // We say no - assert_ok!(Society::vote(Origin::signed(10), 20, false)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 20, false)); run_to_block(16); // User is not added as member assert_eq!(Society::members(), vec![10]); @@ -374,7 +381,11 @@ fn suspended_candidate_rejected_works() { assert_eq!(Society::suspended_candidate(20).is_some(), true); // Suspension judgement origin rejects the candidate - assert_ok!(Society::judge_suspended_candidate(Origin::signed(2), 20, Judgement::Reject)); + assert_ok!(Society::judge_suspended_candidate( + RuntimeOrigin::signed(2), + 20, + Judgement::Reject + )); // User is slashed assert_eq!(Balances::free_balance(20), 25); assert_eq!(Balances::reserved_balance(20), 0); @@ -392,13 +403,16 @@ fn vouch_works() { // 10 is the only member assert_eq!(Society::members(), vec![10]); // A non-member cannot vouch - assert_noop!(Society::vouch(Origin::signed(1), 20, 1000, 100), Error::::NotMember); + assert_noop!( + Society::vouch(RuntimeOrigin::signed(1), 20, 1000, 100), + Error::::NotMember + ); // A member can though - assert_ok!(Society::vouch(Origin::signed(10), 20, 1000, 100)); + assert_ok!(Society::vouch(RuntimeOrigin::signed(10), 20, 1000, 100)); assert_eq!(>::get(10), Some(VouchingStatus::Vouching)); // A member cannot vouch twice at the same time assert_noop!( - Society::vouch(Origin::signed(10), 30, 100, 0), + Society::vouch(RuntimeOrigin::signed(10), 30, 100, 0), Error::::AlreadyVouching ); // Vouching creates the right kind of bid @@ -407,7 +421,7 @@ fn vouch_works() { run_to_block(4); assert_eq!(Society::candidates(), vec![create_bid(1000, 20, BidKind::Vouch(10, 100))]); // Vote yes - assert_ok!(Society::vote(Origin::signed(10), 20, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 20, true)); // Vouched user can win run_to_block(8); assert_eq!(Society::members(), vec![10, 20]); @@ -426,14 +440,14 @@ fn voucher_cannot_win_more_than_bid() { // 10 is the only member assert_eq!(Society::members(), vec![10]); // 10 vouches, but asks for more than the bid - assert_ok!(Society::vouch(Origin::signed(10), 20, 100, 1000)); + assert_ok!(Society::vouch(RuntimeOrigin::signed(10), 20, 100, 1000)); // Vouching creates the right kind of bid assert_eq!(>::get(), vec![create_bid(100, 20, BidKind::Vouch(10, 1000))]); // Vouched user can become candidate run_to_block(4); assert_eq!(Society::candidates(), vec![create_bid(100, 20, BidKind::Vouch(10, 1000))]); // Vote yes - assert_ok!(Society::vote(Origin::signed(10), 20, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 20, true)); // Vouched user can win run_to_block(8); assert_eq!(Society::members(), vec![10, 20]); @@ -450,25 +464,25 @@ fn unvouch_works() { // 10 is the only member assert_eq!(Society::members(), vec![10]); // 10 vouches for 20 - assert_ok!(Society::vouch(Origin::signed(10), 20, 100, 0)); + assert_ok!(Society::vouch(RuntimeOrigin::signed(10), 20, 100, 0)); // 20 has a bid assert_eq!(>::get(), vec![create_bid(100, 20, BidKind::Vouch(10, 0))]); // 10 is vouched assert_eq!(>::get(10), Some(VouchingStatus::Vouching)); // To unvouch, you must know the right bid position - assert_noop!(Society::unvouch(Origin::signed(10), 2), Error::::BadPosition); + assert_noop!(Society::unvouch(RuntimeOrigin::signed(10), 2), Error::::BadPosition); // 10 can unvouch with the right position - assert_ok!(Society::unvouch(Origin::signed(10), 0)); + assert_ok!(Society::unvouch(RuntimeOrigin::signed(10), 0)); // 20 no longer has a bid assert_eq!(>::get(), vec![]); // 10 is no longer vouching assert_eq!(>::get(10), None); // Cannot unvouch after they become candidate - assert_ok!(Society::vouch(Origin::signed(10), 20, 100, 0)); + assert_ok!(Society::vouch(RuntimeOrigin::signed(10), 20, 100, 0)); run_to_block(4); assert_eq!(Society::candidates(), vec![create_bid(100, 20, BidKind::Vouch(10, 0))]); - assert_noop!(Society::unvouch(Origin::signed(10), 0), Error::::BadPosition); + assert_noop!(Society::unvouch(RuntimeOrigin::signed(10), 0), Error::::BadPosition); // 10 is still vouching until candidate is approved or rejected assert_eq!(>::get(10), Some(VouchingStatus::Vouching)); run_to_block(8); @@ -478,18 +492,22 @@ fn unvouch_works() { // User is stuck vouching until judgement origin resolves suspended candidate assert_eq!(>::get(10), Some(VouchingStatus::Vouching)); // Judge denies candidate - assert_ok!(Society::judge_suspended_candidate(Origin::signed(2), 20, Judgement::Reject)); + assert_ok!(Society::judge_suspended_candidate( + RuntimeOrigin::signed(2), + 20, + Judgement::Reject + )); // 10 is banned from vouching assert_eq!(>::get(10), Some(VouchingStatus::Banned)); assert_eq!(Society::members(), vec![10]); // 10 cannot vouch again assert_noop!( - Society::vouch(Origin::signed(10), 30, 100, 0), + Society::vouch(RuntimeOrigin::signed(10), 30, 100, 0), Error::::AlreadyVouching ); // 10 cannot unvouch either, so they are banned forever. - assert_noop!(Society::unvouch(Origin::signed(10), 0), Error::::NotVouching); + assert_noop!(Society::unvouch(RuntimeOrigin::signed(10), 0), Error::::NotVouching); }); } @@ -499,13 +517,13 @@ fn unbid_vouch_works() { // 10 is the only member assert_eq!(Society::members(), vec![10]); // 10 vouches for 20 - assert_ok!(Society::vouch(Origin::signed(10), 20, 100, 0)); + assert_ok!(Society::vouch(RuntimeOrigin::signed(10), 20, 100, 0)); // 20 has a bid assert_eq!(>::get(), vec![create_bid(100, 20, BidKind::Vouch(10, 0))]); // 10 is vouched assert_eq!(>::get(10), Some(VouchingStatus::Vouching)); // 20 doesn't want to be a member and can unbid themselves. - assert_ok!(Society::unbid(Origin::signed(20), 0)); + assert_ok!(Society::unbid(RuntimeOrigin::signed(20), 0)); // Everything is cleaned up assert_eq!(>::get(10), None); assert_eq!(>::get(), vec![]); @@ -520,22 +538,22 @@ fn founder_and_head_cannot_be_removed() { assert_eq!(Society::founder(), Some(10)); assert_eq!(Society::head(), Some(10)); // 10 can still accumulate strikes - assert_ok!(Society::bid(Origin::signed(20), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 0)); run_to_block(8); assert_eq!(Strikes::::get(10), 1); - assert_ok!(Society::bid(Origin::signed(30), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(30), 0)); run_to_block(16); assert_eq!(Strikes::::get(10), 2); // Awkwardly they can obtain more than MAX_STRIKES... - assert_ok!(Society::bid(Origin::signed(40), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(40), 0)); run_to_block(24); assert_eq!(Strikes::::get(10), 3); // Replace the head - assert_ok!(Society::bid(Origin::signed(50), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(50), 0)); run_to_block(28); - assert_ok!(Society::vote(Origin::signed(10), 50, true)); - assert_ok!(Society::defender_vote(Origin::signed(10), true)); // Keep defender around + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 50, true)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(10), true)); // Keep defender around run_to_block(32); assert_eq!(Society::members(), vec![10, 50]); assert_eq!(Society::head(), Some(50)); @@ -543,29 +561,29 @@ fn founder_and_head_cannot_be_removed() { assert_eq!(Society::founder(), Some(10)); // 50 can still accumulate strikes - assert_ok!(Society::bid(Origin::signed(60), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(60), 0)); run_to_block(40); assert_eq!(Strikes::::get(50), 1); - assert_ok!(Society::bid(Origin::signed(70), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(70), 0)); run_to_block(48); assert_eq!(Strikes::::get(50), 2); // Replace the head - assert_ok!(Society::bid(Origin::signed(80), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(80), 0)); run_to_block(52); - assert_ok!(Society::vote(Origin::signed(10), 80, true)); - assert_ok!(Society::vote(Origin::signed(50), 80, true)); - assert_ok!(Society::defender_vote(Origin::signed(10), true)); // Keep defender around + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 80, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(50), 80, true)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(10), true)); // Keep defender around run_to_block(56); assert_eq!(Society::members(), vec![10, 50, 80]); assert_eq!(Society::head(), Some(80)); assert_eq!(Society::founder(), Some(10)); // 50 can now be suspended for strikes - assert_ok!(Society::bid(Origin::signed(90), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(90), 0)); run_to_block(60); // The candidate is rejected, so voting approve will give a strike - assert_ok!(Society::vote(Origin::signed(50), 90, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(50), 90, true)); run_to_block(64); assert_eq!(Strikes::::get(50), 0); assert_eq!(>::get(50), true); @@ -592,19 +610,22 @@ fn challenges_work() { run_to_block(8); assert_eq!(Society::defender(), Some(30)); // They can always free vote for themselves - assert_ok!(Society::defender_vote(Origin::signed(30), true)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(30), true)); // If no one else votes, nothing happens run_to_block(16); assert_eq!(Society::members(), vec![10, 20, 30, 40]); // New challenge period assert_eq!(Society::defender(), Some(30)); // Non-member cannot challenge - assert_noop!(Society::defender_vote(Origin::signed(1), true), Error::::NotMember); + assert_noop!( + Society::defender_vote(RuntimeOrigin::signed(1), true), + Error::::NotMember + ); // 3 people say accept, 1 reject - assert_ok!(Society::defender_vote(Origin::signed(10), true)); - assert_ok!(Society::defender_vote(Origin::signed(20), true)); - assert_ok!(Society::defender_vote(Origin::signed(30), true)); - assert_ok!(Society::defender_vote(Origin::signed(40), false)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(10), true)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(20), true)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(30), true)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(40), false)); run_to_block(24); // 20 survives assert_eq!(Society::members(), vec![10, 20, 30, 40]); @@ -616,10 +637,10 @@ fn challenges_work() { // One more time assert_eq!(Society::defender(), Some(30)); // 2 people say accept, 2 reject - assert_ok!(Society::defender_vote(Origin::signed(10), true)); - assert_ok!(Society::defender_vote(Origin::signed(20), true)); - assert_ok!(Society::defender_vote(Origin::signed(30), false)); - assert_ok!(Society::defender_vote(Origin::signed(40), false)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(10), true)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(20), true)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(30), false)); + assert_ok!(Society::defender_vote(RuntimeOrigin::signed(40), false)); run_to_block(32); // 20 is suspended assert_eq!(Society::members(), vec![10, 20, 40]); @@ -653,12 +674,12 @@ fn bad_vote_slash_works() { assert_eq!(>::get(30), vec![(5, 100)]); assert_eq!(>::get(40), vec![(5, 100)]); // Create a new bid - assert_ok!(Society::bid(Origin::signed(50), 1000)); + assert_ok!(Society::bid(RuntimeOrigin::signed(50), 1000)); run_to_block(4); - assert_ok!(Society::vote(Origin::signed(10), 50, false)); - assert_ok!(Society::vote(Origin::signed(20), 50, true)); - assert_ok!(Society::vote(Origin::signed(30), 50, false)); - assert_ok!(Society::vote(Origin::signed(40), 50, false)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 50, false)); + assert_ok!(Society::vote(RuntimeOrigin::signed(20), 50, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(30), 50, false)); + assert_ok!(Society::vote(RuntimeOrigin::signed(40), 50, false)); run_to_block(8); // Wrong voter gained a strike assert_eq!(>::get(10), 0); @@ -677,15 +698,15 @@ fn bad_vote_slash_works() { fn user_cannot_bid_twice() { EnvBuilder::new().execute(|| { // Cannot bid twice - assert_ok!(Society::bid(Origin::signed(20), 100)); - assert_noop!(Society::bid(Origin::signed(20), 100), Error::::AlreadyBid); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 100)); + assert_noop!(Society::bid(RuntimeOrigin::signed(20), 100), Error::::AlreadyBid); // Cannot bid when vouched - assert_ok!(Society::vouch(Origin::signed(10), 30, 100, 100)); - assert_noop!(Society::bid(Origin::signed(30), 100), Error::::AlreadyBid); + assert_ok!(Society::vouch(RuntimeOrigin::signed(10), 30, 100, 100)); + assert_noop!(Society::bid(RuntimeOrigin::signed(30), 100), Error::::AlreadyBid); // Cannot vouch when already bid assert_ok!(Society::add_member(&50)); assert_noop!( - Society::vouch(Origin::signed(50), 20, 100, 100), + Society::vouch(RuntimeOrigin::signed(50), 20, 100, 100), Error::::AlreadyBid ); }); @@ -697,7 +718,7 @@ fn vouching_handles_removed_member_with_bid() { // Add a member assert_ok!(Society::add_member(&20)); // Have that member vouch for a user - assert_ok!(Society::vouch(Origin::signed(20), 30, 1000, 100)); + assert_ok!(Society::vouch(RuntimeOrigin::signed(20), 30, 1000, 100)); // That user is now a bid and the member is vouching assert_eq!(>::get(), vec![create_bid(1000, 30, BidKind::Vouch(20, 100))]); assert_eq!(>::get(20), Some(VouchingStatus::Vouching)); @@ -708,7 +729,7 @@ fn vouching_handles_removed_member_with_bid() { assert_eq!(>::get(), vec![create_bid(1000, 30, BidKind::Vouch(20, 100))]); assert_eq!(>::get(20), Some(VouchingStatus::Vouching)); // Remove member - assert_ok!(Society::judge_suspended_member(Origin::signed(2), 20, false)); + assert_ok!(Society::judge_suspended_member(RuntimeOrigin::signed(2), 20, false)); // Bid is removed, vouching status is removed assert_eq!(>::get(), vec![]); assert_eq!(>::get(20), None); @@ -721,7 +742,7 @@ fn vouching_handles_removed_member_with_candidate() { // Add a member assert_ok!(Society::add_member(&20)); // Have that member vouch for a user - assert_ok!(Society::vouch(Origin::signed(20), 30, 1000, 100)); + assert_ok!(Society::vouch(RuntimeOrigin::signed(20), 30, 1000, 100)); // That user is now a bid and the member is vouching assert_eq!(>::get(), vec![create_bid(1000, 30, BidKind::Vouch(20, 100))]); assert_eq!(>::get(20), Some(VouchingStatus::Vouching)); @@ -735,12 +756,12 @@ fn vouching_handles_removed_member_with_candidate() { assert_eq!(Society::candidates(), vec![create_bid(1000, 30, BidKind::Vouch(20, 100))]); assert_eq!(>::get(20), Some(VouchingStatus::Vouching)); // Remove member - assert_ok!(Society::judge_suspended_member(Origin::signed(2), 20, false)); + assert_ok!(Society::judge_suspended_member(RuntimeOrigin::signed(2), 20, false)); // Vouching status is removed, but candidate is still in the queue assert_eq!(>::get(20), None); assert_eq!(Society::candidates(), vec![create_bid(1000, 30, BidKind::Vouch(20, 100))]); // Candidate wins - assert_ok!(Society::vote(Origin::signed(10), 30, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 30, true)); run_to_block(8); assert_eq!(Society::members(), vec![10, 30]); // Payout does not go to removed member @@ -753,16 +774,19 @@ fn vouching_handles_removed_member_with_candidate() { fn votes_are_working() { EnvBuilder::new().execute(|| { // Users make bids of various amounts - assert_ok!(Society::bid(Origin::signed(50), 500)); - assert_ok!(Society::bid(Origin::signed(40), 400)); - assert_ok!(Society::bid(Origin::signed(30), 300)); + assert_ok!(Society::bid(RuntimeOrigin::signed(50), 500)); + assert_ok!(Society::bid(RuntimeOrigin::signed(40), 400)); + assert_ok!(Society::bid(RuntimeOrigin::signed(30), 300)); // Rotate period run_to_block(4); // A member votes for these candidates to join the society - assert_ok!(Society::vote(Origin::signed(10), 30, true)); - assert_ok!(Society::vote(Origin::signed(10), 40, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 30, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 40, true)); // You cannot vote for a non-candidate - assert_noop!(Society::vote(Origin::signed(10), 50, true), Error::::NotCandidate); + assert_noop!( + Society::vote(RuntimeOrigin::signed(10), 50, true), + Error::::NotCandidate + ); // Votes are stored assert_eq!(>::get(30, 10), Some(Vote::Approve)); assert_eq!(>::get(40, 10), Some(Vote::Approve)); @@ -784,7 +808,7 @@ fn max_limits_work() { for i in (100..1110).rev() { // Give them some funds let _ = Balances::make_free_balance_be(&(i as u128), 1000); - assert_ok!(Society::bid(Origin::signed(i as u128), i)); + assert_ok!(Society::bid(RuntimeOrigin::signed(i as u128), i)); } let bids = >::get(); // Length is 1000 @@ -810,7 +834,7 @@ fn max_limits_work() { // Fill up members with suspended candidates from the first rotation for i in 100..104 { assert_ok!(Society::judge_suspended_candidate( - Origin::signed(2), + RuntimeOrigin::signed(2), i, Judgement::Approve )); @@ -821,9 +845,9 @@ fn max_limits_work() { // However, a fringe scenario allows for in-progress candidates to increase the membership // pool, but it has no real after-effects. for i in Society::members().iter() { - assert_ok!(Society::vote(Origin::signed(*i), 110, true)); - assert_ok!(Society::vote(Origin::signed(*i), 111, true)); - assert_ok!(Society::vote(Origin::signed(*i), 112, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(*i), 110, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(*i), 111, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(*i), 112, true)); } // Rotate period run_to_block(12); @@ -832,7 +856,7 @@ fn max_limits_work() { // No candidates because full assert_eq!(Society::candidates().len(), 0); // Increase member limit - assert_ok!(Society::set_max_members(Origin::root(), 200)); + assert_ok!(Society::set_max_members(RuntimeOrigin::root(), 200)); // Rotate period run_to_block(16); // Candidates are back! @@ -847,11 +871,11 @@ fn zero_bid_works() { // * That zero bid is placed as head when accepted. EnvBuilder::new().execute(|| { // Users make bids of various amounts - assert_ok!(Society::bid(Origin::signed(60), 400)); - assert_ok!(Society::bid(Origin::signed(50), 300)); - assert_ok!(Society::bid(Origin::signed(30), 0)); - assert_ok!(Society::bid(Origin::signed(20), 0)); - assert_ok!(Society::bid(Origin::signed(40), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(60), 400)); + assert_ok!(Society::bid(RuntimeOrigin::signed(50), 300)); + assert_ok!(Society::bid(RuntimeOrigin::signed(30), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(20), 0)); + assert_ok!(Society::bid(RuntimeOrigin::signed(40), 0)); // Rotate period run_to_block(4); @@ -872,9 +896,9 @@ fn zero_bid_works() { vec![create_bid(0, 20, BidKind::Deposit(25)), create_bid(0, 40, BidKind::Deposit(25)),] ); // A member votes for these candidates to join the society - assert_ok!(Society::vote(Origin::signed(10), 30, true)); - assert_ok!(Society::vote(Origin::signed(10), 50, true)); - assert_ok!(Society::vote(Origin::signed(10), 60, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 30, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 50, true)); + assert_ok!(Society::vote(RuntimeOrigin::signed(10), 60, true)); run_to_block(8); // Candidates become members after a period rotation assert_eq!(Society::members(), vec![10, 30, 50, 60]); @@ -892,7 +916,7 @@ fn bids_ordered_correctly() { for j in 0..5 { // Give them some funds let _ = Balances::make_free_balance_be(&(100 + (i * 5 + j) as u128), 1000); - assert_ok!(Society::bid(Origin::signed(100 + (i * 5 + j) as u128), j)); + assert_ok!(Society::bid(RuntimeOrigin::signed(100 + (i * 5 + j) as u128), j)); } } diff --git a/frame/staking/Cargo.toml b/frame/staking/Cargo.toml index 37d13a54ba5ed..cf9e12dcd82b4 100644 --- a/frame/staking/Cargo.toml +++ b/frame/staking/Cargo.toml @@ -43,7 +43,7 @@ sp-npos-elections = { version = "4.0.0-dev", path = "../../primitives/npos-elect pallet-balances = { version = "4.0.0-dev", path = "../balances" } pallet-timestamp = { version = "4.0.0-dev", path = "../timestamp" } pallet-staking-reward-curve = { version = "4.0.0-dev", path = "../staking/reward-curve" } -pallet-bags-list = { version = "4.0.0-dev", features = ["runtime-benchmarks"], path = "../bags-list" } +pallet-bags-list = { version = "4.0.0-dev", path = "../bags-list" } substrate-test-utils = { version = "4.0.0-dev", path = "../../test-utils" } frame-benchmarking = { version = "4.0.0-dev", path = "../benchmarking" } frame-election-provider-support = { version = "4.0.0-dev", path = "../election-provider-support" } @@ -52,6 +52,7 @@ rand_chacha = { version = "0.2" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "serde", "codec/std", "scale-info/std", @@ -61,6 +62,7 @@ std = [ "sp-runtime/std", "sp-staking/std", "pallet-session/std", + "pallet-bags-list/std", "frame-system/std", "pallet-authorship/std", "sp-application-crypto/std", @@ -72,5 +74,10 @@ runtime-benchmarks = [ "frame-election-provider-support/runtime-benchmarks", "rand_chacha", "sp-staking/runtime-benchmarks", + "pallet-bags-list/runtime-benchmarks", ] try-runtime = ["frame-support/try-runtime"] +fuzz = [ + "pallet-bags-list/fuzz", + "frame-election-provider-support/fuzz", +] diff --git a/frame/staking/src/benchmarking.rs b/frame/staking/src/benchmarking.rs index 2d5943b51758d..dcb861e2ce419 100644 --- a/frame/staking/src/benchmarking.rs +++ b/frame/staking/src/benchmarking.rs @@ -88,6 +88,7 @@ pub fn create_validator_with_nominators( points_total += 10; points_individual.push((v_stash.clone(), 10)); + let original_nominator_count = Nominators::::count(); let mut nominators = Vec::new(); // Give the validator n nominators, but keep total users in the system the same. @@ -114,7 +115,7 @@ pub fn create_validator_with_nominators( assert_eq!(new_validators.len(), 1); assert_eq!(new_validators[0], v_stash, "Our validator was not selected!"); assert_ne!(Validators::::count(), 0); - assert_ne!(Nominators::::count(), 0); + assert_eq!(Nominators::::count(), original_nominator_count + nominators.len() as u32); // Give Era Points let reward = EraRewardPoints:: { @@ -544,7 +545,7 @@ benchmarks! { } payout_stakers_dead_controller { - let n in 1 .. T::MaxNominatorRewardedPerValidator::get() as u32; + let n in 0 .. T::MaxNominatorRewardedPerValidator::get() as u32; let (validator, nominators) = create_validator_with_nominators::( n, T::MaxNominatorRewardedPerValidator::get() as u32, @@ -577,7 +578,7 @@ benchmarks! { } payout_stakers_alive_staked { - let n in 1 .. T::MaxNominatorRewardedPerValidator::get() as u32; + let n in 0 .. T::MaxNominatorRewardedPerValidator::get() as u32; let (validator, nominators) = create_validator_with_nominators::( n, T::MaxNominatorRewardedPerValidator::get() as u32, @@ -613,7 +614,7 @@ benchmarks! { } rebond { - let l in 1 .. MaxUnlockingChunks::get() as u32; + let l in 1 .. T::MaxUnlockingChunks::get() as u32; // clean up any existing state. clear_validators_and_nominators::(); @@ -660,25 +661,6 @@ benchmarks! { assert!(original_bonded < new_bonded); } - set_history_depth { - let e in 1 .. 100; - HistoryDepth::::put(e); - CurrentEra::::put(e); - let dummy = || -> T::AccountId { codec::Decode::decode(&mut TrailingZeroInput::zeroes()).unwrap() }; - for i in 0 .. e { - >::insert(i, dummy(), Exposure::>::default()); - >::insert(i, dummy(), Exposure::>::default()); - >::insert(i, dummy(), ValidatorPrefs::default()); - >::insert(i, BalanceOf::::one()); - >::insert(i, EraRewardPoints::::default()); - >::insert(i, BalanceOf::::one()); - ErasStartSessionIndex::::insert(i, i); - } - }: _(RawOrigin::Root, EraIndex::zero(), u32::MAX) - verify { - assert_eq!(HistoryDepth::::get(), 0); - } - reap_stash { let s in 1 .. MAX_SPANS; // clean up any existing state. @@ -698,7 +680,7 @@ benchmarks! { active: T::Currency::minimum_balance() - One::one(), total: T::Currency::minimum_balance() - One::one(), unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: Default::default(), }; Ledger::::insert(&controller, l); @@ -714,7 +696,7 @@ benchmarks! { new_era { let v in 1 .. 10; - let n in 1 .. 100; + let n in 0 .. 100; create_validators_with_nominators_for_era::( v, @@ -733,7 +715,7 @@ benchmarks! { #[extra] payout_all { let v in 1 .. 10; - let n in 1 .. 100; + let n in 0 .. 100; create_validators_with_nominators_for_era::( v, n, @@ -783,7 +765,7 @@ benchmarks! { #[extra] do_slash { - let l in 1 .. MaxUnlockingChunks::get() as u32; + let l in 1 .. T::MaxUnlockingChunks::get() as u32; let (stash, controller) = create_stash_controller::(0, 100, Default::default())?; let mut staking_ledger = Ledger::::get(controller.clone()).unwrap(); let unlock_chunk = UnlockChunk::> { @@ -844,7 +826,7 @@ benchmarks! { v, n, T::MaxNominations::get() as usize, false, None )?; }: { - let targets = >::get_npos_targets(); + let targets = >::get_npos_targets(None); assert_eq!(targets.len() as u32, v); } @@ -953,7 +935,7 @@ benchmarks! { #[cfg(test)] mod tests { use super::*; - use crate::mock::{Balances, ExtBuilder, Origin, Staking, Test}; + use crate::mock::{Balances, ExtBuilder, RuntimeOrigin, Staking, Test}; use frame_support::assert_ok; #[test] @@ -1000,7 +982,11 @@ mod tests { let current_era = CurrentEra::::get().unwrap(); let original_free_balance = Balances::free_balance(&validator_stash); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), validator_stash, current_era)); + assert_ok!(Staking::payout_stakers( + RuntimeOrigin::signed(1337), + validator_stash, + current_era + )); let new_free_balance = Balances::free_balance(&validator_stash); assert!(original_free_balance < new_free_balance); diff --git a/frame/staking/src/lib.rs b/frame/staking/src/lib.rs index 4a1f0cb886ed0..a0144463540be 100644 --- a/frame/staking/src/lib.rs +++ b/frame/staking/src/lib.rs @@ -299,12 +299,11 @@ pub mod weights; mod pallet; -use codec::{Decode, Encode, HasCompact}; +use codec::{Decode, Encode, HasCompact, MaxEncodedLen}; use frame_support::{ - parameter_types, traits::{Currency, Defensive, Get}, weights::Weight, - BoundedVec, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, + BoundedVec, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; use scale_info::TypeInfo; use sp_runtime::{ @@ -349,12 +348,8 @@ type NegativeImbalanceOf = <::Currency as Currency< type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; -parameter_types! { - pub MaxUnlockingChunks: u32 = 32; -} - /// Information regarding the active era (era in used in session). -#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct ActiveEraInfo { /// Index of era. pub index: EraIndex, @@ -395,7 +390,7 @@ pub enum StakerStatus { } /// A destination account for payment. -#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[derive(PartialEq, Eq, Copy, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum RewardDestination { /// Pay into the stash account, increasing the amount at stake accordingly. Staked, @@ -416,7 +411,7 @@ impl Default for RewardDestination { } /// Preference of what happens regarding validation. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, Default, MaxEncodedLen)] pub struct ValidatorPrefs { /// Reward that validator takes up-front; only the rest is split between themselves and /// nominators. @@ -429,8 +424,8 @@ pub struct ValidatorPrefs { } /// Just a Balance/BlockNumber tuple to encode when a chunk of funds will be unlocked. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] -pub struct UnlockChunk { +#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct UnlockChunk { /// Amount of funds to be unlocked. #[codec(compact)] value: Balance, @@ -440,7 +435,16 @@ pub struct UnlockChunk { } /// The ledger of a (bonded) stash. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebugNoBound, TypeInfo)] +#[derive( + PartialEqNoBound, + EqNoBound, + CloneNoBound, + Encode, + Decode, + RuntimeDebugNoBound, + TypeInfo, + MaxEncodedLen, +)] #[scale_info(skip_type_params(T))] pub struct StakingLedger { /// The stash account whose balance is actually locked and at stake. @@ -456,10 +460,10 @@ pub struct StakingLedger { /// Any balance that is becoming free, which may eventually be transferred out of the stash /// (assuming it doesn't get slashed first). It is assumed that this will be treated as a first /// in, first out queue where the new (higher value) eras get pushed on the back. - pub unlocking: BoundedVec>, MaxUnlockingChunks>, + pub unlocking: BoundedVec>, T::MaxUnlockingChunks>, /// List of eras for which the stakers behind a validator have claimed rewards. Only updated /// for validators. - pub claimed_rewards: Vec, + pub claimed_rewards: BoundedVec, } impl StakingLedger { @@ -470,7 +474,7 @@ impl StakingLedger { total: Zero::zero(), active: Zero::zero(), unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: Default::default(), } } @@ -554,7 +558,7 @@ impl StakingLedger { /// /// This calls `Config::OnStakerSlash::on_slash` with information as to how the slash was /// applied. - fn slash( + pub fn slash( &mut self, slash_amount: BalanceOf, minimum_balance: BalanceOf, @@ -676,7 +680,9 @@ impl StakingLedger { } /// A record of the nominations made by a specific account. -#[derive(PartialEqNoBound, EqNoBound, Clone, Encode, Decode, RuntimeDebugNoBound, TypeInfo)] +#[derive( + PartialEqNoBound, EqNoBound, Clone, Encode, Decode, RuntimeDebugNoBound, TypeInfo, MaxEncodedLen, +)] #[codec(mel_bound())] #[scale_info(skip_type_params(T))] pub struct Nominations { @@ -850,7 +856,7 @@ impl VoterBagsList + V12_0_0, // remove `HistoryDepth`. } impl Default for Releases { fn default() -> Self { - Releases::V10_0_0 + Releases::V11_0_0 } } @@ -940,7 +948,9 @@ where if bonded_eras.first().filter(|(_, start)| offence_session >= *start).is_some() { R::report_offence(reporters, offence) } else { - >::deposit_event(Event::::OldSlashingReportDiscarded(offence_session)); + >::deposit_event(Event::::OldSlashingReportDiscarded { + session_index: offence_session, + }); Ok(()) } } diff --git a/frame/staking/src/migrations.rs b/frame/staking/src/migrations.rs index ff01e1fe3b09b..f2ccb4f8b096f 100644 --- a/frame/staking/src/migrations.rs +++ b/frame/staking/src/migrations.rs @@ -20,6 +20,155 @@ use super::*; use frame_election_provider_support::SortedListProvider; use frame_support::traits::OnRuntimeUpgrade; +pub mod v12 { + use super::*; + use frame_support::{pallet_prelude::ValueQuery, storage_alias}; + + #[storage_alias] + type HistoryDepth = StorageValue, u32, ValueQuery>; + + /// Clean up `HistoryDepth` from storage. + /// + /// We will be depending on the configurable value of `HistoryDepth` post + /// this release. + pub struct MigrateToV12(sp_std::marker::PhantomData); + impl OnRuntimeUpgrade for MigrateToV12 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + frame_support::ensure!( + StorageVersion::::get() == Releases::V11_0_0, + "Expected v11 before upgrading to v12" + ); + + if HistoryDepth::::exists() { + frame_support::ensure!( + T::HistoryDepth::get() == HistoryDepth::::get(), + "Provided value of HistoryDepth should be same as the existing storage value" + ); + } else { + log::info!("No HistoryDepth in storage; nothing to remove"); + } + + Ok(Default::default()) + } + + fn on_runtime_upgrade() -> frame_support::weights::Weight { + if StorageVersion::::get() == Releases::V11_0_0 { + HistoryDepth::::kill(); + StorageVersion::::put(Releases::V12_0_0); + + log!(info, "v12 applied successfully"); + T::DbWeight::get().reads_writes(1, 2) + } else { + log!(warn, "Skipping v12, should be removed"); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { + frame_support::ensure!( + StorageVersion::::get() == crate::Releases::V12_0_0, + "v12 not applied" + ); + Ok(()) + } + } +} + +pub mod v11 { + use super::*; + use frame_support::{ + storage::migration::move_pallet, + traits::{GetStorageVersion, PalletInfoAccess}, + }; + #[cfg(feature = "try-runtime")] + use sp_io::hashing::twox_128; + + pub struct MigrateToV11(sp_std::marker::PhantomData<(T, P, N)>); + impl> OnRuntimeUpgrade + for MigrateToV11 + { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, &'static str> { + frame_support::ensure!( + StorageVersion::::get() == crate::Releases::V10_0_0, + "must upgrade linearly" + ); + let old_pallet_prefix = twox_128(N::get().as_bytes()); + + frame_support::ensure!( + sp_io::storage::next_key(&old_pallet_prefix).is_some(), + "no data for the old pallet name has been detected" + ); + + Ok(Default::default()) + } + + /// Migrate the entire storage of this pallet to a new prefix. + /// + /// This new prefix must be the same as the one set in construct_runtime. For safety, use + /// `PalletInfo` to get it, as: + /// `::PalletInfo::name::`. + /// + /// The migration will look into the storage version in order to avoid triggering a + /// migration on an up to date storage. + fn on_runtime_upgrade() -> Weight { + let old_pallet_name = N::get(); + let new_pallet_name =

::name(); + + if StorageVersion::::get() == Releases::V10_0_0 { + // bump version anyway, even if we don't need to move the prefix + StorageVersion::::put(Releases::V11_0_0); + if new_pallet_name == old_pallet_name { + log!( + warn, + "new bags-list name is equal to the old one, only bumping the version" + ); + return T::DbWeight::get().reads(1).saturating_add(T::DbWeight::get().writes(1)) + } + + move_pallet(old_pallet_name.as_bytes(), new_pallet_name.as_bytes()); + ::BlockWeights::get().max_block + } else { + log!(warn, "v11::migrate should be removed."); + T::DbWeight::get().reads(1) + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { + frame_support::ensure!( + StorageVersion::::get() == crate::Releases::V11_0_0, + "wrong version after the upgrade" + ); + + let old_pallet_name = N::get(); + let new_pallet_name =

::name(); + + // skip storage prefix checks for the same pallet names + if new_pallet_name == old_pallet_name { + return Ok(()) + } + + let old_pallet_prefix = twox_128(N::get().as_bytes()); + frame_support::ensure!( + sp_io::storage::next_key(&old_pallet_prefix).is_none(), + "old pallet data hasn't been removed" + ); + + let new_pallet_name =

::name(); + let new_pallet_prefix = twox_128(new_pallet_name.as_bytes()); + frame_support::ensure!( + sp_io::storage::next_key(&new_pallet_prefix).is_some(), + "new pallet data hasn't been created" + ); + + Ok(()) + } + } +} + pub mod v10 { use super::*; use frame_support::storage_alias; @@ -61,6 +210,10 @@ pub mod v10 { pub mod v9 { use super::*; + #[cfg(feature = "try-runtime")] + use frame_support::codec::{Decode, Encode}; + #[cfg(feature = "try-runtime")] + use sp_std::vec::Vec; /// Migration implementation that injects all validators into sorted list. /// @@ -99,23 +252,22 @@ pub mod v9 { } #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { - use frame_support::traits::OnRuntimeUpgradeHelpersExt; + fn pre_upgrade() -> Result, &'static str> { frame_support::ensure!( StorageVersion::::get() == crate::Releases::V8_0_0, "must upgrade linearly" ); let prev_count = T::VoterList::count(); - Self::set_temp_storage(prev_count, "prev"); - Ok(()) + Ok(prev_count.encode()) } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { - use frame_support::traits::OnRuntimeUpgradeHelpersExt; + fn post_upgrade(prev_count: Vec) -> Result<(), &'static str> { + let prev_count: u32 = Decode::decode(&mut prev_count.as_slice()).expect( + "the state parameter should be something that was generated by pre_upgrade", + ); let post_count = T::VoterList::count(); - let prev_count = Self::get_temp_storage::("prev").unwrap(); let validators = Validators::::count(); assert!(post_count == prev_count + validators); diff --git a/frame/staking/src/mock.rs b/frame/staking/src/mock.rs index 7911428b3337c..24e5aa97160ee 100644 --- a/frame/staking/src/mock.rs +++ b/frame/staking/src/mock.rs @@ -18,9 +18,7 @@ //! Test utilities use crate::{self as pallet_staking, *}; -use frame_election_provider_support::{ - onchain, SequentialPhragmen, SortedListProvider, VoteWeight, -}; +use frame_election_provider_support::{onchain, SequentialPhragmen, VoteWeight}; use frame_support::{ assert_ok, parameter_types, traits::{ @@ -37,7 +35,6 @@ use sp_runtime::{ traits::{IdentityLookup, Zero}, }; use sp_staking::offence::{DisableStrategy, OffenceDetails, OnOffenceHandler}; -use std::cell::RefCell; pub const INIT_TIMESTAMP: u64 = 30_000; pub const BLOCK_TIME: u64 = 1000; @@ -100,7 +97,7 @@ frame_support::construct_runtime!( Staking: pallet_staking::{Pallet, Call, Config, Storage, Event}, Session: pallet_session::{Pallet, Call, Storage, Event, Config}, Historical: pallet_session::historical::{Pallet, Storage}, - BagsList: pallet_bags_list::{Pallet, Call, Storage, Event}, + VoterBagsList: pallet_bags_list::::{Pallet, Call, Storage, Event}, } ); @@ -132,16 +129,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = RocksDbWeight; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = AccountIndex; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -158,7 +155,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; type AccountStore = System; @@ -175,7 +172,7 @@ impl pallet_session::Config for Test { type Keys = SessionKeys; type ShouldEndSession = pallet_session::PeriodicSessions; type SessionHandler = (OtherSessionHandler,); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ValidatorId = AccountId; type ValidatorIdOf = crate::StashOf; type NextSessionRotation = pallet_session::PeriodicSessions; @@ -216,16 +213,16 @@ parameter_types! { pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(75); } -thread_local! { - pub static REWARD_REMAINDER_UNBALANCED: RefCell = RefCell::new(0); +parameter_types! { + pub static RewardRemainderUnbalanced: u128 = 0; } pub struct RewardRemainderMock; impl OnUnbalanced> for RewardRemainderMock { fn on_nonzero_unbalanced(amount: NegativeImbalanceOf) { - REWARD_REMAINDER_UNBALANCED.with(|v| { - *v.borrow_mut() += amount.peek(); + RewardRemainderUnbalanced::mutate(|v| { + *v += amount.peek(); }); drop(amount); } @@ -237,13 +234,17 @@ const THRESHOLDS: [sp_npos_elections::VoteWeight; 9] = parameter_types! { pub static BagThresholds: &'static [sp_npos_elections::VoteWeight] = &THRESHOLDS; pub static MaxNominations: u32 = 16; + pub static HistoryDepth: u32 = 80; + pub static MaxUnlockingChunks: u32 = 32; pub static RewardOnUnbalanceWasCalled: bool = false; pub static LedgerSlashPerEra: (BalanceOf, BTreeMap>) = (Zero::zero(), BTreeMap::new()); } -impl pallet_bags_list::Config for Test { - type Event = Event; +type VoterBagsListInstance = pallet_bags_list::Instance1; +impl pallet_bags_list::Config for Test { + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); + // Staking is the source of truth for voter bags list, since they are not kept up to date. type ScoreProvider = Staking; type BagThresholds = BagThresholds; type Score = VoteWeight; @@ -282,7 +283,7 @@ impl crate::pallet::pallet::Config for Test { type UnixTime = Timestamp; type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote; type RewardRemainder = RewardRemainderMock; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Slash = (); type Reward = MockReward; type SessionsPerEra = SessionsPerEra; @@ -297,15 +298,17 @@ impl crate::pallet::pallet::Config for Test { type ElectionProvider = onchain::UnboundedExecution; type GenesisElectionProvider = Self::ElectionProvider; // NOTE: consider a macro and use `UseNominatorsAndValidatorsMap` as well. - type VoterList = BagsList; - type MaxUnlockingChunks = ConstU32<32>; + type VoterList = VoterBagsList; + type TargetList = UseValidatorsMap; + type MaxUnlockingChunks = MaxUnlockingChunks; + type HistoryDepth = HistoryDepth; type OnStakerSlash = OnStakerSlashMock; type BenchmarkingConfig = TestBenchmarkingConfig; type WeightInfo = (); } pub(crate) type StakingCall = crate::Call; -pub(crate) type TestRuntimeCall = ::Call; +pub(crate) type TestCall = ::RuntimeCall; pub struct ExtBuilder { nominate: bool, @@ -543,108 +546,10 @@ impl ExtBuilder { sp_tracing::try_init_simple(); let mut ext = self.build(); ext.execute_with(test); - ext.execute_with(post_conditions); - } -} - -fn post_conditions() { - check_nominators(); - check_exposures(); - check_ledgers(); - check_count(); -} - -fn check_count() { - let nominator_count = Nominators::::iter_keys().count() as u32; - let validator_count = Validators::::iter().count() as u32; - assert_eq!(nominator_count, Nominators::::count()); - assert_eq!(validator_count, Validators::::count()); - - // the voters that the `VoterList` list is storing for us. - let external_voters = ::VoterList::count(); - assert_eq!(external_voters, nominator_count + validator_count); -} - -fn check_ledgers() { - // check the ledger of all stakers. - Bonded::::iter().for_each(|(_, ctrl)| assert_ledger_consistent(ctrl)) -} - -fn check_exposures() { - // a check per validator to ensure the exposure struct is always sane. - let era = active_era(); - ErasStakers::::iter_prefix_values(era).for_each(|expo| { - assert_eq!( - expo.total as u128, - expo.own as u128 + expo.others.iter().map(|e| e.value as u128).sum::(), - "wrong total exposure.", - ); - }) -} - -fn check_nominators() { - // a check per nominator to ensure their entire stake is correctly distributed. Will only kick- - // in if the nomination was submitted before the current era. - let era = active_era(); - >::iter() - .filter_map( - |(nominator, nomination)| { - if nomination.submitted_in > era { - Some(nominator) - } else { - None - } - }, - ) - .for_each(|nominator| { - // must be bonded. - assert_is_stash(nominator); - let mut sum = 0; - Session::validators() - .iter() - .map(|v| Staking::eras_stakers(era, v)) - .for_each(|e| { - let individual = - e.others.iter().filter(|e| e.who == nominator).collect::>(); - let len = individual.len(); - match len { - 0 => { /* not supporting this validator at all. */ }, - 1 => sum += individual[0].value, - _ => panic!("nominator cannot back a validator more than once."), - }; - }); - - let nominator_stake = Staking::slashable_balance_of(&nominator); - // a nominator cannot over-spend. - assert!( - nominator_stake >= sum, - "failed: Nominator({}) stake({}) >= sum divided({})", - nominator, - nominator_stake, - sum, - ); - - let diff = nominator_stake - sum; - assert!(diff < 100); + ext.execute_with(|| { + Staking::do_try_state(System::block_number()).unwrap(); }); -} - -fn assert_is_stash(acc: AccountId) { - assert!(Staking::bonded(&acc).is_some(), "Not a stash."); -} - -fn assert_ledger_consistent(ctrl: AccountId) { - // ensures ledger.total == ledger.active + sum(ledger.unlocking). - let ledger = Staking::ledger(ctrl).expect("Not a controller."); - let real_total: Balance = ledger.unlocking.iter().fold(ledger.active, |a, c| a + c.value); - assert_eq!(real_total, ledger.total); - assert!( - ledger.active >= Balances::minimum_balance() || ledger.active == 0, - "{}: active ledger amount ({}) must be greater than ED {}", - ctrl, - ledger.active, - Balances::minimum_balance() - ); + } } pub(crate) fn active_era() -> EraIndex { @@ -658,13 +563,22 @@ pub(crate) fn current_era() -> EraIndex { pub(crate) fn bond(stash: AccountId, ctrl: AccountId, val: Balance) { let _ = Balances::make_free_balance_be(&stash, val); let _ = Balances::make_free_balance_be(&ctrl, val); - assert_ok!(Staking::bond(Origin::signed(stash), ctrl, val, RewardDestination::Controller)); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(stash), + ctrl, + val, + RewardDestination::Controller + )); } pub(crate) fn bond_validator(stash: AccountId, ctrl: AccountId, val: Balance) { bond(stash, ctrl, val); - assert_ok!(Staking::validate(Origin::signed(ctrl), ValidatorPrefs::default())); - assert_ok!(Session::set_keys(Origin::signed(ctrl), SessionKeys { other: ctrl.into() }, vec![])); + assert_ok!(Staking::validate(RuntimeOrigin::signed(ctrl), ValidatorPrefs::default())); + assert_ok!(Session::set_keys( + RuntimeOrigin::signed(ctrl), + SessionKeys { other: ctrl.into() }, + vec![] + )); } pub(crate) fn bond_nominator( @@ -674,7 +588,7 @@ pub(crate) fn bond_nominator( target: Vec, ) { bond(stash, ctrl, val); - assert_ok!(Staking::nominate(Origin::signed(ctrl), target)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(ctrl), target)); } /// Progress to the given block, triggering session and era changes as we progress. @@ -844,7 +758,7 @@ pub(crate) fn make_all_reward_payment(era: EraIndex) { // reward validators for validator_controller in validators_with_reward.iter().filter_map(Staking::bonded) { let ledger = >::get(&validator_controller).unwrap(); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), ledger.stash, era)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), ledger.stash, era)); } } @@ -872,7 +786,7 @@ pub(crate) fn staking_events() -> Vec> { System::events() .into_iter() .map(|r| r.event) - .filter_map(|e| if let Event::Staking(inner) = e { Some(inner) } else { None }) + .filter_map(|e| if let RuntimeEvent::Staking(inner) = e { Some(inner) } else { None }) .collect() } @@ -883,7 +797,7 @@ parameter_types! { pub(crate) fn staking_events_since_last_call() -> Vec> { let all: Vec<_> = System::events() .into_iter() - .filter_map(|r| if let Event::Staking(inner) = r.event { Some(inner) } else { None }) + .filter_map(|r| if let RuntimeEvent::Staking(inner) = r.event { Some(inner) } else { None }) .collect(); let seen = StakingEventsIndex::get(); StakingEventsIndex::set(all.len()); diff --git a/frame/staking/src/pallet/impls.rs b/frame/staking/src/pallet/impls.rs index 386c413132f6c..4ef064229693c 100644 --- a/frame/staking/src/pallet/impls.rs +++ b/frame/staking/src/pallet/impls.rs @@ -22,12 +22,13 @@ use frame_election_provider_support::{ Supports, VoteWeight, VoterOf, }; use frame_support::{ + dispatch::WithPostDispatchInfo, pallet_prelude::*, traits::{ - Currency, CurrencyToVote, Defensive, EstimateNextNewSession, Get, Imbalance, - LockableCurrency, OnUnbalanced, UnixTime, WithdrawReasons, + Currency, CurrencyToVote, Defensive, DefensiveResult, EstimateNextNewSession, Get, + Imbalance, LockableCurrency, OnUnbalanced, UnixTime, WithdrawReasons, }, - weights::{Weight, WithPostDispatchInfo}, + weights::Weight, }; use frame_system::{pallet_prelude::BlockNumberFor, RawOrigin}; use pallet_session::historical; @@ -100,7 +101,7 @@ impl Pallet { Error::::InvalidEraToReward .with_weight(T::WeightInfo::payout_stakers_alive_staked(0)) })?; - let history_depth = Self::history_depth(); + let history_depth = T::HistoryDepth::get(); ensure!( era <= current_era && era >= current_era.saturating_sub(history_depth), Error::::InvalidEraToReward @@ -122,11 +123,18 @@ impl Pallet { ledger .claimed_rewards .retain(|&x| x >= current_era.saturating_sub(history_depth)); + match ledger.claimed_rewards.binary_search(&era) { Ok(_) => return Err(Error::::AlreadyClaimed .with_weight(T::WeightInfo::payout_stakers_alive_staked(0))), - Err(pos) => ledger.claimed_rewards.insert(pos, era), + Err(pos) => ledger + .claimed_rewards + .try_insert(pos, era) + // Since we retain era entries in `claimed_rewards` only upto + // `HistoryDepth`, following bound is always expected to be + // satisfied. + .defensive_map_err(|_| Error::::BoundNotMet)?, } let exposure = >::get(&era, &ledger.stash); @@ -173,14 +181,20 @@ impl Pallet { let validator_exposure_part = Perbill::from_rational(exposure.own, exposure.total); let validator_staking_payout = validator_exposure_part * validator_leftover_payout; - Self::deposit_event(Event::::PayoutStarted(era, ledger.stash.clone())); + Self::deposit_event(Event::::PayoutStarted { + era_index: era, + validator_stash: ledger.stash.clone(), + }); let mut total_imbalance = PositiveImbalanceOf::::zero(); // We can now make total validator payout: if let Some(imbalance) = Self::make_payout(&ledger.stash, validator_staking_payout + validator_commission_payout) { - Self::deposit_event(Event::::Rewarded(ledger.stash, imbalance.peek())); + Self::deposit_event(Event::::Rewarded { + stash: ledger.stash, + amount: imbalance.peek(), + }); total_imbalance.subsume(imbalance); } @@ -200,7 +214,8 @@ impl Pallet { if let Some(imbalance) = Self::make_payout(&nominator.who, nominator_reward) { // Note: this logic does not count payouts for `RewardDestination::None`. nominator_payout_count += 1; - let e = Event::::Rewarded(nominator.who.clone(), imbalance.peek()); + let e = + Event::::Rewarded { stash: nominator.who.clone(), amount: imbalance.peek() }; Self::deposit_event(e); total_imbalance.subsume(imbalance); } @@ -224,7 +239,7 @@ impl Pallet { let chilled_as_validator = Self::do_remove_validator(stash); let chilled_as_nominator = Self::do_remove_nominator(stash); if chilled_as_validator || chilled_as_nominator { - Self::deposit_event(Event::::Chilled(stash.clone())); + Self::deposit_event(Event::::Chilled { stash: stash.clone() }); } } @@ -383,13 +398,18 @@ impl Pallet { let era_duration = (now_as_millis_u64 - active_era_start).saturated_into::(); let staked = Self::eras_total_stake(&active_era.index); let issuance = T::Currency::total_issuance(); - let (validator_payout, rest) = T::EraPayout::era_payout(staked, issuance, era_duration); + let (validator_payout, remainder) = + T::EraPayout::era_payout(staked, issuance, era_duration); - Self::deposit_event(Event::::EraPaid(active_era.index, validator_payout, rest)); + Self::deposit_event(Event::::EraPaid { + era_index: active_era.index, + validator_payout, + remainder, + }); // Set ending era reward. >::insert(&active_era.index, validator_payout); - T::RewardRemainder::on_unbalanced(T::Currency::issue(rest)); + T::RewardRemainder::on_unbalanced(T::Currency::issue(remainder)); // Clear offending validators. >::kill(); @@ -416,7 +436,7 @@ impl Pallet { ErasStartSessionIndex::::insert(&new_planned_era, &start_session_index); // Clean old era information. - if let Some(old_era) = new_planned_era.checked_sub(Self::history_depth() + 1) { + if let Some(old_era) = new_planned_era.checked_sub(T::HistoryDepth::get() + 1) { Self::clear_era_information(old_era); } @@ -645,10 +665,10 @@ impl Pallet { #[cfg(feature = "runtime-benchmarks")] pub fn add_era_stakers( current_era: EraIndex, - controller: T::AccountId, + stash: T::AccountId, exposure: Exposure>, ) { - >::insert(¤t_era, &controller, &exposure); + >::insert(¤t_era, &stash, &exposure); } #[cfg(feature = "runtime-benchmarks")] @@ -755,18 +775,32 @@ impl Pallet { /// Get the targets for an upcoming npos election. /// /// This function is self-weighing as [`DispatchClass::Mandatory`]. - pub fn get_npos_targets() -> Vec { - let mut validator_count = 0u32; - let targets = Validators::::iter() - .map(|(v, _)| { - validator_count.saturating_inc(); - v - }) - .collect::>(); + pub fn get_npos_targets(maybe_max_len: Option) -> Vec { + let max_allowed_len = maybe_max_len.unwrap_or_else(|| T::TargetList::count() as usize); + let mut all_targets = Vec::::with_capacity(max_allowed_len); + let mut targets_seen = 0; + + let mut targets_iter = T::TargetList::iter(); + while all_targets.len() < max_allowed_len && + targets_seen < (NPOS_MAX_ITERATIONS_COEFFICIENT * max_allowed_len as u32) + { + let target = match targets_iter.next() { + Some(target) => { + targets_seen.saturating_inc(); + target + }, + None => break, + }; - Self::register_weight(T::WeightInfo::get_npos_targets(validator_count)); + if Validators::::contains_key(&target) { + all_targets.push(target); + } + } - targets + Self::register_weight(T::WeightInfo::get_npos_targets(all_targets.len() as u32)); + log!(info, "generated {} npos targets", all_targets.len()); + + all_targets } /// This function will add a nominator to the `Nominators` storage map, @@ -898,7 +932,7 @@ impl ElectionDataProvider for Pallet { return Err("Target snapshot too big") } - Ok(Self::get_npos_targets()) + Ok(Self::get_npos_targets(None)) } fn next_election_prediction(now: T::BlockNumber) -> T::BlockNumber { @@ -951,7 +985,7 @@ impl ElectionDataProvider for Pallet { active: stake, total: stake, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: Default::default(), }, ); @@ -969,7 +1003,7 @@ impl ElectionDataProvider for Pallet { active: stake, total: stake, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: Default::default(), }, ); Self::do_add_validator( @@ -1010,7 +1044,7 @@ impl ElectionDataProvider for Pallet { active: stake, total: stake, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: Default::default(), }, ); Self::do_add_validator( @@ -1031,7 +1065,7 @@ impl ElectionDataProvider for Pallet { active: stake, total: stake, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: Default::default(), }, ); Self::do_add_nominator( @@ -1281,7 +1315,7 @@ impl ScoreProvider for Pallet { Self::weight_of(who) } - #[cfg(feature = "runtime-benchmarks")] + #[cfg(any(feature = "runtime-benchmarks", feature = "fuzz"))] fn set_score_of(who: &T::AccountId, weight: Self::Score) { // this will clearly results in an inconsistent state, but it should not matter for a // benchmark. @@ -1305,6 +1339,70 @@ impl ScoreProvider for Pallet { } } +/// A simple sorted list implementation that does not require any additional pallets. Note, this +/// does not provide validators in sorted order. If you desire nominators in a sorted order take +/// a look at [`pallet-bags-list`]. +pub struct UseValidatorsMap(sp_std::marker::PhantomData); +impl SortedListProvider for UseValidatorsMap { + type Score = BalanceOf; + type Error = (); + + /// Returns iterator over voter list, which can have `take` called on it. + fn iter() -> Box> { + Box::new(Validators::::iter().map(|(v, _)| v)) + } + fn iter_from( + start: &T::AccountId, + ) -> Result>, Self::Error> { + if Validators::::contains_key(start) { + let start_key = Validators::::hashed_key_for(start); + Ok(Box::new(Validators::::iter_from(start_key).map(|(n, _)| n))) + } else { + Err(()) + } + } + fn count() -> u32 { + Validators::::count() + } + fn contains(id: &T::AccountId) -> bool { + Validators::::contains_key(id) + } + fn on_insert(_: T::AccountId, _weight: Self::Score) -> Result<(), Self::Error> { + // nothing to do on insert. + Ok(()) + } + fn get_score(id: &T::AccountId) -> Result { + Ok(Pallet::::weight_of(id).into()) + } + fn on_update(_: &T::AccountId, _weight: Self::Score) -> Result<(), Self::Error> { + // nothing to do on update. + Ok(()) + } + fn on_remove(_: &T::AccountId) -> Result<(), Self::Error> { + // nothing to do on remove. + Ok(()) + } + fn unsafe_regenerate( + _: impl IntoIterator, + _: Box Self::Score>, + ) -> u32 { + // nothing to do upon regenerate. + 0 + } + fn try_state() -> Result<(), &'static str> { + Ok(()) + } + fn unsafe_clear() { + #[allow(deprecated)] + Validators::::remove_all(); + } + + #[cfg(feature = "runtime-benchmarks")] + fn score_update_worst_case(_who: &T::AccountId, _is_increase: bool) -> Self::Score { + unimplemented!() + } +} + /// A simple voter list implementation that does not require any additional pallets. Note, this /// does not provided nominators in sorted ordered. If you desire nominators in a sorted order take /// a look at [`pallet-bags-list]. @@ -1377,6 +1475,11 @@ impl SortedListProvider for UseNominatorsAndValidatorsM #[allow(deprecated)] Validators::::remove_all(); } + + #[cfg(feature = "runtime-benchmarks")] + fn score_update_worst_case(_who: &T::AccountId, _is_increase: bool) -> Self::Score { + unimplemented!() + } } impl StakingInterface for Pallet { @@ -1449,9 +1552,14 @@ impl StakingInterface for Pallet { } } -#[cfg(feature = "try-runtime")] +#[cfg(any(test, feature = "try-runtime"))] impl Pallet { pub(crate) fn do_try_state(_: BlockNumberFor) -> Result<(), &'static str> { + ensure!( + T::VoterList::iter() + .all(|x| >::contains_key(&x) || >::contains_key(&x)), + "VoterList contains non-nominators" + ); T::VoterList::try_state()?; Self::check_nominators()?; Self::check_exposures()?; diff --git a/frame/staking/src/pallet/mod.rs b/frame/staking/src/pallet/mod.rs index 74374cc586a23..560c3b6ed830c 100644 --- a/frame/staking/src/pallet/mod.rs +++ b/frame/staking/src/pallet/mod.rs @@ -22,10 +22,12 @@ use frame_support::{ dispatch::Codec, pallet_prelude::*, traits::{ - Currency, CurrencyToVote, Defensive, DefensiveSaturating, EnsureOrigin, - EstimateNextNewSession, Get, LockIdentifier, LockableCurrency, OnUnbalanced, UnixTime, + Currency, CurrencyToVote, Defensive, DefensiveResult, DefensiveSaturating, EnsureOrigin, + EstimateNextNewSession, Get, LockIdentifier, LockableCurrency, OnUnbalanced, TryCollect, + UnixTime, }, weights::Weight, + BoundedVec, }; use frame_system::{ensure_root, ensure_signed, pallet_prelude::*}; use sp_runtime::{ @@ -33,7 +35,7 @@ use sp_runtime::{ Perbill, Percent, }; use sp_staking::{EraIndex, SessionIndex}; -use sp_std::{cmp::max, prelude::*}; +use sp_std::prelude::*; mod impls; @@ -41,9 +43,9 @@ pub use impls::*; use crate::{ slashing, weights::WeightInfo, AccountIdLookupOf, ActiveEraInfo, BalanceOf, EraPayout, - EraRewardPoints, Exposure, Forcing, MaxUnlockingChunks, NegativeImbalanceOf, Nominations, - PositiveImbalanceOf, Releases, RewardDestination, SessionInterface, StakingLedger, - UnappliedSlash, UnlockChunk, ValidatorPrefs, + EraRewardPoints, Exposure, Forcing, NegativeImbalanceOf, Nominations, PositiveImbalanceOf, + Releases, RewardDestination, SessionInterface, StakingLedger, UnappliedSlash, UnlockChunk, + ValidatorPrefs, }; const STAKING_ID: LockIdentifier = *b"staking "; @@ -58,7 +60,6 @@ pub mod pallet { #[pallet::pallet] #[pallet::generate_store(pub(crate) trait Store)] - #[pallet::without_storage_info] pub struct Pallet(_); /// Possible operations on the configuration values of this pallet. @@ -124,12 +125,35 @@ pub mod pallet { #[pallet::constant] type MaxNominations: Get; + /// Number of eras to keep in history. + /// + /// Following information is kept for eras in `[current_era - + /// HistoryDepth, current_era]`: `ErasStakers`, `ErasStakersClipped`, + /// `ErasValidatorPrefs`, `ErasValidatorReward`, `ErasRewardPoints`, + /// `ErasTotalStake`, `ErasStartSessionIndex`, + /// `StakingLedger.claimed_rewards`. + /// + /// Must be more than the number of eras delayed by session. + /// I.e. active era must always be in history. I.e. `active_era > + /// current_era - history_depth` must be guaranteed. + /// + /// If migrating an existing pallet from storage value to config value, + /// this should be set to same value or greater as in storage. + /// + /// Note: `HistoryDepth` is used as the upper bound for the `BoundedVec` + /// item `StakingLedger.claimed_rewards`. Setting this value lower than + /// the existing value can lead to inconsistencies in the + /// `StakingLedger` and will need to be handled properly in a migration. + /// The test `reducing_history_depth_abrupt` shows this effect. + #[pallet::constant] + type HistoryDepth: Get; + /// Tokens have been minted and are unused for validator-reward. /// See [Era payout](./index.html#era-payout). type RewardRemainder: OnUnbalanced>; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Handler for the unbalanced reduction when slashing a staker. type Slash: OnUnbalanced>; @@ -155,7 +179,7 @@ pub mod pallet { type SlashDeferDuration: Get; /// The origin which can cancel a deferred slash. Root can always do this. - type SlashCancelOrigin: EnsureOrigin; + type SlashCancelOrigin: EnsureOrigin; /// Interface for interacting with a session pallet. type SessionInterface: SessionInterface; @@ -184,10 +208,46 @@ pub mod pallet { /// /// The changes to nominators are reported to this. Moreover, each validator's self-vote is /// also reported as one independent vote. + /// + /// To keep the load off the chain as much as possible, changes made to the staked amount + /// via rewards and slashes are not reported and thus need to be manually fixed by the + /// staker. In case of `bags-list`, this always means using `rebag` and `putInFrontOf`. + /// + /// Invariant: what comes out of this list will always be a nominator. type VoterList: SortedListProvider; - /// The maximum number of `unlocking` chunks a [`StakingLedger`] can have. Effectively - /// determines how many unique eras a staker may be unbonding in. + /// WIP: This is a noop as of now, the actual business logic that's described below is going + /// to be introduced in a follow-up PR. + /// + /// Something that provides a best-effort sorted list of targets aka electable validators, + /// used for NPoS election. + /// + /// The changes to the approval stake of each validator are reported to this. This means any + /// change to: + /// 1. The stake of any validator or nominator. + /// 2. The targets of any nominator + /// 3. The role of any staker (e.g. validator -> chilled, nominator -> validator, etc) + /// + /// Unlike `VoterList`, the values in this list are always kept up to date with reward and + /// slash as well, and thus represent the accurate approval stake of all account being + /// nominated by nominators. + /// + /// Note that while at the time of nomination, all targets are checked to be real + /// validators, they can chill at any point, and their approval stakes will still be + /// recorded. This implies that what comes out of iterating this list MIGHT NOT BE AN ACTIVE + /// VALIDATOR. + type TargetList: SortedListProvider>; + + /// The maximum number of `unlocking` chunks a [`StakingLedger`] can + /// have. Effectively determines how many unique eras a staker may be + /// unbonding in. + /// + /// Note: `MaxUnlockingChunks` is used as the upper bound for the + /// `BoundedVec` item `StakingLedger.unlocking`. Setting this value + /// lower than the existing value can lead to inconsistencies in the + /// `StakingLedger` and will need to be handled properly in a runtime + /// migration. The test `reducing_max_unlocking_chunks_abrupt` shows + /// this effect. #[pallet::constant] type MaxUnlockingChunks: Get; @@ -202,22 +262,6 @@ pub mod pallet { type WeightInfo: WeightInfo; } - #[pallet::type_value] - pub(crate) fn HistoryDepthOnEmpty() -> u32 { - 84u32 - } - - /// Number of eras to keep in history. - /// - /// Information is kept for eras in `[current_era - history_depth; current_era]`. - /// - /// Must be more than the number of eras delayed by session otherwise. I.e. active era must - /// always be in history. I.e. `active_era > current_era - history_depth` must be - /// guaranteed. - #[pallet::storage] - #[pallet::getter(fn history_depth)] - pub(crate) type HistoryDepth = StorageValue<_, u32, ValueQuery, HistoryDepthOnEmpty>; - /// The ideal number of staking participants. #[pallet::storage] #[pallet::getter(fn validator_count)] @@ -233,6 +277,7 @@ pub mod pallet { /// invulnerables) and restricted to testnets. #[pallet::storage] #[pallet::getter(fn invulnerables)] + #[pallet::unbounded] pub type Invulnerables = StorageValue<_, Vec, ValueQuery>; /// Map from all locked "stash" accounts to the controller account. @@ -336,6 +381,7 @@ pub mod pallet { /// If stakers hasn't been set or has been removed then empty exposure is returned. #[pallet::storage] #[pallet::getter(fn eras_stakers)] + #[pallet::unbounded] pub type ErasStakers = StorageDoubleMap< _, Twox64Concat, @@ -358,6 +404,7 @@ pub mod pallet { /// Is it removed after `HISTORY_DEPTH` eras. /// If stakers hasn't been set or has been removed then empty exposure is returned. #[pallet::storage] + #[pallet::unbounded] #[pallet::getter(fn eras_stakers_clipped)] pub type ErasStakersClipped = StorageDoubleMap< _, @@ -397,6 +444,7 @@ pub mod pallet { /// Rewards for the last `HISTORY_DEPTH` eras. /// If reward hasn't been set or has been removed then 0 reward is returned. #[pallet::storage] + #[pallet::unbounded] #[pallet::getter(fn eras_reward_points)] pub type ErasRewardPoints = StorageMap<_, Twox64Concat, EraIndex, EraRewardPoints, ValueQuery>; @@ -428,6 +476,7 @@ pub mod pallet { /// All unapplied slashes that are queued for later. #[pallet::storage] + #[pallet::unbounded] pub type UnappliedSlashes = StorageMap< _, Twox64Concat, @@ -441,6 +490,7 @@ pub mod pallet { /// Must contains information for eras for the range: /// `[active_era - bounding_duration; active_era]` #[pallet::storage] + #[pallet::unbounded] pub(crate) type BondedEras = StorageValue<_, Vec<(EraIndex, SessionIndex)>, ValueQuery>; @@ -463,6 +513,8 @@ pub mod pallet { /// Slashing spans for stash accounts. #[pallet::storage] + #[pallet::getter(fn slashing_spans)] + #[pallet::unbounded] pub(crate) type SlashingSpans = StorageMap<_, Twox64Concat, T::AccountId, slashing::SlashingSpans>; @@ -494,6 +546,7 @@ pub mod pallet { /// whether a given validator has previously offended using binary search. It gets cleared when /// the era ends. #[pallet::storage] + #[pallet::unbounded] #[pallet::getter(fn offending_validators)] pub type OffendingValidators = StorageValue<_, Vec<(u32, bool)>, ValueQuery>; @@ -512,7 +565,6 @@ pub mod pallet { #[pallet::genesis_config] pub struct GenesisConfig { - pub history_depth: u32, pub validator_count: u32, pub minimum_validator_count: u32, pub invulnerables: Vec, @@ -531,7 +583,6 @@ pub mod pallet { impl Default for GenesisConfig { fn default() -> Self { GenesisConfig { - history_depth: 84u32, validator_count: Default::default(), minimum_validator_count: Default::default(), invulnerables: Default::default(), @@ -550,7 +601,6 @@ pub mod pallet { #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { - HistoryDepth::::put(self.history_depth); ValidatorCount::::put(self.validator_count); MinimumValidatorCount::::put(self.minimum_validator_count); Invulnerables::::put(&self.invulnerables); @@ -580,18 +630,18 @@ pub mod pallet { "Stash does not have enough balance to bond." ); frame_support::assert_ok!(>::bond( - T::Origin::from(Some(stash.clone()).into()), + T::RuntimeOrigin::from(Some(stash.clone()).into()), T::Lookup::unlookup(controller.clone()), balance, RewardDestination::Staked, )); frame_support::assert_ok!(match status { crate::StakerStatus::Validator => >::validate( - T::Origin::from(Some(controller.clone()).into()), + T::RuntimeOrigin::from(Some(controller.clone()).into()), Default::default(), ), crate::StakerStatus::Nominator(votes) => >::nominate( - T::Origin::from(Some(controller.clone()).into()), + T::RuntimeOrigin::from(Some(controller.clone()).into()), votes.iter().map(|l| T::Lookup::unlookup(l.clone())).collect(), ), _ => Ok(()), @@ -612,39 +662,36 @@ pub mod pallet { pub enum Event { /// The era payout has been set; the first balance is the validator-payout; the second is /// the remainder from the maximum amount of reward. - /// \[era_index, validator_payout, remainder\] - EraPaid(EraIndex, BalanceOf, BalanceOf), - /// The nominator has been rewarded by this amount. \[stash, amount\] - Rewarded(T::AccountId, BalanceOf), - /// One validator (and its nominators) has been slashed by the given amount. - /// \[validator, amount\] - Slashed(T::AccountId, BalanceOf), + EraPaid { era_index: EraIndex, validator_payout: BalanceOf, remainder: BalanceOf }, + /// The nominator has been rewarded by this amount. + Rewarded { stash: T::AccountId, amount: BalanceOf }, + /// One staker (and potentially its nominators) has been slashed by the given amount. + Slashed { staker: T::AccountId, amount: BalanceOf }, /// An old slashing report from a prior era was discarded because it could - /// not be processed. \[session_index\] - OldSlashingReportDiscarded(SessionIndex), + /// not be processed. + OldSlashingReportDiscarded { session_index: SessionIndex }, /// A new set of stakers was elected. StakersElected, /// An account has bonded this amount. \[stash, amount\] /// /// NOTE: This event is only emitted when funds are bonded via a dispatchable. Notably, /// it will not be emitted for staking rewards when they are added to stake. - Bonded(T::AccountId, BalanceOf), - /// An account has unbonded this amount. \[stash, amount\] - Unbonded(T::AccountId, BalanceOf), + Bonded { stash: T::AccountId, amount: BalanceOf }, + /// An account has unbonded this amount. + Unbonded { stash: T::AccountId, amount: BalanceOf }, /// An account has called `withdraw_unbonded` and removed unbonding chunks worth `Balance` - /// from the unlocking queue. \[stash, amount\] - Withdrawn(T::AccountId, BalanceOf), - /// A nominator has been kicked from a validator. \[nominator, stash\] - Kicked(T::AccountId, T::AccountId), + /// from the unlocking queue. + Withdrawn { stash: T::AccountId, amount: BalanceOf }, + /// A nominator has been kicked from a validator. + Kicked { nominator: T::AccountId, stash: T::AccountId }, /// The election failed. No new era is planned. StakingElectionFailed, /// An account has stopped participating as either a validator or nominator. - /// \[stash\] - Chilled(T::AccountId), - /// The stakers' rewards are getting paid. \[era_index, validator_stash\] - PayoutStarted(EraIndex, T::AccountId), + Chilled { stash: T::AccountId }, + /// The stakers' rewards are getting paid. + PayoutStarted { era_index: EraIndex, validator_stash: T::AccountId }, /// A validator has set their preferences. - ValidatorPrefsSet(T::AccountId, ValidatorPrefs), + ValidatorPrefsSet { stash: T::AccountId, prefs: ValidatorPrefs }, } #[pallet::error] @@ -701,6 +748,8 @@ pub mod pallet { TooManyValidators, /// Commission is too low. Must be at least `MinCommission`. CommissionTooLow, + /// Some bound is not met. + BoundNotMet, } #[pallet::hooks] @@ -802,18 +851,23 @@ pub mod pallet { >::insert(&stash, payee); let current_era = CurrentEra::::get().unwrap_or(0); - let history_depth = Self::history_depth(); + let history_depth = T::HistoryDepth::get(); let last_reward_era = current_era.saturating_sub(history_depth); let stash_balance = T::Currency::free_balance(&stash); let value = value.min(stash_balance); - Self::deposit_event(Event::::Bonded(stash.clone(), value)); + Self::deposit_event(Event::::Bonded { stash: stash.clone(), amount: value }); let item = StakingLedger { stash, total: value, active: value, unlocking: Default::default(), - claimed_rewards: (last_reward_era..current_era).collect(), + claimed_rewards: (last_reward_era..current_era) + .try_collect() + // Since last_reward_era is calculated as `current_era - + // HistoryDepth`, following bound is always expected to be + // satisfied. + .defensive_map_err(|_| Error::::BoundNotMet)?, }; Self::update_ledger(&controller, &item); Ok(()) @@ -863,7 +917,7 @@ pub mod pallet { T::VoterList::on_update(&stash, Self::weight_of(&ledger.stash)).defensive(); } - Self::deposit_event(Event::::Bonded(stash, extra)); + Self::deposit_event(Event::::Bonded { stash, amount: extra }); } Ok(()) } @@ -895,7 +949,7 @@ pub mod pallet { let controller = ensure_signed(origin)?; let mut ledger = Self::ledger(&controller).ok_or(Error::::NotController)?; ensure!( - ledger.unlocking.len() < MaxUnlockingChunks::get() as usize, + ledger.unlocking.len() < T::MaxUnlockingChunks::get() as usize, Error::::NoMoreChunks, ); @@ -946,7 +1000,7 @@ pub mod pallet { .defensive(); } - Self::deposit_event(Event::::Unbonded(ledger.stash, value)); + Self::deposit_event(Event::::Unbonded { stash: ledger.stash, amount: value }); } Ok(()) } @@ -1002,7 +1056,7 @@ pub mod pallet { if ledger.total < old_total { // Already checked that this won't overflow by entry condition. let value = old_total - ledger.total; - Self::deposit_event(Event::::Withdrawn(stash, value)); + Self::deposit_event(Event::::Withdrawn { stash, amount: value }); } Ok(post_info_weight.into()) @@ -1040,7 +1094,7 @@ pub mod pallet { Self::do_remove_nominator(stash); Self::do_add_validator(stash, prefs.clone()); - Self::deposit_event(Event::::ValidatorPrefsSet(ledger.stash, prefs)); + Self::deposit_event(Event::::ValidatorPrefsSet { stash: ledger.stash, prefs }); Ok(()) } @@ -1409,7 +1463,7 @@ pub mod pallet { /// - Bounded by `MaxUnlockingChunks`. /// - Storage changes: Can't increase storage, only decrease it. /// # - #[pallet::weight(T::WeightInfo::rebond(MaxUnlockingChunks::get() as u32))] + #[pallet::weight(T::WeightInfo::rebond(T::MaxUnlockingChunks::get() as u32))] pub fn rebond( origin: OriginFor, #[pallet::compact] value: BalanceOf, @@ -1423,7 +1477,10 @@ pub mod pallet { // Last check: the new active amount of ledger must be more than ED. ensure!(ledger.active >= T::Currency::minimum_balance(), Error::::InsufficientBond); - Self::deposit_event(Event::::Bonded(ledger.stash.clone(), rebonded_value)); + Self::deposit_event(Event::::Bonded { + stash: ledger.stash.clone(), + amount: rebonded_value, + }); // NOTE: ledger must be updated prior to calling `Self::weight_of`. Self::update_ledger(&controller, &ledger); @@ -1438,48 +1495,6 @@ pub mod pallet { Ok(Some(T::WeightInfo::rebond(removed_chunks)).into()) } - /// Set `HistoryDepth` value. This function will delete any history information - /// when `HistoryDepth` is reduced. - /// - /// Parameters: - /// - `new_history_depth`: The new history depth you would like to set. - /// - `era_items_deleted`: The number of items that will be deleted by this dispatch. This - /// should report all the storage items that will be deleted by clearing old era history. - /// Needed to report an accurate weight for the dispatch. Trusted by `Root` to report an - /// accurate number. - /// - /// Origin must be root. - /// - /// # - /// - E: Number of history depths removed, i.e. 10 -> 7 = 3 - /// - Weight: O(E) - /// - DB Weight: - /// - Reads: Current Era, History Depth - /// - Writes: History Depth - /// - Clear Prefix Each: Era Stakers, EraStakersClipped, ErasValidatorPrefs - /// - Writes Each: ErasValidatorReward, ErasRewardPoints, ErasTotalStake, - /// ErasStartSessionIndex - /// # - #[pallet::weight(T::WeightInfo::set_history_depth(*_era_items_deleted))] - pub fn set_history_depth( - origin: OriginFor, - #[pallet::compact] new_history_depth: EraIndex, - #[pallet::compact] _era_items_deleted: u32, - ) -> DispatchResult { - ensure_root(origin)?; - if let Some(current_era) = Self::current_era() { - HistoryDepth::::mutate(|history_depth| { - let last_kept = current_era.saturating_sub(*history_depth); - let new_last_kept = current_era.saturating_sub(new_history_depth); - for era_index in last_kept..new_last_kept { - Self::clear_era_information(era_index); - } - *history_depth = new_history_depth - }) - } - Ok(()) - } - /// Remove all data structures concerning a staker/stash once it is at a state where it can /// be considered `dust` in the staking system. The requirements are: /// @@ -1540,10 +1555,10 @@ pub mod pallet { if let Some(ref mut nom) = maybe_nom { if let Some(pos) = nom.targets.iter().position(|v| v == stash) { nom.targets.swap_remove(pos); - Self::deposit_event(Event::::Kicked( - nom_stash.clone(), - stash.clone(), - )); + Self::deposit_event(Event::::Kicked { + nominator: nom_stash.clone(), + stash: stash.clone(), + }); } } }); @@ -1565,16 +1580,16 @@ pub mod pallet { /// * `min_commission`: The minimum amount of commission that each validators must maintain. /// This is checked only upon calling `validate`. Existing validators are not affected. /// - /// Origin must be Root to call this function. + /// RuntimeOrigin must be Root to call this function. /// /// NOTE: Existing nominators and validators will not be affected by this update. /// to kick people under the new limits, `chill_other` should be called. // We assume the worst case for this call is either: all items are set or all items are // removed. - #[pallet::weight(max( - T::WeightInfo::set_staking_configs_all_set(), - T::WeightInfo::set_staking_configs_all_remove() - ))] + #[pallet::weight( + T::WeightInfo::set_staking_configs_all_set() + .max(T::WeightInfo::set_staking_configs_all_remove()) + )] pub fn set_staking_configs( origin: OriginFor, min_nominator_bond: ConfigOp>, diff --git a/frame/staking/src/slashing.rs b/frame/staking/src/slashing.rs index 7372c4390f816..a1900136d64fd 100644 --- a/frame/staking/src/slashing.rs +++ b/frame/staking/src/slashing.rs @@ -53,7 +53,7 @@ use crate::{ BalanceOf, Config, Error, Exposure, NegativeImbalanceOf, Pallet, Perbill, SessionInterface, Store, UnappliedSlash, }; -use codec::{Decode, Encode}; +use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{ ensure, traits::{Currency, Defensive, Get, Imbalance, OnUnbalanced}, @@ -182,7 +182,7 @@ impl SlashingSpans { } /// A slashing-span record for a particular stash. -#[derive(Encode, Decode, Default, TypeInfo)] +#[derive(Encode, Decode, Default, TypeInfo, MaxEncodedLen)] pub(crate) struct SpanRecord { slashed: Balance, paid_out: Balance, @@ -626,7 +626,10 @@ pub fn do_slash( >::update_ledger(&controller, &ledger); // trigger the event - >::deposit_event(super::Event::::Slashed(stash.clone(), value)); + >::deposit_event(super::Event::::Slashed { + staker: stash.clone(), + amount: value, + }); } } diff --git a/frame/staking/src/tests.rs b/frame/staking/src/tests.rs index 0d00f5a5e61df..4812c105c0d80 100644 --- a/frame/staking/src/tests.rs +++ b/frame/staking/src/tests.rs @@ -17,14 +17,13 @@ //! Tests for the module. -use super::{ConfigOp, Event, MaxUnlockingChunks, *}; +use super::{ConfigOp, Event, *}; use frame_election_provider_support::{ElectionProvider, SortedListProvider, Support}; use frame_support::{ assert_noop, assert_ok, assert_storage_noop, bounded_vec, - dispatch::WithPostDispatchInfo, + dispatch::{extract_actual_weight, GetDispatchInfo, WithPostDispatchInfo}, pallet_prelude::*, traits::{Currency, Get, ReservableCurrency}, - weights::{extract_actual_weight, GetDispatchInfo}, }; use mock::*; use pallet_balances::Error as BalancesError; @@ -45,7 +44,7 @@ fn set_staking_configs_works() { ExtBuilder::default().build_and_execute(|| { // setting works assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Set(1_500), ConfigOp::Set(2_000), ConfigOp::Set(10), @@ -62,7 +61,7 @@ fn set_staking_configs_works() { // noop does nothing assert_storage_noop!(assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Noop, @@ -73,7 +72,7 @@ fn set_staking_configs_works() { // removing works assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Remove, ConfigOp::Remove, ConfigOp::Remove, @@ -99,22 +98,22 @@ fn force_unstake_works() { add_slash(&11); // Cant transfer assert_noop!( - Balances::transfer(Origin::signed(11), 1, 10), + Balances::transfer(RuntimeOrigin::signed(11), 1, 10), BalancesError::::LiquidityRestrictions ); // Force unstake requires root. - assert_noop!(Staking::force_unstake(Origin::signed(11), 11, 2), BadOrigin); + assert_noop!(Staking::force_unstake(RuntimeOrigin::signed(11), 11, 2), BadOrigin); // Force unstake needs correct number of slashing spans (for weight calculation) assert_noop!( - Staking::force_unstake(Origin::root(), 11, 0), + Staking::force_unstake(RuntimeOrigin::root(), 11, 0), Error::::IncorrectSlashingSpans ); // We now force them to unstake - assert_ok!(Staking::force_unstake(Origin::root(), 11, 2)); + assert_ok!(Staking::force_unstake(RuntimeOrigin::root(), 11, 2)); // No longer bonded. assert_eq!(Staking::bonded(&11), None); // Transfer works. - assert_ok!(Balances::transfer(Origin::signed(11), 1, 10)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(11), 1, 10)); }); } @@ -149,14 +148,14 @@ fn basic_setup_works() { // Account 10 controls the stash from account 11, which is 100 * balance_factor units assert_eq!( - Staking::ledger(&10), - Some(StakingLedger { + Staking::ledger(&10).unwrap(), + StakingLedger { stash: 11, total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![] - }) + claimed_rewards: bounded_vec![], + } ); // Account 20 controls the stash from account 21, which is 200 * balance_factor units assert_eq!( @@ -166,7 +165,7 @@ fn basic_setup_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], }) ); // Account 1 does not control any stash @@ -189,7 +188,7 @@ fn basic_setup_works() { total: 500, active: 500, unlocking: Default::default(), - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], }) ); assert_eq!(Staking::nominators(101).unwrap().targets, vec![11, 21]); @@ -236,19 +235,19 @@ fn change_controller_works() { assert_eq!(Staking::bonded(&11), Some(10)); // 10 can control 11 who is initially a validator. - assert_ok!(Staking::chill(Origin::signed(10))); + assert_ok!(Staking::chill(RuntimeOrigin::signed(10))); // change controller - assert_ok!(Staking::set_controller(Origin::signed(11), 5)); + assert_ok!(Staking::set_controller(RuntimeOrigin::signed(11), 5)); assert_eq!(Staking::bonded(&11), Some(5)); mock::start_active_era(1); // 10 is no longer in control. assert_noop!( - Staking::validate(Origin::signed(10), ValidatorPrefs::default()), + Staking::validate(RuntimeOrigin::signed(10), ValidatorPrefs::default()), Error::::NotController, ); - assert_ok!(Staking::validate(Origin::signed(5), ValidatorPrefs::default())); + assert_ok!(Staking::validate(RuntimeOrigin::signed(5), ValidatorPrefs::default())); }) } @@ -301,13 +300,14 @@ fn rewards_should_work() { start_session(3); assert_eq!(active_era(), 1); - assert_eq!( - mock::REWARD_REMAINDER_UNBALANCED.with(|v| *v.borrow()), - maximum_payout - total_payout_0, - ); + assert_eq!(mock::RewardRemainderUnbalanced::get(), maximum_payout - total_payout_0,); assert_eq!( *mock::staking_events().last().unwrap(), - Event::EraPaid(0, total_payout_0, maximum_payout - total_payout_0) + Event::EraPaid { + era_index: 0, + validator_payout: total_payout_0, + remainder: maximum_payout - total_payout_0 + } ); mock::make_all_reward_payment(0); @@ -340,12 +340,16 @@ fn rewards_should_work() { mock::start_active_era(2); assert_eq!( - mock::REWARD_REMAINDER_UNBALANCED.with(|v| *v.borrow()), + mock::RewardRemainderUnbalanced::get(), maximum_payout * 2 - total_payout_0 - total_payout_1, ); assert_eq!( *mock::staking_events().last().unwrap(), - Event::EraPaid(1, total_payout_1, maximum_payout - total_payout_1) + Event::EraPaid { + era_index: 1, + validator_payout: total_payout_1, + remainder: maximum_payout - total_payout_1 + } ); mock::make_all_reward_payment(1); @@ -386,9 +390,13 @@ fn staking_should_work() { // --- Block 2: start_session(2); // add a new candidate for being a validator. account 3 controlled by 4. - assert_ok!(Staking::bond(Origin::signed(3), 4, 1500, RewardDestination::Controller)); - assert_ok!(Staking::validate(Origin::signed(4), ValidatorPrefs::default())); - assert_ok!(Session::set_keys(Origin::signed(4), SessionKeys { other: 4.into() }, vec![])); + assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 4, 1500, RewardDestination::Controller)); + assert_ok!(Staking::validate(RuntimeOrigin::signed(4), ValidatorPrefs::default())); + assert_ok!(Session::set_keys( + RuntimeOrigin::signed(4), + SessionKeys { other: 4.into() }, + vec![] + )); // No effects will be seen so far. assert_eq_uvec!(validator_controllers(), vec![20, 10]); @@ -412,7 +420,7 @@ fn staking_should_work() { assert_eq_uvec!(validator_controllers(), vec![20, 4]); // --- Block 6: Unstake 4 as a validator, freeing up the balance stashed in 3 // 4 will chill - Staking::chill(Origin::signed(4)).unwrap(); + Staking::chill(RuntimeOrigin::signed(4)).unwrap(); // --- Block 7: nothing. 4 is still there. start_session(7); @@ -433,7 +441,7 @@ fn staking_should_work() { total: 1500, active: 1500, unlocking: Default::default(), - claimed_rewards: vec![0], + claimed_rewards: bounded_vec![0], }) ); // e.g. it cannot reserve more than 500 that it has free from the total 2000 @@ -451,20 +459,20 @@ fn blocking_and_kicking_works() { .build_and_execute(|| { // block validator 10/11 assert_ok!(Staking::validate( - Origin::signed(10), + RuntimeOrigin::signed(10), ValidatorPrefs { blocked: true, ..Default::default() } )); // attempt to nominate from 100/101... - assert_ok!(Staking::nominate(Origin::signed(100), vec![11])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(100), vec![11])); // should have worked since we're already nominated them assert_eq!(Nominators::::get(&101).unwrap().targets, vec![11]); // kick the nominator - assert_ok!(Staking::kick(Origin::signed(10), vec![101])); + assert_ok!(Staking::kick(RuntimeOrigin::signed(10), vec![101])); // should have been kicked now assert!(Nominators::::get(&101).unwrap().targets.is_empty()); // attempt to nominate from 100/101... assert_noop!( - Staking::nominate(Origin::signed(100), vec![11]), + Staking::nominate(RuntimeOrigin::signed(100), vec![11]), Error::::BadTarget ); }); @@ -510,7 +518,7 @@ fn no_candidate_emergency_condition() { ::MinimumValidatorCount::put(10); // try to chill - let res = Staking::chill(Origin::signed(10)); + let res = Staking::chill(RuntimeOrigin::signed(10)); assert_ok!(res); let current_era = CurrentEra::::get(); @@ -546,14 +554,26 @@ fn nominating_and_rewards_should_work() { assert_eq_uvec!(validator_controllers(), vec![40, 20]); // re-validate with 11 and 31. - assert_ok!(Staking::validate(Origin::signed(10), Default::default())); - assert_ok!(Staking::validate(Origin::signed(30), Default::default())); + assert_ok!(Staking::validate(RuntimeOrigin::signed(10), Default::default())); + assert_ok!(Staking::validate(RuntimeOrigin::signed(30), Default::default())); // Set payee to controller. - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); - assert_ok!(Staking::set_payee(Origin::signed(20), RewardDestination::Controller)); - assert_ok!(Staking::set_payee(Origin::signed(30), RewardDestination::Controller)); - assert_ok!(Staking::set_payee(Origin::signed(40), RewardDestination::Controller)); + assert_ok!(Staking::set_payee( + RuntimeOrigin::signed(10), + RewardDestination::Controller + )); + assert_ok!(Staking::set_payee( + RuntimeOrigin::signed(20), + RewardDestination::Controller + )); + assert_ok!(Staking::set_payee( + RuntimeOrigin::signed(30), + RewardDestination::Controller + )); + assert_ok!(Staking::set_payee( + RuntimeOrigin::signed(40), + RewardDestination::Controller + )); // give the man some money let initial_balance = 1000; @@ -562,11 +582,21 @@ fn nominating_and_rewards_should_work() { } // bond two account pairs and state interest in nomination. - assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 21, 31])); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(1), + 2, + 1000, + RewardDestination::Controller + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(2), vec![11, 21, 31])); - assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(4), vec![11, 21, 41])); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(3), + 4, + 1000, + RewardDestination::Controller + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![11, 21, 41])); // the total reward for era 0 let total_payout_0 = current_total_payout_for_duration(reward_time_per_era()); @@ -718,20 +748,28 @@ fn double_staking_should_fail() { let arbitrary_value = 5; // 2 = controller, 1 stashed => ok assert_ok!(Staking::bond( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, arbitrary_value, RewardDestination::default() )); // 4 = not used so far, 1 stashed => not allowed. assert_noop!( - Staking::bond(Origin::signed(1), 4, arbitrary_value, RewardDestination::default()), + Staking::bond( + RuntimeOrigin::signed(1), + 4, + arbitrary_value, + RewardDestination::default() + ), Error::::AlreadyBonded, ); // 1 = stashed => attempting to nominate should fail. - assert_noop!(Staking::nominate(Origin::signed(1), vec![1]), Error::::NotController); + assert_noop!( + Staking::nominate(RuntimeOrigin::signed(1), vec![1]), + Error::::NotController + ); // 2 = controller => nominating should work. - assert_ok!(Staking::nominate(Origin::signed(2), vec![1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(2), vec![1])); }); } @@ -744,14 +782,19 @@ fn double_controlling_should_fail() { let arbitrary_value = 5; // 2 = controller, 1 stashed => ok assert_ok!(Staking::bond( - Origin::signed(1), + RuntimeOrigin::signed(1), 2, arbitrary_value, RewardDestination::default(), )); // 2 = controller, 3 stashed (Note that 2 is reused.) => no-op assert_noop!( - Staking::bond(Origin::signed(3), 2, arbitrary_value, RewardDestination::default()), + Staking::bond( + RuntimeOrigin::signed(3), + 2, + arbitrary_value, + RewardDestination::default() + ), Error::::AlreadyPaired, ); }); @@ -917,14 +960,14 @@ fn cannot_transfer_staked_balance() { assert_eq!(Staking::eras_stakers(active_era(), 11).total, 1000); // Confirm account 11 cannot transfer as a result assert_noop!( - Balances::transfer(Origin::signed(11), 20, 1), + Balances::transfer(RuntimeOrigin::signed(11), 20, 1), BalancesError::::LiquidityRestrictions ); // Give account 11 extra free balance let _ = Balances::make_free_balance_be(&11, 10000); // Confirm that account 11 can now transfer some balance - assert_ok!(Balances::transfer(Origin::signed(11), 20, 1)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(11), 20, 1)); }); } @@ -942,10 +985,10 @@ fn cannot_transfer_staked_balance_2() { assert_eq!(Staking::eras_stakers(active_era(), 21).total, 1000); // Confirm account 21 can transfer at most 1000 assert_noop!( - Balances::transfer(Origin::signed(21), 20, 1001), + Balances::transfer(RuntimeOrigin::signed(21), 20, 1001), BalancesError::::LiquidityRestrictions ); - assert_ok!(Balances::transfer(Origin::signed(21), 20, 1000)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(21), 20, 1000)); }); } @@ -987,7 +1030,7 @@ fn reward_destination_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1010,7 +1053,7 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), - claimed_rewards: vec![0], + claimed_rewards: bounded_vec![0], }) ); @@ -1038,7 +1081,7 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), - claimed_rewards: vec![0, 1], + claimed_rewards: bounded_vec![0, 1], }) ); @@ -1067,7 +1110,7 @@ fn reward_destination_works() { total: 1000 + total_payout_0, active: 1000 + total_payout_0, unlocking: Default::default(), - claimed_rewards: vec![0, 1, 2], + claimed_rewards: bounded_vec![0, 1, 2], }) ); // Check that amount in staked account is NOT increased. @@ -1129,7 +1172,7 @@ fn bond_extra_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1137,7 +1180,7 @@ fn bond_extra_works() { let _ = Balances::make_free_balance_be(&11, 1000000); // Call the bond_extra function from controller, add only 100 - assert_ok!(Staking::bond_extra(Origin::signed(11), 100)); + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), 100)); // There should be 100 more `total` and `active` in the ledger assert_eq!( Staking::ledger(&10), @@ -1146,12 +1189,12 @@ fn bond_extra_works() { total: 1000 + 100, active: 1000 + 100, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); // Call the bond_extra function with a large number, should handle it - assert_ok!(Staking::bond_extra(Origin::signed(11), Balance::max_value())); + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(11), Balance::max_value())); // The full amount of the funds should now be in the total and active assert_eq!( Staking::ledger(&10), @@ -1160,7 +1203,7 @@ fn bond_extra_works() { total: 1000000, active: 1000000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); }); @@ -1176,7 +1219,7 @@ fn bond_extra_and_withdraw_unbonded_works() { // * Once the unbonding period is done, it can actually take the funds out of the stash. ExtBuilder::default().nominate(false).build_and_execute(|| { // Set payee to controller. avoids confusion - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(10), RewardDestination::Controller)); // Give account 11 some large free balance greater than total let _ = Balances::make_free_balance_be(&11, 1000000); @@ -1198,7 +1241,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); assert_eq!( @@ -1207,7 +1250,7 @@ fn bond_extra_and_withdraw_unbonded_works() { ); // deposit the extra 100 units - Staking::bond_extra(Origin::signed(11), 100).unwrap(); + Staking::bond_extra(RuntimeOrigin::signed(11), 100).unwrap(); assert_eq!( Staking::ledger(&10), @@ -1216,7 +1259,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 1000 + 100, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); // Exposure is a snapshot! only updated after the next era update. @@ -1237,7 +1280,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 1000 + 100, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); // Exposure is now updated. @@ -1247,7 +1290,7 @@ fn bond_extra_and_withdraw_unbonded_works() { ); // Unbond almost all of the funds in stash. - Staking::unbond(Origin::signed(10), 1000).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 1000).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1255,12 +1298,12 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 100, unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], }), ); // Attempting to free the balances now will fail. 2 eras need to pass. - assert_ok!(Staking::withdraw_unbonded(Origin::signed(10), 0)); + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(10), 0)); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1268,7 +1311,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 100, unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], }), ); @@ -1276,7 +1319,7 @@ fn bond_extra_and_withdraw_unbonded_works() { mock::start_active_era(3); // nothing yet - assert_ok!(Staking::withdraw_unbonded(Origin::signed(10), 0)); + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(10), 0)); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1284,14 +1327,14 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 1000 + 100, active: 100, unlocking: bounded_vec![UnlockChunk { value: 1000, era: 2 + 3 }], - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], }), ); // trigger next era. mock::start_active_era(5); - assert_ok!(Staking::withdraw_unbonded(Origin::signed(10), 0)); + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(10), 0)); // Now the value is free and the staking ledger is updated. assert_eq!( Staking::ledger(&10), @@ -1300,7 +1343,7 @@ fn bond_extra_and_withdraw_unbonded_works() { total: 100, active: 100, unlocking: Default::default(), - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], }), ); }) @@ -1311,11 +1354,12 @@ fn too_many_unbond_calls_should_not_work() { ExtBuilder::default().build_and_execute(|| { let mut current_era = 0; // locked at era MaxUnlockingChunks - 1 until 3 - for i in 0..MaxUnlockingChunks::get() - 1 { + + for i in 0..<::MaxUnlockingChunks as Get>::get() - 1 { // There is only 1 chunk per era, so we need to be in a new era to create a chunk. current_era = i as u32; mock::start_active_era(current_era); - assert_ok!(Staking::unbond(Origin::signed(10), 1)); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); } current_era += 1; @@ -1323,24 +1367,24 @@ fn too_many_unbond_calls_should_not_work() { // This chunk is locked at `current_era` through `current_era + 2` (because BondingDuration // == 3). - assert_ok!(Staking::unbond(Origin::signed(10), 1)); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); assert_eq!( Staking::ledger(&10).unwrap().unlocking.len(), - MaxUnlockingChunks::get() as usize + <::MaxUnlockingChunks as Get>::get() as usize ); // can't do more. - assert_noop!(Staking::unbond(Origin::signed(10), 1), Error::::NoMoreChunks); + assert_noop!(Staking::unbond(RuntimeOrigin::signed(10), 1), Error::::NoMoreChunks); current_era += 2; mock::start_active_era(current_era); - assert_noop!(Staking::unbond(Origin::signed(10), 1), Error::::NoMoreChunks); + assert_noop!(Staking::unbond(RuntimeOrigin::signed(10), 1), Error::::NoMoreChunks); // free up everything except the most recently added chunk. - assert_ok!(Staking::withdraw_unbonded(Origin::signed(10), 0)); + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(10), 0)); assert_eq!(Staking::ledger(&10).unwrap().unlocking.len(), 1); // Can add again. - assert_ok!(Staking::unbond(Origin::signed(10), 1)); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1)); assert_eq!(Staking::ledger(&10).unwrap().unlocking.len(), 2); }) } @@ -1354,7 +1398,7 @@ fn rebond_works() { // * it can re-bond a portion of the funds scheduled to unlock. ExtBuilder::default().nominate(false).build_and_execute(|| { // Set payee to controller. avoids confusion - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(10), RewardDestination::Controller)); // Give account 11 some large free balance greater than total let _ = Balances::make_free_balance_be(&11, 1000000); @@ -1370,7 +1414,7 @@ fn rebond_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1378,10 +1422,10 @@ fn rebond_works() { assert_eq!(active_era(), 2); // Try to rebond some funds. We get an error since no fund is unbonded. - assert_noop!(Staking::rebond(Origin::signed(10), 500), Error::::NoUnlockChunk); + assert_noop!(Staking::rebond(RuntimeOrigin::signed(10), 500), Error::::NoUnlockChunk); // Unbond almost all of the funds in stash. - Staking::unbond(Origin::signed(10), 900).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 900).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1389,12 +1433,12 @@ fn rebond_works() { total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 2 + 3 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); // Re-bond all the funds unbonded. - Staking::rebond(Origin::signed(10), 900).unwrap(); + Staking::rebond(RuntimeOrigin::signed(10), 900).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1402,12 +1446,12 @@ fn rebond_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); // Unbond almost all of the funds in stash. - Staking::unbond(Origin::signed(10), 900).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 900).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1415,12 +1459,12 @@ fn rebond_works() { total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 5 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); // Re-bond part of the funds unbonded. - Staking::rebond(Origin::signed(10), 500).unwrap(); + Staking::rebond(RuntimeOrigin::signed(10), 500).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1428,12 +1472,12 @@ fn rebond_works() { total: 1000, active: 600, unlocking: bounded_vec![UnlockChunk { value: 400, era: 5 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); // Re-bond the remainder of the funds unbonded. - Staking::rebond(Origin::signed(10), 500).unwrap(); + Staking::rebond(RuntimeOrigin::signed(10), 500).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1441,14 +1485,14 @@ fn rebond_works() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); // Unbond parts of the funds in stash. - Staking::unbond(Origin::signed(10), 300).unwrap(); - Staking::unbond(Origin::signed(10), 300).unwrap(); - Staking::unbond(Origin::signed(10), 300).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 300).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 300).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 300).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1456,12 +1500,12 @@ fn rebond_works() { total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 5 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); // Re-bond part of the funds unbonded. - Staking::rebond(Origin::signed(10), 500).unwrap(); + Staking::rebond(RuntimeOrigin::signed(10), 500).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1469,7 +1513,7 @@ fn rebond_works() { total: 1000, active: 600, unlocking: bounded_vec![UnlockChunk { value: 400, era: 5 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); }) @@ -1480,7 +1524,7 @@ fn rebond_is_fifo() { // Rebond should proceed by reversing the most recent bond operations. ExtBuilder::default().nominate(false).build_and_execute(|| { // Set payee to controller. avoids confusion - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(10), RewardDestination::Controller)); // Give account 11 some large free balance greater than total let _ = Balances::make_free_balance_be(&11, 1000000); @@ -1496,14 +1540,14 @@ fn rebond_is_fifo() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); mock::start_active_era(2); // Unbond some of the funds in stash. - Staking::unbond(Origin::signed(10), 400).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 400).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1511,14 +1555,14 @@ fn rebond_is_fifo() { total: 1000, active: 600, unlocking: bounded_vec![UnlockChunk { value: 400, era: 2 + 3 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); mock::start_active_era(3); // Unbond more of the funds in stash. - Staking::unbond(Origin::signed(10), 300).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 300).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1529,14 +1573,14 @@ fn rebond_is_fifo() { UnlockChunk { value: 400, era: 2 + 3 }, UnlockChunk { value: 300, era: 3 + 3 }, ], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); mock::start_active_era(4); // Unbond yet more of the funds in stash. - Staking::unbond(Origin::signed(10), 200).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 200).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1548,12 +1592,12 @@ fn rebond_is_fifo() { UnlockChunk { value: 300, era: 3 + 3 }, UnlockChunk { value: 200, era: 4 + 3 }, ], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); // Re-bond half of the unbonding funds. - Staking::rebond(Origin::signed(10), 400).unwrap(); + Staking::rebond(RuntimeOrigin::signed(10), 400).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1564,7 +1608,7 @@ fn rebond_is_fifo() { UnlockChunk { value: 400, era: 2 + 3 }, UnlockChunk { value: 100, era: 3 + 3 }, ], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); }) @@ -1576,7 +1620,7 @@ fn rebond_emits_right_value_in_event() { // and the rebond event emits the actual value rebonded. ExtBuilder::default().nominate(false).build_and_execute(|| { // Set payee to controller. avoids confusion - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(10), RewardDestination::Controller)); // Give account 11 some large free balance greater than total let _ = Balances::make_free_balance_be(&11, 1000000); @@ -1585,7 +1629,7 @@ fn rebond_emits_right_value_in_event() { mock::start_active_era(1); // Unbond almost all of the funds in stash. - Staking::unbond(Origin::signed(10), 900).unwrap(); + Staking::unbond(RuntimeOrigin::signed(10), 900).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1593,12 +1637,12 @@ fn rebond_emits_right_value_in_event() { total: 1000, active: 100, unlocking: bounded_vec![UnlockChunk { value: 900, era: 1 + 3 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); // Re-bond less than the total - Staking::rebond(Origin::signed(10), 100).unwrap(); + Staking::rebond(RuntimeOrigin::signed(10), 100).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1606,14 +1650,14 @@ fn rebond_emits_right_value_in_event() { total: 1000, active: 200, unlocking: bounded_vec![UnlockChunk { value: 800, era: 1 + 3 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); // Event emitted should be correct - assert_eq!(*staking_events().last().unwrap(), Event::Bonded(11, 100)); + assert_eq!(*staking_events().last().unwrap(), Event::Bonded { stash: 11, amount: 100 }); // Re-bond way more than available - Staking::rebond(Origin::signed(10), 100_000).unwrap(); + Staking::rebond(RuntimeOrigin::signed(10), 100_000).unwrap(); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -1621,11 +1665,11 @@ fn rebond_emits_right_value_in_event() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); // Event emitted should be correct, only 800 - assert_eq!(*staking_events().last().unwrap(), Event::Bonded(11, 800)); + assert_eq!(*staking_events().last().unwrap(), Event::Bonded { stash: 11, amount: 800 }); }); } @@ -1657,7 +1701,7 @@ fn reward_to_stake_works() { total: 69, active: 69, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }, ); @@ -1703,11 +1747,14 @@ fn reap_stash_works() { // stash is not reapable assert_noop!( - Staking::reap_stash(Origin::signed(20), 11, 0), + Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0), Error::::FundedTarget ); // controller or any other account is not reapable - assert_noop!(Staking::reap_stash(Origin::signed(20), 10, 0), Error::::NotStash); + assert_noop!( + Staking::reap_stash(RuntimeOrigin::signed(20), 10, 0), + Error::::NotStash + ); // no easy way to cause an account to go below ED, we tweak their staking ledger // instead. @@ -1718,12 +1765,12 @@ fn reap_stash_works() { total: 5, active: 5, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }, ); // reap-able - assert_ok!(Staking::reap_stash(Origin::signed(20), 11, 0)); + assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0)); // then assert!(!>::contains_key(&10)); @@ -1740,7 +1787,10 @@ fn switching_roles() { ExtBuilder::default().nominate(false).build_and_execute(|| { // Reset reward destination for i in &[10, 20] { - assert_ok!(Staking::set_payee(Origin::signed(*i), RewardDestination::Controller)); + assert_ok!(Staking::set_payee( + RuntimeOrigin::signed(*i), + RewardDestination::Controller + )); } assert_eq_uvec!(validator_controllers(), vec![20, 10]); @@ -1751,16 +1801,20 @@ fn switching_roles() { } // add 2 nominators - assert_ok!(Staking::bond(Origin::signed(1), 2, 2000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 5])); + assert_ok!(Staking::bond(RuntimeOrigin::signed(1), 2, 2000, RewardDestination::Controller)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(2), vec![11, 5])); - assert_ok!(Staking::bond(Origin::signed(3), 4, 500, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 1])); + assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 4, 500, RewardDestination::Controller)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![21, 1])); // add a new validator candidate - assert_ok!(Staking::bond(Origin::signed(5), 6, 1000, RewardDestination::Controller)); - assert_ok!(Staking::validate(Origin::signed(6), ValidatorPrefs::default())); - assert_ok!(Session::set_keys(Origin::signed(6), SessionKeys { other: 6.into() }, vec![])); + assert_ok!(Staking::bond(RuntimeOrigin::signed(5), 6, 1000, RewardDestination::Controller)); + assert_ok!(Staking::validate(RuntimeOrigin::signed(6), ValidatorPrefs::default())); + assert_ok!(Session::set_keys( + RuntimeOrigin::signed(6), + SessionKeys { other: 6.into() }, + vec![] + )); mock::start_active_era(1); @@ -1768,8 +1822,12 @@ fn switching_roles() { assert_eq_uvec!(validator_controllers(), vec![6, 10]); // 2 decides to be a validator. Consequences: - assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); - assert_ok!(Session::set_keys(Origin::signed(2), SessionKeys { other: 2.into() }, vec![])); + assert_ok!(Staking::validate(RuntimeOrigin::signed(2), ValidatorPrefs::default())); + assert_ok!(Session::set_keys( + RuntimeOrigin::signed(2), + SessionKeys { other: 2.into() }, + vec![] + )); // new stakes: // 10: 1000 self vote // 20: 1000 self vote + 250 vote @@ -1821,15 +1879,20 @@ fn bond_with_no_staked_value() { .build_and_execute(|| { // Can't bond with 1 assert_noop!( - Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller), + Staking::bond(RuntimeOrigin::signed(1), 2, 1, RewardDestination::Controller), Error::::InsufficientBond, ); // bonded with absolute minimum value possible. - assert_ok!(Staking::bond(Origin::signed(1), 2, 5, RewardDestination::Controller)); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(1), + 2, + 5, + RewardDestination::Controller + )); assert_eq!(Balances::locks(&1)[0].amount, 5); // unbonding even 1 will cause all to be unbonded. - assert_ok!(Staking::unbond(Origin::signed(2), 1)); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(2), 1)); assert_eq!( Staking::ledger(2), Some(StakingLedger { @@ -1837,7 +1900,7 @@ fn bond_with_no_staked_value() { active: 0, total: 5, unlocking: bounded_vec![UnlockChunk { value: 5, era: 3 }], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); @@ -1845,14 +1908,14 @@ fn bond_with_no_staked_value() { mock::start_active_era(2); // not yet removed. - assert_ok!(Staking::withdraw_unbonded(Origin::signed(2), 0)); + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(2), 0)); assert!(Staking::ledger(2).is_some()); assert_eq!(Balances::locks(&1)[0].amount, 5); mock::start_active_era(3); // poof. Account 1 is removed from the staking system. - assert_ok!(Staking::withdraw_unbonded(Origin::signed(2), 0)); + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(2), 0)); assert!(Staking::ledger(2).is_none()); assert_eq!(Balances::locks(&1).len(), 0); }); @@ -1866,16 +1929,24 @@ fn bond_with_little_staked_value_bounded() { .minimum_validator_count(1) .build_and_execute(|| { // setup - assert_ok!(Staking::chill(Origin::signed(30))); - assert_ok!(Staking::set_payee(Origin::signed(10), RewardDestination::Controller)); + assert_ok!(Staking::chill(RuntimeOrigin::signed(30))); + assert_ok!(Staking::set_payee( + RuntimeOrigin::signed(10), + RewardDestination::Controller + )); let init_balance_2 = Balances::free_balance(&2); let init_balance_10 = Balances::free_balance(&10); // Stingy validator. - assert_ok!(Staking::bond(Origin::signed(1), 2, 1, RewardDestination::Controller)); - assert_ok!(Staking::validate(Origin::signed(2), ValidatorPrefs::default())); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(1), + 2, + 1, + RewardDestination::Controller + )); + assert_ok!(Staking::validate(RuntimeOrigin::signed(2), ValidatorPrefs::default())); assert_ok!(Session::set_keys( - Origin::signed(2), + RuntimeOrigin::signed(2), SessionKeys { other: 2.into() }, vec![] )); @@ -1948,11 +2019,21 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider() { let _ = Balances::make_free_balance_be(i, initial_balance); } - assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 11, 11, 21, 31])); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(1), + 2, + 1000, + RewardDestination::Controller + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(2), vec![11, 11, 11, 21, 31])); - assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(4), vec![21, 31])); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(3), + 4, + 1000, + RewardDestination::Controller + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![21, 31])); // winners should be 21 and 31. Otherwise this election is taking duplicates into // account. @@ -1993,11 +2074,21 @@ fn bond_with_duplicate_vote_should_be_ignored_by_election_provider_elected() { let _ = Balances::make_free_balance_be(i, initial_balance); } - assert_ok!(Staking::bond(Origin::signed(1), 2, 1000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(2), vec![11, 11, 11, 21])); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(1), + 2, + 1000, + RewardDestination::Controller + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(2), vec![11, 11, 11, 21])); - assert_ok!(Staking::bond(Origin::signed(3), 4, 1000, RewardDestination::Controller)); - assert_ok!(Staking::nominate(Origin::signed(4), vec![21])); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(3), + 4, + 1000, + RewardDestination::Controller + )); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![21])); // winners should be 21 and 11. let supports = ::ElectionProvider::elect().unwrap(); @@ -2029,8 +2120,8 @@ fn phragmen_should_not_overflow() { // This is the maximum value that we can have as the outcome of CurrencyToVote. type Votes = u64; - let _ = Staking::chill(Origin::signed(10)); - let _ = Staking::chill(Origin::signed(20)); + let _ = Staking::chill(RuntimeOrigin::signed(10)); + let _ = Staking::chill(RuntimeOrigin::signed(20)); bond_validator(3, 2, Votes::max_value() as Balance); bond_validator(5, 4, Votes::max_value() as Balance); @@ -2071,7 +2162,7 @@ fn reward_validator_slashing_validator_does_not_overflow() { ErasStakers::::insert(0, 11, &exposure); ErasStakersClipped::::insert(0, 11, exposure); ErasValidatorReward::::insert(0, stake); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 0)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0)); assert_eq!(Balances::total_balance(&11), stake * 2); // Set staker @@ -2079,7 +2170,8 @@ fn reward_validator_slashing_validator_does_not_overflow() { let _ = Balances::make_free_balance_be(&2, stake); // only slashes out of bonded stake are applied. without this line, it is 0. - Staking::bond(Origin::signed(2), 20000, stake - 1, RewardDestination::default()).unwrap(); + Staking::bond(RuntimeOrigin::signed(2), 20000, stake - 1, RewardDestination::default()) + .unwrap(); // Override exposure of 11 ErasStakers::::insert( 0, @@ -2155,7 +2247,7 @@ fn unbonded_balance_is_not_slashable() { // total amount staked is slashable. assert_eq!(Staking::slashable_balance_of(&11), 1000); - assert_ok!(Staking::unbond(Origin::signed(10), 800)); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 800)); // only the active portion. assert_eq!(Staking::slashable_balance_of(&11), 200); @@ -2211,7 +2303,7 @@ fn offence_forces_new_era() { #[test] fn offence_ensures_new_era_without_clobbering() { ExtBuilder::default().build_and_execute(|| { - assert_ok!(Staking::force_new_era_always(Origin::root())); + assert_ok!(Staking::force_new_era_always(RuntimeOrigin::root())); assert_eq!(Staking::force_era(), Forcing::ForceAlways); on_offence_now( @@ -2292,7 +2384,7 @@ fn slash_in_old_span_does_not_deselect() { mock::start_active_era(2); - Staking::validate(Origin::signed(10), Default::default()).unwrap(); + Staking::validate(RuntimeOrigin::signed(10), Default::default()).unwrap(); assert_eq!(Staking::force_era(), Forcing::NotForcing); assert!(>::contains_key(11)); assert!(!Session::validators().contains(&11)); @@ -2551,10 +2643,10 @@ fn garbage_collection_after_slashing() { // reap_stash respects num_slashing_spans so that weight is accurate assert_noop!( - Staking::reap_stash(Origin::signed(20), 11, 0), + Staking::reap_stash(RuntimeOrigin::signed(20), 11, 0), Error::::IncorrectSlashingSpans ); - assert_ok!(Staking::reap_stash(Origin::signed(20), 11, 2)); + assert_ok!(Staking::reap_stash(RuntimeOrigin::signed(20), 11, 2)); assert!(::SlashingSpans::get(&11).is_none()); assert_eq!(::SpanSlash::get(&(11, 0)).amount(), &0); @@ -2717,7 +2809,7 @@ fn slashes_are_summed_across_spans() { assert_eq!(Balances::free_balance(21), 1900); // 21 has been force-chilled. re-signal intent to validate. - Staking::validate(Origin::signed(20), Default::default()).unwrap(); + Staking::validate(RuntimeOrigin::signed(20), Default::default()).unwrap(); mock::start_active_era(4); @@ -2787,9 +2879,9 @@ fn deferred_slashes_are_deferred() { staking_events_since_last_call(), vec![ Event::StakersElected, - Event::EraPaid(3, 11075, 33225), - Event::Slashed(11, 100), - Event::Slashed(101, 12) + Event::EraPaid { era_index: 3, validator_payout: 11075, remainder: 33225 }, + Event::Slashed { staker: 11, amount: 100 }, + Event::Slashed { staker: 101, amount: 12 } ] ); }) @@ -2818,9 +2910,9 @@ fn retroactive_deferred_slashes_two_eras_before() { staking_events_since_last_call(), vec![ Event::StakersElected, - Event::EraPaid(3, 7100, 21300), - Event::Slashed(11, 100), - Event::Slashed(101, 12) + Event::EraPaid { era_index: 3, validator_payout: 7100, remainder: 21300 }, + Event::Slashed { staker: 11, amount: 100 }, + Event::Slashed { staker: 101, amount: 12 }, ] ); }) @@ -2836,8 +2928,8 @@ fn retroactive_deferred_slashes_one_before() { // unbond at slash era. mock::start_active_era(2); - assert_ok!(Staking::chill(Origin::signed(10))); - assert_ok!(Staking::unbond(Origin::signed(10), 100)); + assert_ok!(Staking::chill(RuntimeOrigin::signed(10))); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 100)); mock::start_active_era(3); on_offence_in_era( @@ -2851,7 +2943,10 @@ fn retroactive_deferred_slashes_one_before() { mock::start_active_era(4); assert_eq!( staking_events_since_last_call(), - vec![Event::StakersElected, Event::EraPaid(3, 11075, 33225)] + vec![ + Event::StakersElected, + Event::EraPaid { era_index: 3, validator_payout: 11075, remainder: 33225 } + ] ); assert_eq!(Staking::ledger(10).unwrap().total, 1000); @@ -2861,15 +2956,15 @@ fn retroactive_deferred_slashes_one_before() { staking_events_since_last_call(), vec![ Event::StakersElected, - Event::EraPaid(4, 11075, 33225), - Event::Slashed(11, 100), - Event::Slashed(101, 12) + Event::EraPaid { era_index: 4, validator_payout: 11075, remainder: 33225 }, + Event::Slashed { staker: 11, amount: 100 }, + Event::Slashed { staker: 101, amount: 12 } ] ); // their ledger has already been slashed. assert_eq!(Staking::ledger(10).unwrap().total, 900); - assert_ok!(Staking::unbond(Origin::signed(10), 1000)); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(10), 1000)); assert_eq!(Staking::ledger(10).unwrap().total, 900); }) } @@ -2895,8 +2990,8 @@ fn staker_cannot_bail_deferred_slash() { ); // now we chill - assert_ok!(Staking::chill(Origin::signed(100))); - assert_ok!(Staking::unbond(Origin::signed(100), 500)); + assert_ok!(Staking::chill(RuntimeOrigin::signed(100))); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(100), 500)); assert_eq!(Staking::current_era().unwrap(), 1); assert_eq!(active_era(), 1); @@ -2907,7 +3002,7 @@ fn staker_cannot_bail_deferred_slash() { active: 0, total: 500, stash: 101, - claimed_rewards: Default::default(), + claimed_rewards: bounded_vec![], unlocking: bounded_vec![UnlockChunk { era: 4u32, value: 500 }], } ); @@ -2931,7 +3026,9 @@ fn staker_cannot_bail_deferred_slash() { assert_eq!(active_era(), 3); // and cannot yet unbond: - assert_storage_noop!(assert!(Staking::withdraw_unbonded(Origin::signed(100), 0).is_ok())); + assert_storage_noop!(assert!( + Staking::withdraw_unbonded(RuntimeOrigin::signed(100), 0).is_ok() + )); assert_eq!( Ledger::::get(100).unwrap().unlocking.into_inner(), vec![UnlockChunk { era: 4u32, value: 500 as Balance }], @@ -2980,12 +3077,12 @@ fn remove_deferred() { // fails if empty assert_noop!( - Staking::cancel_deferred_slash(Origin::root(), 1, vec![]), + Staking::cancel_deferred_slash(RuntimeOrigin::root(), 1, vec![]), Error::::EmptyTargets ); // cancel one of them. - assert_ok!(Staking::cancel_deferred_slash(Origin::root(), 4, vec![0])); + assert_ok!(Staking::cancel_deferred_slash(RuntimeOrigin::root(), 4, vec![0])); assert_eq!(Balances::free_balance(11), 1000); assert_eq!(Balances::free_balance(101), 2000); @@ -3005,9 +3102,9 @@ fn remove_deferred() { staking_events_since_last_call(), vec![ Event::StakersElected, - Event::EraPaid(3, 11075, 33225), - Event::Slashed(11, 50), - Event::Slashed(101, 7) + Event::EraPaid { era_index: 3, validator_payout: 11075, remainder: 33225 }, + Event::Slashed { staker: 11, amount: 50 }, + Event::Slashed { staker: 101, amount: 7 } ] ); @@ -3066,21 +3163,21 @@ fn remove_multi_deferred() { // fails if list is not sorted assert_noop!( - Staking::cancel_deferred_slash(Origin::root(), 1, vec![2, 0, 4]), + Staking::cancel_deferred_slash(RuntimeOrigin::root(), 1, vec![2, 0, 4]), Error::::NotSortedAndUnique ); // fails if list is not unique assert_noop!( - Staking::cancel_deferred_slash(Origin::root(), 1, vec![0, 2, 2]), + Staking::cancel_deferred_slash(RuntimeOrigin::root(), 1, vec![0, 2, 2]), Error::::NotSortedAndUnique ); // fails if bad index assert_noop!( - Staking::cancel_deferred_slash(Origin::root(), 1, vec![1, 2, 3, 4, 5]), + Staking::cancel_deferred_slash(RuntimeOrigin::root(), 1, vec![1, 2, 3, 4, 5]), Error::::InvalidSlashIndex ); - assert_ok!(Staking::cancel_deferred_slash(Origin::root(), 4, vec![0, 2, 4])); + assert_ok!(Staking::cancel_deferred_slash(RuntimeOrigin::root(), 4, vec![0, 2, 4])); let slashes = ::UnappliedSlashes::get(&4); assert_eq!(slashes.len(), 2); @@ -3130,7 +3227,7 @@ fn slash_kicks_validators_not_nominators_and_disables_nominator_for_kicked_valid assert!(nominations.submitted_in < last_slash); // actually re-bond the slashed validator - assert_ok!(Staking::validate(Origin::signed(10), Default::default())); + assert_ok!(Staking::validate(RuntimeOrigin::signed(10), Default::default())); mock::start_active_era(2); let exposure_11 = Staking::eras_stakers(active_era(), &11); @@ -3312,7 +3409,7 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { // * double claim of one era fails ExtBuilder::default().nominate(true).build_and_execute(|| { // Consumed weight for all payout_stakers dispatches that fail - let err_weight = weights::SubstrateWeight::::payout_stakers_alive_staked(0); + let err_weight = ::WeightInfo::payout_stakers_alive_staked(0); let init_balance_10 = Balances::total_balance(&10); let init_balance_100 = Balances::total_balance(&100); @@ -3347,7 +3444,7 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { assert!(total_payout_2 != total_payout_0); assert!(total_payout_2 != total_payout_1); - mock::start_active_era(Staking::history_depth() + 1); + mock::start_active_era(HistoryDepth::get() + 1); let active_era = active_era(); @@ -3355,21 +3452,21 @@ fn claim_reward_at_the_last_era_and_no_double_claim_and_invalid_claim() { let current_era = Staking::current_era().unwrap(); // Last kept is 1: - assert!(current_era - Staking::history_depth() == 1); + assert!(current_era - HistoryDepth::get() == 1); assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 11, 0), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 0), // Fail: Era out of history Error::::InvalidEraToReward.with_weight(err_weight) ); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1)); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 2)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2)); assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 11, 2), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2), // Fail: Double claim Error::::AlreadyClaimed.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 11, active_era), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, active_era), // Fail: Era not finished yet Error::::InvalidEraToReward.with_weight(err_weight) ); @@ -3490,12 +3587,12 @@ fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward( let balance = 10_000 + i as Balance; Balances::make_free_balance_be(&stash, balance); assert_ok!(Staking::bond( - Origin::signed(stash), + RuntimeOrigin::signed(stash), controller, balance, RewardDestination::Stash )); - assert_ok!(Staking::nominate(Origin::signed(controller), vec![11])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(controller), vec![11])); } mock::start_active_era(1); @@ -3519,25 +3616,6 @@ fn test_max_nominator_rewarded_per_validator_and_cant_steal_someone_else_reward( }); } -#[test] -fn set_history_depth_works() { - ExtBuilder::default().build_and_execute(|| { - mock::start_active_era(10); - Staking::set_history_depth(Origin::root(), 20, 0).unwrap(); - assert!(::ErasTotalStake::contains_key(10 - 4)); - assert!(::ErasTotalStake::contains_key(10 - 5)); - Staking::set_history_depth(Origin::root(), 4, 0).unwrap(); - assert!(::ErasTotalStake::contains_key(10 - 4)); - assert!(!::ErasTotalStake::contains_key(10 - 5)); - Staking::set_history_depth(Origin::root(), 3, 0).unwrap(); - assert!(!::ErasTotalStake::contains_key(10 - 4)); - assert!(!::ErasTotalStake::contains_key(10 - 5)); - Staking::set_history_depth(Origin::root(), 8, 0).unwrap(); - assert!(!::ErasTotalStake::contains_key(10 - 4)); - assert!(!::ErasTotalStake::contains_key(10 - 5)); - }); -} - #[test] fn test_payout_stakers() { // Test that payout_stakers work in general, including that only the top @@ -3574,7 +3652,7 @@ fn test_payout_stakers() { let pre_payout_total_issuance = Balances::total_issuance(); RewardOnUnbalanceWasCalled::set(false); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); assert_eq_error_rate!( Balances::total_issuance(), pre_payout_total_issuance + actual_paid_out, @@ -3601,7 +3679,7 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![1] + claimed_rewards: bounded_vec![1] }) ); @@ -3615,7 +3693,7 @@ fn test_payout_stakers() { mock::start_active_era(i); RewardOnUnbalanceWasCalled::set(false); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, i - 1)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, i - 1)); assert_eq_error_rate!( Balances::total_issuance(), pre_payout_total_issuance + actual_paid_out, @@ -3632,11 +3710,15 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: (1..=14).collect() + claimed_rewards: (1..=14).collect::>().try_into().unwrap() }) ); - for i in 16..100 { + let last_era = 99; + let history_depth = HistoryDepth::get(); + let expected_last_reward_era = last_era - 1; + let expected_start_reward_era = last_era - history_depth; + for i in 16..=last_era { Staking::reward_by_ids(vec![(11, 1)]); // compute and ensure the reward amount is greater than zero. let _ = current_total_payout_for_duration(reward_time_per_era()); @@ -3644,8 +3726,16 @@ fn test_payout_stakers() { } // We clean it up as history passes - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 15)); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 98)); + assert_ok!(Staking::payout_stakers( + RuntimeOrigin::signed(1337), + 11, + expected_start_reward_era + )); + assert_ok!(Staking::payout_stakers( + RuntimeOrigin::signed(1337), + 11, + expected_last_reward_era + )); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -3653,14 +3743,14 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![15, 98] + claimed_rewards: bounded_vec![expected_start_reward_era, expected_last_reward_era] }) ); // Out of order claims works. - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 69)); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 23)); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 42)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 69)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 23)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 42)); assert_eq!( Staking::ledger(&10), Some(StakingLedger { @@ -3668,7 +3758,13 @@ fn test_payout_stakers() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![15, 23, 42, 69, 98] + claimed_rewards: bounded_vec![ + expected_start_reward_era, + 23, + 42, + 69, + expected_last_reward_era + ] }) ); }); @@ -3679,7 +3775,7 @@ fn payout_stakers_handles_basic_errors() { // Here we will test payouts handle all errors. ExtBuilder::default().has_stakers(false).build_and_execute(|| { // Consumed weight for all payout_stakers dispatches that fail - let err_weight = weights::SubstrateWeight::::payout_stakers_alive_staked(0); + let err_weight = ::WeightInfo::payout_stakers_alive_staked(0); // Same setup as the test above let balance = 1000; @@ -3700,41 +3796,56 @@ fn payout_stakers_handles_basic_errors() { // Wrong Era, too big assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 11, 2), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 2), Error::::InvalidEraToReward.with_weight(err_weight) ); // Wrong Staker assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 10, 1), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 10, 1), Error::::NotStash.with_weight(err_weight) ); - for i in 3..100 { + let last_era = 99; + for i in 3..=last_era { Staking::reward_by_ids(vec![(11, 1)]); // compute and ensure the reward amount is greater than zero. let _ = current_total_payout_for_duration(reward_time_per_era()); mock::start_active_era(i); } - // We are at era 99, with history depth of 84 - // We should be able to payout era 15 through 98 (84 total eras), but not 14 or 99. + + let history_depth = HistoryDepth::get(); + let expected_last_reward_era = last_era - 1; + let expected_start_reward_era = last_era - history_depth; + + // We are at era last_era=99. Given history_depth=80, we should be able + // to payout era starting from expected_start_reward_era=19 through + // expected_last_reward_era=98 (80 total eras), but not 18 or 99. assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 11, 14), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_start_reward_era - 1), Error::::InvalidEraToReward.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 11, 99), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_last_reward_era + 1), Error::::InvalidEraToReward.with_weight(err_weight) ); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 15)); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 98)); + assert_ok!(Staking::payout_stakers( + RuntimeOrigin::signed(1337), + 11, + expected_start_reward_era + )); + assert_ok!(Staking::payout_stakers( + RuntimeOrigin::signed(1337), + 11, + expected_last_reward_era + )); // Can't claim again assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 11, 15), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_start_reward_era), Error::::AlreadyClaimed.with_weight(err_weight) ); assert_noop!( - Staking::payout_stakers(Origin::signed(1337), 11, 98), + Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, expected_last_reward_era), Error::::AlreadyClaimed.with_weight(err_weight) ); }); @@ -3759,9 +3870,9 @@ fn payout_stakers_handles_weight_refund() { let half_max_nom_rewarded_weight = ::WeightInfo::payout_stakers_alive_staked(half_max_nom_rewarded); let zero_nom_payouts_weight = ::WeightInfo::payout_stakers_alive_staked(0); - assert!(zero_nom_payouts_weight > Weight::zero()); - assert!(half_max_nom_rewarded_weight > zero_nom_payouts_weight); - assert!(max_nom_rewarded_weight > half_max_nom_rewarded_weight); + assert!(zero_nom_payouts_weight.any_gt(Weight::zero())); + assert!(half_max_nom_rewarded_weight.any_gt(zero_nom_payouts_weight)); + assert!(max_nom_rewarded_weight.any_gt(half_max_nom_rewarded_weight)); let balance = 1000; bond_validator(11, 10, balance); @@ -3782,10 +3893,9 @@ fn payout_stakers_handles_weight_refund() { start_active_era(2); // Collect payouts when there are no nominators - let call = - TestRuntimeCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 1 }); + let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 1 }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(20)); + let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), zero_nom_payouts_weight); @@ -3796,10 +3906,9 @@ fn payout_stakers_handles_weight_refund() { start_active_era(3); // Collect payouts for an era where the validator did not receive any points. - let call = - TestRuntimeCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 2 }); + let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 2 }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(20)); + let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), zero_nom_payouts_weight); @@ -3810,10 +3919,9 @@ fn payout_stakers_handles_weight_refund() { start_active_era(4); // Collect payouts when the validator has `half_max_nom_rewarded` nominators. - let call = - TestRuntimeCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 3 }); + let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 3 }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(20)); + let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), half_max_nom_rewarded_weight); @@ -3834,18 +3942,16 @@ fn payout_stakers_handles_weight_refund() { start_active_era(6); // Collect payouts when the validator had `half_max_nom_rewarded` nominators. - let call = - TestRuntimeCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5 }); + let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5 }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(20)); + let result = call.dispatch(RuntimeOrigin::signed(20)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), max_nom_rewarded_weight); // Try and collect payouts for an era that has already been collected. - let call = - TestRuntimeCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5 }); + let call = TestCall::Staking(StakingCall::payout_stakers { validator_stash: 11, era: 5 }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(20)); + let result = call.dispatch(RuntimeOrigin::signed(20)); assert!(result.is_err()); // When there is an error the consumed weight == weight when there are 0 nominator payouts. assert_eq!(extract_actual_weight(&result, &info), zero_nom_payouts_weight); @@ -3864,7 +3970,7 @@ fn bond_during_era_correctly_populates_claimed_rewards() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }) ); mock::start_active_era(5); @@ -3876,10 +3982,14 @@ fn bond_during_era_correctly_populates_claimed_rewards() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: (0..5).collect(), + claimed_rewards: (0..5).collect::>().try_into().unwrap(), }) ); - mock::start_active_era(99); + + // make sure only era upto history depth is stored + let current_era = 99; + let last_reward_era = 99 - HistoryDepth::get(); + mock::start_active_era(current_era); bond_validator(13, 12, 1000); assert_eq!( Staking::ledger(&12), @@ -3888,7 +3998,10 @@ fn bond_during_era_correctly_populates_claimed_rewards() { total: 1000, active: 1000, unlocking: Default::default(), - claimed_rewards: (15..99).collect(), + claimed_rewards: (last_reward_era..current_era) + .collect::>() + .try_into() + .unwrap(), }) ); }); @@ -3956,7 +4069,7 @@ fn offences_weight_calculated_correctly() { &one_offender, &[Perbill::from_percent(50)], 0, - DisableStrategy::WhenSlashed + DisableStrategy::WhenSlashed{} ), one_offence_unapplied_weight ); @@ -3974,7 +4087,7 @@ fn payout_creates_controller() { bond_nominator(1234, 1337, 100, vec![11]); // kill controller - assert_ok!(Balances::transfer(Origin::signed(1337), 1234, 100)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1337), 1234, 100)); assert_eq!(Balances::free_balance(1337), 0); mock::start_active_era(1); @@ -3982,7 +4095,7 @@ fn payout_creates_controller() { // compute and ensure the reward amount is greater than zero. let _ = current_total_payout_for_duration(reward_time_per_era()); mock::start_active_era(2); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); // Controller is created assert!(Balances::free_balance(1337) > 0); @@ -4000,7 +4113,7 @@ fn payout_to_any_account_works() { bond_nominator(1234, 1337, 100, vec![11]); // Update payout location - assert_ok!(Staking::set_payee(Origin::signed(1337), RewardDestination::Account(42))); + assert_ok!(Staking::set_payee(RuntimeOrigin::signed(1337), RewardDestination::Account(42))); // Reward Destination account doesn't exist assert_eq!(Balances::free_balance(42), 0); @@ -4010,7 +4123,7 @@ fn payout_to_any_account_works() { // compute and ensure the reward amount is greater than zero. let _ = current_total_payout_for_duration(reward_time_per_era()); mock::start_active_era(2); - assert_ok!(Staking::payout_stakers(Origin::signed(1337), 11, 1)); + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(1337), 11, 1)); // Payment is successful assert!(Balances::free_balance(42) > 0); @@ -4133,13 +4246,13 @@ fn cannot_rebond_to_lower_than_ed() { total: 10 * 1000, active: 10 * 1000, unlocking: Default::default(), - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], } ); // unbond all of it. must be chilled first. - assert_ok!(Staking::chill(Origin::signed(20))); - assert_ok!(Staking::unbond(Origin::signed(20), 10 * 1000)); + assert_ok!(Staking::chill(RuntimeOrigin::signed(20))); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(20), 10 * 1000)); assert_eq!( Staking::ledger(&20).unwrap(), StakingLedger { @@ -4147,12 +4260,15 @@ fn cannot_rebond_to_lower_than_ed() { total: 10 * 1000, active: 0, unlocking: bounded_vec![UnlockChunk { value: 10 * 1000, era: 3 }], - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], } ); // now bond a wee bit more - assert_noop!(Staking::rebond(Origin::signed(20), 5), Error::::InsufficientBond); + assert_noop!( + Staking::rebond(RuntimeOrigin::signed(20), 5), + Error::::InsufficientBond + ); }) } @@ -4170,13 +4286,13 @@ fn cannot_bond_extra_to_lower_than_ed() { total: 10 * 1000, active: 10 * 1000, unlocking: Default::default(), - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], } ); // unbond all of it. must be chilled first. - assert_ok!(Staking::chill(Origin::signed(20))); - assert_ok!(Staking::unbond(Origin::signed(20), 10 * 1000)); + assert_ok!(Staking::chill(RuntimeOrigin::signed(20))); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(20), 10 * 1000)); assert_eq!( Staking::ledger(&20).unwrap(), StakingLedger { @@ -4184,13 +4300,13 @@ fn cannot_bond_extra_to_lower_than_ed() { total: 10 * 1000, active: 0, unlocking: bounded_vec![UnlockChunk { value: 10 * 1000, era: 3 }], - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], } ); // now bond a wee bit more assert_noop!( - Staking::bond_extra(Origin::signed(21), 5), + Staking::bond_extra(RuntimeOrigin::signed(21), 5), Error::::InsufficientBond, ); }) @@ -4211,14 +4327,14 @@ fn do_not_die_when_active_is_ed() { total: 1000 * ed, active: 1000 * ed, unlocking: Default::default(), - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], } ); // when unbond all of it except ed. - assert_ok!(Staking::unbond(Origin::signed(20), 999 * ed)); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(20), 999 * ed)); start_active_era(3); - assert_ok!(Staking::withdraw_unbonded(Origin::signed(20), 100)); + assert_ok!(Staking::withdraw_unbonded(RuntimeOrigin::signed(20), 100)); // then assert_eq!( @@ -4228,7 +4344,7 @@ fn do_not_die_when_active_is_ed() { total: ed, active: ed, unlocking: Default::default(), - claimed_rewards: vec![] + claimed_rewards: bounded_vec![], } ); }) @@ -4238,7 +4354,7 @@ fn do_not_die_when_active_is_ed() { fn on_finalize_weight_is_nonzero() { ExtBuilder::default().build_and_execute(|| { let on_finalize_weight = ::DbWeight::get().reads(1); - assert!(>::on_initialize(1) >= on_finalize_weight); + assert!(>::on_initialize(1).all_gte(on_finalize_weight)); }) } @@ -4249,8 +4365,8 @@ mod election_data_provider { #[test] fn targets_2sec_block() { let mut validators = 1000; - while ::WeightInfo::get_npos_targets(validators) < - 2u64 * frame_support::weights::constants::WEIGHT_PER_SECOND + while ::WeightInfo::get_npos_targets(validators) + .all_lt(2u64 * frame_support::weights::constants::WEIGHT_PER_SECOND) { validators += 1; } @@ -4267,8 +4383,8 @@ mod election_data_provider { let slashing_spans = validators; let mut nominators = 1000; - while ::WeightInfo::get_npos_voters(validators, nominators, slashing_spans) < - 2u64 * frame_support::weights::constants::WEIGHT_PER_SECOND + while ::WeightInfo::get_npos_voters(validators, nominators, slashing_spans) + .all_lt(2u64 * frame_support::weights::constants::WEIGHT_PER_SECOND) { nominators += 1; } @@ -4321,7 +4437,7 @@ mod election_data_provider { ); // resubmit and it is back - assert_ok!(Staking::nominate(Origin::signed(100), vec![11, 21])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(100), vec![11, 21])); assert_eq!( ::electing_voters(None) .unwrap() @@ -4479,13 +4595,13 @@ mod election_data_provider { assert_eq!(staking_events().len(), 3); assert_eq!(*staking_events().last().unwrap(), Event::StakersElected); - Staking::force_no_eras(Origin::root()).unwrap(); + Staking::force_no_eras(RuntimeOrigin::root()).unwrap(); assert_eq!(Staking::next_election_prediction(System::block_number()), u64::MAX); - Staking::force_new_era_always(Origin::root()).unwrap(); + Staking::force_new_era_always(RuntimeOrigin::root()).unwrap(); assert_eq!(Staking::next_election_prediction(System::block_number()), 45 + 5); - Staking::force_new_era(Origin::root()).unwrap(); + Staking::force_new_era(RuntimeOrigin::root()).unwrap(); assert_eq!(Staking::next_election_prediction(System::block_number()), 45 + 5); // Do a fail election @@ -4535,40 +4651,51 @@ fn min_bond_checks_work() { .min_validator_bond(1_500) .build_and_execute(|| { // 500 is not enough for any role - assert_ok!(Staking::bond(Origin::signed(3), 4, 500, RewardDestination::Controller)); + assert_ok!(Staking::bond( + RuntimeOrigin::signed(3), + 4, + 500, + RewardDestination::Controller + )); assert_noop!( - Staking::nominate(Origin::signed(4), vec![1]), + Staking::nominate(RuntimeOrigin::signed(4), vec![1]), Error::::InsufficientBond ); assert_noop!( - Staking::validate(Origin::signed(4), ValidatorPrefs::default()), + Staking::validate(RuntimeOrigin::signed(4), ValidatorPrefs::default()), Error::::InsufficientBond, ); // 1000 is enough for nominator - assert_ok!(Staking::bond_extra(Origin::signed(3), 500)); - assert_ok!(Staking::nominate(Origin::signed(4), vec![1])); + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(3), 500)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![1])); assert_noop!( - Staking::validate(Origin::signed(4), ValidatorPrefs::default()), + Staking::validate(RuntimeOrigin::signed(4), ValidatorPrefs::default()), Error::::InsufficientBond, ); // 1500 is enough for validator - assert_ok!(Staking::bond_extra(Origin::signed(3), 500)); - assert_ok!(Staking::nominate(Origin::signed(4), vec![1])); - assert_ok!(Staking::validate(Origin::signed(4), ValidatorPrefs::default())); + assert_ok!(Staking::bond_extra(RuntimeOrigin::signed(3), 500)); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![1])); + assert_ok!(Staking::validate(RuntimeOrigin::signed(4), ValidatorPrefs::default())); // Can't unbond anything as validator - assert_noop!(Staking::unbond(Origin::signed(4), 500), Error::::InsufficientBond); + assert_noop!( + Staking::unbond(RuntimeOrigin::signed(4), 500), + Error::::InsufficientBond + ); // Once they are a nominator, they can unbond 500 - assert_ok!(Staking::nominate(Origin::signed(4), vec![1])); - assert_ok!(Staking::unbond(Origin::signed(4), 500)); - assert_noop!(Staking::unbond(Origin::signed(4), 500), Error::::InsufficientBond); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(4), vec![1])); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(4), 500)); + assert_noop!( + Staking::unbond(RuntimeOrigin::signed(4), 500), + Error::::InsufficientBond + ); // Once they are chilled they can unbond everything - assert_ok!(Staking::chill(Origin::signed(4))); - assert_ok!(Staking::unbond(Origin::signed(4), 1000)); + assert_ok!(Staking::chill(RuntimeOrigin::signed(4))); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(4), 1000)); }) } @@ -4594,21 +4721,21 @@ fn chill_other_works() { // Nominator assert_ok!(Staking::bond( - Origin::signed(a), + RuntimeOrigin::signed(a), b, 1000, RewardDestination::Controller )); - assert_ok!(Staking::nominate(Origin::signed(b), vec![1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(b), vec![1])); // Validator assert_ok!(Staking::bond( - Origin::signed(c), + RuntimeOrigin::signed(c), d, 1500, RewardDestination::Controller )); - assert_ok!(Staking::validate(Origin::signed(d), ValidatorPrefs::default())); + assert_ok!(Staking::validate(RuntimeOrigin::signed(d), ValidatorPrefs::default())); } // To chill other users, we need to: @@ -4621,17 +4748,17 @@ fn chill_other_works() { // Can't chill these users assert_noop!( - Staking::chill_other(Origin::signed(1337), 1), + Staking::chill_other(RuntimeOrigin::signed(1337), 1), Error::::CannotChillOther ); assert_noop!( - Staking::chill_other(Origin::signed(1337), 3), + Staking::chill_other(RuntimeOrigin::signed(1337), 3), Error::::CannotChillOther ); // Change the minimum bond... but no limits. assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Set(1_500), ConfigOp::Set(2_000), ConfigOp::Remove, @@ -4642,17 +4769,17 @@ fn chill_other_works() { // Still can't chill these users assert_noop!( - Staking::chill_other(Origin::signed(1337), 1), + Staking::chill_other(RuntimeOrigin::signed(1337), 1), Error::::CannotChillOther ); assert_noop!( - Staking::chill_other(Origin::signed(1337), 3), + Staking::chill_other(RuntimeOrigin::signed(1337), 3), Error::::CannotChillOther ); // Add limits, but no threshold assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Set(10), @@ -4663,17 +4790,17 @@ fn chill_other_works() { // Still can't chill these users assert_noop!( - Staking::chill_other(Origin::signed(1337), 1), + Staking::chill_other(RuntimeOrigin::signed(1337), 1), Error::::CannotChillOther ); assert_noop!( - Staking::chill_other(Origin::signed(1337), 3), + Staking::chill_other(RuntimeOrigin::signed(1337), 3), Error::::CannotChillOther ); // Add threshold, but no limits assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Remove, @@ -4684,17 +4811,17 @@ fn chill_other_works() { // Still can't chill these users assert_noop!( - Staking::chill_other(Origin::signed(1337), 1), + Staking::chill_other(RuntimeOrigin::signed(1337), 1), Error::::CannotChillOther ); assert_noop!( - Staking::chill_other(Origin::signed(1337), 3), + Staking::chill_other(RuntimeOrigin::signed(1337), 3), Error::::CannotChillOther ); // Add threshold and limits assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Set(10), @@ -4712,19 +4839,19 @@ fn chill_other_works() { for i in 6..15 { let b = 4 * i + 1; let d = 4 * i + 3; - assert_ok!(Staking::chill_other(Origin::signed(1337), b)); - assert_ok!(Staking::chill_other(Origin::signed(1337), d)); + assert_ok!(Staking::chill_other(RuntimeOrigin::signed(1337), b)); + assert_ok!(Staking::chill_other(RuntimeOrigin::signed(1337), d)); } // chill a nominator. Limit is not reached, not chill-able assert_eq!(Nominators::::count(), 7); assert_noop!( - Staking::chill_other(Origin::signed(1337), 1), + Staking::chill_other(RuntimeOrigin::signed(1337), 1), Error::::CannotChillOther ); // chill a validator. Limit is reached, chill-able. assert_eq!(Validators::::count(), 9); - assert_ok!(Staking::chill_other(Origin::signed(1337), 3)); + assert_ok!(Staking::chill_other(RuntimeOrigin::signed(1337), 3)); }) } @@ -4739,7 +4866,7 @@ fn capped_stakers_works() { // Change the maximums let max = 10; assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Set(10), ConfigOp::Set(10), ConfigOp::Set(max), @@ -4757,7 +4884,10 @@ fn capped_stakers_works() { RewardDestination::Controller, ) .unwrap(); - assert_ok!(Staking::validate(Origin::signed(controller), ValidatorPrefs::default())); + assert_ok!(Staking::validate( + RuntimeOrigin::signed(controller), + ValidatorPrefs::default() + )); some_existing_validator = controller; } @@ -4770,7 +4900,7 @@ fn capped_stakers_works() { .unwrap(); assert_noop!( - Staking::validate(Origin::signed(last_validator), ValidatorPrefs::default()), + Staking::validate(RuntimeOrigin::signed(last_validator), ValidatorPrefs::default()), Error::::TooManyValidators, ); @@ -4783,7 +4913,7 @@ fn capped_stakers_works() { RewardDestination::Controller, ) .unwrap(); - assert_ok!(Staking::nominate(Origin::signed(controller), vec![1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(controller), vec![1])); some_existing_nominator = controller; } @@ -4795,21 +4925,21 @@ fn capped_stakers_works() { ) .unwrap(); assert_noop!( - Staking::nominate(Origin::signed(last_nominator), vec![1]), + Staking::nominate(RuntimeOrigin::signed(last_nominator), vec![1]), Error::::TooManyNominators ); // Re-nominate works fine - assert_ok!(Staking::nominate(Origin::signed(some_existing_nominator), vec![1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(some_existing_nominator), vec![1])); // Re-validate works fine assert_ok!(Staking::validate( - Origin::signed(some_existing_validator), + RuntimeOrigin::signed(some_existing_validator), ValidatorPrefs::default() )); // No problem when we set to `None` again assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Noop, ConfigOp::Noop, ConfigOp::Remove, @@ -4817,8 +4947,11 @@ fn capped_stakers_works() { ConfigOp::Noop, ConfigOp::Noop, )); - assert_ok!(Staking::nominate(Origin::signed(last_nominator), vec![1])); - assert_ok!(Staking::validate(Origin::signed(last_validator), ValidatorPrefs::default())); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(last_nominator), vec![1])); + assert_ok!(Staking::validate( + RuntimeOrigin::signed(last_validator), + ValidatorPrefs::default() + )); }) } @@ -4827,21 +4960,21 @@ fn min_commission_works() { ExtBuilder::default().build_and_execute(|| { // account 10 controls the stash from account 11 assert_ok!(Staking::validate( - Origin::signed(10), + RuntimeOrigin::signed(10), ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false } )); // event emitted should be correct assert_eq!( *staking_events().last().unwrap(), - Event::ValidatorPrefsSet( - 11, - ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false } - ) + Event::ValidatorPrefsSet { + stash: 11, + prefs: ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false } + } ); assert_ok!(Staking::set_staking_configs( - Origin::root(), + RuntimeOrigin::root(), ConfigOp::Remove, ConfigOp::Remove, ConfigOp::Remove, @@ -4853,7 +4986,7 @@ fn min_commission_works() { // can't make it less than 10 now assert_noop!( Staking::validate( - Origin::signed(10), + RuntimeOrigin::signed(10), ValidatorPrefs { commission: Perbill::from_percent(5), blocked: false } ), Error::::CommissionTooLow @@ -4861,12 +4994,12 @@ fn min_commission_works() { // can only change to higher. assert_ok!(Staking::validate( - Origin::signed(10), + RuntimeOrigin::signed(10), ValidatorPrefs { commission: Perbill::from_percent(10), blocked: false } )); assert_ok!(Staking::validate( - Origin::signed(10), + RuntimeOrigin::signed(10), ValidatorPrefs { commission: Perbill::from_percent(15), blocked: false } )); }) @@ -4949,7 +5082,7 @@ fn change_of_max_nominations() { assert_eq!(Staking::electing_voters(None).unwrap().len(), 3 + 1); // now one of them can revive themselves by re-nominating to a proper value. - assert_ok!(Staking::nominate(Origin::signed(71), vec![1])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(71), vec![1])); assert_eq!( Nominators::::iter() .map(|(k, n)| (k, n.targets.len())) @@ -4960,7 +5093,7 @@ fn change_of_max_nominations() { // or they can be chilled by any account. assert!(Nominators::::contains_key(101)); assert!(Nominators::::get(101).is_none()); - assert_ok!(Staking::chill_other(Origin::signed(70), 100)); + assert_ok!(Staking::chill_other(RuntimeOrigin::signed(70), 100)); assert!(!Nominators::::contains_key(101)); assert!(Nominators::::get(101).is_none()); }) @@ -4984,7 +5117,7 @@ mod sorted_list_provider { ); // when account 101 renominates - assert_ok!(Staking::nominate(Origin::signed(100), vec![41])); + assert_ok!(Staking::nominate(RuntimeOrigin::signed(100), vec![41])); // then counts don't change assert_eq!(::VoterList::count(), pre_insert_voter_count); @@ -5007,7 +5140,7 @@ mod sorted_list_provider { assert_eq!(::VoterList::iter().collect::>(), vec![11, 21, 31]); // when account 11 re-validates - assert_ok!(Staking::validate(Origin::signed(10), Default::default())); + assert_ok!(Staking::validate(RuntimeOrigin::signed(10), Default::default())); // then counts don't change assert_eq!(::VoterList::count(), pre_insert_voter_count); @@ -5022,31 +5155,31 @@ fn force_apply_min_commission_works() { let prefs = |c| ValidatorPrefs { commission: Perbill::from_percent(c), blocked: false }; let validators = || Validators::::iter().collect::>(); ExtBuilder::default().build_and_execute(|| { - assert_ok!(Staking::validate(Origin::signed(30), prefs(10))); - assert_ok!(Staking::validate(Origin::signed(20), prefs(5))); + assert_ok!(Staking::validate(RuntimeOrigin::signed(30), prefs(10))); + assert_ok!(Staking::validate(RuntimeOrigin::signed(20), prefs(5))); // Given assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(0))]); MinCommission::::set(Perbill::from_percent(5)); // When applying to a commission greater than min - assert_ok!(Staking::force_apply_min_commission(Origin::signed(1), 31)); + assert_ok!(Staking::force_apply_min_commission(RuntimeOrigin::signed(1), 31)); // Then the commission is not changed assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(0))]); // When applying to a commission that is equal to min - assert_ok!(Staking::force_apply_min_commission(Origin::signed(1), 21)); + assert_ok!(Staking::force_apply_min_commission(RuntimeOrigin::signed(1), 21)); // Then the commission is not changed assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(0))]); // When applying to a commission that is less than the min - assert_ok!(Staking::force_apply_min_commission(Origin::signed(1), 11)); + assert_ok!(Staking::force_apply_min_commission(RuntimeOrigin::signed(1), 11)); // Then the commission is bumped to the min assert_eq!(validators(), vec![(31, prefs(10)), (21, prefs(5)), (11, prefs(5))]); // When applying commission to a validator that doesn't exist then storage is not altered assert_noop!( - Staking::force_apply_min_commission(Origin::signed(1), 420), + Staking::force_apply_min_commission(RuntimeOrigin::signed(1), 420), Error::::NotStash ); }); @@ -5062,7 +5195,7 @@ fn proportional_slash_stop_slashing_if_remaining_zero() { active: 20, // we have some chunks, but they are not affected. unlocking: bounded_vec![c(1, 10), c(2, 10)], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }; assert_eq!(BondingDuration::get(), 3); @@ -5080,7 +5213,7 @@ fn proportional_ledger_slash_works() { total: 10, active: 10, unlocking: bounded_vec![], - claimed_rewards: vec![], + claimed_rewards: bounded_vec![], }; assert_eq!(BondingDuration::get(), 3); @@ -5296,3 +5429,198 @@ fn proportional_ledger_slash_works() { BTreeMap::from([(4, 0), (5, value_slashed), (6, 0), (7, 0)]) ); } + +#[test] +fn pre_bonding_era_cannot_be_claimed() { + // Verifies initial conditions of mock + ExtBuilder::default().nominate(false).build_and_execute(|| { + let history_depth = HistoryDepth::get(); + // jump to some era above history_depth + let mut current_era = history_depth + 10; + let last_reward_era = current_era - 1; + let start_reward_era = current_era - history_depth; + + // put some money in stash=3 and controller=4. + for i in 3..5 { + let _ = Balances::make_free_balance_be(&i, 2000); + } + + mock::start_active_era(current_era); + + // add a new candidate for being a validator. account 3 controlled by 4. + assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 4, 1500, RewardDestination::Controller)); + + let claimed_rewards: BoundedVec<_, _> = + (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); + assert_eq!( + Staking::ledger(&4).unwrap(), + StakingLedger { + stash: 3, + total: 1500, + active: 1500, + unlocking: Default::default(), + claimed_rewards, + } + ); + + // start next era + current_era = current_era + 1; + mock::start_active_era(current_era); + + // claiming reward for last era in which validator was active works + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 1)); + + // consumed weight for all payout_stakers dispatches that fail + let err_weight = ::WeightInfo::payout_stakers_alive_staked(0); + // cannot claim rewards for an era before bonding occured as it is + // already marked as claimed. + assert_noop!( + Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 2), + Error::::AlreadyClaimed.with_weight(err_weight) + ); + + // decoding will fail now since Staking Ledger is in corrupt state + HistoryDepth::set(history_depth - 1); + assert_eq!(Staking::ledger(&4), None); + + // make sure stakers still cannot claim rewards that they are not meant to + assert_noop!( + Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 2), + Error::::NotController + ); + + // fix the corrupted state for post conditions check + HistoryDepth::set(history_depth); + }); +} + +#[test] +fn reducing_history_depth_abrupt() { + // Verifies initial conditions of mock + ExtBuilder::default().nominate(false).build_and_execute(|| { + let original_history_depth = HistoryDepth::get(); + let mut current_era = original_history_depth + 10; + let last_reward_era = current_era - 1; + let start_reward_era = current_era - original_history_depth; + + // put some money in (stash, controller)=(3,4),(5,6). + for i in 3..7 { + let _ = Balances::make_free_balance_be(&i, 2000); + } + + // start current era + mock::start_active_era(current_era); + + // add a new candidate for being a staker. account 3 controlled by 4. + assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 4, 1500, RewardDestination::Controller)); + + // all previous era before the bonding action should be marked as + // claimed. + let claimed_rewards: BoundedVec<_, _> = + (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); + assert_eq!( + Staking::ledger(&4).unwrap(), + StakingLedger { + stash: 3, + total: 1500, + active: 1500, + unlocking: Default::default(), + claimed_rewards, + } + ); + + // next era + current_era = current_era + 1; + mock::start_active_era(current_era); + + // claiming reward for last era in which validator was active works + assert_ok!(Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 1)); + + // next era + current_era = current_era + 1; + mock::start_active_era(current_era); + + // history_depth reduced without migration + let history_depth = original_history_depth - 1; + HistoryDepth::set(history_depth); + // claiming reward does not work anymore + assert_noop!( + Staking::payout_stakers(RuntimeOrigin::signed(4), 3, current_era - 1), + Error::::NotController + ); + + // new stakers can still bond + assert_ok!(Staking::bond(RuntimeOrigin::signed(5), 6, 1200, RewardDestination::Controller)); + + // new staking ledgers created will be bounded by the current history depth + let last_reward_era = current_era - 1; + let start_reward_era = current_era - history_depth; + let claimed_rewards: BoundedVec<_, _> = + (start_reward_era..=last_reward_era).collect::>().try_into().unwrap(); + assert_eq!( + Staking::ledger(&6).unwrap(), + StakingLedger { + stash: 5, + total: 1200, + active: 1200, + unlocking: Default::default(), + claimed_rewards, + } + ); + + // fix the corrupted state for post conditions check + HistoryDepth::set(original_history_depth); + }); +} + +#[test] +fn reducing_max_unlocking_chunks_abrupt() { + // Concern is on validators only + // By Default 11, 10 are stash and ctrl and 21,20 + ExtBuilder::default().build_and_execute(|| { + // given a staker at era=10 and MaxUnlockChunks set to 2 + MaxUnlockingChunks::set(2); + start_active_era(10); + assert_ok!(Staking::bond(RuntimeOrigin::signed(3), 4, 300, RewardDestination::Staked)); + assert!(matches!(Staking::ledger(4), Some(_))); + + // when staker unbonds + assert_ok!(Staking::unbond(RuntimeOrigin::signed(4), 20)); + + // then an unlocking chunk is added at `current_era + bonding_duration` + // => 10 + 3 = 13 + let expected_unlocking: BoundedVec, MaxUnlockingChunks> = + bounded_vec![UnlockChunk { value: 20 as Balance, era: 13 as EraIndex }]; + assert!(matches!(Staking::ledger(4), + Some(StakingLedger { + unlocking, + .. + }) if unlocking==expected_unlocking)); + + // when staker unbonds at next era + start_active_era(11); + assert_ok!(Staking::unbond(RuntimeOrigin::signed(4), 50)); + // then another unlock chunk is added + let expected_unlocking: BoundedVec, MaxUnlockingChunks> = + bounded_vec![UnlockChunk { value: 20, era: 13 }, UnlockChunk { value: 50, era: 14 }]; + assert!(matches!(Staking::ledger(4), + Some(StakingLedger { + unlocking, + .. + }) if unlocking==expected_unlocking)); + + // when staker unbonds further + start_active_era(12); + // then further unbonding not possible + assert_noop!(Staking::unbond(RuntimeOrigin::signed(4), 20), Error::::NoMoreChunks); + + // when max unlocking chunks is reduced abruptly to a low value + MaxUnlockingChunks::set(1); + // then unbond, rebond ops are blocked with ledger in corrupt state + assert_noop!(Staking::unbond(RuntimeOrigin::signed(4), 20), Error::::NotController); + assert_noop!(Staking::rebond(RuntimeOrigin::signed(4), 100), Error::::NotController); + + // reset the ledger corruption + MaxUnlockingChunks::set(2); + }) +} diff --git a/frame/staking/src/weights.rs b/frame/staking/src/weights.rs index 09c2d8b5de113..5070232365d3e 100644 --- a/frame/staking/src/weights.rs +++ b/frame/staking/src/weights.rs @@ -18,22 +18,24 @@ //! Autogenerated weights for pallet_staking //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-05-24, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2022-09-19, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet -// --chain=dev // --steps=50 // --repeat=20 -// --pallet=pallet_staking // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --template=./.maintain/frame-weight-template.hbs +// --heap-pages=4096 +// --pallet=pallet_staking +// --chain=dev // --output=./frame/staking/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -65,7 +67,6 @@ pub trait WeightInfo { fn payout_stakers_dead_controller(n: u32, ) -> Weight; fn payout_stakers_alive_staked(n: u32, ) -> Weight; fn rebond(l: u32, ) -> Weight; - fn set_history_depth(e: u32, ) -> Weight; fn reap_stash(s: u32, ) -> Weight; fn new_era(v: u32, n: u32, ) -> Weight; fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight; @@ -82,21 +83,20 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - Weight::from_ref_time(43_992_000 as u64) - .saturating_add(T::DbWeight::get().reads(5 as u64)) + Weight::from_ref_time(52_281_000 as u64) + .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterBagsList ListNodes (r:3 w:3) + // Storage: VoterBagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - Weight::from_ref_time(75_827_000 as u64) + Weight::from_ref_time(89_748_000 as u64) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().writes(7 as u64)) } @@ -106,11 +106,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) + // Storage: VoterBagsList ListNodes (r:3 w:3) // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterBagsList ListBags (r:2 w:2) fn unbond() -> Weight { - Weight::from_ref_time(81_075_000 as u64) + Weight::from_ref_time(94_782_000 as u64) .saturating_add(T::DbWeight::get().reads(12 as u64)) .saturating_add(T::DbWeight::get().writes(8 as u64)) } @@ -118,10 +118,11 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - Weight::from_ref_time(35_763_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(57_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(44_499_000 as u64) + // Standard Error: 387 + .saturating_add(Weight::from_ref_time(72_726 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(4 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -132,14 +133,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - Weight::from_ref_time(66_938_000 as u64) + /// The range of component `s` is `[0, 100]`. + fn withdraw_unbonded_kill(s: u32, ) -> Weight { + Weight::from_ref_time(83_230_000 as u64) + // Standard Error: 612 + .saturating_add(Weight::from_ref_time(10_289 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(13 as u64)) .saturating_add(T::DbWeight::get().writes(11 as u64)) } @@ -150,23 +154,25 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxValidatorsCount (r:1 w:0) // Storage: Staking Nominators (r:1 w:0) // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListNodes (r:1 w:1) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:1 w:1) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - Weight::from_ref_time(52_943_000 as u64) + Weight::from_ref_time(64_430_000 as u64) .saturating_add(T::DbWeight::get().reads(11 as u64)) .saturating_add(T::DbWeight::get().writes(5 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) + /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - Weight::from_ref_time(23_264_000 as u64) - // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(8_006_000 as u64).saturating_mul(k as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) + Weight::from_ref_time(42_030_000 as u64) + // Standard Error: 5_873 + .saturating_add(Weight::from_ref_time(6_747_156 as u64).saturating_mul(k as u64)) + .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(k as u64))) + .saturating_add(T::DbWeight::get().writes(1 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(k as u64))) } // Storage: Staking Ledger (r:1 w:0) @@ -176,15 +182,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:2 w:0) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) + /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - Weight::from_ref_time(56_596_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(3_644_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(12 as u64)) + Weight::from_ref_time(70_834_000 as u64) + // Standard Error: 4_405 + .saturating_add(Weight::from_ref_time(2_583_120 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(13 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(6 as u64)) } @@ -192,53 +199,54 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - Weight::from_ref_time(51_117_000 as u64) + Weight::from_ref_time(63_328_000 as u64) .saturating_add(T::DbWeight::get().reads(8 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - Weight::from_ref_time(11_223_000 as u64) + Weight::from_ref_time(17_763_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - Weight::from_ref_time(19_826_000 as u64) + Weight::from_ref_time(26_163_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - Weight::from_ref_time(3_789_000 as u64) + Weight::from_ref_time(4_842_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - Weight::from_ref_time(3_793_000 as u64) + Weight::from_ref_time(4_974_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - Weight::from_ref_time(3_802_000 as u64) + Weight::from_ref_time(5_039_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - Weight::from_ref_time(3_762_000 as u64) + Weight::from_ref_time(4_950_000 as u64) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking Invulnerables (r:0 w:1) + /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - Weight::from_ref_time(4_318_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(10_000 as u64).saturating_mul(v as u64)) + Weight::from_ref_time(5_150_000 as u64) + // Standard Error: 30 + .saturating_add(Weight::from_ref_time(10_540 as u64).saturating_mul(v as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking Bonded (r:1 w:1) @@ -246,32 +254,33 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Ledger (r:0 w:1) // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) + /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - Weight::from_ref_time(65_265_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_029_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(76_282_000 as u64) + // Standard Error: 2_397 + .saturating_add(Weight::from_ref_time(1_137_934 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(11 as u64)) - .saturating_add(T::DbWeight::get().writes(12 as u64)) + .saturating_add(T::DbWeight::get().writes(11 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Staking UnappliedSlashes (r:1 w:1) + /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - Weight::from_ref_time(903_312_000 as u64) - // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(4_968_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(93_690_000 as u64) + // Standard Error: 43_203 + .saturating_add(Weight::from_ref_time(6_149_862 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) // Storage: Staking Bonded (r:2 w:0) // Storage: Staking Ledger (r:1 w:1) @@ -280,17 +289,17 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ErasValidatorPrefs (r:1 w:0) // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) + /// The range of component `n` is `[1, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - Weight::from_ref_time(87_569_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(24_232_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(10 as u64)) + Weight::from_ref_time(151_647_000 as u64) + // Standard Error: 8_237 + .saturating_add(Weight::from_ref_time(21_296_415 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(12 as u64)) .saturating_add(T::DbWeight::get().reads((3 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(2 as u64)) + .saturating_add(T::DbWeight::get().writes(3 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(n as u64))) } // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) // Storage: Staking Bonded (r:2 w:0) // Storage: Staking Ledger (r:2 w:2) @@ -300,45 +309,30 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) + /// The range of component `n` is `[1, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - Weight::from_ref_time(98_839_000 as u64) - // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(34_480_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(11 as u64)) + Weight::from_ref_time(197_310_000 as u64) + // Standard Error: 13_818 + .saturating_add(Weight::from_ref_time(30_053_043 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(15 as u64)) .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(n as u64))) } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) + // Storage: VoterBagsList ListNodes (r:3 w:3) // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterBagsList ListBags (r:2 w:2) + /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - Weight::from_ref_time(74_865_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(64_000 as u64).saturating_mul(l as u64)) + Weight::from_ref_time(89_469_000 as u64) + // Standard Error: 1_197 + .saturating_add(Weight::from_ref_time(74_212 as u64).saturating_mul(l as u64)) .saturating_add(T::DbWeight::get().reads(9 as u64)) .saturating_add(T::DbWeight::get().writes(8 as u64)) } - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:1) - // Storage: Staking ErasStakersClipped (r:0 w:2) - // Storage: Staking ErasValidatorPrefs (r:0 w:2) - // Storage: Staking ErasValidatorReward (r:0 w:1) - // Storage: Staking ErasRewardPoints (r:0 w:1) - // Storage: Staking ErasStakers (r:0 w:2) - // Storage: Staking ErasTotalStake (r:0 w:1) - // Storage: Staking ErasStartSessionIndex (r:0 w:1) - fn set_history_depth(e: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 62_000 - .saturating_add(Weight::from_ref_time(22_829_000 as u64).saturating_mul(e as u64)) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(4 as u64)) - .saturating_add(T::DbWeight::get().writes((7 as u64).saturating_mul(e as u64))) - } // Storage: System Account (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:1 w:1) @@ -346,24 +340,25 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) + /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - Weight::from_ref_time(70_933_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_021_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(88_333_000 as u64) + // Standard Error: 1_567 + .saturating_add(Weight::from_ref_time(1_101_099 as u64).saturating_mul(s as u64)) .saturating_add(T::DbWeight::get().reads(12 as u64)) - .saturating_add(T::DbWeight::get().writes(12 as u64)) + .saturating_add(T::DbWeight::get().writes(13 as u64)) .saturating_add(T::DbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } - // Storage: BagsList CounterForListNodes (r:1 w:0) + // Storage: VoterBagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:1 w:0) - // Storage: BagsList ListBags (r:200 w:0) - // Storage: BagsList ListNodes (r:101 w:0) + // Storage: VoterBagsList ListBags (r:200 w:0) + // Storage: VoterBagsList ListNodes (r:101 w:0) // Storage: Staking Nominators (r:101 w:0) // Storage: Staking Validators (r:2 w:0) // Storage: Staking Bonded (r:101 w:0) @@ -372,52 +367,54 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking ValidatorCount (r:1 w:0) // Storage: Staking MinimumValidatorCount (r:1 w:0) // Storage: Staking CurrentEra (r:1 w:1) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Staking ErasStakersClipped (r:0 w:1) // Storage: Staking ErasValidatorPrefs (r:0 w:1) // Storage: Staking ErasStakers (r:0 w:1) // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) + /// The range of component `v` is `[1, 10]`. + /// The range of component `n` is `[1, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 897_000 - .saturating_add(Weight::from_ref_time(213_100_000 as u64).saturating_mul(v as u64)) - // Standard Error: 45_000 - .saturating_add(Weight::from_ref_time(31_123_000 as u64).saturating_mul(n as u64)) - .saturating_add(T::DbWeight::get().reads(208 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(v as u64))) + Weight::from_ref_time(572_530_000 as u64) + // Standard Error: 3_166_542 + .saturating_add(Weight::from_ref_time(101_354_358 as u64).saturating_mul(v as u64)) + // Standard Error: 315_238 + .saturating_add(Weight::from_ref_time(15_565_319 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(261 as u64)) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(v as u64))) .saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(3 as u64)) + .saturating_add(T::DbWeight::get().writes(6 as u64)) .saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(v as u64))) } - // Storage: BagsList CounterForListNodes (r:1 w:0) + // Storage: VoterBagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:21 w:0) - // Storage: BagsList ListBags (r:200 w:0) - // Storage: BagsList ListNodes (r:1500 w:0) + // Storage: VoterBagsList ListBags (r:200 w:0) + // Storage: VoterBagsList ListNodes (r:1500 w:0) // Storage: Staking Nominators (r:1500 w:0) // Storage: Staking Validators (r:500 w:0) // Storage: Staking Bonded (r:1500 w:0) // Storage: Staking Ledger (r:1500 w:0) - fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(23_745_000 as u64).saturating_mul(v as u64)) - // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(22_497_000 as u64).saturating_mul(n as u64)) - // Standard Error: 3_968_000 - .saturating_add(Weight::from_ref_time(20_676_000 as u64).saturating_mul(s as u64)) - .saturating_add(T::DbWeight::get().reads(202 as u64)) - .saturating_add(T::DbWeight::get().reads((5 as u64).saturating_mul(v as u64))) - .saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + /// The range of component `v` is `[500, 1000]`. + /// The range of component `n` is `[500, 1000]`. + /// The range of component `s` is `[1, 20]`. + fn get_npos_voters(v: u32, n: u32, _s: u32, ) -> Weight { + Weight::from_ref_time(24_930_788_000 as u64) + // Standard Error: 266_386 + .saturating_add(Weight::from_ref_time(6_687_552 as u64).saturating_mul(v as u64)) + // Standard Error: 266_386 + .saturating_add(Weight::from_ref_time(6_839_134 as u64).saturating_mul(n as u64)) + .saturating_add(T::DbWeight::get().reads(6722 as u64)) + .saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(v as u64))) + .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) } + // Storage: Staking CounterForValidators (r:1 w:0) // Storage: Staking Validators (r:501 w:0) + /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 36_000 - .saturating_add(Weight::from_ref_time(8_097_000 as u64).saturating_mul(v as u64)) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(v as u64))) + Weight::from_ref_time(4_864_727_000 as u64) + // Standard Error: 54_240 + .saturating_add(Weight::from_ref_time(3_319_738 as u64).saturating_mul(v as u64)) + .saturating_add(T::DbWeight::get().reads(502 as u64)) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -426,7 +423,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - Weight::from_ref_time(7_041_000 as u64) + Weight::from_ref_time(10_141_000 as u64) .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking MinCommission (r:0 w:1) @@ -436,7 +433,7 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - Weight::from_ref_time(6_495_000 as u64) + Weight::from_ref_time(8_993_000 as u64) .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) @@ -446,18 +443,18 @@ impl WeightInfo for SubstrateWeight { // Storage: Staking CounterForNominators (r:1 w:1) // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: Staking Validators (r:1 w:0) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - Weight::from_ref_time(62_014_000 as u64) + Weight::from_ref_time(79_082_000 as u64) .saturating_add(T::DbWeight::get().reads(11 as u64)) .saturating_add(T::DbWeight::get().writes(6 as u64)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - Weight::from_ref_time(12_814_000 as u64) + Weight::from_ref_time(19_265_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -468,21 +465,20 @@ impl WeightInfo for () { // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:1 w:1) // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) fn bond() -> Weight { - Weight::from_ref_time(43_992_000 as u64) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) + Weight::from_ref_time(52_281_000 as u64) + .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Staking Bonded (r:1 w:0) // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterBagsList ListNodes (r:3 w:3) + // Storage: VoterBagsList ListBags (r:2 w:2) fn bond_extra() -> Weight { - Weight::from_ref_time(75_827_000 as u64) + Weight::from_ref_time(89_748_000 as u64) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().writes(7 as u64)) } @@ -492,11 +488,11 @@ impl WeightInfo for () { // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) + // Storage: VoterBagsList ListNodes (r:3 w:3) // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterBagsList ListBags (r:2 w:2) fn unbond() -> Weight { - Weight::from_ref_time(81_075_000 as u64) + Weight::from_ref_time(94_782_000 as u64) .saturating_add(RocksDbWeight::get().reads(12 as u64)) .saturating_add(RocksDbWeight::get().writes(8 as u64)) } @@ -504,10 +500,11 @@ impl WeightInfo for () { // Storage: Staking CurrentEra (r:1 w:0) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) + /// The range of component `s` is `[0, 100]`. fn withdraw_unbonded_update(s: u32, ) -> Weight { - Weight::from_ref_time(35_763_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(57_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(44_499_000 as u64) + // Standard Error: 387 + .saturating_add(Weight::from_ref_time(72_726 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(4 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -518,14 +515,17 @@ impl WeightInfo for () { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) - fn withdraw_unbonded_kill(_s: u32, ) -> Weight { - Weight::from_ref_time(66_938_000 as u64) + /// The range of component `s` is `[0, 100]`. + fn withdraw_unbonded_kill(s: u32, ) -> Weight { + Weight::from_ref_time(83_230_000 as u64) + // Standard Error: 612 + .saturating_add(Weight::from_ref_time(10_289 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(13 as u64)) .saturating_add(RocksDbWeight::get().writes(11 as u64)) } @@ -536,23 +536,25 @@ impl WeightInfo for () { // Storage: Staking MaxValidatorsCount (r:1 w:0) // Storage: Staking Nominators (r:1 w:0) // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListNodes (r:1 w:1) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:1 w:1) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForValidators (r:1 w:1) fn validate() -> Weight { - Weight::from_ref_time(52_943_000 as u64) + Weight::from_ref_time(64_430_000 as u64) .saturating_add(RocksDbWeight::get().reads(11 as u64)) .saturating_add(RocksDbWeight::get().writes(5 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) + /// The range of component `k` is `[1, 128]`. fn kick(k: u32, ) -> Weight { - Weight::from_ref_time(23_264_000 as u64) - // Standard Error: 11_000 - .saturating_add(Weight::from_ref_time(8_006_000 as u64).saturating_mul(k as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) + Weight::from_ref_time(42_030_000 as u64) + // Standard Error: 5_873 + .saturating_add(Weight::from_ref_time(6_747_156 as u64).saturating_mul(k as u64)) + .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(k as u64))) + .saturating_add(RocksDbWeight::get().writes(1 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(k as u64))) } // Storage: Staking Ledger (r:1 w:0) @@ -562,15 +564,16 @@ impl WeightInfo for () { // Storage: Staking Validators (r:2 w:0) // Storage: Staking CurrentEra (r:1 w:0) // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) + /// The range of component `n` is `[1, 16]`. fn nominate(n: u32, ) -> Weight { - Weight::from_ref_time(56_596_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(3_644_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(12 as u64)) + Weight::from_ref_time(70_834_000 as u64) + // Standard Error: 4_405 + .saturating_add(Weight::from_ref_time(2_583_120 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(13 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } @@ -578,53 +581,54 @@ impl WeightInfo for () { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) fn chill() -> Weight { - Weight::from_ref_time(51_117_000 as u64) + Weight::from_ref_time(63_328_000 as u64) .saturating_add(RocksDbWeight::get().reads(8 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) // Storage: Staking Payee (r:0 w:1) fn set_payee() -> Weight { - Weight::from_ref_time(11_223_000 as u64) + Weight::from_ref_time(17_763_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:2 w:2) fn set_controller() -> Weight { - Weight::from_ref_time(19_826_000 as u64) + Weight::from_ref_time(26_163_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } // Storage: Staking ValidatorCount (r:0 w:1) fn set_validator_count() -> Weight { - Weight::from_ref_time(3_789_000 as u64) + Weight::from_ref_time(4_842_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_no_eras() -> Weight { - Weight::from_ref_time(3_793_000 as u64) + Weight::from_ref_time(4_974_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era() -> Weight { - Weight::from_ref_time(3_802_000 as u64) + Weight::from_ref_time(5_039_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking ForceEra (r:0 w:1) fn force_new_era_always() -> Weight { - Weight::from_ref_time(3_762_000 as u64) + Weight::from_ref_time(4_950_000 as u64) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking Invulnerables (r:0 w:1) + /// The range of component `v` is `[0, 1000]`. fn set_invulnerables(v: u32, ) -> Weight { - Weight::from_ref_time(4_318_000 as u64) - // Standard Error: 0 - .saturating_add(Weight::from_ref_time(10_000 as u64).saturating_mul(v as u64)) + Weight::from_ref_time(5_150_000 as u64) + // Standard Error: 30 + .saturating_add(Weight::from_ref_time(10_540 as u64).saturating_mul(v as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking Bonded (r:1 w:1) @@ -632,32 +636,33 @@ impl WeightInfo for () { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: System Account (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Ledger (r:0 w:1) // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:2) + /// The range of component `s` is `[0, 100]`. fn force_unstake(s: u32, ) -> Weight { - Weight::from_ref_time(65_265_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_029_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(76_282_000 as u64) + // Standard Error: 2_397 + .saturating_add(Weight::from_ref_time(1_137_934 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(11 as u64)) - .saturating_add(RocksDbWeight::get().writes(12 as u64)) + .saturating_add(RocksDbWeight::get().writes(11 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } // Storage: Staking UnappliedSlashes (r:1 w:1) + /// The range of component `s` is `[1, 1000]`. fn cancel_deferred_slash(s: u32, ) -> Weight { - Weight::from_ref_time(903_312_000 as u64) - // Standard Error: 56_000 - .saturating_add(Weight::from_ref_time(4_968_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(93_690_000 as u64) + // Standard Error: 43_203 + .saturating_add(Weight::from_ref_time(6_149_862 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) // Storage: Staking Bonded (r:2 w:0) // Storage: Staking Ledger (r:1 w:1) @@ -666,17 +671,17 @@ impl WeightInfo for () { // Storage: Staking ErasValidatorPrefs (r:1 w:0) // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) + /// The range of component `n` is `[1, 256]`. fn payout_stakers_dead_controller(n: u32, ) -> Weight { - Weight::from_ref_time(87_569_000 as u64) - // Standard Error: 14_000 - .saturating_add(Weight::from_ref_time(24_232_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(10 as u64)) + Weight::from_ref_time(151_647_000 as u64) + // Standard Error: 8_237 + .saturating_add(Weight::from_ref_time(21_296_415 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(12 as u64)) .saturating_add(RocksDbWeight::get().reads((3 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) + .saturating_add(RocksDbWeight::get().writes(3 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(n as u64))) } // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Staking ErasValidatorReward (r:1 w:0) // Storage: Staking Bonded (r:2 w:0) // Storage: Staking Ledger (r:2 w:2) @@ -686,45 +691,30 @@ impl WeightInfo for () { // Storage: Staking Payee (r:2 w:0) // Storage: System Account (r:2 w:2) // Storage: Balances Locks (r:2 w:2) + /// The range of component `n` is `[1, 256]`. fn payout_stakers_alive_staked(n: u32, ) -> Weight { - Weight::from_ref_time(98_839_000 as u64) - // Standard Error: 21_000 - .saturating_add(Weight::from_ref_time(34_480_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(11 as u64)) + Weight::from_ref_time(197_310_000 as u64) + // Standard Error: 13_818 + .saturating_add(Weight::from_ref_time(30_053_043 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(15 as u64)) .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(n as u64))) } // Storage: Staking Ledger (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: System Account (r:1 w:1) - // Storage: BagsList ListNodes (r:3 w:3) + // Storage: VoterBagsList ListNodes (r:3 w:3) // Storage: Staking Bonded (r:1 w:0) - // Storage: BagsList ListBags (r:2 w:2) + // Storage: VoterBagsList ListBags (r:2 w:2) + /// The range of component `l` is `[1, 32]`. fn rebond(l: u32, ) -> Weight { - Weight::from_ref_time(74_865_000 as u64) - // Standard Error: 3_000 - .saturating_add(Weight::from_ref_time(64_000 as u64).saturating_mul(l as u64)) + Weight::from_ref_time(89_469_000 as u64) + // Standard Error: 1_197 + .saturating_add(Weight::from_ref_time(74_212 as u64).saturating_mul(l as u64)) .saturating_add(RocksDbWeight::get().reads(9 as u64)) .saturating_add(RocksDbWeight::get().writes(8 as u64)) } - // Storage: Staking CurrentEra (r:1 w:0) - // Storage: Staking HistoryDepth (r:1 w:1) - // Storage: Staking ErasStakersClipped (r:0 w:2) - // Storage: Staking ErasValidatorPrefs (r:0 w:2) - // Storage: Staking ErasValidatorReward (r:0 w:1) - // Storage: Staking ErasRewardPoints (r:0 w:1) - // Storage: Staking ErasStakers (r:0 w:2) - // Storage: Staking ErasTotalStake (r:0 w:1) - // Storage: Staking ErasStartSessionIndex (r:0 w:1) - fn set_history_depth(e: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 62_000 - .saturating_add(Weight::from_ref_time(22_829_000 as u64).saturating_mul(e as u64)) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(4 as u64)) - .saturating_add(RocksDbWeight::get().writes((7 as u64).saturating_mul(e as u64))) - } // Storage: System Account (r:1 w:1) // Storage: Staking Bonded (r:1 w:1) // Storage: Staking Ledger (r:1 w:1) @@ -732,24 +722,25 @@ impl WeightInfo for () { // Storage: Staking Validators (r:1 w:0) // Storage: Staking Nominators (r:1 w:1) // Storage: Staking CounterForNominators (r:1 w:1) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) // Storage: Balances Locks (r:1 w:1) // Storage: Staking Payee (r:0 w:1) // Storage: Staking SpanSlash (r:0 w:1) + /// The range of component `s` is `[1, 100]`. fn reap_stash(s: u32, ) -> Weight { - Weight::from_ref_time(70_933_000 as u64) - // Standard Error: 1_000 - .saturating_add(Weight::from_ref_time(1_021_000 as u64).saturating_mul(s as u64)) + Weight::from_ref_time(88_333_000 as u64) + // Standard Error: 1_567 + .saturating_add(Weight::from_ref_time(1_101_099 as u64).saturating_mul(s as u64)) .saturating_add(RocksDbWeight::get().reads(12 as u64)) - .saturating_add(RocksDbWeight::get().writes(12 as u64)) + .saturating_add(RocksDbWeight::get().writes(13 as u64)) .saturating_add(RocksDbWeight::get().writes((1 as u64).saturating_mul(s as u64))) } - // Storage: BagsList CounterForListNodes (r:1 w:0) + // Storage: VoterBagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:1 w:0) - // Storage: BagsList ListBags (r:200 w:0) - // Storage: BagsList ListNodes (r:101 w:0) + // Storage: VoterBagsList ListBags (r:200 w:0) + // Storage: VoterBagsList ListNodes (r:101 w:0) // Storage: Staking Nominators (r:101 w:0) // Storage: Staking Validators (r:2 w:0) // Storage: Staking Bonded (r:101 w:0) @@ -758,52 +749,54 @@ impl WeightInfo for () { // Storage: Staking ValidatorCount (r:1 w:0) // Storage: Staking MinimumValidatorCount (r:1 w:0) // Storage: Staking CurrentEra (r:1 w:1) - // Storage: Staking HistoryDepth (r:1 w:0) // Storage: Staking ErasStakersClipped (r:0 w:1) // Storage: Staking ErasValidatorPrefs (r:0 w:1) // Storage: Staking ErasStakers (r:0 w:1) // Storage: Staking ErasTotalStake (r:0 w:1) // Storage: Staking ErasStartSessionIndex (r:0 w:1) + /// The range of component `v` is `[1, 10]`. + /// The range of component `n` is `[1, 100]`. fn new_era(v: u32, n: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 897_000 - .saturating_add(Weight::from_ref_time(213_100_000 as u64).saturating_mul(v as u64)) - // Standard Error: 45_000 - .saturating_add(Weight::from_ref_time(31_123_000 as u64).saturating_mul(n as u64)) - .saturating_add(RocksDbWeight::get().reads(208 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(v as u64))) + Weight::from_ref_time(572_530_000 as u64) + // Standard Error: 3_166_542 + .saturating_add(Weight::from_ref_time(101_354_358 as u64).saturating_mul(v as u64)) + // Standard Error: 315_238 + .saturating_add(Weight::from_ref_time(15_565_319 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(261 as u64)) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(v as u64))) .saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) + .saturating_add(RocksDbWeight::get().writes(6 as u64)) .saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(v as u64))) } - // Storage: BagsList CounterForListNodes (r:1 w:0) + // Storage: VoterBagsList CounterForListNodes (r:1 w:0) // Storage: Staking SlashingSpans (r:21 w:0) - // Storage: BagsList ListBags (r:200 w:0) - // Storage: BagsList ListNodes (r:1500 w:0) + // Storage: VoterBagsList ListBags (r:200 w:0) + // Storage: VoterBagsList ListNodes (r:1500 w:0) // Storage: Staking Nominators (r:1500 w:0) // Storage: Staking Validators (r:500 w:0) // Storage: Staking Bonded (r:1500 w:0) // Storage: Staking Ledger (r:1500 w:0) - fn get_npos_voters(v: u32, n: u32, s: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(23_745_000 as u64).saturating_mul(v as u64)) - // Standard Error: 116_000 - .saturating_add(Weight::from_ref_time(22_497_000 as u64).saturating_mul(n as u64)) - // Standard Error: 3_968_000 - .saturating_add(Weight::from_ref_time(20_676_000 as u64).saturating_mul(s as u64)) - .saturating_add(RocksDbWeight::get().reads(202 as u64)) - .saturating_add(RocksDbWeight::get().reads((5 as u64).saturating_mul(v as u64))) - .saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(s as u64))) + /// The range of component `v` is `[500, 1000]`. + /// The range of component `n` is `[500, 1000]`. + /// The range of component `s` is `[1, 20]`. + fn get_npos_voters(v: u32, n: u32, _s: u32, ) -> Weight { + Weight::from_ref_time(24_930_788_000 as u64) + // Standard Error: 266_386 + .saturating_add(Weight::from_ref_time(6_687_552 as u64).saturating_mul(v as u64)) + // Standard Error: 266_386 + .saturating_add(Weight::from_ref_time(6_839_134 as u64).saturating_mul(n as u64)) + .saturating_add(RocksDbWeight::get().reads(6722 as u64)) + .saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(v as u64))) + .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(n as u64))) } + // Storage: Staking CounterForValidators (r:1 w:0) // Storage: Staking Validators (r:501 w:0) + /// The range of component `v` is `[500, 1000]`. fn get_npos_targets(v: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 36_000 - .saturating_add(Weight::from_ref_time(8_097_000 as u64).saturating_mul(v as u64)) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(v as u64))) + Weight::from_ref_time(4_864_727_000 as u64) + // Standard Error: 54_240 + .saturating_add(Weight::from_ref_time(3_319_738 as u64).saturating_mul(v as u64)) + .saturating_add(RocksDbWeight::get().reads(502 as u64)) } // Storage: Staking MinCommission (r:0 w:1) // Storage: Staking MinValidatorBond (r:0 w:1) @@ -812,7 +805,7 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_set() -> Weight { - Weight::from_ref_time(7_041_000 as u64) + Weight::from_ref_time(10_141_000 as u64) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Staking MinCommission (r:0 w:1) @@ -822,7 +815,7 @@ impl WeightInfo for () { // Storage: Staking MaxNominatorsCount (r:0 w:1) // Storage: Staking MinNominatorBond (r:0 w:1) fn set_staking_configs_all_remove() -> Weight { - Weight::from_ref_time(6_495_000 as u64) + Weight::from_ref_time(8_993_000 as u64) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Staking Ledger (r:1 w:0) @@ -832,18 +825,18 @@ impl WeightInfo for () { // Storage: Staking CounterForNominators (r:1 w:1) // Storage: Staking MinNominatorBond (r:1 w:0) // Storage: Staking Validators (r:1 w:0) - // Storage: BagsList ListNodes (r:2 w:2) - // Storage: BagsList ListBags (r:1 w:1) - // Storage: BagsList CounterForListNodes (r:1 w:1) + // Storage: VoterBagsList ListNodes (r:2 w:2) + // Storage: VoterBagsList ListBags (r:1 w:1) + // Storage: VoterBagsList CounterForListNodes (r:1 w:1) fn chill_other() -> Weight { - Weight::from_ref_time(62_014_000 as u64) + Weight::from_ref_time(79_082_000 as u64) .saturating_add(RocksDbWeight::get().reads(11 as u64)) .saturating_add(RocksDbWeight::get().writes(6 as u64)) } // Storage: Staking MinCommission (r:1 w:0) // Storage: Staking Validators (r:1 w:1) fn force_apply_min_commission() -> Weight { - Weight::from_ref_time(12_814_000 as u64) + Weight::from_ref_time(19_265_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } diff --git a/frame/state-trie-migration/Cargo.toml b/frame/state-trie-migration/Cargo.toml index f8a3b1ba3aab4..b803aad69263f 100644 --- a/frame/state-trie-migration/Cargo.toml +++ b/frame/state-trie-migration/Cargo.toml @@ -39,7 +39,7 @@ sp-tracing = { path = "../../primitives/tracing" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/state-trie-migration/src/lib.rs b/frame/state-trie-migration/src/lib.rs index e29115382819a..5255d4f6f3800 100644 --- a/frame/state-trie-migration/src/lib.rs +++ b/frame/state-trie-migration/src/lib.rs @@ -446,13 +446,13 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// Origin that can control the configurations of this pallet. - type ControlOrigin: frame_support::traits::EnsureOrigin; + type ControlOrigin: frame_support::traits::EnsureOrigin; /// Filter on which origin that trigger the manual migrations. - type SignedFilter: EnsureOrigin; + type SignedFilter: EnsureOrigin; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The currency provider type. type Currency: Currency; @@ -964,7 +964,7 @@ mod benchmarks { ); frame_system::Pallet::::assert_last_event( - ::Event::from(crate::Event::Slashed { + ::RuntimeEvent::from(crate::Event::Slashed { who: caller.clone(), amount: T::SignedDepositBase::get() .saturating_add(T::SignedDepositPerItem::get().saturating_mul(1u32.into())), @@ -1084,8 +1084,8 @@ mod mock { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u32; type Hash = H256; @@ -1093,7 +1093,7 @@ mod mock { type AccountId = u64; type Lookup = IdentityLookup; type Header = sp_runtime::generic::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU32<250>; type DbWeight = (); type Version = (); @@ -1115,7 +1115,7 @@ mod mock { impl pallet_balances::Config for Test { type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -1153,7 +1153,7 @@ mod mock { } impl pallet_state_trie_migration::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ControlOrigin = EnsureRoot; type Currency = Balances; type MaxKeyLen = MigrationMaxKeyLen; @@ -1293,7 +1293,7 @@ mod test { // fails if the top key is too long. frame_support::assert_ok!(StateTrieMigration::continue_migrate( - Origin::signed(1), + RuntimeOrigin::signed(1), MigrationLimits { item: 50, size: 1 << 20 }, Bounded::max_value(), MigrationProcess::::get() @@ -1328,7 +1328,7 @@ mod test { // fails if the top key is too long. frame_support::assert_ok!(StateTrieMigration::continue_migrate( - Origin::signed(1), + RuntimeOrigin::signed(1), MigrationLimits { item: 50, size: 1 << 20 }, Bounded::max_value(), MigrationProcess::::get() @@ -1457,7 +1457,7 @@ mod test { // can't submit if limit is too high. frame_support::assert_err!( StateTrieMigration::continue_migrate( - Origin::signed(1), + RuntimeOrigin::signed(1), MigrationLimits { item: 5, size: sp_runtime::traits::Bounded::max_value() }, Bounded::max_value(), MigrationProcess::::get() @@ -1468,7 +1468,7 @@ mod test { // can't submit if poor. frame_support::assert_err!( StateTrieMigration::continue_migrate( - Origin::signed(2), + RuntimeOrigin::signed(2), MigrationLimits { item: 5, size: 100 }, 100, MigrationProcess::::get() @@ -1479,7 +1479,7 @@ mod test { // can't submit with bad witness. frame_support::assert_err_ignore_postinfo!( StateTrieMigration::continue_migrate( - Origin::signed(1), + RuntimeOrigin::signed(1), MigrationLimits { item: 5, size: 100 }, 100, MigrationTask { @@ -1500,7 +1500,7 @@ mod test { assert!(result.is_ok()); frame_support::assert_ok!(StateTrieMigration::continue_migrate( - Origin::signed(1), + RuntimeOrigin::signed(1), StateTrieMigration::signed_migration_max_limits().unwrap(), task.dyn_size, MigrationProcess::::get() @@ -1523,7 +1523,7 @@ mod test { let correct_witness = 3 + sp_core::storage::TRIE_VALUE_NODE_THRESHOLD * 3 + 1 + 2 + 3; new_test_ext(StateVersion::V0, true, None, None).execute_with(|| { frame_support::assert_ok!(StateTrieMigration::migrate_custom_top( - Origin::signed(1), + RuntimeOrigin::signed(1), vec![b"key1".to_vec(), b"key2".to_vec(), b"key3".to_vec()], correct_witness, )); @@ -1536,7 +1536,7 @@ mod test { new_test_ext(StateVersion::V0, true, None, None).execute_with(|| { // works if the witness is an overestimate frame_support::assert_ok!(StateTrieMigration::migrate_custom_top( - Origin::signed(1), + RuntimeOrigin::signed(1), vec![b"key1".to_vec(), b"key2".to_vec(), b"key3".to_vec()], correct_witness + 99, )); @@ -1551,7 +1551,7 @@ mod test { // note that we don't expect this to be a noop -- we do slash. frame_support::assert_ok!(StateTrieMigration::migrate_custom_top( - Origin::signed(1), + RuntimeOrigin::signed(1), vec![b"key1".to_vec(), b"key2".to_vec(), b"key3".to_vec()], correct_witness - 1, ),); @@ -1569,7 +1569,7 @@ mod test { fn custom_migrate_child_works() { new_test_ext(StateVersion::V0, true, None, None).execute_with(|| { frame_support::assert_ok!(StateTrieMigration::migrate_custom_child( - Origin::signed(1), + RuntimeOrigin::signed(1), StateTrieMigration::childify("chk1"), vec![b"key1".to_vec(), b"key2".to_vec()], 55 + 66, @@ -1585,7 +1585,7 @@ mod test { // note that we don't expect this to be a noop -- we do slash. frame_support::assert_ok!(StateTrieMigration::migrate_custom_child( - Origin::signed(1), + RuntimeOrigin::signed(1), StateTrieMigration::childify("chk1"), vec![b"key1".to_vec(), b"key2".to_vec()], 999999, // wrong witness @@ -1640,13 +1640,12 @@ pub(crate) mod remote_tests { /// /// This will print some very useful statistics, make sure [`crate::LOG_TARGET`] is enabled. #[allow(dead_code)] - pub(crate) async fn run_with_limits< + pub(crate) async fn run_with_limits(limits: MigrationLimits, mode: Mode) + where Runtime: crate::Config, - Block: BlockT + serde::de::DeserializeOwned, - >( - limits: MigrationLimits, - mode: Mode, - ) { + Block: BlockT, + Block::Header: serde::de::DeserializeOwned, + { let mut ext = remote_externalities::Builder::::new() .mode(mode) .state_version(sp_core::storage::StateVersion::V0) diff --git a/frame/sudo-mangata/src/lib.rs b/frame/sudo-mangata/src/lib.rs index 0995dbb3e0a1a..c789b930244d0 100644 --- a/frame/sudo-mangata/src/lib.rs +++ b/frame/sudo-mangata/src/lib.rs @@ -95,7 +95,7 @@ use sp_runtime::{traits::StaticLookup, DispatchResult}; use sp_std::prelude::*; -use frame_support::{traits::UnfilteredDispatchable, weights::GetDispatchInfo}; +use frame_support::{dispatch::GetDispatchInfo, traits::UnfilteredDispatchable}; #[cfg(test)] mod mock; @@ -129,10 +129,12 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// A sudo-able call. - type Call: Parameter + UnfilteredDispatchable + GetDispatchInfo; + type RuntimeCall: Parameter + + UnfilteredDispatchable + + GetDispatchInfo; } #[pallet::pallet] @@ -157,7 +159,7 @@ pub mod pallet { })] pub fn sudo( origin: OriginFor, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResultWithPostInfo { // This is a public call, so we ensure that the origin is some signed account. let sender = ensure_signed(origin)?; @@ -185,7 +187,7 @@ pub mod pallet { #[pallet::weight((*_weight, call.get_dispatch_info().class))] pub fn sudo_unchecked_weight( origin: OriginFor, - call: Box<::Call>, + call: Box<::RuntimeCall>, _weight: Weight, ) -> DispatchResultWithPostInfo { // This is a public call, so we ensure that the origin is some signed account. @@ -256,7 +258,7 @@ pub mod pallet { pub fn sudo_as( origin: OriginFor, who: AccountIdLookupOf, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResultWithPostInfo { // This is a public call, so we ensure that the origin is some signed account. let sender = ensure_signed(origin)?; diff --git a/frame/sudo/src/lib.rs b/frame/sudo/src/lib.rs index bde69f11106dc..75d15d23c680a 100644 --- a/frame/sudo/src/lib.rs +++ b/frame/sudo/src/lib.rs @@ -95,7 +95,7 @@ use sp_runtime::{traits::StaticLookup, DispatchResult}; use sp_std::prelude::*; -use frame_support::{traits::UnfilteredDispatchable, weights::GetDispatchInfo}; +use frame_support::{dispatch::GetDispatchInfo, traits::UnfilteredDispatchable}; #[cfg(test)] mod mock; @@ -115,10 +115,12 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// A sudo-able call. - type Call: Parameter + UnfilteredDispatchable + GetDispatchInfo; + type RuntimeCall: Parameter + + UnfilteredDispatchable + + GetDispatchInfo; } #[pallet::pallet] @@ -143,7 +145,7 @@ pub mod pallet { })] pub fn sudo( origin: OriginFor, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResultWithPostInfo { // This is a public call, so we ensure that the origin is some signed account. let sender = ensure_signed(origin)?; @@ -168,7 +170,7 @@ pub mod pallet { #[pallet::weight((*_weight, call.get_dispatch_info().class))] pub fn sudo_unchecked_weight( origin: OriginFor, - call: Box<::Call>, + call: Box<::RuntimeCall>, _weight: Weight, ) -> DispatchResultWithPostInfo { // This is a public call, so we ensure that the origin is some signed account. @@ -230,7 +232,7 @@ pub mod pallet { pub fn sudo_as( origin: OriginFor, who: AccountIdLookupOf, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResultWithPostInfo { // This is a public call, so we ensure that the origin is some signed account. let sender = ensure_signed(origin)?; diff --git a/frame/sudo/src/mock.rs b/frame/sudo/src/mock.rs index c895eaf830136..db2ad4d563910 100644 --- a/frame/sudo/src/mock.rs +++ b/frame/sudo/src/mock.rs @@ -40,7 +40,7 @@ pub mod logger { #[pallet::config] pub trait Config: frame_system::Config { - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; } #[pallet::pallet] @@ -114,8 +114,8 @@ parameter_types! { } pub struct BlockEverything; -impl Contains for BlockEverything { - fn contains(_: &Call) -> bool { +impl Contains for BlockEverything { + fn contains(_: &RuntimeCall) -> bool { false } } @@ -125,8 +125,8 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -134,7 +134,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -149,13 +149,13 @@ impl frame_system::Config for Test { // Implement the logger module's `Config` on the Test runtime. impl logger::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; } // Implement the sudo module's `Config` on the Test runtime. impl Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; } // New types for dispatchable functions. diff --git a/frame/sudo/src/tests.rs b/frame/sudo/src/tests.rs index 0508772cc88ec..ae8f198736004 100644 --- a/frame/sudo/src/tests.rs +++ b/frame/sudo/src/tests.rs @@ -20,8 +20,8 @@ use super::*; use frame_support::{assert_noop, assert_ok, weights::Weight}; use mock::{ - new_test_ext, Call, Event as TestEvent, Logger, LoggerCall, Origin, Sudo, SudoCall, System, - Test, + new_test_ext, Logger, LoggerCall, RuntimeCall, RuntimeEvent as TestEvent, RuntimeOrigin, Sudo, + SudoCall, System, Test, }; #[test] @@ -39,19 +39,19 @@ fn sudo_basics() { // Configure a default test environment and set the root `key` to 1. new_test_ext(1).execute_with(|| { // A privileged function should work when `sudo` is passed the root `key` as `origin`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::from_ref_time(1_000), })); - assert_ok!(Sudo::sudo(Origin::signed(1), call)); + assert_ok!(Sudo::sudo(RuntimeOrigin::signed(1), call)); assert_eq!(Logger::i32_log(), vec![42i32]); // A privileged function should not work when `sudo` is passed a non-root `key` as `origin`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::from_ref_time(1_000), })); - assert_noop!(Sudo::sudo(Origin::signed(2), call), Error::::RequireSudo); + assert_noop!(Sudo::sudo(RuntimeOrigin::signed(2), call), Error::::RequireSudo); }); } @@ -62,11 +62,11 @@ fn sudo_emits_events_correctly() { System::set_block_number(1); // Should emit event to indicate success when called with the root `key` and `call` is `Ok`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::from_ref_time(1), })); - assert_ok!(Sudo::sudo(Origin::signed(1), call)); + assert_ok!(Sudo::sudo(RuntimeOrigin::signed(1), call)); System::assert_has_event(TestEvent::Sudo(Event::Sudid { sudo_result: Ok(()) })); }) } @@ -75,31 +75,35 @@ fn sudo_emits_events_correctly() { fn sudo_unchecked_weight_basics() { new_test_ext(1).execute_with(|| { // A privileged function should work when `sudo` is passed the root `key` as origin. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::from_ref_time(1_000), })); assert_ok!(Sudo::sudo_unchecked_weight( - Origin::signed(1), + RuntimeOrigin::signed(1), call, Weight::from_ref_time(1_000) )); assert_eq!(Logger::i32_log(), vec![42i32]); // A privileged function should not work when called with a non-root `key`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::from_ref_time(1_000), })); assert_noop!( - Sudo::sudo_unchecked_weight(Origin::signed(2), call, Weight::from_ref_time(1_000)), + Sudo::sudo_unchecked_weight( + RuntimeOrigin::signed(2), + call, + Weight::from_ref_time(1_000) + ), Error::::RequireSudo, ); // `I32Log` is unchanged after unsuccessful call. assert_eq!(Logger::i32_log(), vec![42i32]); // Controls the dispatched weight. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::from_ref_time(1), })); @@ -117,12 +121,12 @@ fn sudo_unchecked_weight_emits_events_correctly() { System::set_block_number(1); // Should emit event to indicate success when called with the root `key` and `call` is `Ok`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::from_ref_time(1), })); assert_ok!(Sudo::sudo_unchecked_weight( - Origin::signed(1), + RuntimeOrigin::signed(1), call, Weight::from_ref_time(1_000) )); @@ -134,14 +138,14 @@ fn sudo_unchecked_weight_emits_events_correctly() { fn set_key_basics() { new_test_ext(1).execute_with(|| { // A root `key` can change the root `key` - assert_ok!(Sudo::set_key(Origin::signed(1), 2)); + assert_ok!(Sudo::set_key(RuntimeOrigin::signed(1), 2)); assert_eq!(Sudo::key(), Some(2u64)); }); new_test_ext(1).execute_with(|| { // A non-root `key` will trigger a `RequireSudo` error and a non-root `key` cannot change // the root `key`. - assert_noop!(Sudo::set_key(Origin::signed(2), 3), Error::::RequireSudo); + assert_noop!(Sudo::set_key(RuntimeOrigin::signed(2), 3), Error::::RequireSudo); }); } @@ -152,10 +156,10 @@ fn set_key_emits_events_correctly() { System::set_block_number(1); // A root `key` can change the root `key`. - assert_ok!(Sudo::set_key(Origin::signed(1), 2)); + assert_ok!(Sudo::set_key(RuntimeOrigin::signed(1), 2)); System::assert_has_event(TestEvent::Sudo(Event::KeyChanged { old_sudoer: Some(1) })); // Double check. - assert_ok!(Sudo::set_key(Origin::signed(2), 4)); + assert_ok!(Sudo::set_key(RuntimeOrigin::signed(2), 4)); System::assert_has_event(TestEvent::Sudo(Event::KeyChanged { old_sudoer: Some(2) })); }); } @@ -164,27 +168,27 @@ fn set_key_emits_events_correctly() { fn sudo_as_basics() { new_test_ext(1).execute_with(|| { // A privileged function will not work when passed to `sudo_as`. - let call = Box::new(Call::Logger(LoggerCall::privileged_i32_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::privileged_i32_log { i: 42, weight: Weight::from_ref_time(1_000), })); - assert_ok!(Sudo::sudo_as(Origin::signed(1), 2, call)); + assert_ok!(Sudo::sudo_as(RuntimeOrigin::signed(1), 2, call)); assert!(Logger::i32_log().is_empty()); assert!(Logger::account_log().is_empty()); // A non-privileged function should not work when called with a non-root `key`. - let call = Box::new(Call::Logger(LoggerCall::non_privileged_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::non_privileged_log { i: 42, weight: Weight::from_ref_time(1), })); - assert_noop!(Sudo::sudo_as(Origin::signed(3), 2, call), Error::::RequireSudo); + assert_noop!(Sudo::sudo_as(RuntimeOrigin::signed(3), 2, call), Error::::RequireSudo); // A non-privileged function will work when passed to `sudo_as` with the root `key`. - let call = Box::new(Call::Logger(LoggerCall::non_privileged_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::non_privileged_log { i: 42, weight: Weight::from_ref_time(1), })); - assert_ok!(Sudo::sudo_as(Origin::signed(1), 2, call)); + assert_ok!(Sudo::sudo_as(RuntimeOrigin::signed(1), 2, call)); assert_eq!(Logger::i32_log(), vec![42i32]); // The correct user makes the call within `sudo_as`. assert_eq!(Logger::account_log(), vec![2]); @@ -198,11 +202,11 @@ fn sudo_as_emits_events_correctly() { System::set_block_number(1); // A non-privileged function will work when passed to `sudo_as` with the root `key`. - let call = Box::new(Call::Logger(LoggerCall::non_privileged_log { + let call = Box::new(RuntimeCall::Logger(LoggerCall::non_privileged_log { i: 42, weight: Weight::from_ref_time(1), })); - assert_ok!(Sudo::sudo_as(Origin::signed(1), 2, call)); + assert_ok!(Sudo::sudo_as(RuntimeOrigin::signed(1), 2, call)); System::assert_has_event(TestEvent::Sudo(Event::SudoAsDone { sudo_result: Ok(()) })); }); } diff --git a/frame/support/Cargo.toml b/frame/support/Cargo.toml index dea95ccec2b68..af2ad6c783839 100644 --- a/frame/support/Cargo.toml +++ b/frame/support/Cargo.toml @@ -27,11 +27,12 @@ sp-core = { version = "6.0.0", default-features = false, path = "../../primitive sp-arithmetic = { version = "5.0.0", default-features = false, path = "../../primitives/arithmetic" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-staking = { version = "4.0.0-dev", default-features = false, path = "../../primitives/staking" } +sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } tt-call = "1.0.8" frame-support-procedural = { version = "4.0.0-dev", default-features = false, path = "./procedural" } paste = "1.0" once_cell = { version = "1", default-features = false, optional = true } -sp-state-machine = { version = "0.12.0", optional = true, path = "../../primitives/state-machine" } +sp-state-machine = { version = "0.12.0", default-features = false, optional = true, path = "../../primitives/state-machine" } bitflags = "1.3" impl-trait-for-tuples = "0.2.2" smallvec = "1.8.0" @@ -44,11 +45,13 @@ serde_json = "1.0.85" assert_matches = "1.3.0" pretty_assertions = "1.2.1" frame-system = { version = "4.0.0-dev", path = "../system" } -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } [features] default = ["std"] std = [ + "sp-core/std", + "k256/std", "once_cell", "serde", "sp-api/std", @@ -62,7 +65,8 @@ std = [ "frame-metadata/std", "sp-inherents/std", "sp-staking/std", - "sp-state-machine", + "sp-state-machine/std", + "sp-weights/std", "frame-support-procedural/std", "log/std", ] diff --git a/frame/support/procedural/src/construct_runtime/expand/call.rs b/frame/support/procedural/src/construct_runtime/expand/call.rs index 028e68f0198d1..8f07448f5785e 100644 --- a/frame/support/procedural/src/construct_runtime/expand/call.rs +++ b/frame/support/procedural/src/construct_runtime/expand/call.rs @@ -55,7 +55,7 @@ pub fn expand_outer_dispatch( #[codec(index = #index)] #name( #scrate::dispatch::CallableCallFor<#name, #runtime> ), }); - variant_patterns.push(quote!(Call::#name(call))); + variant_patterns.push(quote!(RuntimeCall::#name(call))); pallet_names.push(name); pallet_attrs.push(attr); query_call_part_macros.push(quote! { @@ -73,11 +73,11 @@ pub fn expand_outer_dispatch( #scrate::scale_info::TypeInfo, #scrate::RuntimeDebug, )] - pub enum Call { + pub enum RuntimeCall { #variant_defs } #[cfg(test)] - impl Call { + impl RuntimeCall { /// Return a list of the module names together with their size in memory. pub const fn sizes() -> &'static [( &'static str, usize )] { use #scrate::dispatch::Callable; @@ -86,7 +86,7 @@ pub fn expand_outer_dispatch( #pallet_attrs ( stringify!(#pallet_names), - size_of::< <#pallet_names as Callable<#runtime>>::Call >(), + size_of::< <#pallet_names as Callable<#runtime>>::RuntimeCall >(), ), )*] } @@ -113,7 +113,7 @@ pub fn expand_outer_dispatch( } } } - impl #scrate::dispatch::GetDispatchInfo for Call { + impl #scrate::dispatch::GetDispatchInfo for RuntimeCall { fn get_dispatch_info(&self) -> #scrate::dispatch::DispatchInfo { match self { #( @@ -123,7 +123,10 @@ pub fn expand_outer_dispatch( } } } - impl #scrate::dispatch::GetCallMetadata for Call { + // Deprecated, but will warn when used + #[allow(deprecated)] + impl #scrate::weights::GetDispatchInfo for RuntimeCall {} + impl #scrate::dispatch::GetCallMetadata for RuntimeCall { fn get_call_metadata(&self) -> #scrate::dispatch::CallMetadata { use #scrate::dispatch::GetCallName; match self { @@ -151,20 +154,20 @@ pub fn expand_outer_dispatch( #( #pallet_attrs stringify!(#pallet_names) => - <<#pallet_names as Callable<#runtime>>::Call + <<#pallet_names as Callable<#runtime>>::RuntimeCall as GetCallName>::get_call_names(), )* _ => unreachable!(), } } } - impl #scrate::dispatch::Dispatchable for Call { - type Origin = Origin; - type Config = Call; - type Info = #scrate::weights::DispatchInfo; - type PostInfo = #scrate::weights::PostDispatchInfo; - fn dispatch(self, origin: Origin) -> #scrate::dispatch::DispatchResultWithPostInfo { - if !::filter_call(&origin, &self) { + impl #scrate::dispatch::Dispatchable for RuntimeCall { + type RuntimeOrigin = RuntimeOrigin; + type Config = RuntimeCall; + type Info = #scrate::dispatch::DispatchInfo; + type PostInfo = #scrate::dispatch::PostDispatchInfo; + fn dispatch(self, origin: RuntimeOrigin) -> #scrate::dispatch::DispatchResultWithPostInfo { + if !::filter_call(&origin, &self) { return #scrate::sp_std::result::Result::Err( #system_path::Error::<#runtime>::CallFiltered.into() ); @@ -173,9 +176,9 @@ pub fn expand_outer_dispatch( #scrate::traits::UnfilteredDispatchable::dispatch_bypass_filter(self, origin) } } - impl #scrate::traits::UnfilteredDispatchable for Call { - type Origin = Origin; - fn dispatch_bypass_filter(self, origin: Origin) -> #scrate::dispatch::DispatchResultWithPostInfo { + impl #scrate::traits::UnfilteredDispatchable for RuntimeCall { + type RuntimeOrigin = RuntimeOrigin; + fn dispatch_bypass_filter(self, origin: RuntimeOrigin) -> #scrate::dispatch::DispatchResultWithPostInfo { match self { #( #pallet_attrs @@ -188,7 +191,7 @@ pub fn expand_outer_dispatch( #( #pallet_attrs - impl #scrate::traits::IsSubType<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for Call { + impl #scrate::traits::IsSubType<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for RuntimeCall { #[allow(unreachable_patterns)] fn is_sub_type(&self) -> Option<&#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> { match self { @@ -200,7 +203,7 @@ pub fn expand_outer_dispatch( } #pallet_attrs - impl From<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for Call { + impl From<#scrate::dispatch::CallableCallFor<#pallet_names, #runtime>> for RuntimeCall { fn from(call: #scrate::dispatch::CallableCallFor<#pallet_names, #runtime>) -> Self { #variant_patterns } diff --git a/frame/support/procedural/src/construct_runtime/expand/event.rs b/frame/support/procedural/src/construct_runtime/expand/event.rs index f145327d37af5..b11fcef1bfd53 100644 --- a/frame/support/procedural/src/construct_runtime/expand/event.rs +++ b/frame/support/procedural/src/construct_runtime/expand/event.rs @@ -80,7 +80,7 @@ pub fn expand_outer_event( #scrate::RuntimeDebug, )] #[allow(non_camel_case_types)] - pub enum Event { + pub enum RuntimeEvent { #event_variants } @@ -148,13 +148,13 @@ fn expand_event_conversion( quote! { #attr - impl From<#pallet_event> for Event { + impl From<#pallet_event> for RuntimeEvent { fn from(x: #pallet_event) -> Self { - Event::#variant_name(x) + RuntimeEvent::#variant_name(x) } } #attr - impl TryInto<#pallet_event> for Event { + impl TryInto<#pallet_event> for RuntimeEvent { type Error = (); fn try_into(self) -> #scrate::sp_std::result::Result<#pallet_event, Self::Error> { diff --git a/frame/support/procedural/src/construct_runtime/expand/origin.rs b/frame/support/procedural/src/construct_runtime/expand/origin.rs index a4bb0d9cbaa02..1551d85ea4c96 100644 --- a/frame/support/procedural/src/construct_runtime/expand/origin.rs +++ b/frame/support/procedural/src/construct_runtime/expand/origin.rs @@ -103,13 +103,13 @@ pub fn expand_outer_origin( /// #[doc = #doc_string] #[derive(Clone)] - pub struct Origin { + pub struct RuntimeOrigin { caller: OriginCaller, - filter: #scrate::sp_std::rc::Rc::Call) -> bool>>, + filter: #scrate::sp_std::rc::Rc::RuntimeCall) -> bool>>, } #[cfg(not(feature = "std"))] - impl #scrate::sp_std::fmt::Debug for Origin { + impl #scrate::sp_std::fmt::Debug for RuntimeOrigin { fn fmt( &self, fmt: &mut #scrate::sp_std::fmt::Formatter, @@ -119,7 +119,7 @@ pub fn expand_outer_origin( } #[cfg(feature = "std")] - impl #scrate::sp_std::fmt::Debug for Origin { + impl #scrate::sp_std::fmt::Debug for RuntimeOrigin { fn fmt( &self, fmt: &mut #scrate::sp_std::fmt::Formatter, @@ -131,8 +131,8 @@ pub fn expand_outer_origin( } } - impl #scrate::traits::OriginTrait for Origin { - type Call = <#runtime as #system_path::Config>::Call; + impl #scrate::traits::OriginTrait for RuntimeOrigin { + type Call = <#runtime as #system_path::Config>::RuntimeCall; type PalletsOrigin = OriginCaller; type AccountId = <#runtime as #system_path::Config>::AccountId; @@ -147,7 +147,7 @@ pub fn expand_outer_origin( fn reset_filter(&mut self) { let filter = < <#runtime as #system_path::Config>::BaseCallFilter - as #scrate::traits::Contains<<#runtime as #system_path::Config>::Call> + as #scrate::traits::Contains<<#runtime as #system_path::Config>::RuntimeCall> >::contains; self.filter = #scrate::sp_std::rc::Rc::new(Box::new(filter)); @@ -169,6 +169,10 @@ pub fn expand_outer_origin( &self.caller } + fn into_caller(self) -> Self::PalletsOrigin { + self.caller + } + fn try_with_caller( mut self, f: impl FnOnce(Self::PalletsOrigin) -> Result, @@ -190,13 +194,6 @@ pub fn expand_outer_origin( fn signed(by: Self::AccountId) -> Self { #system_path::RawOrigin::Signed(by).into() } - - fn as_signed(self) -> Option { - match self.caller { - OriginCaller::system(#system_path::RawOrigin::Signed(by)) => Some(by), - _ => None, - } - } } #[derive( @@ -214,21 +211,20 @@ pub fn expand_outer_origin( // For backwards compatibility and ease of accessing these functions. #[allow(dead_code)] - impl Origin { - + impl RuntimeOrigin { #[doc = #doc_string_none_origin] pub fn none() -> Self { - ::none() + ::none() } #[doc = #doc_string_root_origin] pub fn root() -> Self { - ::root() + ::root() } #[doc = #doc_string_signed_origin] pub fn signed(by: <#runtime as #system_path::Config>::AccountId) -> Self { - ::signed(by) + ::signed(by) } } @@ -238,6 +234,21 @@ pub fn expand_outer_origin( } } + impl #scrate::traits::CallerTrait<<#runtime as #system_path::Config>::AccountId> for OriginCaller { + fn into_system(self) -> Option<#system_path::RawOrigin<<#runtime as #system_path::Config>::AccountId>> { + match self { + OriginCaller::system(x) => Some(x), + _ => None, + } + } + fn as_system_ref(&self) -> Option<&#system_path::RawOrigin<<#runtime as #system_path::Config>::AccountId>> { + match &self { + OriginCaller::system(o) => Some(o), + _ => None, + } + } + } + impl TryFrom for #system_path::Origin<#runtime> { type Error = OriginCaller; fn try_from(x: OriginCaller) @@ -251,7 +262,7 @@ pub fn expand_outer_origin( } } - impl From<#system_path::Origin<#runtime>> for Origin { + impl From<#system_path::Origin<#runtime>> for RuntimeOrigin { #[doc = #doc_string_runtime_origin] fn from(x: #system_path::Origin<#runtime>) -> Self { @@ -260,9 +271,9 @@ pub fn expand_outer_origin( } } - impl From for Origin { + impl From for RuntimeOrigin { fn from(x: OriginCaller) -> Self { - let mut o = Origin { + let mut o = RuntimeOrigin { caller: x, filter: #scrate::sp_std::rc::Rc::new(Box::new(|_| true)), }; @@ -273,9 +284,9 @@ pub fn expand_outer_origin( } } - impl From for #scrate::sp_std::result::Result<#system_path::Origin<#runtime>, Origin> { + impl From for #scrate::sp_std::result::Result<#system_path::Origin<#runtime>, RuntimeOrigin> { /// NOTE: converting to pallet origin loses the origin filter information. - fn from(val: Origin) -> Self { + fn from(val: RuntimeOrigin) -> Self { if let OriginCaller::system(l) = val.caller { Ok(l) } else { @@ -283,7 +294,7 @@ pub fn expand_outer_origin( } } } - impl From::AccountId>> for Origin { + impl From::AccountId>> for RuntimeOrigin { #[doc = #doc_string_runtime_origin_with_caller] fn from(x: Option<<#runtime as #system_path::Config>::AccountId>) -> Self { <#system_path::Origin<#runtime>>::from(x).into() @@ -374,7 +385,7 @@ fn expand_origin_pallet_conversions( } #attr - impl From<#pallet_origin> for Origin { + impl From<#pallet_origin> for RuntimeOrigin { #[doc = #doc_string] fn from(x: #pallet_origin) -> Self { let x: OriginCaller = x.into(); @@ -383,9 +394,9 @@ fn expand_origin_pallet_conversions( } #attr - impl From for #scrate::sp_std::result::Result<#pallet_origin, Origin> { + impl From for #scrate::sp_std::result::Result<#pallet_origin, RuntimeOrigin> { /// NOTE: converting to pallet origin loses the origin filter information. - fn from(val: Origin) -> Self { + fn from(val: RuntimeOrigin) -> Self { if let OriginCaller::#variant_name(l) = val.caller { Ok(l) } else { diff --git a/frame/support/procedural/src/construct_runtime/expand/unsigned.rs b/frame/support/procedural/src/construct_runtime/expand/unsigned.rs index 310516793472f..1d528779423a7 100644 --- a/frame/support/procedural/src/construct_runtime/expand/unsigned.rs +++ b/frame/support/procedural/src/construct_runtime/expand/unsigned.rs @@ -55,14 +55,14 @@ pub fn expand_outer_validate_unsigned( #( #query_validate_unsigned_part_macros )* impl #scrate::unsigned::ValidateUnsigned for #runtime { - type Call = Call; + type Call = RuntimeCall; fn pre_dispatch(call: &Self::Call) -> Result<(), #scrate::unsigned::TransactionValidityError> { #[allow(unreachable_patterns)] match call { #( #pallet_attrs - Call::#pallet_names(inner_call) => #pallet_names::pre_dispatch(inner_call), + RuntimeCall::#pallet_names(inner_call) => #pallet_names::pre_dispatch(inner_call), )* // pre-dispatch should not stop inherent extrinsics, validation should prevent // including arbitrary (non-inherent) extrinsics to blocks. @@ -79,7 +79,7 @@ pub fn expand_outer_validate_unsigned( match call { #( #pallet_attrs - Call::#pallet_names(inner_call) => #pallet_names::validate_unsigned(source, inner_call), + RuntimeCall::#pallet_names(inner_call) => #pallet_names::validate_unsigned(source, inner_call), )* _ => #scrate::unsigned::UnknownTransaction::NoUnsignedValidator.into(), } diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index cfd582d0e4472..73d0d54343eb9 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -156,10 +156,7 @@ use parse::{ use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use quote::quote; -use std::{ - collections::{HashMap, HashSet}, - str::FromStr, -}; +use std::{collections::HashSet, str::FromStr}; use syn::{Ident, Result}; /// The fixed name of the system pallet. @@ -324,11 +321,15 @@ fn decl_all_pallets<'a>( features: &HashSet<&str>, ) -> TokenStream2 { let mut types = TokenStream2::new(); - let mut names_by_feature = features + + // Every feature set to the pallet names that should be included by this feature set. + let mut features_to_names = features .iter() + .map(|f| *f) .powerset() - .map(|feat| (feat, Vec::new())) - .collect::>(); + .map(|feat| (HashSet::from_iter(feat), Vec::new())) + .collect::, Vec<_>)>>(); + for pallet_declaration in pallet_declarations { let type_name = &pallet_declaration.name; let pallet = &pallet_declaration.path; @@ -346,21 +347,22 @@ fn decl_all_pallets<'a>( types.extend(type_decl); if pallet_declaration.cfg_pattern.is_empty() { - for names in names_by_feature.values_mut() { + for (_, names) in features_to_names.iter_mut() { names.push(&pallet_declaration.name); } } else { - for (feature_set, names) in &mut names_by_feature { + for (feature_set, names) in &mut features_to_names { // Rust tidbit: if we have multiple `#[cfg]` feature on the same item, then the // predicates listed in all `#[cfg]` attributes are effectively joined by `and()`, // meaning that all of them must match in order to activate the item let is_feature_active = pallet_declaration.cfg_pattern.iter().all(|expr| { expr.eval(|pred| match pred { - Predicate::Feature(f) => feature_set.contains(&f), - Predicate::Test => feature_set.contains(&&"test"), + Predicate::Feature(f) => feature_set.contains(f), + Predicate::Test => feature_set.contains(&"test"), _ => false, }) }); + if is_feature_active { names.push(&pallet_declaration.name); } @@ -368,11 +370,34 @@ fn decl_all_pallets<'a>( } } - let all_pallets_without_system = names_by_feature.iter().map(|(feature_set, names)| { - let mut feature_set = feature_set.iter().collect::>(); - let test_cfg = feature_set.remove(&&&"test").then_some(quote!(test)).into_iter(); - let feature_set = feature_set.into_iter(); - let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #feature_set),* ))]); + // All possible features. This will be used below for the empty feature set. + let mut all_features = features_to_names + .iter() + .flat_map(|f| f.0.iter().cloned()) + .collect::>(); + let attribute_to_names = features_to_names + .into_iter() + .map(|(mut features, names)| { + // If this is the empty feature set, it needs to be changed to negate all available + // features. So, we ensure that there is some type declared when all features are not + // enabled. + if features.is_empty() { + let test_cfg = all_features.remove("test").then_some(quote!(test)).into_iter(); + let features = all_features.iter(); + let attr = quote!(#[cfg(all( #(not(#test_cfg)),* #(not(feature = #features)),* ))]); + + (attr, names) + } else { + let test_cfg = features.remove("test").then_some(quote!(test)).into_iter(); + let features = features.iter(); + let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #features),* ))]); + + (attr, names) + } + }) + .collect::>(); + + let all_pallets_without_system = attribute_to_names.iter().map(|(attr, names)| { let names = names.iter().filter(|n| **n != SYSTEM_PALLET_NAME); quote! { #attr @@ -382,11 +407,7 @@ fn decl_all_pallets<'a>( } }); - let all_pallets_with_system = names_by_feature.iter().map(|(feature_set, names)| { - let mut feature_set = feature_set.iter().collect::>(); - let test_cfg = feature_set.remove(&&&"test").then_some(quote!(test)).into_iter(); - let feature_set = feature_set.into_iter(); - let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #feature_set),* ))]); + let all_pallets_with_system = attribute_to_names.iter().map(|(attr, names)| { quote! { #attr /// All pallets included in the runtime as a nested tuple of types. @@ -394,67 +415,42 @@ fn decl_all_pallets<'a>( } }); - let all_pallets_without_system_reversed = - names_by_feature.iter().map(|(feature_set, names)| { - let mut feature_set = feature_set.iter().collect::>(); - let test_cfg = feature_set.remove(&&&"test").then_some(quote!(test)).into_iter(); - let feature_set = feature_set.into_iter(); - let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #feature_set),* ))]); - let names = names.iter().filter(|n| **n != SYSTEM_PALLET_NAME).rev(); - quote! { - #attr - /// All pallets included in the runtime as a nested tuple of types in reversed order. - /// Excludes the System pallet. - #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ - `AllPalletWithSystem or AllPalletsWithoutSystem`")] - pub type AllPalletsWithoutSystemReversed = ( #(#names,)* ); - } - }); + let all_pallets_without_system_reversed = attribute_to_names.iter().map(|(attr, names)| { + let names = names.iter().filter(|n| **n != SYSTEM_PALLET_NAME).rev(); + quote! { + #attr + /// All pallets included in the runtime as a nested tuple of types in reversed order. + /// Excludes the System pallet. + #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ + `AllPalletsWithSystem or AllPalletsWithoutSystem`")] + pub type AllPalletsWithoutSystemReversed = ( #(#names,)* ); + } + }); - let all_pallets_with_system_reversed = names_by_feature.iter().map(|(feature_set, names)| { - let mut feature_set = feature_set.iter().collect::>(); - let test_cfg = feature_set.remove(&&&"test").then_some(quote!(test)).into_iter(); - let feature_set = feature_set.into_iter(); - let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #feature_set),* ))]); + let all_pallets_with_system_reversed = attribute_to_names.iter().map(|(attr, names)| { let names = names.iter().rev(); quote! { #attr /// All pallets included in the runtime as a nested tuple of types in reversed order. #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ - `AllPalletWithSystem or AllPalletsWithoutSystem`")] + `AllPalletsWithSystem or AllPalletsWithoutSystem`")] pub type AllPalletsWithSystemReversed = ( #(#names,)* ); } }); - let system_pallet = - match names_by_feature[&Vec::new()].iter().find(|n| **n == SYSTEM_PALLET_NAME) { - Some(name) => name, - None => - return syn::Error::new( - proc_macro2::Span::call_site(), - "`System` pallet declaration is missing. \ - Please add this line: `System: frame_system,`", - ) - .into_compile_error(), - }; - - let all_pallets_reversed_with_system_first = - names_by_feature.iter().map(|(feature_set, names)| { - let mut feature_set = feature_set.iter().collect::>(); - let test_cfg = feature_set.remove(&&&"test").then_some(quote!(test)).into_iter(); - let feature_set = feature_set.into_iter(); - let attr = quote!(#[cfg(all( #(#test_cfg),* #(feature = #feature_set),* ))]); - let names = std::iter::once(system_pallet) - .chain(names.iter().rev().filter(|n| **n != SYSTEM_PALLET_NAME)); - quote! { - #attr - /// All pallets included in the runtime as a nested tuple of types in reversed order. - /// With the system pallet first. - #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ - `AllPalletWithSystem or AllPalletsWithoutSystem`")] - pub type AllPalletsReversedWithSystemFirst = ( #(#names,)* ); - } - }); + let all_pallets_reversed_with_system_first = attribute_to_names.iter().map(|(attr, names)| { + let system = quote::format_ident!("{}", SYSTEM_PALLET_NAME); + let names = std::iter::once(&system) + .chain(names.iter().rev().filter(|n| **n != SYSTEM_PALLET_NAME).cloned()); + quote! { + #attr + /// All pallets included in the runtime as a nested tuple of types in reversed order. + /// With the system pallet first. + #[deprecated(note = "Using reverse pallet orders is deprecated. use only \ + `AllPalletsWithSystem or AllPalletsWithoutSystem`")] + pub type AllPalletsReversedWithSystemFirst = ( #(#names,)* ); + } + }); quote!( #types diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index 00204b7a4d906..ccff5488c93be 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -36,6 +36,7 @@ mod transactional; mod tt_macro; use proc_macro::TokenStream; +use quote::quote; use std::{cell::RefCell, str::FromStr}; pub(crate) use storage::INHERENT_INSTANCE_NAME; @@ -311,7 +312,7 @@ pub fn decl_storage(input: TokenStream) -> TokenStream { /// System: frame_system::{Pallet, Call, Event, Config} = 0, /// Test: path::to::test::{Pallet, Call} = 1, /// -/// // Pallets with instances +/// // Pallets with instances. /// Test2_Instance1: test2::::{Pallet, Call, Storage, Event, Config, Origin}, /// Test2_DefaultInstance: test2::{Pallet, Call, Storage, Event, Config, Origin} = 4, /// @@ -402,7 +403,49 @@ pub fn construct_runtime(input: TokenStream) -> TokenStream { construct_runtime::construct_runtime(input) } -/// Macro to define a pallet. Docs are at `frame_support::pallet`. +/// The pallet struct placeholder `#[pallet::pallet]` is mandatory and allows you to specify +/// pallet information. +/// +/// The struct must be defined as follows: +/// ```ignore +/// #[pallet::pallet] +/// pub struct Pallet(_); +/// ``` +/// I.e. a regular struct definition named `Pallet`, with generic T and no where clause. +/// +/// ## Macro expansion: +/// +/// The macro adds this attribute to the struct definition: +/// ```ignore +/// #[derive( +/// frame_support::CloneNoBound, +/// frame_support::EqNoBound, +/// frame_support::PartialEqNoBound, +/// frame_support::RuntimeDebugNoBound, +/// )] +/// ``` +/// and replaces the type `_` with `PhantomData`. It also implements on the pallet: +/// * `GetStorageVersion` +/// * `OnGenesis`: contains some logic to write the pallet version into storage. +/// * `PalletErrorTypeInfo`: provides the type information for the pallet error, if defined. +/// +/// It declares `type Module` type alias for `Pallet`, used by `construct_runtime`. +/// +/// It implements `PalletInfoAccess` on `Pallet` to ease access to pallet information given by +/// `frame_support::traits::PalletInfo`. (The implementation uses the associated type +/// `frame_system::Config::PalletInfo`). +/// +/// It implements `StorageInfoTrait` on `Pallet` which give information about all storages. +/// +/// If the attribute `generate_store` is set then the macro creates the trait `Store` and +/// implements it on `Pallet`. +/// +/// If the attribute `set_storage_max_encoded_len` is set then the macro calls +/// `StorageInfoTrait` for each storage in the implementation of `StorageInfoTrait` for the +/// pallet. Otherwise it implements `StorageInfoTrait` for the pallet using the +/// `PartialStorageInfoTrait` implementation of storages. +/// +/// See `frame_support::pallet` docs for more info. #[proc_macro_attribute] pub fn pallet(attr: TokenStream, item: TokenStream) -> TokenStream { pallet::pallet(attr, item) @@ -583,3 +626,638 @@ pub fn storage_alias(_: TokenStream, input: TokenStream) -> TokenStream { .unwrap_or_else(|r| r.into_compile_error()) .into() } + +/// Used internally to decorate pallet attribute macro stubs when they are erroneously used +/// outside of a pallet module +fn pallet_macro_stub() -> TokenStream { + quote!(compile_error!( + "This attribute can only be used from within a pallet module marked with `#[frame_support::pallet]`" + )) + .into() +} + +/// The mandatory attribute `#[pallet::config]` defines the configurable options for the pallet. +/// +/// Item must be defined as: +/// +/// ```ignore +/// #[pallet::config] +/// pub trait Config: frame_system::Config + $optionally_some_other_supertraits +/// $optional_where_clause +/// { +/// ... +/// } +/// ``` +/// +/// I.e. a regular trait definition named `Config`, with the supertrait +/// `frame_system::pallet::Config`, and optionally other supertraits and a where clause. +/// (Specifying other supertraits here is known as [tight +/// coupling](https://docs.substrate.io/reference/how-to-guides/pallet-design/use-tight-coupling/)) +/// +/// The associated type `RuntimeEvent` is reserved. If defined, it must have the bounds +/// `From` and `IsType<::RuntimeEvent>`. +/// +/// [`pallet::event`](`macro@event`) must be present if `RuntimeEvent` exists as a config item +/// in your `#[pallet::config]`. +#[proc_macro_attribute] +pub fn config(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::constant]` attribute can be used to add an associated type trait bounded by `Get` +/// from [`pallet::config`](`macro@config`) into metadata, e.g.: +/// +/// ```ignore +/// #[pallet::config] +/// pub trait Config: frame_system::Config { +/// #[pallet::constant] +/// type Foo: Get; +/// } +/// ``` +#[proc_macro_attribute] +pub fn constant(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// To bypass the `frame_system::Config` supertrait check, use the attribute +/// `pallet::disable_frame_system_supertrait_check`, e.g.: +/// +/// ```ignore +/// #[pallet::config] +/// #[pallet::disable_frame_system_supertrait_check] +/// pub trait Config: pallet_timestamp::Config {} +/// ``` +/// +/// NOTE: Bypassing the `frame_system::Config` supertrait check is typically desirable when you +/// want to write an alternative to the `frame_system` pallet. +#[proc_macro_attribute] +pub fn disable_frame_system_supertrait_check(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// To generate a `Store` trait associating all storages, annotate your `Pallet` struct with +/// the attribute `#[pallet::generate_store($vis trait Store)]`, e.g.: +/// +/// ```ignore +/// #[pallet::pallet] +/// #[pallet::generate_store(pub(super) trait Store)] +/// pub struct Pallet(_); +/// ``` +/// More precisely, the `Store` trait contains an associated type for each storage. It is +/// implemented for `Pallet` allowing access to the storage from pallet struct. +/// +/// Thus when defining a storage named `Foo`, it can later be accessed from `Pallet` using +/// `::Foo`. +/// +/// NOTE: this attribute is only valid when applied _directly_ to your `Pallet` struct +/// definition. +#[proc_macro_attribute] +pub fn generate_store(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// To generate the full storage info (used for PoV calculation) use the attribute +/// `#[pallet::generate_storage_info]`, e.g.: +/// +/// ```ignore +/// #[pallet::pallet] +/// #[pallet::generate_storage_info] +/// pub struct Pallet(_); +/// ``` +/// +/// This requires all storage items to implement the trait `StorageInfoTrait`, thus all keys +/// and value types must be bound by `MaxEncodedLen`. Individual storages can opt-out from this +/// constraint by using [`#[pallet::unbounded]`](`macro@unbounded`) (see +/// [`#[pallet::storage]`](`macro@storage`) for more info). +#[proc_macro_attribute] +pub fn generate_storage_info(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// Because the `pallet::pallet` macro implements `GetStorageVersion`, the current storage +/// version needs to be communicated to the macro. This can be done by using the +/// `pallet::storage_version` attribute: +/// +/// ```ignore +/// const STORAGE_VERSION: StorageVersion = StorageVersion::new(5); +/// +/// #[pallet::pallet] +/// #[pallet::storage_version(STORAGE_VERSION)] +/// pub struct Pallet(_); +/// ``` +/// +/// If not present, the current storage version is set to the default value. +#[proc_macro_attribute] +pub fn storage_version(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::hooks]` attribute allows you to specify a `Hooks` implementation for +/// `Pallet` that specifies pallet-specific logic. +/// +/// The item the attribute attaches to must be defined as follows: +/// ```ignore +/// #[pallet::hooks] +/// impl Hooks> for Pallet $optional_where_clause { +/// ... +/// } +/// ``` +/// I.e. a regular trait implementation with generic bound: `T: Config`, for the trait +/// `Hooks>` (they are defined in preludes), for the type `Pallet` and +/// with an optional where clause. +/// +/// If no `#[pallet::hooks]` exists, then the following default implementation is +/// automatically generated: +/// ```ignore +/// #[pallet::hooks] +/// impl Hooks> for Pallet {} +/// ``` +/// +/// ## Macro expansion +/// +/// The macro implements the traits `OnInitialize`, `OnIdle`, `OnFinalize`, `OnRuntimeUpgrade`, +/// `OffchainWorker`, and `IntegrityTest` using the provided `Hooks` implementation. +/// +/// NOTE: `OnRuntimeUpgrade` is implemented with `Hooks::on_runtime_upgrade` and some +/// additional logic. E.g. logic to write the pallet version into storage. +/// +/// NOTE: The macro also adds some tracing logic when implementing the above traits. The +/// following hooks emit traces: `on_initialize`, `on_finalize` and `on_runtime_upgrade`. +#[proc_macro_attribute] +pub fn hooks(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// Each dispatchable needs to define a weight with `#[pallet::weight($expr)]` attribute, the +/// first argument must be `origin: OriginFor`. +#[proc_macro_attribute] +pub fn weight(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// Compact encoding for arguments can be achieved via `#[pallet::compact]`. The function must +/// return a `DispatchResultWithPostInfo` or `DispatchResult`. +#[proc_macro_attribute] +pub fn compact(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// Each dispatchable may also be annotated with the `#[pallet::call_index($idx)]` attribute, +/// which explicitly defines the codec index for the dispatchable function in the `Call` enum. +/// +/// All call indexes start from 0, until it encounters a dispatchable function with a defined +/// call index. The dispatchable function that lexically follows the function with a defined +/// call index will have that call index, but incremented by 1, e.g. if there are 3 +/// dispatchable functions `fn foo`, `fn bar` and `fn qux` in that order, and only `fn bar` +/// has a call index of 10, then `fn qux` will have an index of 11, instead of 1. +/// +/// All arguments must implement [`Debug`], [`PartialEq`], [`Eq`], `Decode`, `Encode`, and +/// [`Clone`]. For ease of use, bound by the trait `frame_support::pallet_prelude::Member`. +/// +/// If no `#[pallet::call]` exists, then a default implementation corresponding to the +/// following code is automatically generated: +/// +/// ```ignore +/// #[pallet::call] +/// impl Pallet {} +/// ``` +/// +/// **WARNING**: modifying dispatchables, changing their order, removing some, etc., must be +/// done with care. Indeed this will change the outer runtime call type (which is an enum with +/// one variant per pallet), this outer runtime call can be stored on-chain (e.g. in +/// `pallet-scheduler`). Thus migration might be needed. To mitigate against some of this, the +/// `#[pallet::call_index($idx)]` attribute can be used to fix the order of the dispatchable so +/// that the `Call` enum encoding does not change after modification. As a general rule of +/// thumb, it is therefore adventageous to always add new calls to the end so you can maintain +/// the existing order of calls. +/// +/// ### Macro expansion +/// +/// The macro creates an enum `Call` with one variant per dispatchable. This enum implements: +/// [`Clone`], [`Eq`], [`PartialEq`], [`Debug`] (with stripped implementation in `not("std")`), +/// `Encode`, `Decode`, `GetDispatchInfo`, `GetCallName`, and `UnfilteredDispatchable`. +/// +/// The macro implements the `Callable` trait on `Pallet` and a function `call_functions` +/// which returns the dispatchable metadata. +#[proc_macro_attribute] +pub fn call_index(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// Allows you to define some extra constants to be added into constant metadata. +/// +/// Item must be defined as: +/// +/// ```ignore +/// #[pallet::extra_constants] +/// impl Pallet where $optional_where_clause { +/// /// $some_doc +/// $vis fn $fn_name() -> $some_return_type { +/// ... +/// } +/// ... +/// } +/// ``` +/// I.e. a regular rust `impl` block with some optional where clause and functions with 0 args, +/// 0 generics, and some return type. +/// +/// ## Macro expansion +/// +/// The macro add some extra constants to pallet constant metadata. +#[proc_macro_attribute] +pub fn extra_constants(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::error]` attribute allows you to define an error enum that will be returned +/// from the dispatchable when an error occurs. The information for this error type is then +/// stored in metadata. +/// +/// Item must be defined as: +/// +/// ```ignore +/// #[pallet::error] +/// pub enum Error { +/// /// $some_optional_doc +/// $SomeFieldLessVariant, +/// /// $some_more_optional_doc +/// $SomeVariantWithOneField(FieldType), +/// ... +/// } +/// ``` +/// I.e. a regular enum named `Error`, with generic `T` and fieldless or multiple-field +/// variants. +/// +/// Any field type in the enum variants must implement `TypeInfo` in order to be properly used +/// in the metadata, and its encoded size should be as small as possible, preferably 1 byte in +/// size in order to reduce storage size. The error enum itself has an absolute maximum encoded +/// size specified by `MAX_MODULE_ERROR_ENCODED_SIZE`. +/// +/// (1 byte can still be 256 different errors. The more specific the error, the easier it is to +/// diagnose problems and give a better experience to the user. Don't skimp on having lots of +/// individual error conditions.) +/// +/// Field types in enum variants must also implement `PalletError`, otherwise the pallet will +/// fail to compile. Rust primitive types have already implemented the `PalletError` trait +/// along with some commonly used stdlib types such as [`Option`] and `PhantomData`, and hence +/// in most use cases, a manual implementation is not necessary and is discouraged. +/// +/// The generic `T` must not bound anything and a `where` clause is not allowed. That said, +/// bounds and/or a where clause should not needed for any use-case. +/// +/// ## Macro expansion +/// +/// The macro implements the [`Debug`] trait and functions `as_u8` using variant position, and +/// `as_str` using variant doc. +/// +/// The macro also implements `From>` for `&'static str` and `From>` for +/// `DispatchError`. +#[proc_macro_attribute] +pub fn error(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::event]` attribute allows you to define pallet events. Pallet events are +/// stored under the `system` / `events` key when the block is applied (and then replaced when +/// the next block writes it's events). +/// +/// The Event enum must be defined as follows: +/// +/// ```ignore +/// #[pallet::event] +/// #[pallet::generate_deposit($visibility fn deposit_event)] // Optional +/// pub enum Event<$some_generic> $optional_where_clause { +/// /// Some doc +/// $SomeName($SomeType, $YetanotherType, ...), +/// ... +/// } +/// ``` +/// +/// I.e. an enum (with named or unnamed fields variant), named `Event`, with generic: none or +/// `T` or `T: Config`, and optional w here clause. +/// +/// Each field must implement [`Clone`], [`Eq`], [`PartialEq`], `Encode`, `Decode`, and +/// [`Debug`] (on std only). For ease of use, bound by the trait `Member`, available in +/// `frame_support::pallet_prelude`. +#[proc_macro_attribute] +pub fn event(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The attribute `#[pallet::generate_deposit($visibility fn deposit_event)]` generates a +/// helper function on `Pallet` that handles deposit events. +/// +/// NOTE: For instantiable pallets, the event must be generic over `T` and `I`. +/// +/// ## Macro expansion +/// +/// The macro will add on enum `Event` the attributes: +/// * `#[derive(frame_support::CloneNoBound)]` +/// * `#[derive(frame_support::EqNoBound)]` +/// * `#[derive(frame_support::PartialEqNoBound)]` +/// * `#[derive(frame_support::RuntimeDebugNoBound)]` +/// * `#[derive(codec::Encode)]` +/// * `#[derive(codec::Decode)]` +/// +/// The macro implements `From>` for (). +/// +/// The macro implements a metadata function on `Event` returning the `EventMetadata`. +/// +/// If `#[pallet::generate_deposit]` is present then the macro implements `fn deposit_event` on +/// `Pallet`. +#[proc_macro_attribute] +pub fn generate_deposit(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::storage]` attribute lets you define some abstract storage inside of runtime +/// storage and also set its metadata. This attribute can be used multiple times. +/// +/// Item should be defined as: +/// +/// ```ignore +/// #[pallet::storage] +/// #[pallet::getter(fn $getter_name)] // optional +/// $vis type $StorageName<$some_generic> $optional_where_clause +/// = $StorageType<$generic_name = $some_generics, $other_name = $some_other, ...>; +/// ``` +/// +/// or with unnamed generic: +/// +/// ```ignore +/// #[pallet::storage] +/// #[pallet::getter(fn $getter_name)] // optional +/// $vis type $StorageName<$some_generic> $optional_where_clause +/// = $StorageType<_, $some_generics, ...>; +/// ``` +/// +/// I.e. it must be a type alias, with generics: `T` or `T: Config`. The aliased type must be +/// one of `StorageValue`, `StorageMap` or `StorageDoubleMap`. The generic arguments of the +/// storage type can be given in two manners: named and unnamed. For named generic arguments, +/// the name for each argument should match the name defined for it on the storage struct: +/// * `StorageValue` expects `Value` and optionally `QueryKind` and `OnEmpty`, +/// * `StorageMap` expects `Hasher`, `Key`, `Value` and optionally `QueryKind` and `OnEmpty`, +/// * `CountedStorageMap` expects `Hasher`, `Key`, `Value` and optionally `QueryKind` and `OnEmpty`, +/// * `StorageDoubleMap` expects `Hasher1`, `Key1`, `Hasher2`, `Key2`, `Value` and optionally +/// `QueryKind` and `OnEmpty`. +/// +/// For unnamed generic arguments: Their first generic must be `_` as it is replaced by the +/// macro and other generic must declared as a normal generic type declaration. +/// +/// The `Prefix` generic written by the macro is generated using +/// `PalletInfo::name::>()` and the name of the storage type. E.g. if runtime names +/// the pallet "MyExample" then the storage `type Foo = ...` should use the prefix: +/// `Twox128(b"MyExample") ++ Twox128(b"Foo")`. +/// +/// For the `CountedStorageMap` variant, the `Prefix` also implements +/// `CountedStorageMapInstance`. It also associates a `CounterPrefix`, which is implemented the +/// same as above, but the storage prefix is prepend with `"CounterFor"`. E.g. if runtime names +/// the pallet "MyExample" then the storage `type Foo = CountedStorageaMap<...>` will store +/// its counter at the prefix: `Twox128(b"MyExample") ++ Twox128(b"CounterForFoo")`. +/// +/// E.g: +/// +/// ```ignore +/// #[pallet::storage] +/// pub(super) type MyStorage = StorageMap; +/// ``` +/// +/// In this case the final prefix used by the map is `Twox128(b"MyExample") ++ +/// Twox128(b"OtherName")`. +#[proc_macro_attribute] +pub fn storage(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The optional attribute `#[pallet::getter(fn $my_getter_fn_name)]` allows you to define a +/// getter function on `Pallet`. +/// +/// Also see [`pallet::storage`](`macro@storage`) +#[proc_macro_attribute] +pub fn getter(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The optional attribute `#[pallet::storage_prefix = "SomeName"]` allows you to define the +/// storage prefix to use. This is helpful if you wish to rename the storage field but don't +/// want to perform a migration. +/// +/// E.g: +/// +/// ```ignore +/// #[pallet::storage] +/// #[pallet::storage_prefix = "foo"] +/// #[pallet::getter(fn my_storage)] +/// pub(super) type MyStorage = StorageMap; +/// ``` +/// +/// or +/// +/// ```ignore +/// #[pallet::storage] +/// #[pallet::getter(fn my_storage)] +/// pub(super) type MyStorage = StorageMap<_, Blake2_128Concat, u32, u32>; +/// ``` +#[proc_macro_attribute] +pub fn storage_prefix(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The optional attribute `#[pallet::unbounded]` declares the storage as unbounded. When +/// implementating the storage info (when `#[pallet::generate_storage_info]` is specified on +/// the pallet struct placeholder), the size of the storage will be declared as unbounded. This +/// can be useful for storage which can never go into PoV (Proof of Validity). +#[proc_macro_attribute] +pub fn unbounded(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The optional attribute `#[pallet::whitelist_storage]` will declare the +/// storage as whitelisted from benchmarking. Doing so will exclude reads of +/// that value's storage key from counting towards weight calculations during +/// benchmarking. +/// +/// This attribute should only be attached to storages that are known to be +/// read/used in every block. This will result in a more accurate benchmarking weight. +/// +/// ### Example +/// ```ignore +/// #[pallet::storage] +/// #[pallet::whitelist_storage] +/// pub(super) type Number = StorageValue<_, T::BlockNumber, ValueQuery>; +/// ``` +/// +/// NOTE: As with all `pallet::*` attributes, this one _must_ be written as +/// `#[pallet::whitelist_storage]` and can only be placed inside a `pallet` module in order for +/// it to work properly. +#[proc_macro_attribute] +pub fn whitelist_storage(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::type_value]` attribute lets you define a struct implementing the `Get` trait +/// to ease the use of storage types. This attribute is meant to be used alongside +/// [`#[pallet::storage]`](`macro@storage`) to define a storage's default value. This attribute +/// can be used multiple times. +/// +/// Item must be defined as: +/// +/// ```ignore +/// #[pallet::type_value] +/// fn $MyDefaultName<$some_generic>() -> $default_type $optional_where_clause { $expr } +/// ``` +/// +/// I.e.: a function definition with generics none or `T: Config` and a returned type. +/// +/// E.g.: +/// +/// ```ignore +/// #[pallet::type_value] +/// fn MyDefault() -> T::Balance { 3.into() } +/// ``` +/// +/// ## Macro expansion +/// +/// The macro renames the function to some internal name, generates a struct with the original +/// name of the function and its generic, and implements `Get<$ReturnType>` by calling the user +/// defined function. +#[proc_macro_attribute] +pub fn type_value(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::genesis_config]` attribute allows you to define the genesis configuration +/// for the pallet. +/// +/// Item is defined as either an enum or a struct. It needs to be public and implement the +/// trait `GenesisBuild` with [`#[pallet::genesis_build]`](`macro@genesis_build`). The type +/// generics are constrained to be either none, or `T` or `T: Config`. +/// +/// E.g: +/// +/// ```ignore +/// #[pallet::genesis_config] +/// pub struct GenesisConfig { +/// _myfield: BalanceOf, +/// } +/// ``` +#[proc_macro_attribute] +pub fn genesis_config(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::genesis_build]` attribute allows you to define how `genesis_configuration` +/// is built. This takes as input the `GenesisConfig` type (as `self`) and constructs the pallet's +/// initial state. +/// +/// The impl must be defined as: +/// +/// ```ignore +/// #[pallet::genesis_build] +/// impl GenesisBuild for GenesisConfig<$maybe_generics> { +/// fn build(&self) { $expr } +/// } +/// ``` +/// +/// I.e. a trait implementation with generic `T: Config`, of trait `GenesisBuild` on +/// type `GenesisConfig` with generics none or `T`. +/// +/// E.g.: +/// +/// ```ignore +/// #[pallet::genesis_build] +/// impl GenesisBuild for GenesisConfig { +/// fn build(&self) {} +/// } +/// ``` +/// +/// ## Macro expansion +/// +/// The macro will add the following attribute: +/// * `#[cfg(feature = "std")]` +/// +/// The macro will implement `sp_runtime::BuildModuleGenesisStorage` using `()` as a second +/// generic for non-instantiable pallets. +#[proc_macro_attribute] +pub fn genesis_build(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::inherent]` attribute allows the pallet to provide some +/// [inherent](https://docs.substrate.io/fundamentals/transaction-types/#inherent-transactions). +/// An inherent is some piece of data that is inserted by a block authoring node at block +/// creation time and can either be accepted or rejected by validators based on whether the +/// data falls within an acceptable range. +/// +/// The most common inherent is the `timestamp` that is inserted into every block. Since there +/// is no way to validate timestamps, validators simply check that the timestamp reported by +/// the block authoring node falls within an acceptable range. +/// +/// Item must be defined as: +/// +/// ```ignore +/// #[pallet::inherent] +/// impl ProvideInherent for Pallet { +/// // ... regular trait implementation +/// } +/// ``` +/// +/// I.e. a trait implementation with bound `T: Config`, of trait `ProvideInherent` for type +/// `Pallet`, and some optional where clause. +/// +/// ## Macro expansion +/// +/// The macro currently makes no use of this information, but it might use this information in +/// the future to give information directly to `construct_runtime`. +#[proc_macro_attribute] +pub fn inherent(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::validate_unsigned]` attribute allows the pallet to validate some unsigned +/// transaction: +/// +/// Item must be defined as: +/// +/// ```ignore +/// #[pallet::validate_unsigned] +/// impl ValidateUnsigned for Pallet { +/// // ... regular trait implementation +/// } +/// ``` +/// +/// I.e. a trait implementation with bound `T: Config`, of trait `ValidateUnsigned` for type +/// `Pallet`, and some optional where clause. +/// +/// NOTE: There is also the `sp_runtime::traits::SignedExtension` trait that can be used to add +/// some specific logic for transaction validation. +/// +/// ## Macro expansion +/// +/// The macro currently makes no use of this information, but it might use this information in +/// the future to give information directly to `construct_runtime`. +#[proc_macro_attribute] +pub fn validate_unsigned(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + +/// The `#[pallet::origin]` attribute allows you to define some origin for the pallet. +/// +/// Item must be either a type alias, an enum, or a struct. It needs to be public. +/// +/// E.g.: +/// +/// ```ignore +/// #[pallet::origin] +/// pub struct Origin(PhantomData<(T)>); +/// ``` +/// +/// **WARNING**: modifying origin changes the outer runtime origin. This outer runtime origin +/// can be stored on-chain (e.g. in `pallet-scheduler`), thus any change must be done with care +/// as it might require some migration. +/// +/// NOTE: for instantiable pallets, the origin must be generic over `T` and `I`. +#[proc_macro_attribute] +pub fn origin(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} diff --git a/frame/support/procedural/src/pallet/expand/call.rs b/frame/support/procedural/src/pallet/expand/call.rs index a9468451ad1d4..6b166e6726d38 100644 --- a/frame/support/procedural/src/pallet/expand/call.rs +++ b/frame/support/procedural/src/pallet/expand/call.rs @@ -16,6 +16,7 @@ // limitations under the License. use crate::{pallet::Def, COUNTER}; +use quote::ToTokens; use syn::spanned::Spanned; /// @@ -31,7 +32,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { (span, where_clause, methods, docs) }, - None => (def.item.span(), None, Vec::new(), Vec::new()), + None => (def.item.span(), def.config.where_clause.clone(), Vec::new(), Vec::new()), }; let frame_support = &def.frame_support; let frame_system = &def.frame_system; @@ -158,6 +159,24 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { }); } + // Extracts #[allow] attributes, necessary so that we don't run into compiler warnings + let maybe_allow_attrs = methods + .iter() + .map(|method| { + method + .attrs + .iter() + .find(|attr| { + if let Ok(syn::Meta::List(syn::MetaList { path, .. })) = attr.parse_meta() { + path.segments.last().map(|seg| seg.ident == "allow").unwrap_or(false) + } else { + false + } + }) + .map_or(proc_macro2::TokenStream::new(), |attr| attr.to_token_stream()) + }) + .collect::>(); + quote::quote_spanned!(span => #[doc(hidden)] pub mod __substrate_call_check { @@ -255,6 +274,10 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { } } + // Deprecated, but will warn when used + #[allow(deprecated)] + impl<#type_impl_gen> #frame_support::weights::GetDispatchInfo for #call_ident<#type_use_gen> #where_clause {} + impl<#type_impl_gen> #frame_support::dispatch::GetCallName for #call_ident<#type_use_gen> #where_clause { @@ -274,10 +297,10 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { for #call_ident<#type_use_gen> #where_clause { - type Origin = #frame_system::pallet_prelude::OriginFor; + type RuntimeOrigin = #frame_system::pallet_prelude::OriginFor; fn dispatch_bypass_filter( self, - origin: Self::Origin + origin: Self::RuntimeOrigin ) -> #frame_support::dispatch::DispatchResultWithPostInfo { match self { #( @@ -285,6 +308,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { #frame_support::sp_tracing::enter_span!( #frame_support::sp_tracing::trace_span!(stringify!(#fn_name)) ); + #maybe_allow_attrs <#pallet_ident<#type_use_gen>>::#fn_name(origin, #( #args_name, )* ) .map(Into::into).map_err(Into::into) }, @@ -300,7 +324,7 @@ pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream { impl<#type_impl_gen> #frame_support::dispatch::Callable for #pallet_ident<#type_use_gen> #where_clause { - type Call = #call_ident<#type_use_gen>; + type RuntimeCall = #call_ident<#type_use_gen>; } impl<#type_impl_gen> #pallet_ident<#type_use_gen> #where_clause { diff --git a/frame/support/procedural/src/pallet/expand/event.rs b/frame/support/procedural/src/pallet/expand/event.rs index 791f930302207..abed680eb245e 100644 --- a/frame/support/procedural/src/pallet/expand/event.rs +++ b/frame/support/procedural/src/pallet/expand/event.rs @@ -61,7 +61,8 @@ pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream { let event_where_clause = &event.where_clause; // NOTE: actually event where clause must be a subset of config where clause because of - // `type Event: From>`. But we merge either way for potential better error message + // `type RuntimeEvent: From>`. But we merge either way for potential better error + // message let completed_where_clause = super::merge_where_clauses(&[&event.where_clause, &def.config.where_clause]); @@ -136,13 +137,13 @@ pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream { impl<#type_impl_gen> Pallet<#type_use_gen> #completed_where_clause { #fn_vis fn deposit_event(event: Event<#event_use_gen>) { let event = < - ::Event as + ::RuntimeEvent as From> >::from(event); let event = < - ::Event as - Into<::Event> + ::RuntimeEvent as + Into<::RuntimeEvent> >::into(event); <#frame_system::Pallet>::deposit_event(event) diff --git a/frame/support/procedural/src/pallet/expand/hooks.rs b/frame/support/procedural/src/pallet/expand/hooks.rs index 03878f3f186df..d8d009cf3c940 100644 --- a/frame/support/procedural/src/pallet/expand/hooks.rs +++ b/frame/support/procedural/src/pallet/expand/hooks.rs @@ -26,7 +26,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { let has_runtime_upgrade = hooks.has_runtime_upgrade; (where_clause, span, has_runtime_upgrade) }, - None => (None, def.pallet_struct.attr_span, false), + None => (def.config.where_clause.clone(), def.pallet_struct.attr_span, false), }; let frame_support = &def.frame_support; @@ -160,7 +160,7 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { } #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { + fn pre_upgrade() -> Result<#frame_support::sp_std::vec::Vec, &'static str> { < Self as @@ -169,12 +169,12 @@ pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream { } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { + fn post_upgrade(state: #frame_support::sp_std::vec::Vec) -> Result<(), &'static str> { < Self as #frame_support::traits::Hooks<::BlockNumber> - >::post_upgrade() + >::post_upgrade(state) } } diff --git a/frame/support/procedural/src/pallet/expand/pallet_struct.rs b/frame/support/procedural/src/pallet/expand/pallet_struct.rs index f0fb6bacedffb..e5941a33fee13 100644 --- a/frame/support/procedural/src/pallet/expand/pallet_struct.rs +++ b/frame/support/procedural/src/pallet/expand/pallet_struct.rs @@ -166,6 +166,24 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { quote::quote! { #frame_support::traits::StorageVersion::default() } }; + let whitelisted_storage_idents: Vec = def + .storages + .iter() + .filter_map(|s| s.whitelisted.then_some(s.ident.clone())) + .collect(); + + let whitelisted_storage_keys_impl = quote::quote![ + use #frame_support::traits::{StorageInfoTrait, TrackedStorageKey, WhitelistedStorageKeys}; + impl<#type_impl_gen> WhitelistedStorageKeys for #pallet_ident<#type_use_gen> #storages_where_clauses { + fn whitelisted_storage_keys() -> #frame_support::sp_std::vec::Vec { + use #frame_support::sp_std::vec; + vec![#( + TrackedStorageKey::new(#whitelisted_storage_idents::<#type_use_gen>::hashed_key().to_vec()) + ),*] + } + } + ]; + quote::quote_spanned!(def.pallet_struct.attr_span => #pallet_error_metadata @@ -253,5 +271,6 @@ pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream { } #storage_info + #whitelisted_storage_keys_impl ) } diff --git a/frame/support/procedural/src/pallet/expand/storage.rs b/frame/support/procedural/src/pallet/expand/storage.rs index 181f35b545496..9109640966969 100644 --- a/frame/support/procedural/src/pallet/expand/storage.rs +++ b/frame/support/procedural/src/pallet/expand/storage.rs @@ -374,10 +374,11 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span => Option<#value> ), - QueryKind::ResultQuery(error_path, _) => + QueryKind::ResultQuery(error_path, _) => { quote::quote_spanned!(storage.attr_span => Result<#value, #error_path> - ), + ) + }, QueryKind::ValueQuery => quote::quote!(#value), }; quote::quote_spanned!(storage.attr_span => @@ -397,10 +398,11 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span => Option<#value> ), - QueryKind::ResultQuery(error_path, _) => + QueryKind::ResultQuery(error_path, _) => { quote::quote_spanned!(storage.attr_span => Result<#value, #error_path> - ), + ) + }, QueryKind::ValueQuery => quote::quote!(#value), }; quote::quote_spanned!(storage.attr_span => @@ -422,10 +424,11 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span => Option<#value> ), - QueryKind::ResultQuery(error_path, _) => + QueryKind::ResultQuery(error_path, _) => { quote::quote_spanned!(storage.attr_span => Result<#value, #error_path> - ), + ) + }, QueryKind::ValueQuery => quote::quote!(#value), }; quote::quote_spanned!(storage.attr_span => @@ -447,10 +450,11 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span => Option<#value> ), - QueryKind::ResultQuery(error_path, _) => + QueryKind::ResultQuery(error_path, _) => { quote::quote_spanned!(storage.attr_span => Result<#value, #error_path> - ), + ) + }, QueryKind::ValueQuery => quote::quote!(#value), }; quote::quote_spanned!(storage.attr_span => @@ -474,10 +478,11 @@ pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream { QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span => Option<#value> ), - QueryKind::ResultQuery(error_path, _) => + QueryKind::ResultQuery(error_path, _) => { quote::quote_spanned!(storage.attr_span => Result<#value, #error_path> - ), + ) + }, QueryKind::ValueQuery => quote::quote!(#value), }; quote::quote_spanned!(storage.attr_span => diff --git a/frame/support/procedural/src/pallet/parse/call.rs b/frame/support/procedural/src/pallet/parse/call.rs index 336e08c3d39b7..f7b2c9544d831 100644 --- a/frame/support/procedural/src/pallet/parse/call.rs +++ b/frame/support/procedural/src/pallet/parse/call.rs @@ -61,6 +61,8 @@ pub struct CallVariantDef { pub call_index: u8, /// Docs, used for metadata. pub docs: Vec, + /// Attributes annotated at the top of the dispatchable function. + pub attrs: Vec, } /// Attributes for functions in call impl block. @@ -287,6 +289,7 @@ impl CallDef { call_index: final_index, args, docs, + attrs: method.attrs.clone(), }); } else { let msg = "Invalid pallet::call, only method accepted"; diff --git a/frame/support/procedural/src/pallet/parse/config.rs b/frame/support/procedural/src/pallet/parse/config.rs index 60888fc5dd357..0f3aa69b170ce 100644 --- a/frame/support/procedural/src/pallet/parse/config.rs +++ b/frame/support/procedural/src/pallet/parse/config.rs @@ -28,6 +28,7 @@ mod keyword { syn::custom_keyword!(I); syn::custom_keyword!(config); syn::custom_keyword!(IsType); + syn::custom_keyword!(RuntimeEvent); syn::custom_keyword!(Event); syn::custom_keyword!(constant); syn::custom_keyword!(frame_system); @@ -42,8 +43,9 @@ pub struct ConfigDef { pub has_instance: bool, /// Const associated type. pub consts_metadata: Vec, - /// Whether the trait has the associated type `Event`, note that those bounds are checked: - /// * `IsType::Event` + /// Whether the trait has the associated type `Event`, note that those bounds are + /// checked: + /// * `IsType::RuntimeEvent` /// * `From` or `From>` or `From>` pub has_event_type: bool, /// The where clause on trait definition but modified so `Self` is `T`. @@ -159,7 +161,7 @@ impl syn::parse::Parse for ConfigBoundParse { } } -/// Parse for `IsType<::Event>` and retrieve `$ident` +/// Parse for `IsType<::RuntimeEvent>` and retrieve `$ident` pub struct IsTypeBoundEventParse(syn::Ident); impl syn::parse::Parse for IsTypeBoundEventParse { @@ -174,7 +176,7 @@ impl syn::parse::Parse for IsTypeBoundEventParse { input.parse::()?; input.parse::]>()?; input.parse::()?; - input.parse::()?; + input.parse::()?; input.parse::]>()?; Ok(Self(ident)) @@ -212,7 +214,7 @@ impl syn::parse::Parse for FromEventParse { } } -/// Check if trait_item is `type Event`, if so checks its bounds are those expected. +/// Check if trait_item is `type RuntimeEvent`, if so checks its bounds are those expected. /// (Event type is reserved type) fn check_event_type( frame_system: &syn::Ident, @@ -220,10 +222,10 @@ fn check_event_type( trait_has_instance: bool, ) -> syn::Result { if let syn::TraitItem::Type(type_) = trait_item { - if type_.ident == "Event" { + if type_.ident == "RuntimeEvent" { // Check event has no generics if !type_.generics.params.is_empty() || type_.generics.where_clause.is_some() { - let msg = "Invalid `type Event`, associated type `Event` is reserved and must have\ + let msg = "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must have\ no generics nor where_clause"; return Err(syn::Error::new(trait_item.span(), msg)) } @@ -236,8 +238,8 @@ fn check_event_type( if !has_is_type_bound { let msg = format!( - "Invalid `type Event`, associated type `Event` is reserved and must \ - bound: `IsType<::Event>`", + "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must \ + bound: `IsType<::RuntimeEvent>`", frame_system, ); return Err(syn::Error::new(type_.span(), msg)) @@ -251,14 +253,14 @@ fn check_event_type( let from_event_bound = if let Some(b) = from_event_bound { b } else { - let msg = "Invalid `type Event`, associated type `Event` is reserved and must \ + let msg = "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must \ bound: `From` or `From>` or `From>`"; return Err(syn::Error::new(type_.span(), msg)) }; if from_event_bound.is_generic && (from_event_bound.has_instance != trait_has_instance) { - let msg = "Invalid `type Event`, associated type `Event` bounds inconsistent \ + let msg = "Invalid `type RuntimeEvent`, associated type `RuntimeEvent` bounds inconsistent \ `From`. Config and generic Event must be both with instance or \ without instance"; return Err(syn::Error::new(type_.span(), msg)) diff --git a/frame/support/procedural/src/pallet/parse/mod.rs b/frame/support/procedural/src/pallet/parse/mod.rs index a436f7e09c1d7..8b4ab154b306a 100644 --- a/frame/support/procedural/src/pallet/parse/mod.rs +++ b/frame/support/procedural/src/pallet/parse/mod.rs @@ -105,11 +105,11 @@ impl Def { let m = hooks::HooksDef::try_from(span, index, item)?; hooks = Some(m); }, - Some(PalletAttr::Call(span)) if call.is_none() => + Some(PalletAttr::RuntimeCall(span)) if call.is_none() => call = Some(call::CallDef::try_from(span, index, item)?), Some(PalletAttr::Error(span)) if error.is_none() => error = Some(error::ErrorDef::try_from(span, index, item)?), - Some(PalletAttr::Event(span)) if event.is_none() => + Some(PalletAttr::RuntimeEvent(span)) if event.is_none() => event = Some(event::EventDef::try_from(span, index, item)?), Some(PalletAttr::GenesisConfig(_)) if genesis_config.is_none() => { let g = genesis_config::GenesisConfigDef::try_from(index, item)?; @@ -119,7 +119,7 @@ impl Def { let g = genesis_build::GenesisBuildDef::try_from(span, index, item)?; genesis_build = Some(g); }, - Some(PalletAttr::Origin(_)) if origin.is_none() => + Some(PalletAttr::RuntimeOrigin(_)) if origin.is_none() => origin = Some(origin::OriginDef::try_from(index, item)?), Some(PalletAttr::Inherent(_)) if inherent.is_none() => inherent = Some(inherent::InherentDef::try_from(index, item)?), @@ -182,19 +182,19 @@ impl Def { } /// Check that usage of trait `Event` is consistent with the definition, i.e. it is declared - /// and trait defines type Event, or not declared and no trait associated type. + /// and trait defines type RuntimeEvent, or not declared and no trait associated type. fn check_event_usage(&self) -> syn::Result<()> { match (self.config.has_event_type, self.event.is_some()) { (true, false) => { - let msg = "Invalid usage of Event, `Config` contains associated type `Event`, \ + let msg = "Invalid usage of RuntimeEvent, `Config` contains associated type `RuntimeEvent`, \ but enum `Event` is not declared (i.e. no use of `#[pallet::event]`). \ - Note that type `Event` in trait is reserved to work alongside pallet event."; + Note that type `RuntimeEvent` in trait is reserved to work alongside pallet event."; Err(syn::Error::new(proc_macro2::Span::call_site(), msg)) }, (false, true) => { - let msg = "Invalid usage of Event, `Config` contains no associated type \ - `Event`, but enum `Event` is declared (in use of `#[pallet::event]`). \ - An Event associated type must be declare on trait `Config`."; + let msg = "Invalid usage of RuntimeEvent, `Config` contains no associated type \ + `RuntimeEvent`, but enum `Event` is declared (in use of `#[pallet::event]`). \ + An RuntimeEvent associated type must be declare on trait `Config`."; Err(syn::Error::new(proc_macro2::Span::call_site(), msg)) }, _ => Ok(()), @@ -391,10 +391,10 @@ enum PalletAttr { Config(proc_macro2::Span), Pallet(proc_macro2::Span), Hooks(proc_macro2::Span), - Call(proc_macro2::Span), + RuntimeCall(proc_macro2::Span), Error(proc_macro2::Span), - Event(proc_macro2::Span), - Origin(proc_macro2::Span), + RuntimeEvent(proc_macro2::Span), + RuntimeOrigin(proc_macro2::Span), Inherent(proc_macro2::Span), Storage(proc_macro2::Span), GenesisConfig(proc_macro2::Span), @@ -410,10 +410,10 @@ impl PalletAttr { Self::Config(span) => *span, Self::Pallet(span) => *span, Self::Hooks(span) => *span, - Self::Call(span) => *span, + Self::RuntimeCall(span) => *span, Self::Error(span) => *span, - Self::Event(span) => *span, - Self::Origin(span) => *span, + Self::RuntimeEvent(span) => *span, + Self::RuntimeOrigin(span) => *span, Self::Inherent(span) => *span, Self::Storage(span) => *span, Self::GenesisConfig(span) => *span, @@ -441,13 +441,13 @@ impl syn::parse::Parse for PalletAttr { } else if lookahead.peek(keyword::hooks) { Ok(PalletAttr::Hooks(content.parse::()?.span())) } else if lookahead.peek(keyword::call) { - Ok(PalletAttr::Call(content.parse::()?.span())) + Ok(PalletAttr::RuntimeCall(content.parse::()?.span())) } else if lookahead.peek(keyword::error) { Ok(PalletAttr::Error(content.parse::()?.span())) } else if lookahead.peek(keyword::event) { - Ok(PalletAttr::Event(content.parse::()?.span())) + Ok(PalletAttr::RuntimeEvent(content.parse::()?.span())) } else if lookahead.peek(keyword::origin) { - Ok(PalletAttr::Origin(content.parse::()?.span())) + Ok(PalletAttr::RuntimeOrigin(content.parse::()?.span())) } else if lookahead.peek(keyword::inherent) { Ok(PalletAttr::Inherent(content.parse::()?.span())) } else if lookahead.peek(keyword::storage) { diff --git a/frame/support/procedural/src/pallet/parse/storage.rs b/frame/support/procedural/src/pallet/parse/storage.rs index f0e1353774910..b16ff05803d98 100644 --- a/frame/support/procedural/src/pallet/parse/storage.rs +++ b/frame/support/procedural/src/pallet/parse/storage.rs @@ -28,6 +28,7 @@ mod keyword { syn::custom_keyword!(getter); syn::custom_keyword!(storage_prefix); syn::custom_keyword!(unbounded); + syn::custom_keyword!(whitelist_storage); syn::custom_keyword!(OptionQuery); syn::custom_keyword!(ResultQuery); syn::custom_keyword!(ValueQuery); @@ -37,16 +38,21 @@ mod keyword { /// * `#[pallet::getter(fn dummy)]` /// * `#[pallet::storage_prefix = "CustomName"]` /// * `#[pallet::unbounded]` +/// * `#[pallet::whitelist_storage] pub enum PalletStorageAttr { Getter(syn::Ident, proc_macro2::Span), StorageName(syn::LitStr, proc_macro2::Span), Unbounded(proc_macro2::Span), + WhitelistStorage(proc_macro2::Span), } impl PalletStorageAttr { fn attr_span(&self) -> proc_macro2::Span { match self { - Self::Getter(_, span) | Self::StorageName(_, span) | Self::Unbounded(span) => *span, + Self::Getter(_, span) | + Self::StorageName(_, span) | + Self::Unbounded(span) | + Self::WhitelistStorage(span) => *span, } } } @@ -84,6 +90,9 @@ impl syn::parse::Parse for PalletStorageAttr { content.parse::()?; Ok(Self::Unbounded(attr_span)) + } else if lookahead.peek(keyword::whitelist_storage) { + content.parse::()?; + Ok(Self::WhitelistStorage(attr_span)) } else { Err(lookahead.error()) } @@ -94,6 +103,7 @@ struct PalletStorageAttrInfo { getter: Option, rename_as: Option, unbounded: bool, + whitelisted: bool, } impl PalletStorageAttrInfo { @@ -101,12 +111,14 @@ impl PalletStorageAttrInfo { let mut getter = None; let mut rename_as = None; let mut unbounded = false; + let mut whitelisted = false; for attr in attrs { match attr { PalletStorageAttr::Getter(ident, ..) if getter.is_none() => getter = Some(ident), PalletStorageAttr::StorageName(name, ..) if rename_as.is_none() => rename_as = Some(name), PalletStorageAttr::Unbounded(..) if !unbounded => unbounded = true, + PalletStorageAttr::WhitelistStorage(..) if !whitelisted => whitelisted = true, attr => return Err(syn::Error::new( attr.attr_span(), @@ -115,7 +127,7 @@ impl PalletStorageAttrInfo { } } - Ok(PalletStorageAttrInfo { getter, rename_as, unbounded }) + Ok(PalletStorageAttrInfo { getter, rename_as, unbounded, whitelisted }) } } @@ -171,6 +183,8 @@ pub struct StorageDef { pub named_generics: Option, /// If the value stored in this storage is unbounded. pub unbounded: bool, + /// Whether or not reads to this storage key will be ignored by benchmarking + pub whitelisted: bool, } /// The parsed generic from the @@ -541,8 +555,8 @@ fn process_generics( found => { let msg = format!( "Invalid pallet::storage, expected ident: `StorageValue` or \ - `StorageMap` or `StorageDoubleMap` or `StorageNMap` in order to expand metadata, \ - found `{}`.", + `StorageMap` or `CountedStorageMap` or `StorageDoubleMap` or `StorageNMap` \ + in order to expand metadata, found `{}`.", found, ); return Err(syn::Error::new(segment.ident.span(), msg)) @@ -672,7 +686,7 @@ impl StorageDef { }; let attrs: Vec = helper::take_item_pallet_attrs(&mut item.attrs)?; - let PalletStorageAttrInfo { getter, rename_as, unbounded } = + let PalletStorageAttrInfo { getter, rename_as, unbounded, whitelisted } = PalletStorageAttrInfo::from_attrs(attrs)?; let cfg_attrs = helper::get_item_cfg_attrs(&item.attrs); @@ -814,6 +828,7 @@ impl StorageDef { cfg_attrs, named_generics, unbounded, + whitelisted, }) } } diff --git a/frame/support/procedural/src/storage/mod.rs b/frame/support/procedural/src/storage/mod.rs index 756653f7ba85d..e8e2d7529cb3f 100644 --- a/frame/support/procedural/src/storage/mod.rs +++ b/frame/support/procedural/src/storage/mod.rs @@ -32,6 +32,7 @@ pub(crate) use instance_trait::INHERENT_INSTANCE_NAME; use frame_support_procedural_tools::{ generate_crate_access, generate_hidden_includes, syn_ext as ext, }; + use quote::quote; /// All information contained in input of decl_storage diff --git a/frame/support/src/dispatch.rs b/frame/support/src/dispatch.rs index 42799bb8bac4a..d975fdf821ca6 100644 --- a/frame/support/src/dispatch.rs +++ b/frame/support/src/dispatch.rs @@ -31,18 +31,22 @@ pub use crate::{ traits::{ CallMetadata, GetCallMetadata, GetCallName, GetStorageVersion, UnfilteredDispatchable, }, - weights::{ - ClassifyDispatch, DispatchInfo, GetDispatchInfo, PaysFee, PostDispatchInfo, - TransactionPriority, WeighData, Weight, WithPostDispatchInfo, - }, }; -pub use sp_runtime::{traits::Dispatchable, DispatchError, RuntimeDebug}; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; +use sp_runtime::{ + generic::{CheckedExtrinsic, UncheckedExtrinsic}, + traits::SignedExtension, +}; +pub use sp_runtime::{ + traits::Dispatchable, transaction_validity::TransactionPriority, DispatchError, RuntimeDebug, +}; +pub use sp_weights::Weight; /// The return type of a `Dispatchable` in frame. When returned explicitly from /// a dispatchable function it allows overriding the default `PostDispatchInfo` /// returned from a dispatch. -pub type DispatchResultWithPostInfo = - sp_runtime::DispatchResultWithInfo; +pub type DispatchResultWithPostInfo = sp_runtime::DispatchResultWithInfo; /// Unaugmented version of `DispatchResultWithPostInfo` that can be returned from /// dispatchable functions and is automatically converted to the augmented type. Should be @@ -51,17 +55,16 @@ pub type DispatchResultWithPostInfo = pub type DispatchResult = Result<(), sp_runtime::DispatchError>; /// The error type contained in a `DispatchResultWithPostInfo`. -pub type DispatchErrorWithPostInfo = - sp_runtime::DispatchErrorWithPostInfo; +pub type DispatchErrorWithPostInfo = sp_runtime::DispatchErrorWithPostInfo; /// Serializable version of pallet dispatchable. pub trait Callable { - type Call: UnfilteredDispatchable + Codec + Clone + PartialEq + Eq; + type RuntimeCall: UnfilteredDispatchable + Codec + Clone + PartialEq + Eq; } // dirty hack to work around serde_derive issue // https://github.com/rust-lang/rust/issues/51331 -pub type CallableCallFor = >::Call; +pub type CallableCallFor = >::RuntimeCall; /// Origin for the System pallet. #[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] @@ -91,6 +94,552 @@ impl From> for RawOrigin { pub trait Parameter: Codec + EncodeLike + Clone + Eq + fmt::Debug + scale_info::TypeInfo {} impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug + scale_info::TypeInfo {} +/// Means of classifying a dispatchable function. +pub trait ClassifyDispatch { + /// Classify the dispatch function based on input data `target` of type `T`. When implementing + /// this for a dispatchable, `T` will be a tuple of all arguments given to the function (except + /// origin). + fn classify_dispatch(&self, target: T) -> DispatchClass; +} + +/// Indicates if dispatch function should pay fees or not. +/// +/// If set to `Pays::No`, the block resource limits are applied, yet no fee is deducted. +pub trait PaysFee { + fn pays_fee(&self, _target: T) -> Pays; +} + +/// Explicit enum to denote if a transaction pays fee or not. +#[derive(Clone, Copy, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo)] +pub enum Pays { + /// Transactor will pay related fees. + Yes, + /// Transactor will NOT pay related fees. + No, +} + +impl Default for Pays { + fn default() -> Self { + Self::Yes + } +} + +impl From for PostDispatchInfo { + fn from(pays_fee: Pays) -> Self { + Self { actual_weight: None, pays_fee } + } +} + +/// A generalized group of dispatch types. +/// +/// NOTE whenever upgrading the enum make sure to also update +/// [DispatchClass::all] and [DispatchClass::non_mandatory] helper functions. +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum DispatchClass { + /// A normal dispatch. + Normal, + /// An operational dispatch. + Operational, + /// A mandatory dispatch. These kinds of dispatch are always included regardless of their + /// weight, therefore it is critical that they are separately validated to ensure that a + /// malicious validator cannot craft a valid but impossibly heavy block. Usually this just + /// means ensuring that the extrinsic can only be included once and that it is always very + /// light. + /// + /// Do *NOT* use it for extrinsics that can be heavy. + /// + /// The only real use case for this is inherent extrinsics that are required to execute in a + /// block for the block to be valid, and it solves the issue in the case that the block + /// initialization is sufficiently heavy to mean that those inherents do not fit into the + /// block. Essentially, we assume that in these exceptional circumstances, it is better to + /// allow an overweight block to be created than to not allow any block at all to be created. + Mandatory, +} + +impl Default for DispatchClass { + fn default() -> Self { + Self::Normal + } +} + +impl DispatchClass { + /// Returns an array containing all dispatch classes. + pub fn all() -> &'static [DispatchClass] { + &[DispatchClass::Normal, DispatchClass::Operational, DispatchClass::Mandatory] + } + + /// Returns an array of all dispatch classes except `Mandatory`. + pub fn non_mandatory() -> &'static [DispatchClass] { + &[DispatchClass::Normal, DispatchClass::Operational] + } +} + +/// A trait that represents one or many values of given type. +/// +/// Useful to accept as parameter type to let the caller pass either a single value directly +/// or an iterator. +pub trait OneOrMany { + /// The iterator type. + type Iter: Iterator; + /// Convert this item into an iterator. + fn into_iter(self) -> Self::Iter; +} + +impl OneOrMany for DispatchClass { + type Iter = sp_std::iter::Once; + fn into_iter(self) -> Self::Iter { + sp_std::iter::once(self) + } +} + +impl<'a> OneOrMany for &'a [DispatchClass] { + type Iter = sp_std::iter::Cloned>; + fn into_iter(self) -> Self::Iter { + self.iter().cloned() + } +} + +/// A bundle of static information collected from the `#[pallet::weight]` attributes. +#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] +pub struct DispatchInfo { + /// Weight of this transaction. + pub weight: Weight, + /// Class of this transaction. + pub class: DispatchClass, + /// Does this transaction pay fees. + pub pays_fee: Pays, +} + +/// A `Dispatchable` function (aka transaction) that can carry some static information along with +/// it, using the `#[pallet::weight]` attribute. +pub trait GetDispatchInfo { + /// Return a `DispatchInfo`, containing relevant information of this dispatch. + /// + /// This is done independently of its encoded size. + fn get_dispatch_info(&self) -> DispatchInfo; +} + +impl GetDispatchInfo for () { + fn get_dispatch_info(&self) -> DispatchInfo { + DispatchInfo::default() + } +} + +/// Extract the actual weight from a dispatch result if any or fall back to the default weight. +pub fn extract_actual_weight(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Weight { + match result { + Ok(post_info) => post_info, + Err(err) => &err.post_info, + } + .calc_actual_weight(info) +} + +/// Extract the actual pays_fee from a dispatch result if any or fall back to the default weight. +pub fn extract_actual_pays_fee(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Pays { + match result { + Ok(post_info) => post_info, + Err(err) => &err.post_info, + } + .pays_fee(info) +} + +/// Weight information that is only available post dispatch. +/// NOTE: This can only be used to reduce the weight or fee, not increase it. +#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] +pub struct PostDispatchInfo { + /// Actual weight consumed by a call or `None` which stands for the worst case static weight. + pub actual_weight: Option, + /// Whether this transaction should pay fees when all is said and done. + pub pays_fee: Pays, +} + +impl PostDispatchInfo { + /// Calculate how much (if any) weight was not used by the `Dispatchable`. + pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight { + info.weight - self.calc_actual_weight(info) + } + + /// Calculate how much weight was actually spent by the `Dispatchable`. + pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight { + if let Some(actual_weight) = self.actual_weight { + actual_weight.min(info.weight) + } else { + info.weight + } + } + + /// Determine if user should actually pay fees at the end of the dispatch. + pub fn pays_fee(&self, info: &DispatchInfo) -> Pays { + // If they originally were not paying fees, or the post dispatch info + // says they should not pay fees, then they don't pay fees. + // This is because the pre dispatch information must contain the + // worst case for weight and fees paid. + if info.pays_fee == Pays::No || self.pays_fee == Pays::No { + Pays::No + } else { + // Otherwise they pay. + Pays::Yes + } + } +} + +impl From<()> for PostDispatchInfo { + fn from(_: ()) -> Self { + Self { actual_weight: None, pays_fee: Default::default() } + } +} + +impl sp_runtime::traits::Printable for PostDispatchInfo { + fn print(&self) { + "actual_weight=".print(); + match self.actual_weight { + Some(weight) => weight.print(), + None => "max-weight".print(), + }; + "pays_fee=".print(); + match self.pays_fee { + Pays::Yes => "Yes".print(), + Pays::No => "No".print(), + } + } +} + +/// Allows easy conversion from `DispatchError` to `DispatchErrorWithPostInfo` for dispatchables +/// that want to return a custom a posterior weight on error. +pub trait WithPostDispatchInfo { + /// Call this on your modules custom errors type in order to return a custom weight on error. + /// + /// # Example + /// + /// ```ignore + /// let who = ensure_signed(origin).map_err(|e| e.with_weight(Weight::from_ref_time(100)))?; + /// ensure!(who == me, Error::::NotMe.with_weight(200_000)); + /// ``` + fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo; +} + +impl WithPostDispatchInfo for T +where + T: Into, +{ + fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo { + DispatchErrorWithPostInfo { + post_info: PostDispatchInfo { + actual_weight: Some(actual_weight), + pays_fee: Default::default(), + }, + error: self.into(), + } + } +} + +/// Implementation for unchecked extrinsic. +impl GetDispatchInfo + for UncheckedExtrinsic +where + Call: GetDispatchInfo, + Extra: SignedExtension, +{ + fn get_dispatch_info(&self) -> DispatchInfo { + self.function.get_dispatch_info() + } +} + +/// Implementation for checked extrinsic. +impl GetDispatchInfo for CheckedExtrinsic +where + Call: GetDispatchInfo, +{ + fn get_dispatch_info(&self) -> DispatchInfo { + self.function.get_dispatch_info() + } +} + +/// Implementation for test extrinsic. +#[cfg(feature = "std")] +impl GetDispatchInfo for sp_runtime::testing::TestXt { + fn get_dispatch_info(&self) -> DispatchInfo { + // for testing: weight == size. + DispatchInfo { + weight: Weight::from_ref_time(self.encode().len() as _), + pays_fee: Pays::Yes, + ..Default::default() + } + } +} + +/// A struct holding value for each `DispatchClass`. +#[derive(Clone, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] +pub struct PerDispatchClass { + /// Value for `Normal` extrinsics. + normal: T, + /// Value for `Operational` extrinsics. + operational: T, + /// Value for `Mandatory` extrinsics. + mandatory: T, +} + +impl PerDispatchClass { + /// Create new `PerDispatchClass` with the same value for every class. + pub fn new(val: impl Fn(DispatchClass) -> T) -> Self { + Self { + normal: val(DispatchClass::Normal), + operational: val(DispatchClass::Operational), + mandatory: val(DispatchClass::Mandatory), + } + } + + /// Get a mutable reference to current value of given class. + pub fn get_mut(&mut self, class: DispatchClass) -> &mut T { + match class { + DispatchClass::Operational => &mut self.operational, + DispatchClass::Normal => &mut self.normal, + DispatchClass::Mandatory => &mut self.mandatory, + } + } + + /// Get current value for given class. + pub fn get(&self, class: DispatchClass) -> &T { + match class { + DispatchClass::Normal => &self.normal, + DispatchClass::Operational => &self.operational, + DispatchClass::Mandatory => &self.mandatory, + } + } +} + +impl PerDispatchClass { + /// Set the value of given class. + pub fn set(&mut self, new: T, class: impl OneOrMany) { + for class in class.into_iter() { + *self.get_mut(class) = new.clone(); + } + } +} + +impl PerDispatchClass { + /// Returns the total weight consumed by all extrinsics in the block. + pub fn total(&self) -> Weight { + let mut sum = Weight::zero(); + for class in DispatchClass::all() { + sum = sum.saturating_add(*self.get(*class)); + } + sum + } + + /// Add some weight of a specific dispatch class, saturating at the numeric bounds of `Weight`. + pub fn add(&mut self, weight: Weight, class: DispatchClass) { + let value = self.get_mut(class); + *value = value.saturating_add(weight); + } + + /// Try to add some weight of a specific dispatch class, returning Err(()) if overflow would + /// occur. + pub fn checked_add(&mut self, weight: Weight, class: DispatchClass) -> Result<(), ()> { + let value = self.get_mut(class); + *value = value.checked_add(&weight).ok_or(())?; + Ok(()) + } + + /// Subtract some weight of a specific dispatch class, saturating at the numeric bounds of + /// `Weight`. + pub fn sub(&mut self, weight: Weight, class: DispatchClass) { + let value = self.get_mut(class); + *value = value.saturating_sub(weight); + } +} + +/// Means of weighing some particular kind of data (`T`). +pub trait WeighData { + /// Weigh the data `T` given by `target`. When implementing this for a dispatchable, `T` will be + /// a tuple of all arguments given to the function (except origin). + fn weigh_data(&self, target: T) -> Weight; +} + +impl WeighData for Weight { + fn weigh_data(&self, _: T) -> Weight { + return *self + } +} + +impl PaysFee for (Weight, DispatchClass, Pays) { + fn pays_fee(&self, _: T) -> Pays { + self.2 + } +} + +impl WeighData for (Weight, DispatchClass) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl WeighData for (Weight, DispatchClass, Pays) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl ClassifyDispatch for (Weight, DispatchClass) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + self.1 + } +} + +impl PaysFee for (Weight, DispatchClass) { + fn pays_fee(&self, _: T) -> Pays { + Pays::Yes + } +} + +impl WeighData for (Weight, Pays) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl ClassifyDispatch for (Weight, Pays) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + DispatchClass::Normal + } +} + +impl PaysFee for (Weight, Pays) { + fn pays_fee(&self, _: T) -> Pays { + self.1 + } +} + +impl From<(Option, Pays)> for PostDispatchInfo { + fn from(post_weight_info: (Option, Pays)) -> Self { + let (actual_weight, pays_fee) = post_weight_info; + Self { actual_weight, pays_fee } + } +} + +impl From> for PostDispatchInfo { + fn from(actual_weight: Option) -> Self { + Self { actual_weight, pays_fee: Default::default() } + } +} + +impl ClassifyDispatch for Weight { + fn classify_dispatch(&self, _: T) -> DispatchClass { + DispatchClass::Normal + } +} + +impl PaysFee for Weight { + fn pays_fee(&self, _: T) -> Pays { + Pays::Yes + } +} + +impl ClassifyDispatch for (Weight, DispatchClass, Pays) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + self.1 + } +} + +// TODO: Eventually remove these + +impl From> for PostDispatchInfo { + fn from(maybe_actual_computation: Option) -> Self { + let actual_weight = match maybe_actual_computation { + Some(actual_computation) => Some(Weight::zero().set_ref_time(actual_computation)), + None => None, + }; + Self { actual_weight, pays_fee: Default::default() } + } +} + +impl From<(Option, Pays)> for PostDispatchInfo { + fn from(post_weight_info: (Option, Pays)) -> Self { + let (maybe_actual_time, pays_fee) = post_weight_info; + let actual_weight = match maybe_actual_time { + Some(actual_time) => Some(Weight::zero().set_ref_time(actual_time)), + None => None, + }; + Self { actual_weight, pays_fee } + } +} + +impl ClassifyDispatch for u64 { + fn classify_dispatch(&self, _: T) -> DispatchClass { + DispatchClass::Normal + } +} + +impl PaysFee for u64 { + fn pays_fee(&self, _: T) -> Pays { + Pays::Yes + } +} + +impl WeighData for u64 { + fn weigh_data(&self, _: T) -> Weight { + return Weight::zero().set_ref_time(*self) + } +} + +impl WeighData for (u64, DispatchClass, Pays) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl ClassifyDispatch for (u64, DispatchClass, Pays) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + self.1 + } +} + +impl PaysFee for (u64, DispatchClass, Pays) { + fn pays_fee(&self, _: T) -> Pays { + self.2 + } +} + +impl WeighData for (u64, DispatchClass) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl ClassifyDispatch for (u64, DispatchClass) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + self.1 + } +} + +impl PaysFee for (u64, DispatchClass) { + fn pays_fee(&self, _: T) -> Pays { + Pays::Yes + } +} + +impl WeighData for (u64, Pays) { + fn weigh_data(&self, args: T) -> Weight { + return self.0.weigh_data(args) + } +} + +impl ClassifyDispatch for (u64, Pays) { + fn classify_dispatch(&self, _: T) -> DispatchClass { + DispatchClass::Normal + } +} + +impl PaysFee for (u64, Pays) { + fn pays_fee(&self, _: T) -> Pays { + self.1 + } +} + +// END TODO + /// Declares a `Module` struct and a `Call` enum, which implements the dispatch logic. /// /// ## Declaration @@ -101,7 +650,7 @@ impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug + /// # use frame_support::dispatch; /// # use frame_system::{Config, ensure_signed}; /// decl_module! { -/// pub struct Module for enum Call where origin: T::Origin { +/// pub struct Module for enum Call where origin: T::RuntimeOrigin { /// /// // Private functions are dispatchable, but not available to other /// // FRAME pallets. @@ -128,7 +677,7 @@ impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug + /// * `Module`: The struct generated by the macro, with type `Config`. /// * `Call`: The enum generated for every pallet, which implements /// [`Callable`](./dispatch/trait.Callable.html). -/// * `origin`: Alias of `T::Origin`. +/// * `origin`: Alias of `T::RuntimeOrigin`. /// * `Result`: The expected return type from pallet functions. /// /// The first parameter of dispatchable functions must always be `origin`. @@ -144,7 +693,7 @@ impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug + /// # use frame_support::dispatch; /// # use frame_system::{Config, ensure_signed}; /// decl_module! { -/// pub struct Module for enum Call where origin: T::Origin { +/// pub struct Module for enum Call where origin: T::RuntimeOrigin { /// #[weight = 0] /// fn my_long_function(origin) -> dispatch::DispatchResult { /// // Your implementation @@ -179,7 +728,7 @@ impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug + /// # use frame_support::{weights::Weight, dispatch::{DispatchResultWithPostInfo, WithPostDispatchInfo}}; /// # use frame_system::{Config, ensure_signed}; /// decl_module! { -/// pub struct Module for enum Call where origin: T::Origin { +/// pub struct Module for enum Call where origin: T::RuntimeOrigin { /// #[weight = 1_000_000] /// fn my_long_function(origin, do_expensive_calc: bool) -> DispatchResultWithPostInfo { /// ensure_signed(origin).map_err(|e| e.with_weight(Weight::from_ref_time(100_000)))?; @@ -209,7 +758,7 @@ impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug + /// # use frame_support::transactional; /// # use frame_system::Config; /// decl_module! { -/// pub struct Module for enum Call where origin: T::Origin { +/// pub struct Module for enum Call where origin: T::RuntimeOrigin { /// #[weight = 0] /// #[transactional] /// fn my_short_function(origin) { @@ -230,7 +779,7 @@ impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug + /// # use frame_support::dispatch; /// # use frame_system::{Config, ensure_signed, ensure_root}; /// decl_module! { -/// pub struct Module for enum Call where origin: T::Origin { +/// pub struct Module for enum Call where origin: T::RuntimeOrigin { /// #[weight = 0] /// fn my_privileged_function(origin) -> dispatch::DispatchResult { /// ensure_root(origin)?; @@ -270,7 +819,7 @@ impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug + /// pub trait Config: frame_system::Config {} /// /// decl_module! { -/// pub struct Module, I: Instance = DefaultInstance> for enum Call where origin: T::Origin { +/// pub struct Module, I: Instance = DefaultInstance> for enum Call where origin: T::RuntimeOrigin { /// // Your implementation /// } /// } @@ -282,7 +831,7 @@ impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug + /// /// ## Where clause /// -/// Besides the default `origin: T::Origin`, you can also pass other bounds to the module +/// Besides the default `origin: T::RuntimeOrigin`, you can also pass other bounds to the module /// declaration. This where bound will be replicated to all types generated by this macro. The /// chaining of multiple trait bounds with `+` is not supported. If multiple bounds for one type are /// required, it needs to be split up into multiple bounds. @@ -295,7 +844,7 @@ impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + fmt::Debug + /// pub trait Config: system::Config where Self::AccountId: From {} /// /// decl_module! { -/// pub struct Module for enum Call where origin: T::Origin, T::AccountId: From { +/// pub struct Module for enum Call where origin: T::RuntimeOrigin, T::AccountId: From { /// // Your implementation /// } /// } @@ -1336,7 +1885,7 @@ macro_rules! decl_module { ) ); }; - // Ignore any ident which is not `origin` with type `T::Origin`. + // Ignore any ident which is not `origin` with type `T::RuntimeOrigin`. (@normalize $(#[$attr:meta])* pub struct $mod_type:ident<$trait_instance:ident: $trait_name:ident$(, I: $instantiable:path $(= $module_default_instance:path)?)?> @@ -1357,7 +1906,7 @@ macro_rules! decl_module { $(#[weight = $weight:expr])? $(#[$fn_attr:meta])* $fn_vis:vis fn $fn_name:ident( - $origin:ident : T::Origin $( , $( #[$codec_attr:ident] )* $param_name:ident : $param:ty )* $(,)? + $origin:ident : T::RuntimeOrigin $( , $( #[$codec_attr:ident] )* $param_name:ident : $param:ty )* $(,)? ) $( -> $result:ty )* { $( $impl:tt )* } $($rest:tt)* ) => { @@ -1493,7 +2042,7 @@ macro_rules! decl_module { { /// Deposits an event using `frame_system::Pallet::deposit_event`. $vis fn deposit_event( - event: impl Into<< $trait_instance as $trait_name $(<$instance>)? >::Event> + event: impl Into<< $trait_instance as $trait_name $(<$instance>)? >::RuntimeEvent> ) { <$system::Pallet<$trait_instance>>::deposit_event(event.into()) } @@ -1605,12 +2154,12 @@ macro_rules! decl_module { } #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { - Ok(()) + fn pre_upgrade() -> Result<$crate::sp_std::vec::Vec, &'static str> { + Ok($crate::sp_std::vec::Vec::new()) } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { + fn post_upgrade(_: $crate::sp_std::vec::Vec) -> Result<(), &'static str> { Ok(()) } } @@ -1643,12 +2192,12 @@ macro_rules! decl_module { } #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { - Ok(()) + fn pre_upgrade() -> Result<$crate::sp_std::vec::Vec, &'static str> { + Ok($crate::sp_std::vec::Vec::new()) } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { + fn post_upgrade(_: $crate::sp_std::vec::Vec) -> Result<(), &'static str> { Ok(()) } } @@ -2349,8 +2898,8 @@ macro_rules! decl_module { impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::traits::UnfilteredDispatchable for $call_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* { - type Origin = $origin_type; - fn dispatch_bypass_filter(self, _origin: Self::Origin) -> $crate::dispatch::DispatchResultWithPostInfo { + type RuntimeOrigin = $origin_type; + fn dispatch_bypass_filter(self, _origin: Self::RuntimeOrigin) -> $crate::dispatch::DispatchResultWithPostInfo { match self { $( $call_type::$fn_name { $( $param_name ),* } => { @@ -2368,7 +2917,7 @@ macro_rules! decl_module { impl<$trait_instance: $trait_name $(, $instance: $instantiable)?> $crate::dispatch::Callable<$trait_instance> for $mod_type<$trait_instance $(, $instance)?> where $( $other_where_bounds )* { - type Call = $call_type<$trait_instance $(, $instance)?>; + type RuntimeCall = $call_type<$trait_instance $(, $instance)?>; } $crate::__dispatch_impl_metadata! { @@ -2621,13 +3170,14 @@ macro_rules! __check_reserved_fn_name { mod tests { use super::*; use crate::{ + dispatch::{DispatchClass, DispatchInfo, Pays}, metadata::*, traits::{ - CrateVersion, Get, GetCallName, IntegrityTest, OnFinalize, OnIdle, OnInitialize, - OnRuntimeUpgrade, PalletInfo, + CallerTrait, CrateVersion, Get, GetCallName, IntegrityTest, OnFinalize, OnIdle, + OnInitialize, OnRuntimeUpgrade, PalletInfo, }, - weights::{DispatchClass, DispatchInfo, Pays, RuntimeDbWeight}, }; + use sp_weights::RuntimeDbWeight; pub trait Config: system::Config + Sized where @@ -2640,9 +3190,9 @@ mod tests { pub trait Config: 'static { type AccountId; - type Call; + type RuntimeCall; type BaseCallFilter; - type Origin: crate::traits::OriginTrait; + type RuntimeOrigin: crate::traits::OriginTrait; type BlockNumber: Into; type PalletInfo: crate::traits::PalletInfo; type DbWeight: Get; @@ -2654,7 +3204,7 @@ mod tests { } decl_module! { - pub struct Module for enum Call where origin: T::Origin, system = system, T::AccountId: From { + pub struct Module for enum Call where origin: T::RuntimeOrigin, system = system, T::AccountId: From { /// Hi, this is a comment. #[weight = 0] fn aux_0(_origin) -> DispatchResult { unreachable!() } @@ -2742,8 +3292,18 @@ mod tests { } } + impl CallerTrait<::AccountId> for OuterOrigin { + fn into_system(self) -> Option::AccountId>> { + unimplemented!("Not required in tests!") + } + + fn as_system_ref(&self) -> Option<&RawOrigin<::AccountId>> { + unimplemented!("Not required in tests!") + } + } + impl crate::traits::OriginTrait for OuterOrigin { - type Call = ::Call; + type Call = ::RuntimeCall; type PalletsOrigin = OuterOrigin; type AccountId = ::AccountId; @@ -2767,6 +3327,10 @@ mod tests { unimplemented!("Not required in tests!") } + fn into_caller(self) -> Self::PalletsOrigin { + unimplemented!("Not required in tests!") + } + fn try_with_caller( self, _f: impl FnOnce(Self::PalletsOrigin) -> Result, @@ -2786,12 +3350,15 @@ mod tests { fn as_signed(self) -> Option { unimplemented!("Not required in tests!") } + fn as_system_ref(&self) -> Option<&RawOrigin> { + unimplemented!("Not required in tests!") + } } impl system::Config for TraitImpl { - type Origin = OuterOrigin; + type RuntimeOrigin = OuterOrigin; type AccountId = u32; - type Call = (); + type RuntimeCall = (); type BaseCallFilter = frame_support::traits::Everything; type BlockNumber = u32; type PalletInfo = Self; @@ -2932,3 +3499,187 @@ mod tests { Call::::new_call_variant_aux_0(); } } + +#[cfg(test)] +// Do not complain about unused `dispatch` and `dispatch_aux`. +#[allow(dead_code)] +mod weight_tests { + use super::*; + use sp_core::{parameter_types, Get}; + use sp_weights::RuntimeDbWeight; + + pub trait Config: 'static { + type RuntimeOrigin; + type Balance; + type BlockNumber; + type DbWeight: Get; + type PalletInfo: crate::traits::PalletInfo; + } + + pub struct TraitImpl {} + + parameter_types! { + pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { + read: 100, + write: 1000, + }; + } + + impl Config for TraitImpl { + type RuntimeOrigin = u32; + type BlockNumber = u32; + type Balance = u32; + type DbWeight = DbWeight; + type PalletInfo = crate::tests::PanicPalletInfo; + } + + decl_module! { + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self { + // no arguments, fixed weight + #[weight = 1000] + fn f00(_origin) { unimplemented!(); } + + #[weight = (1000, DispatchClass::Mandatory)] + fn f01(_origin) { unimplemented!(); } + + #[weight = (1000, Pays::No)] + fn f02(_origin) { unimplemented!(); } + + #[weight = (1000, DispatchClass::Operational, Pays::No)] + fn f03(_origin) { unimplemented!(); } + + // weight = a x 10 + b + #[weight = ((_a * 10 + _eb * 1) as u64, DispatchClass::Normal, Pays::Yes)] + fn f11(_origin, _a: u32, _eb: u32) { unimplemented!(); } + + #[weight = (0, DispatchClass::Operational, Pays::Yes)] + fn f12(_origin, _a: u32, _eb: u32) { unimplemented!(); } + + #[weight = T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + Weight::from_ref_time(10_000)] + fn f20(_origin) { unimplemented!(); } + + #[weight = T::DbWeight::get().reads_writes(6, 5) + Weight::from_ref_time(40_000)] + fn f21(_origin) { unimplemented!(); } + + } + } + + #[test] + fn weights_are_correct() { + // #[weight = 1000] + let info = Call::::f00 {}.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_ref_time(1000)); + assert_eq!(info.class, DispatchClass::Normal); + assert_eq!(info.pays_fee, Pays::Yes); + + // #[weight = (1000, DispatchClass::Mandatory)] + let info = Call::::f01 {}.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_ref_time(1000)); + assert_eq!(info.class, DispatchClass::Mandatory); + assert_eq!(info.pays_fee, Pays::Yes); + + // #[weight = (1000, Pays::No)] + let info = Call::::f02 {}.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_ref_time(1000)); + assert_eq!(info.class, DispatchClass::Normal); + assert_eq!(info.pays_fee, Pays::No); + + // #[weight = (1000, DispatchClass::Operational, Pays::No)] + let info = Call::::f03 {}.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_ref_time(1000)); + assert_eq!(info.class, DispatchClass::Operational); + assert_eq!(info.pays_fee, Pays::No); + + // #[weight = ((_a * 10 + _eb * 1) as Weight, DispatchClass::Normal, Pays::Yes)] + let info = Call::::f11 { _a: 13, _eb: 20 }.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_ref_time(150)); // 13*10 + 20 + assert_eq!(info.class, DispatchClass::Normal); + assert_eq!(info.pays_fee, Pays::Yes); + + // #[weight = (0, DispatchClass::Operational, Pays::Yes)] + let info = Call::::f12 { _a: 10, _eb: 20 }.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_ref_time(0)); + assert_eq!(info.class, DispatchClass::Operational); + assert_eq!(info.pays_fee, Pays::Yes); + + // #[weight = T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + 10_000] + let info = Call::::f20 {}.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_ref_time(12300)); // 100*3 + 1000*2 + 10_1000 + assert_eq!(info.class, DispatchClass::Normal); + assert_eq!(info.pays_fee, Pays::Yes); + + // #[weight = T::DbWeight::get().reads_writes(6, 5) + 40_000] + let info = Call::::f21 {}.get_dispatch_info(); + assert_eq!(info.weight, Weight::from_ref_time(45600)); // 100*6 + 1000*5 + 40_1000 + assert_eq!(info.class, DispatchClass::Normal); + assert_eq!(info.pays_fee, Pays::Yes); + } + + #[test] + fn extract_actual_weight_works() { + let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; + assert_eq!(extract_actual_weight(&Ok(Some(7).into()), &pre), Weight::from_ref_time(7)); + assert_eq!( + extract_actual_weight(&Ok(Some(1000).into()), &pre), + Weight::from_ref_time(1000) + ); + assert_eq!( + extract_actual_weight( + &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(9))), + &pre + ), + Weight::from_ref_time(9) + ); + } + + #[test] + fn extract_actual_weight_caps_at_pre_weight() { + let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; + assert_eq!( + extract_actual_weight(&Ok(Some(1250).into()), &pre), + Weight::from_ref_time(1000) + ); + assert_eq!( + extract_actual_weight( + &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(1300))), + &pre + ), + Weight::from_ref_time(1000), + ); + } + + #[test] + fn extract_actual_pays_fee_works() { + let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; + assert_eq!(extract_actual_pays_fee(&Ok(Some(7).into()), &pre), Pays::Yes); + assert_eq!(extract_actual_pays_fee(&Ok(Some(1000).into()), &pre), Pays::Yes); + assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::Yes); + assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::No).into()), &pre), Pays::No); + assert_eq!( + extract_actual_pays_fee( + &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(9))), + &pre + ), + Pays::Yes + ); + assert_eq!( + extract_actual_pays_fee( + &Err(DispatchErrorWithPostInfo { + post_info: PostDispatchInfo { actual_weight: None, pays_fee: Pays::No }, + error: DispatchError::BadOrigin, + }), + &pre + ), + Pays::No + ); + + let pre = DispatchInfo { + weight: Weight::from_ref_time(1000), + pays_fee: Pays::No, + ..Default::default() + }; + assert_eq!(extract_actual_pays_fee(&Ok(Some(7).into()), &pre), Pays::No); + assert_eq!(extract_actual_pays_fee(&Ok(Some(1000).into()), &pre), Pays::No); + assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::No); + } +} diff --git a/frame/support/src/error.rs b/frame/support/src/error.rs index 0ffe4334e2e30..337bd75895c2c 100644 --- a/frame/support/src/error.rs +++ b/frame/support/src/error.rs @@ -51,7 +51,7 @@ pub use sp_runtime::traits::{BadOrigin, LookupError}; /// // exported in the metadata. /// /// decl_module! { -/// pub struct Module for enum Call where origin: T::Origin { +/// pub struct Module for enum Call where origin: T::RuntimeOrigin { /// type Error = MyError; /// /// #[weight = 0] diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 3b2a8b3b62fc2..9b0ee84c34d8a 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -93,7 +93,7 @@ pub mod unsigned { }; } -#[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] +#[cfg(any(feature = "std", feature = "runtime-benchmarks", feature = "try-runtime", test))] pub use self::storage::storage_noop_guard::StorageNoopGuard; pub use self::{ dispatch::{Callable, Parameter}, @@ -361,9 +361,9 @@ macro_rules! parameter_types { } }; (IMPL_STORAGE $name:ident, $type:ty, $value:expr $(, $ty_params:ident)*) => { + #[allow(unused)] impl< $($ty_params),* > $name< $($ty_params),* > { /// Returns the key for this parameter type. - #[allow(unused)] pub fn key() -> [u8; 16] { $crate::sp_core_hashing_proc_macro::twox_128!(b":", $name, b":") } @@ -372,7 +372,6 @@ macro_rules! parameter_types { /// /// This needs to be executed in an externalities provided /// environment. - #[allow(unused)] pub fn set(value: &$type) { $crate::storage::unhashed::put(&Self::key(), value); } @@ -446,6 +445,23 @@ macro_rules! parameter_types_impl_thread_local { pub fn set(t: $type) { [<$name:snake:upper>].with(|v| *v.borrow_mut() = t); } + + /// Mutate the internal value in place. + #[allow(unused)] + pub fn mutate R>(mutate: F) -> R{ + let mut current = Self::get(); + let result = mutate(&mut current); + Self::set(current); + result + } + + /// Get current value and replace with initial value of the parameter type. + #[allow(unused)] + pub fn take() -> $type { + let current = Self::get(); + Self::set($value); + current + } } )* } @@ -728,7 +744,7 @@ macro_rules! assert_err { /// Assert an expression returns an error specified. /// -/// This can be used on`DispatchResultWithPostInfo` when the post info should +/// This can be used on `DispatchResultWithPostInfo` when the post info should /// be ignored. #[macro_export] macro_rules! assert_err_ignore_postinfo { @@ -830,7 +846,7 @@ pub mod tests { pub trait Config: 'static { type BlockNumber: Codec + EncodeLike + Default + TypeInfo; - type Origin; + type RuntimeOrigin; type PalletInfo: crate::traits::PalletInfo; type DbWeight: crate::traits::Get; } @@ -841,7 +857,7 @@ pub mod tests { use super::Config; decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self {} } } @@ -873,7 +889,7 @@ pub mod tests { impl Config for Test { type BlockNumber = u32; - type Origin = u32; + type RuntimeOrigin = u32; type PalletInfo = PanicPalletInfo; type DbWeight = (); } @@ -1361,7 +1377,10 @@ pub mod pallet_prelude { #[cfg(feature = "std")] pub use crate::traits::GenesisBuild; pub use crate::{ - dispatch::{DispatchError, DispatchResult, DispatchResultWithPostInfo, Parameter}, + dispatch::{ + DispatchClass, DispatchError, DispatchResult, DispatchResultWithPostInfo, Parameter, + Pays, + }, ensure, inherent::{InherentData, InherentIdentifier, ProvideInherent}, storage, @@ -1376,11 +1395,11 @@ pub mod pallet_prelude { ConstU32, EnsureOrigin, Get, GetDefault, GetStorageVersion, Hooks, IsType, PalletInfoAccess, StorageInfoTrait, StorageVersion, TypedGet, }, - weights::{DispatchClass, Pays, Weight}, Blake2_128, Blake2_128Concat, Blake2_256, CloneNoBound, DebugNoBound, EqNoBound, Identity, PartialEqNoBound, RuntimeDebug, RuntimeDebugNoBound, Twox128, Twox256, Twox64Concat, }; pub use codec::{Decode, Encode, MaxEncodedLen}; + pub use frame_support::pallet_macros::*; pub use scale_info::TypeInfo; pub use sp_runtime::{ traits::{MaybeSerializeDeserialize, Member, ValidateUnsigned}, @@ -1392,40 +1411,136 @@ pub mod pallet_prelude { MAX_MODULE_ERROR_ENCODED_SIZE, }; pub use sp_std::marker::PhantomData; + pub use sp_weights::Weight; } -/// `pallet` attribute macro allows to define a pallet to be used in `construct_runtime!`. +/// The `pallet` attribute macro defines a pallet that can be used with +/// [`construct_runtime!`]. It must be attached to a module named `pallet` as follows: /// -/// It is define by a module item: /// ```ignore /// #[pallet] /// pub mod pallet { -/// ... +/// ... /// } /// ``` /// -/// Inside the module the macro will parse item with the attribute: `#[pallet::*]`, some -/// attributes are mandatory, some other optional. -/// -/// The attribute are explained with the syntax of non instantiable pallets, to see how pallet -/// with instance work see below example. +/// Note that various types can be automatically imported using +/// [`frame_support::pallet_prelude`] and `frame_system::pallet_prelude`: /// -/// Note various type can be automatically imported using pallet_prelude in frame_support and -/// frame_system: /// ```ignore /// #[pallet] /// pub mod pallet { -/// use frame_support::pallet_prelude::*; -/// use frame_system::pallet_prelude::*; -/// ... +/// use frame_support::pallet_prelude::*; +/// use frame_system::pallet_prelude::*; +/// ... /// } /// ``` /// -/// # Config trait: `#[pallet::config]` mandatory +/// # pallet::* Attributes +/// +/// The `pallet` macro will parse any items within your `pallet` module that are annotated with +/// `#[pallet::*]` attributes. Some of these attributes are mandatory and some are optional, +/// and they can attach to different types of items within your pallet depending on the +/// attribute in question. The full list of `#[pallet::*]` attributes is shown below in the +/// order in which they are mentioned in this document: +/// +/// * [`pallet::pallet`](#pallet-struct-placeholder-palletpallet-mandatory) +/// * [`pallet::config`](#config-trait-palletconfig-mandatory) +/// * [`pallet::constant`](#palletconstant) +/// * [`pallet::disable_frame_system_supertrait_check`](#disable_supertrait_check) +/// * [`pallet::generate_store($vis trait Store)`](#palletgenerate_storevis-trait-store) +/// * [`pallet::generate_storage_info`](#palletgenerate_storage_info) +/// * [`pallet::storage_version`](#palletstorage_version) +/// * [`pallet::hooks`](#hooks-pallethooks-optional) +/// * [`pallet::call`](#call-palletcall-optional) +/// * [`pallet::weight($expr)`](#palletweightexpr) +/// * [`pallet::compact`](#palletcompact-some_arg-some_type) +/// * [`pallet::call_index($idx)`](#palletcall_indexidx) +/// * [`pallet::extra_constants`](#extra-constants-palletextra_constants-optional) +/// * [`pallet::error`](#error-palleterror-optional) +/// * [`pallet::event`](#event-palletevent-optional) +/// * [`pallet::generate_deposit($visibility fn +/// deposit_event)`](#palletgenerate_depositvisibility-fn-deposit_event) +/// * [`pallet::storage`](#storage-palletstorage-optional) +/// * [`pallet::getter(fn $my_getter_fn_name)`](#palletgetterfn-my_getter_fn_name-optional) +/// * [`pallet::storage_prefix = "SomeName"`](#palletstorage_prefix--somename-optional) +/// * [`pallet::unbounded`](#palletunbounded-optional) +/// * [`pallet::whitelist_storage`](#palletwhitelist_storage-optional) +/// * [`cfg(..)`](#cfg-for-storage) (on storage items) +/// * [`pallet::type_value`](#type-value-pallettype_value-optional) +/// * [`pallet::genesis_config`](#genesis-config-palletgenesis_config-optional) +/// * [`pallet::genesis_build`](#genesis-build-palletgenesis_build-optional) +/// * [`pallet::inherent`](#inherent-palletinherent-optional) +/// * [`pallet::validate_unsigned`](#validate-unsigned-palletvalidate_unsigned-optional) +/// * [`pallet::origin`](#origin-palletorigin-optional) +/// +/// Note that at compile-time, the `#[pallet]` macro will analyze and expand all of these +/// attributes, ultimately removing their AST nodes before they can be parsed as real +/// attribute macro calls. This means that technically we do not need attribute macro +/// definitions for any of these attributes, however, for consistency and discoverability +/// reasons, we still maintain stub attribute macro definitions for all of these attributes in +/// the [`pallet_macros`] module which is automatically included in all pallets as part of the +/// pallet prelude. The actual "work" for all of these attribute macros can be found in the +/// macro expansion for `#[pallet]`. +/// +/// Also note that in this document, pallet attributes are explained using the syntax of +/// non-instantiable pallets. For an example of an instantiable pallet, see [this +/// example](#example-of-an-instantiable-pallet). +/// +/// # Pallet struct placeholder: `#[pallet::pallet]` (mandatory) +/// +/// The pallet struct placeholder `#[pallet::pallet]` is mandatory and allows you to specify +/// pallet information. +/// +/// The struct must be defined as follows: +/// ```ignore +/// #[pallet::pallet] +/// pub struct Pallet(_); +/// ``` +/// I.e. a regular struct definition named `Pallet`, with generic T and no where clause. +/// +/// ## Macro expansion: +/// +/// The macro adds this attribute to the struct definition: +/// ```ignore +/// #[derive( +/// frame_support::CloneNoBound, +/// frame_support::EqNoBound, +/// frame_support::PartialEqNoBound, +/// frame_support::RuntimeDebugNoBound, +/// )] +/// ``` +/// and replaces the type `_` with `PhantomData`. It also implements on the pallet: +/// * [`GetStorageVersion`](`traits::GetStorageVersion`) +/// * [`OnGenesis`](`traits::OnGenesis`): contains some logic to write the pallet version into +/// storage. +/// * `PalletErrorTypeInfo`: provides the type information for the pallet error, if defined. +/// +/// It declares `type Module` type alias for `Pallet`, used by `construct_runtime`. +/// +/// It implements [`PalletInfoAccess`](`traits::PalletInfoAccess') on `Pallet` to ease access +/// to pallet information given by [`frame_support::traits::PalletInfo`]. (The implementation +/// uses the associated type `frame_system::Config::PalletInfo`). +/// +/// It implements [`StorageInfoTrait`](`traits::StorageInfoTrait`) on `Pallet` which give +/// information about all storages. +/// +/// If the attribute `generate_store` is set then the macro creates the trait `Store` and +/// implements it on `Pallet`. +/// +/// If the attribute `set_storage_max_encoded_len` is set then the macro calls +/// [`StorageInfoTrait`](`traits::StorageInfoTrait`) for each storage in the implementation of +/// [`StorageInfoTrait`](`traits::StorageInfoTrait`) for the pallet. Otherwise it implements +/// [`StorageInfoTrait`](`traits::StorageInfoTrait`) for the pallet using the +/// [`PartialStorageInfoTrait`](`traits::PartialStorageInfoTrait`) implementation of storages. +/// +/// # Config trait: `#[pallet::config]` (mandatory) /// -/// The trait defining generics of the pallet. +/// The mandatory attribute `#[pallet::config]` defines the configurable options for the +/// pallet. +/// +/// Item must be defined as: /// -/// Item must be defined as /// ```ignore /// #[pallet::config] /// pub trait Config: frame_system::Config + $optionally_some_other_supertraits @@ -1434,74 +1549,103 @@ pub mod pallet_prelude { /// ... /// } /// ``` -/// I.e. a regular trait definition named `Config`, with supertrait `frame_system::Config`, -/// optionally other supertrait and where clause. /// -/// The associated type `Event` is reserved, if defined it must bounds `From` and -/// `IsType<::Event>`, see `#[pallet::event]` for more -/// information. +/// I.e. a regular trait definition named `Config`, with the supertrait +/// `frame_system::pallet::Config`, and optionally other supertraits and a where clause. +/// (Specifying other supertraits here is known as [tight +/// coupling](https://docs.substrate.io/reference/how-to-guides/pallet-design/use-tight-coupling/)) +/// +/// The associated type `RuntimeEvent` is reserved. If defined, it must have the bounds +/// `From` and `IsType<::RuntimeEvent>`. +/// +/// [`pallet::event`](`frame_support::pallet_macros::event`) must be present if `RuntimeEvent` +/// exists as a config item in your `#[pallet::config]`. +/// +/// Also see [`pallet::config`](`frame_support::pallet_macros::config`) +/// +/// ## `pallet::constant` +/// +/// The `#[pallet::constant]` attribute can be used to add an associated type trait bounded by +/// [`Get`](crate::traits::Get) from [`pallet::config`](#palletconfig) into metadata, e.g.: /// -/// To put `Get` associated type into metadatas, use the attribute `#[pallet::constant]`, e.g.: /// ```ignore /// #[pallet::config] /// pub trait Config: frame_system::Config { -/// #[pallet::constant] -/// type Foo: Get; +/// #[pallet::constant] +/// type Foo: Get; /// } /// ``` /// +/// Also see [`pallet::constant`](`frame_support::pallet_macros::constant`) +/// +/// ## `pallet::disable_frame_system_supertrait_check` +/// +/// /// To bypass the `frame_system::Config` supertrait check, use the attribute -/// `#[pallet::disable_frame_system_supertrait_check]`, e.g.: +/// `pallet::disable_frame_system_supertrait_check`, e.g.: +/// /// ```ignore /// #[pallet::config] /// #[pallet::disable_frame_system_supertrait_check] /// pub trait Config: pallet_timestamp::Config {} /// ``` /// -/// ### Macro expansion: +/// NOTE: Bypassing the `frame_system::Config` supertrait check is typically desirable when you +/// want to write an alternative to the `frame_system` pallet. /// -/// The macro expand pallet constant metadata with the information given by -/// `#[pallet::constant]`. +/// Also see +/// [`pallet::disable_frame_system_supertrait_check`](`frame_support::pallet_macros::disable_frame_system_supertrait_check`) /// -/// # Pallet struct placeholder: `#[pallet::pallet]` mandatory +/// ## Macro expansion: /// -/// The placeholder struct, on which is implemented pallet informations. +/// The macro expands pallet constant metadata with the information given by +/// `#[pallet::constant]`. /// -/// Item must be defined as followed: -/// ```ignore -/// #[pallet::pallet] -/// pub struct Pallet(_); -/// ``` -/// I.e. a regular struct definition named `Pallet`, with generic T and no where clause. +/// # `pallet::generate_store($vis trait Store)` +/// +/// To generate a `Store` trait associating all storages, annotate your `Pallet` struct with +/// the attribute `#[pallet::generate_store($vis trait Store)]`, e.g.: /// -/// To generate a `Store` trait associating all storages, use the attribute -/// `#[pallet::generate_store($vis trait Store)]`, e.g.: /// ```ignore /// #[pallet::pallet] /// #[pallet::generate_store(pub(super) trait Store)] /// pub struct Pallet(_); /// ``` -/// More precisely the store trait contains an associated type for each storage. It is -/// implemented for `Pallet` allowing to access the storage from pallet struct. +/// More precisely, the `Store` trait contains an associated type for each storage. It is +/// implemented for `Pallet` allowing access to the storage from pallet struct. /// /// Thus when defining a storage named `Foo`, it can later be accessed from `Pallet` using /// `::Foo`. /// +/// NOTE: this attribute is only valid when applied _directly_ to your `Pallet` struct +/// definition. +/// +/// Also see [`pallet::generate_store`](`frame_support::pallet_macros::generate_store`). +/// +/// # `pallet::generate_storage_info` +/// /// To generate the full storage info (used for PoV calculation) use the attribute /// `#[pallet::generate_storage_info]`, e.g.: +/// /// ```ignore /// #[pallet::pallet] /// #[pallet::generate_storage_info] /// pub struct Pallet(_); /// ``` /// -/// This require all storage to implement the trait [`traits::StorageInfoTrait`], thus all keys -/// and value types must bound [`pallet_prelude::MaxEncodedLen`]. -/// Some individual storage can opt-out from this constraint by using `#[pallet::unbounded]`, -/// see `#[pallet::storage]` documentation. +/// This requires all storage items to implement the trait [`traits::StorageInfoTrait`], thus +/// all keys and value types must be bound by [`pallet_prelude::MaxEncodedLen`]. Individual +/// storages can opt-out from this constraint by using `#[pallet::unbounded]` (see +/// `#[pallet::storage]` for more info). +/// +/// Also see [`pallet::generate_storage_info`](`frame_support::pallet_macros::generate_storage_info`) /// -/// As the macro implements [`traits::GetStorageVersion`], the current storage version needs to -/// be communicated to the macro. This can be done by using the `storage_version` attribute: +/// # `pallet::storage_version` +/// +/// Because the [`pallet::pallet`](#pallet-struct-placeholder-palletpallet-mandatory) macro +/// implements [`traits::GetStorageVersion`], the current storage version needs to be +/// communicated to the macro. This can be done by using the `pallet::storage_version` +/// attribute: /// /// ```ignore /// const STORAGE_VERSION: StorageVersion = StorageVersion::new(5); @@ -1513,75 +1657,34 @@ pub mod pallet_prelude { /// /// If not present, the current storage version is set to the default value. /// -/// ### Macro expansion: -/// -/// The macro add this attribute to the struct definition: -/// ```ignore -/// #[derive( -/// frame_support::CloneNoBound, -/// frame_support::EqNoBound, -/// frame_support::PartialEqNoBound, -/// frame_support::RuntimeDebugNoBound, -/// )] -/// ``` -/// and replace the type `_` by `PhantomData`. +/// Also see [`pallet::storage_version`](`frame_support::pallet_macros::storage_version`) /// -/// It implements on pallet: -/// * [`traits::GetStorageVersion`] -/// * [`traits::OnGenesis`]: contains some logic to write pallet version into storage. -/// * `PalletErrorTypeInfo`: provides the type information for the pallet error, if defined. +/// # Hooks: `#[pallet::hooks]` (optional) /// -/// It declares `type Module` type alias for `Pallet`, used by [`construct_runtime`]. +/// The `pallet::hooks` attribute allows you to specify a `Hooks` implementation for `Pallet` +/// that specifies pallet-specific logic. /// -/// It implements [`traits::PalletInfoAccess`] on `Pallet` to ease access to pallet -/// informations given by [`frame_support::traits::PalletInfo`]. -/// (The implementation uses the associated type `frame_system::Config::PalletInfo`). -/// -/// It implements [`traits::StorageInfoTrait`] on `Pallet` which give information about all -/// storages. -/// -/// If the attribute generate_store is set then the macro creates the trait `Store` and -/// implements it on `Pallet`. -/// -/// If the attribute set_storage_max_encoded_len is set then the macro call -/// [`traits::StorageInfoTrait`] for each storage in the implementation of -/// [`traits::StorageInfoTrait`] for the pallet. -/// Otherwise it implements [`traits::StorageInfoTrait`] for the pallet using the -/// [`traits::PartialStorageInfoTrait`] implementation of storages. -/// -/// # Hooks: `#[pallet::hooks]` optional -/// -/// Implementation of `Hooks` on `Pallet` allowing to define some specific pallet logic. -/// -/// Item must be defined as +/// The item the attribute attaches to must be defined as follows: /// ```ignore /// #[pallet::hooks] /// impl Hooks> for Pallet $optional_where_clause { +/// ... /// } /// ``` /// I.e. a regular trait implementation with generic bound: `T: Config`, for the trait -/// `Hooks>` (they are defined in preludes), for the type `Pallet` -/// and with an optional where clause. +/// `Hooks>` (they are defined in preludes), for the type `Pallet` and +/// with an optional where clause. /// -/// If no `#[pallet::hooks]` exists, then a default implementation corresponding to the -/// following code is automatically generated: +/// If no `#[pallet::hooks]` exists, then the following default implementation is +/// automatically generated: /// ```ignore /// #[pallet::hooks] /// impl Hooks> for Pallet {} /// ``` /// -/// ### Macro expansion: -/// -/// The macro implements the traits `OnInitialize`, `OnIdle`, `OnFinalize`, `OnRuntimeUpgrade`, -/// `OffchainWorker`, `IntegrityTest` using `Hooks` implementation. -/// -/// NOTE: OnRuntimeUpgrade is implemented with `Hooks::on_runtime_upgrade` and some additional -/// logic. E.g. logic to write pallet version into storage. -/// -/// NOTE: The macro also adds some tracing logic when implementing the above traits. The -/// following hooks emit traces: `on_initialize`, `on_finalize` and `on_runtime_upgrade`. +/// Also see [`pallet::hooks`](`frame_support::pallet_macros::hooks`) /// -/// # Call: `#[pallet::call]` optional +/// # Call: `#[pallet::call]` (optional) /// /// Implementation of pallet dispatchables. /// @@ -1603,53 +1706,50 @@ pub mod pallet_prelude { /// } /// ``` /// I.e. a regular type implementation, with generic `T: Config`, on type `Pallet`, with -/// optional where clause. +/// an optional where clause. +/// +/// ## `#[pallet::weight($expr)]` +/// +/// Each dispatchable needs to define a weight with `#[pallet::weight($expr)]` attribute, the +/// first argument must be `origin: OriginFor`. +/// +/// Also see [`pallet::weight`](`frame_support::pallet_macros::weight`) +/// +/// ### `#[pallet::compact] $some_arg: $some_type` /// -/// Each dispatchable needs to define a weight with `#[pallet::weight($expr)]` attribute, -/// the first argument must be `origin: OriginFor`, compact encoding for argument can be -/// used using `#[pallet::compact]`, function must return `DispatchResultWithPostInfo` or -/// `DispatchResult`. +/// Compact encoding for arguments can be achieved via `#[pallet::compact]`. The function must +/// return a `DispatchResultWithPostInfo` or `DispatchResult`. +/// +/// Also see [`pallet::compact`](`frame_support::pallet_macros::compact`) +/// +/// ## `#[pallet::call_index($idx)]` /// /// Each dispatchable may also be annotated with the `#[pallet::call_index($idx)]` attribute, -/// which defines and sets the codec index for the dispatchable function in the `Call` enum. +/// which explicitly defines the codec index for the dispatchable function in the `Call` enum. /// /// All call indexes start from 0, until it encounters a dispatchable function with a defined /// call index. The dispatchable function that lexically follows the function with a defined /// call index will have that call index, but incremented by 1, e.g. if there are 3 -/// dispatchable functions `fn foo`, `fn bar` and `fn qux` in that order, and only `fn bar` has -/// a call index of 10, then `fn qux` will have an index of 11, instead of 1. +/// dispatchable functions `fn foo`, `fn bar` and `fn qux` in that order, and only `fn bar` +/// has a call index of 10, then `fn qux` will have an index of 11, instead of 1. /// -/// All arguments must implement `Debug`, `PartialEq`, `Eq`, `Decode`, `Encode`, `Clone`. For -/// ease of use, bound the trait `Member` available in frame_support::pallet_prelude. -/// -/// If no `#[pallet::call]` exists, then a default implementation corresponding to the -/// following code is automatically generated: -/// ```ignore -/// #[pallet::call] -/// impl Pallet {} -/// ``` -/// -/// **WARNING**: modifying dispatchables, changing their order, removing some must be done with -/// care. Indeed this will change the outer runtime call type (which is an enum with one -/// variant per pallet), this outer runtime call can be stored on-chain (e.g. in -/// pallet-scheduler). Thus migration might be needed. To mitigate against some of this, the +/// **WARNING**: modifying dispatchables, changing their order, removing some, etc., must be +/// done with care. Indeed this will change the outer runtime call type (which is an enum with +/// one variant per pallet), this outer runtime call can be stored on-chain (e.g. in +/// `pallet-scheduler`). Thus migration might be needed. To mitigate against some of this, the /// `#[pallet::call_index($idx)]` attribute can be used to fix the order of the dispatchable so -/// that the `Call` enum encoding does not change after modification. -/// -/// ### Macro expansion -/// -/// The macro creates an enum `Call` with one variant per dispatchable. This enum implements: -/// `Clone`, `Eq`, `PartialEq`, `Debug` (with stripped implementation in `not("std")`), -/// `Encode`, `Decode`, `GetDispatchInfo`, `GetCallName`, `UnfilteredDispatchable`. +/// that the `Call` enum encoding does not change after modification. As a general rule of +/// thumb, it is therefore adventageous to always add new calls to the end so you can maintain +/// the existing order of calls. /// -/// The macro implement the `Callable` trait on `Pallet` and a function `call_functions` which -/// returns the dispatchable metadata. +/// Also see [`pallet::call_index`](`frame_support::pallet_macros::call_index`) /// -/// # Extra constants: `#[pallet::extra_constants]` optional +/// # Extra constants: `#[pallet::extra_constants]` (optional) /// -/// Allow to define some extra constants to put into constant metadata. +/// Allows you to define some extra constants to be added into constant metadata. /// /// Item must be defined as: +/// /// ```ignore /// #[pallet::extra_constants] /// impl Pallet where $optional_where_clause { @@ -1660,19 +1760,23 @@ pub mod pallet_prelude { /// ... /// } /// ``` -/// I.e. a regular rust implement block with some optional where clause and functions with 0 -/// args, 0 generics, and some return type. +/// I.e. a regular rust `impl` block with some optional where clause and functions with 0 args, +/// 0 generics, and some return type. +/// +/// ## Macro expansion /// -/// ### Macro expansion +/// The macro add some extra constants to pallet constant metadata. /// -/// The macro add some extra constant to pallet constant metadata. +/// Also see: [`pallet::extra_constants`](`frame_support::pallet_macros::extra_constants`) /// -/// # Error: `#[pallet::error]` optional +/// # Error: `#[pallet::error]` (optional) /// -/// Allow to define an error type to be return from dispatchable on error. -/// This error type informations are put into metadata. +/// The `#[pallet::error]` attribute allows you to define an error enum that will be returned +/// from the dispatchable when an error occurs. The information for this error type is then +/// stored in metadata. /// /// Item must be defined as: +/// /// ```ignore /// #[pallet::error] /// pub enum Error { @@ -1683,7 +1787,7 @@ pub mod pallet_prelude { /// ... /// } /// ``` -/// I.e. a regular rust enum named `Error`, with generic `T` and fieldless or multiple-field +/// I.e. a regular enum named `Error`, with generic `T` and fieldless or multiple-field /// variants. /// /// Any field type in the enum variants must implement [`scale_info::TypeInfo`] in order to be @@ -1691,29 +1795,28 @@ pub mod pallet_prelude { /// preferably 1 byte in size in order to reduce storage size. The error enum itself has an /// absolute maximum encoded size specified by [`MAX_MODULE_ERROR_ENCODED_SIZE`]. /// +/// (1 byte can still be 256 different errors. The more specific the error, the easier it is to +/// diagnose problems and give a better experience to the user. Don't skimp on having lots of +/// individual error conditions.) +/// /// Field types in enum variants must also implement [`PalletError`](traits::PalletError), /// otherwise the pallet will fail to compile. Rust primitive types have already implemented /// the [`PalletError`](traits::PalletError) trait along with some commonly used stdlib types -/// such as `Option` and `PhantomData`, and hence in most use cases, a manual implementation is -/// not necessary and is discouraged. +/// such as [`Option`] and [`PhantomData`](`frame_support::dispatch::marker::PhantomData`), and +/// hence in most use cases, a manual implementation is not necessary and is discouraged. /// -/// The generic `T` mustn't bound anything and where clause is not allowed. But bounds and -/// where clause shouldn't be needed for any usecase. +/// The generic `T` must not bound anything and a `where` clause is not allowed. That said, +/// bounds and/or a where clause should not needed for any use-case. /// -/// ### Macro expansion +/// Also see: [`pallet::error`](`frame_support::pallet_macros::error`) /// -/// The macro implements `Debug` trait and functions `as_u8` using variant position, and -/// `as_str` using variant doc. +/// # Event: `#[pallet::event]` (optional) /// -/// The macro implements `From>` for `&'static str`. -/// The macro implements `From>` for `DispatchError`. +/// Allows you to define pallet events. Pallet events are stored under the `system` / `events` +/// key when the block is applied (and then replaced when the next block writes it's events). /// -/// # Event: `#[pallet::event]` optional +/// The Event enum must be defined as follows: /// -/// Allow to define pallet events, pallet events are stored in the block when they deposited -/// (and removed in next block). -/// -/// Item is defined as: /// ```ignore /// #[pallet::event] /// #[pallet::generate_deposit($visibility fn deposit_event)] // Optional @@ -1723,117 +1826,148 @@ pub mod pallet_prelude { /// ... /// } /// ``` -/// I.e. an enum (with named or unnamed fields variant), named Event, with generic: none or `T` -/// or `T: Config`, and optional where clause. /// -/// Each field must implement `Clone`, `Eq`, `PartialEq`, `Encode`, `Decode`, and `Debug` (on -/// std only). -/// For ease of use, bound the trait `Member` available in frame_support::pallet_prelude. +/// I.e. an enum (with named or unnamed fields variant), named `Event`, with generic: none or +/// `T` or `T: Config`, and optional w here clause. /// -/// The attribute `#[pallet::generate_deposit($visibility fn deposit_event)]` generate a helper -/// function on `Pallet` to deposit event. +/// Each field must implement [`Clone`], [`Eq`], [`PartialEq`], [`Encode`], [`Decode`], and +/// [`Debug`] (on std only). For ease of use, bound by the trait +/// [`Member`](`frame_support::pallet_prelude::Member`), available in +/// frame_support::pallet_prelude. /// -/// NOTE: For instantiable pallet, event must be generic over T and I. +/// Also see [`pallet::event`](`frame_support::pallet_macros::event`) /// -/// ### Macro expansion: +/// ## `#[pallet::generate_deposit($visibility fn deposit_event)]` /// -/// Macro will add on enum `Event` the attributes: -/// * `#[derive(frame_support::CloneNoBound)]`, -/// * `#[derive(frame_support::EqNoBound)]`, -/// * `#[derive(frame_support::PartialEqNoBound)]`, -/// * `#[derive(codec::Encode)]`, -/// * `#[derive(codec::Decode)]`, -/// * `#[derive(frame_support::RuntimeDebugNoBound)]` +/// The attribute `#[pallet::generate_deposit($visibility fn deposit_event)]` generates a +/// helper function on `Pallet` that handles deposit events. /// -/// Macro implements `From>` for (). +/// NOTE: For instantiable pallets, the event must be generic over `T` and `I`. /// -/// Macro implements metadata function on `Event` returning the `EventMetadata`. +/// Also see [`pallet::generate_deposit`](`frame_support::pallet_macros::generate_deposit`) /// -/// If `#[pallet::generate_deposit]` then macro implement `fn deposit_event` on `Pallet`. +/// # Storage: `#[pallet::storage]` (optional) /// -/// # Storage: `#[pallet::storage]` optional +/// The `#[pallet::storage]` attribute lets you define some abstract storage inside of runtime +/// storage and also set its metadata. This attribute can be used multiple times. /// -/// Allow to define some abstract storage inside runtime storage and also set its metadata. -/// This attribute can be used multiple times. +/// Item should be defined as: /// -/// Item is defined as: /// ```ignore /// #[pallet::storage] /// #[pallet::getter(fn $getter_name)] // optional /// $vis type $StorageName<$some_generic> $optional_where_clause /// = $StorageType<$generic_name = $some_generics, $other_name = $some_other, ...>; /// ``` -/// or with unnamed generic +/// +/// or with unnamed generic: +/// /// ```ignore /// #[pallet::storage] /// #[pallet::getter(fn $getter_name)] // optional /// $vis type $StorageName<$some_generic> $optional_where_clause /// = $StorageType<_, $some_generics, ...>; /// ``` -/// I.e. it must be a type alias, with generics: `T` or `T: Config`, aliased type must be one -/// of `StorageValue`, `StorageMap` or `StorageDoubleMap` (defined in frame_support). -/// The generic arguments of the storage type can be given in two manner: named and unnamed. -/// For named generic argument: the name for each argument is the one as define on the storage -/// struct: -/// * [`pallet_prelude::StorageValue`] expect `Value` and optionally `QueryKind` and `OnEmpty`, -/// * [`pallet_prelude::StorageMap`] expect `Hasher`, `Key`, `Value` and optionally `QueryKind` -/// and `OnEmpty`, -/// * [`pallet_prelude::CountedStorageMap`] expect `Hasher`, `Key`, `Value` and optionally -/// `QueryKind` and `OnEmpty`, -/// * [`pallet_prelude::StorageDoubleMap`] expect `Hasher1`, `Key1`, `Hasher2`, `Key2`, `Value` -/// and optionally `QueryKind` and `OnEmpty`. -/// -/// For unnamed generic argument: Their first generic must be `_` as it is replaced by the -/// macro and other generic must declared as a normal declaration of type generic in rust. /// -/// The Prefix generic written by the macro is generated using -/// `PalletInfo::name::>()` and the name of the storage type. -/// E.g. if runtime names the pallet "MyExample" then the storage `type Foo = ...` use the -/// prefix: `Twox128(b"MyExample") ++ Twox128(b"Foo")`. -/// -/// For the `CountedStorageMap` variant, the Prefix also implements -/// `CountedStorageMapInstance`. It associate a `CounterPrefix`, which is implemented same as -/// above, but the storage prefix is prepend with `"CounterFor"`. -/// E.g. if runtime names the pallet "MyExample" then the storage -/// `type Foo = CountedStorageaMap<...>` will store its counter at the prefix: -/// `Twox128(b"MyExample") ++ Twox128(b"CounterForFoo")`. +/// I.e. it must be a type alias, with generics: `T` or `T: Config`. The aliased type must be +/// one of [`StorageValue`](`pallet_prelude::StorageValue`), +/// [`StorageMap`](`pallet_prelude::StorageMap`) or +/// [`StorageDoubleMap`](`pallet_prelude::StorageDoubleMap`). The generic arguments of the +/// storage type can be given in two manners: named and unnamed. For named generic arguments, +/// the name for each argument should match the name defined for it on the storage struct: +/// * [`StorageValue`](`pallet_prelude::StorageValue`) expects `Value` and optionally +/// `QueryKind` and `OnEmpty`, +/// * [`StorageMap`](`pallet_prelude::StorageMap`) expects `Hasher`, `Key`, `Value` and +/// optionally `QueryKind` and `OnEmpty`, +/// * [`CountedStorageMap`](`pallet_prelude::CountedStorageMap`) expects `Hasher`, `Key`, +/// `Value` and optionally `QueryKind` and `OnEmpty`, +/// * [`StorageDoubleMap`](`pallet_prelude::StorageDoubleMap`) expects `Hasher1`, `Key1`, +/// `Hasher2`, `Key2`, `Value` and optionally `QueryKind` and `OnEmpty`. +/// +/// For unnamed generic arguments: Their first generic must be `_` as it is replaced by the +/// macro and other generic must declared as a normal generic type declaration. +/// +/// The `Prefix` generic written by the macro is generated using +/// `PalletInfo::name::>()` and the name of the storage type. E.g. if runtime names +/// the pallet "MyExample" then the storage `type Foo = ...` should use the prefix: +/// `Twox128(b"MyExample") ++ Twox128(b"Foo")`. +/// +/// For the [`CountedStorageMap`](`pallet_prelude::CountedStorageMap`) variant, the `Prefix` +/// also implements +/// [`CountedStorageMapInstance`](`frame_support::storage::types::CountedStorageMapInstance`). +/// It also associates a [`CounterPrefix`](`pallet_prelude::CounterPrefix'), which is +/// implemented the same as above, but the storage prefix is prepend with `"CounterFor"`. E.g. +/// if runtime names the pallet "MyExample" then the storage `type Foo = +/// CountedStorageaMap<...>` will store its counter at the prefix: `Twox128(b"MyExample") ++ +/// Twox128(b"CounterForFoo")`. /// /// E.g: +/// /// ```ignore /// #[pallet::storage] /// pub(super) type MyStorage = StorageMap; /// ``` -/// In this case the final prefix used by the map is -/// `Twox128(b"MyExample") ++ Twox128(b"OtherName")`. /// -/// The optional attribute `#[pallet::getter(fn $my_getter_fn_name)]` allows to define a +/// In this case the final prefix used by the map is `Twox128(b"MyExample") ++ +/// Twox128(b"OtherName")`. +/// +/// Also see [`pallet::storage`](`frame_support::pallet_macros::storage`) +/// +/// ## `#[pallet::getter(fn $my_getter_fn_name)]` (optional) +/// +/// The optional attribute `#[pallet::getter(fn $my_getter_fn_name)]` allows you to define a /// getter function on `Pallet`. /// -/// The optional attribute `#[pallet::storage_prefix = "SomeName"]` allow to define the storage -/// prefix to use, see how `Prefix` generic is implemented above. +/// Also see [`pallet::getter`](`frame_support::pallet_macros::getter`) +/// +/// ## `#[pallet::storage_prefix = "SomeName"]` (optional) +/// +/// The optional attribute `#[pallet::storage_prefix = "SomeName"]` allows you to define the +/// storage prefix to use, see how `Prefix` generic is implemented above. This is helpful if +/// you wish to rename the storage field but don't want to perform a migration. /// /// E.g: +/// /// ```ignore /// #[pallet::storage] /// #[pallet::storage_prefix = "foo"] /// #[pallet::getter(fn my_storage)] /// pub(super) type MyStorage = StorageMap; /// ``` +/// /// or +/// /// ```ignore /// #[pallet::storage] /// #[pallet::getter(fn my_storage)] /// pub(super) type MyStorage = StorageMap<_, Blake2_128Concat, u32, u32>; /// ``` /// -/// The optional attribute `#[pallet::unbounded]` allows to declare the storage as unbounded. -/// When implementating the storage info (when `#[pallet::generate_storage_info]` is specified -/// on the pallet struct placeholder), the size of the storage will be declared as unbounded. -/// This can be useful for storage which can never go into PoV (Proof of Validity). +/// Also see [`pallet::storage_prefix`](`frame_support::pallet_macros::storage_prefix`) +/// +/// ## `#[pallet::unbounded]` (optional) +/// +/// The optional attribute `#[pallet::unbounded]` declares the storage as unbounded. When +/// implementating the storage info (when `#[pallet::generate_storage_info]` is specified on +/// the pallet struct placeholder), the size of the storage will be declared as unbounded. This +/// can be useful for storage which can never go into PoV (Proof of Validity). /// +/// Also see [`pallet::unbounded`](`frame_support::pallet_macros::unbounded`) +/// +/// ## `#[pallet::whitelist_storage]` (optional) +/// +/// The optional attribute `#[pallet::whitelist_storage]` will declare the storage as +/// whitelisted from benchmarking. +/// +/// See +/// [`pallet::whitelist_storage`](frame_support::pallet_macros::whitelist_storage) +/// for more info. +/// +/// ## `#[cfg(..)]` (for storage) /// The optional attributes `#[cfg(..)]` allow conditional compilation for the storage. /// /// E.g: +/// /// ```ignore /// #[cfg(feature = "my-feature")] /// #[pallet::storage] @@ -1846,19 +1980,20 @@ pub mod pallet_prelude { /// Any type placed as the `QueryKind` parameter must implement /// [`frame_support::storage::types::QueryKindTrait`]. There are 3 implementations of this /// trait by default: -/// 1. [`frame_support::storage::types::OptionQuery`], the default `QueryKind` used when this -/// type parameter is omitted. Specifying this as the `QueryKind` would cause storage map -/// APIs that return a `QueryKind` to instead return an `Option`, returning `Some` when a -/// value does exist under a specified storage key, and `None` otherwise. -/// 2. [`frame_support::storage::types::ValueQuery`] causes storage map APIs that return a -/// `QueryKind` to instead return the value type. In cases where a value does not exist -/// under a specified storage key, the `OnEmpty` type parameter on `QueryKindTrait` is used -/// to return an appropriate value. -/// 3. [`frame_support::storage::types::ResultQuery`] causes storage map APIs that return a -/// `QueryKind` to instead return a `Result`, with `T` being the value type and `E` -/// being the pallet error type specified by the `#[pallet::error]` attribute. In cases -/// where a value does not exist under a specified storage key, an `Err` with the specified -/// pallet error variant is returned. +/// +/// 1. [`OptionQuery`](`frame_support::storage::types::OptionQuery`), the default `QueryKind` +/// used when this type parameter is omitted. Specifying this as the `QueryKind` would cause +/// storage map APIs that return a `QueryKind` to instead return an [`Option`], returning +/// `Some` when a value does exist under a specified storage key, and `None` otherwise. +/// 2. [`ValueQuery`](`frame_support::storage::types::ValueQuery`) causes storage map APIs that +/// return a `QueryKind` to instead return the value type. In cases where a value does not +/// exist under a specified storage key, the `OnEmpty` type parameter on `QueryKindTrait` is +/// used to return an appropriate value. +/// 3. [`ResultQuery`](`frame_support::storage::types::ResultQuery`) causes storage map APIs +/// that return a `QueryKind` to instead return a `Result`, with `T` being the value +/// type and `E` being the pallet error type specified by the `#[pallet::error]` attribute. +/// In cases where a value does not exist under a specified storage key, an `Err` with the +/// specified pallet error variant is returned. /// /// NOTE: If the `QueryKind` generic parameter is still generic at this stage or is using some /// type alias then the generation of the getter might fail. In this case the getter can be @@ -1868,60 +2003,62 @@ pub mod pallet_prelude { /// usable at all). We use [`StorageHasher::METADATA`] for the metadata of the hasher of the /// storage item. Thus generic hasher is supported. /// -/// ### Macro expansion +/// ## Macro expansion /// /// For each storage item the macro generates a struct named /// `_GeneratedPrefixForStorage$NameOfStorage`, and implements /// [`StorageInstance`](traits::StorageInstance) on it using the pallet and storage name. It -/// then uses it as the first generic of the aliased type. -/// For `CountedStorageMap`, `CountedStorageMapInstance` is implemented, and another similar -/// struct is generated. +/// then uses it as the first generic of the aliased type. For +/// [`CountedStorageMap`](`pallet_prelude::CountedStorageMap`), +/// [`CountedStorageMapInstance`](`frame_support::storage::types::CountedStorageMapInstance`) +/// is implemented, and another similar struct is generated. /// -/// For named generic, the macro will reorder the generics, and remove the names. +/// For a named generic, the macro will reorder the generics, and remove the names. /// -/// The macro implements the function `storage_metadata` on `Pallet` implementing the metadata -/// for all storage items based on their kind: +/// The macro implements the function `storage_metadata` on the `Pallet` implementing the +/// metadata for all storage items based on their kind: /// * for a storage value, the type of the value is copied into the metadata /// * for a storage map, the type of the values and the key's type is copied into the metadata -/// * for a storage double map, the type of the values, and the types of key1 and key2 are +/// * for a storage double map, the type of the values, and the types of `key1` and `key2` are /// copied into the metadata. /// -/// # Type value: `#[pallet::type_value]` optional +/// # Type value: `#[pallet::type_value]` (optional) +/// +/// The `#[pallet::type_value]` attribute lets you define a struct implementing the +/// [`Get`](crate::traits::Get) trait to ease use of storage types. This attribute is meant to +/// be used alongside [`#[pallet::storage]`](#storage-palletstorage-optional) to define a +/// storage's default value. This attribute can be used multiple times. /// -/// Helper to define a struct implementing `Get` trait. To ease use of storage types. -/// This attribute can be used multiple time. +/// Item must be defined as: /// -/// Item is defined as /// ```ignore /// #[pallet::type_value] /// fn $MyDefaultName<$some_generic>() -> $default_type $optional_where_clause { $expr } /// ``` +/// /// I.e.: a function definition with generics none or `T: Config` and a returned type. /// /// E.g.: +/// /// ```ignore /// #[pallet::type_value] /// fn MyDefault() -> T::Balance { 3.into() } /// ``` /// -/// NOTE: This attribute is meant to be used alongside `#[pallet::storage]` to defined some -/// specific default value in storage. -/// -/// ### Macro expansion -/// -/// Macro renames the function to some internal name, generate a struct with the original name -/// of the function and its generic, and implement `Get<$ReturnType>` by calling the user -/// defined function. +/// Also see [`pallet::type_value`](`frame_support::pallet_macros::type_value`) /// -/// # Genesis config: `#[pallet::genesis_config]` optional +/// # Genesis config: `#[pallet::genesis_config]` (optional) /// -/// Allow to define the genesis configuration of the pallet. +/// The `#[pallet::genesis_config]` attribute allows you to define the genesis configuration +/// for the pallet. /// -/// Item is defined as either an enum or a struct. -/// It needs to be public and implement trait GenesisBuild with `#[pallet::genesis_build]`. -/// The type generics is constrained to be either none, or `T` or `T: Config`. +/// Item is defined as either an enum or a struct. It needs to be public and implement the +/// trait [`GenesisBuild`](`traits::GenesisBuild`) with +/// [`#[pallet::genesis_build]`](#genesis-build-palletgenesis_build-optional). The type +/// generics are constrained to be either none, or `T` or `T: Config`. /// /// E.g: +/// /// ```ignore /// #[pallet::genesis_config] /// pub struct GenesisConfig { @@ -1929,31 +2066,28 @@ pub mod pallet_prelude { /// } /// ``` /// -/// ### Macro expansion +/// Also see [`pallet::genesis_config`](`frame_support::pallet_macros::genesis_config`) /// -/// Macro will add the following attribute on it: -/// * `#[cfg(feature = "std")]` -/// * `#[derive(Serialize, Deserialize)]` -/// * `#[serde(rename_all = "camelCase")]` -/// * `#[serde(deny_unknown_fields)]` -/// * `#[serde(bound(serialize = ""))]` -/// * `#[serde(bound(deserialize = ""))]` +/// # Genesis build: `#[pallet::genesis_build]` (optional) /// -/// # Genesis build: `#[pallet::genesis_build]` optional +/// The `#[pallet::genesis_build]` attribute allows you to define how `genesis_configuration` +/// is built. This takes as input the `GenesisConfig` type (as `self`) and constructs the +/// pallet's initial state. /// -/// Allow to define how genesis_configuration is built. +/// The impl must be defined as: /// -/// Item is defined as /// ```ignore /// #[pallet::genesis_build] /// impl GenesisBuild for GenesisConfig<$maybe_generics> { /// fn build(&self) { $expr } /// } /// ``` -/// I.e. a rust trait implementation with generic `T: Config`, of trait `GenesisBuild` on +/// +/// I.e. a trait implementation with generic `T: Config`, of trait `GenesisBuild` on /// type `GenesisConfig` with generics none or `T`. /// /// E.g.: +/// /// ```ignore /// #[pallet::genesis_build] /// impl GenesisBuild for GenesisConfig { @@ -1961,87 +2095,93 @@ pub mod pallet_prelude { /// } /// ``` /// -/// ### Macro expansion +/// Also see [`pallet::genesis_build`](`frame_support::pallet_macros::genesis_build`) /// -/// Macro will add the following attribute on it: -/// * `#[cfg(feature = "std")]` +/// # Inherent: `#[pallet::inherent]` (optional) /// -/// Macro will implement `sp_runtime::BuildModuleGenesisStorage` using `()` as second generic -/// for non-instantiable pallets. +/// The `#[pallet::inherent]` attribute allows the pallet to provide some +/// [inherent](https://docs.substrate.io/fundamentals/transaction-types/#inherent-transactions). +/// An inherent is some piece of data that is inserted by a block authoring node at block +/// creation time and can either be accepted or rejected by validators based on whether the +/// data falls within an acceptable range. /// -/// # Inherent: `#[pallet::inherent]` optional +/// The most common inherent is the `timestamp` that is inserted into every block. Since there +/// is no way to validate timestamps, validators simply check that the timestamp reported by +/// the block authoring node falls within an acceptable range. /// -/// Allow the pallet to provide some inherent: +/// Item must be defined as: /// -/// Item is defined as: /// ```ignore /// #[pallet::inherent] /// impl ProvideInherent for Pallet { /// // ... regular trait implementation /// } /// ``` -/// I.e. a trait implementation with bound `T: Config`, of trait `ProvideInherent` for type -/// `Pallet`, and some optional where clause. /// -/// ### Macro expansion +/// I.e. a trait implementation with bound `T: Config`, of trait +/// [`ProvideInherent`](`pallet_prelude::ProvideInherent`) for type `Pallet`, and some +/// optional where clause. +/// +/// Also see [`pallet::inherent`](`frame_support::pallet_macros::inherent`) /// -/// Macro make currently no use of this information, but it might use this information in the -/// future to give information directly to construct_runtime. +/// # Validate unsigned: `#[pallet::validate_unsigned]` (optional) /// -/// # Validate unsigned: `#[pallet::validate_unsigned]` optional +/// The `#[pallet::validate_unsigned]` attribute allows the pallet to validate some unsigned +/// transaction: /// -/// Allow the pallet to validate some unsigned transaction: +/// Item must be defined as: /// -/// Item is defined as: /// ```ignore /// #[pallet::validate_unsigned] /// impl ValidateUnsigned for Pallet { /// // ... regular trait implementation /// } /// ``` -/// I.e. a trait implementation with bound `T: Config`, of trait `ValidateUnsigned` for type -/// `Pallet`, and some optional where clause. /// -/// NOTE: There is also `sp_runtime::traits::SignedExtension` that can be used to add some -/// specific logic for transaction validation. +/// I.e. a trait implementation with bound `T: Config`, of trait +/// [`ValidateUnsigned`](`pallet_prelude::ValidateUnsigned`) for type `Pallet`, and some +/// optional where clause. /// -/// ### Macro expansion +/// NOTE: There is also the [`sp_runtime::traits::SignedExtension`] trait that can be used to +/// add some specific logic for transaction validation. /// -/// Macro make currently no use of this information, but it might use this information in the -/// future to give information directly to construct_runtime. +/// Also see [`pallet::validate_unsigned`](`frame_support::pallet_macros::validate_unsigned`) /// -/// # Origin: `#[pallet::origin]` optional +/// # Origin: `#[pallet::origin]` (optional) /// -/// Allow to define some origin for the pallet. +/// The `#[pallet::origin]` attribute allows you to define some origin for the pallet. /// -/// Item must be either a type alias or an enum or a struct. It needs to be public. +/// Item must be either a type alias, an enum, or a struct. It needs to be public. /// /// E.g.: +/// /// ```ignore /// #[pallet::origin] /// pub struct Origin(PhantomData<(T)>); /// ``` /// /// **WARNING**: modifying origin changes the outer runtime origin. This outer runtime origin -/// can be stored on-chain (e.g. in pallet-scheduler), thus any change must be done with care +/// can be stored on-chain (e.g. in `pallet-scheduler`), thus any change must be done with care /// as it might require some migration. /// -/// NOTE: for instantiable pallet, origin must be generic over T and I. +/// NOTE: for instantiable pallets, the origin must be generic over `T` and `I`. /// -/// # General notes on instantiable pallet +/// Also see [`pallet::origin`](`frame_support::pallet_macros::origin`) /// -/// An instantiable pallet is one where Config is generic, i.e. `Config`. This allow runtime -/// to implement multiple instance of the pallet, by using different type for the generic. -/// This is the sole purpose of the generic `I`. -/// But because `PalletInfo` requires `Pallet` placeholder to be static it is important to -/// bound `'static` whenever `PalletInfo` can be used. -/// And in order to have instantiable pallet usable as a regular pallet without instance, it is -/// important to bound `= ()` on every types. +/// # General notes on instantiable pallets /// -/// Thus impl bound look like `impl, I: 'static>`, and types look like +/// An instantiable pallet is one where Config is generic, i.e. `Config`. This allows +/// runtime to implement multiple instances of the pallet, by using different types for the +/// generic. This is the sole purpose of the generic `I`, but because +/// [`PalletInfo`](`traits::PalletInfo`) requires the `Pallet` placeholder to be static, it is +/// important to bound by `'static` whenever [`PalletInfo`](`traits::PalletInfo`) can be used. +/// Additionally, in order to make an instantiable pallet usable as a regular pallet without an +/// instance, it is important to bound by `= ()` on every type. +/// +/// Thus impl bound looks like `impl, I: 'static>`, and types look like /// `SomeType` or `SomeType, I: 'static = ()>`. /// -/// # Example for pallet without instance. +/// # Example of a non-instantiable pallet /// /// ``` /// pub use pallet::*; // reexport in crate namespace for `construct_runtime!` @@ -2063,7 +2203,7 @@ pub mod pallet_prelude { /// #[pallet::constant] // put the constant in metadata /// type MyGetParam: Get; /// type Balance: Parameter + MaxEncodedLen + From; -/// type Event: From> + IsType<::Event>; +/// type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// } /// /// // Define some additional constant to put into the constant metadata. @@ -2235,7 +2375,7 @@ pub mod pallet_prelude { /// } /// ``` /// -/// # Example for pallet with instance. +/// # Example of an instantiable pallet /// /// ``` /// pub use pallet::*; @@ -2252,7 +2392,7 @@ pub mod pallet_prelude { /// #[pallet::constant] /// type MyGetParam: Get; /// type Balance: Parameter + MaxEncodedLen + From; -/// type Event: From> + IsType<::Event>; +/// type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// } /// /// #[pallet::extra_constants] @@ -2366,28 +2506,28 @@ pub mod pallet_prelude { /// } /// ``` /// -/// ## Upgrade guidelines: +/// # Upgrade guidelines /// /// 1. Export the metadata of the pallet for later checks /// - run your node with the pallet active /// - query the metadata using the `state_getMetadata` RPC and curl, or use `subsee -p /// > meta.json` -/// 2. generate the template upgrade for the pallet provided by decl_storage -/// with environment variable `PRINT_PALLET_UPGRADE`: -/// `PRINT_PALLET_UPGRADE=1 cargo check -p my_pallet` This template can be -/// used as information it contains all information for storages, genesis -/// config and genesis build. -/// 3. reorganize pallet to have trait `Config`, `decl_*` macros, `ValidateUnsigned`, -/// `ProvideInherent`, `Origin` all together in one file. Suggested order: -/// * Config, -/// * decl_module, -/// * decl_event, -/// * decl_error, -/// * decl_storage, -/// * origin, -/// * validate_unsigned, -/// * provide_inherent, -/// so far it should compile and all be correct. +/// 2. Generate the template upgrade for the pallet provided by `decl_storage` with the +/// environment variable `PRINT_PALLET_UPGRADE`: `PRINT_PALLET_UPGRADE=1 cargo check -p +/// my_pallet`. This template can be used as it contains all information for storages, +/// genesis config and genesis build. +/// 3. Reorganize the pallet to have the trait `Config`, `decl_*` macros, +/// [`ValidateUnsigned`](`pallet_prelude::ValidateUnsigned`), +/// [`ProvideInherent`](`pallet_prelude::ProvideInherent`), and Origin` all together in one +/// file. Suggested order: +/// * `Config`, +/// * `decl_module`, +/// * `decl_event`, +/// * `decl_error`, +/// * `decl_storage`, +/// * `origin`, +/// * `validate_unsigned`, +/// * `provide_inherent`, so far it should compile and all be correct. /// 4. start writing the new pallet module /// ```ignore /// pub use pallet::*; @@ -2407,16 +2547,17 @@ pub mod pallet_prelude { /// } /// ``` /// 5. **migrate Config**: move trait into the module with -/// * all const in decl_module to `#[pallet::constant]` -/// * add bound `IsType<::Event>` to `type Event` +/// * all const in `decl_module` to [`#[pallet::constant]`](#palletconstant) +/// * add the bound `IsType<::RuntimeEvent>` to `type +/// RuntimeEvent` /// 7. **migrate decl_module**: write: /// ```ignore /// #[pallet::hooks] /// impl Hooks for Pallet { /// } /// ``` -/// and write inside -/// `on_initialize`, `on_finalize`, `on_runtime_upgrade`, `offchain_worker`, `integrity_test`. +/// and write inside `on_initialize`, `on_finalize`, `on_runtime_upgrade`, +/// `offchain_worker`, and `integrity_test`. /// /// then write: /// ```ignore @@ -2424,25 +2565,26 @@ pub mod pallet_prelude { /// impl Pallet { /// } /// ``` -/// and write inside all the calls in decl_module with a few changes in the signature: -/// - origin must now be written completely, e.g. `origin: OriginFor` -/// - result type must be `DispatchResultWithPostInfo`, you need to write it and also you -/// might -/// need to put `Ok(().into())` at the end or the function. -/// - `#[compact]` must now be written `#[pallet::compact]` -/// - `#[weight = ..]` must now be written `#[pallet::weight(..)]` -/// -/// 7. **migrate event**: -/// rewrite as a simple enum under with the attribute `#[pallet::event]`, -/// use `#[pallet::generate_deposit($vis fn deposit_event)]` to generate deposit_event, -/// 8. **migrate error**: rewrite it with attribute `#[pallet::error]`. -/// 9. **migrate storage**: -/// decl_storage provide an upgrade template (see 3.). All storages, genesis config, genesis -/// build and default implementation of genesis config can be taken from it directly. -/// -/// Otherwise here is the manual process: -/// -/// first migrate the genesis logic. write: +/// and write inside all the calls in `decl_module` with a few changes in the signature: +/// - origin must now be written completely, e.g. `origin: OriginFor` +/// - result type must be `DispatchResultWithPostInfo`, you need to write it and also you +/// might need to put `Ok(().into())` at the end or the function. +/// - `#[compact]` must now be written +/// [`#[pallet::compact]`](#palletcompact-some_arg-some_type) +/// - `#[weight = ..]` must now be written [`#[pallet::weight(..)]`](#palletweightexpr) +/// +/// 7. **migrate event**: rewrite as a simple enum with the attribute +/// [`#[pallet::event]`](#event-palletevent-optional), use [`#[pallet::generate_deposit($vis +/// fn deposit_event)]`](#event-palletevent-optional) to generate `deposit_event`, +/// 8. **migrate error**: rewrite it with attribute +/// [`#[pallet::error]`](#error-palleterror-optional). +/// 9. **migrate storage**: `decl_storage` provide an upgrade template (see 3.). All storages, +/// genesis config, genesis build and default implementation of genesis config can be +/// taken from it directly. +/// +/// Otherwise here is the manual process: +/// +/// first migrate the genesis logic. write: /// ```ignore /// #[pallet::genesis_config] /// struct GenesisConfig { @@ -2460,79 +2602,85 @@ pub mod pallet_prelude { /// } /// } /// ``` -/// for each storages, if it contains config(..) then add a fields, and make its default to the -/// value in `= ..;` or the type default if none, if it contains no build then also add the -/// logic to build the value. -/// for each storages if it contains build(..) then add the logic to genesis_build. -/// -/// NOTE: in decl_storage: is executed first the individual config and build and at the end the -/// add_extra_genesis build -/// -/// Once this is done you can migrate storage individually, a few notes: -/// - for private storage use `pub(crate) type ` or `pub(super) type` or nothing, -/// - for storage with `get(fn ..)` use `#[pallet::getter(fn ...)]` -/// - for storage with value being `Option<$something>` make generic `Value` being -/// `$something` -/// and generic `QueryKind` being `OptionQuery` (note: this is default). Otherwise make -/// `Value` the complete value type and `QueryKind` being `ValueQuery`. -/// - for storage with default value: `= $expr;` provide some specific OnEmpty generic. To do -/// so -/// use of `#[pallet::type_value]` to generate the wanted struct to put. -/// example: `MyStorage: u32 = 3u32` would be written: -/// ```ignore +/// for each storage, if it contains `config(..)` then add fields, and make it default to +/// the value in `= ..;` or the type default if none, if it contains no build then also add +/// the logic to build the value. for each storage if it contains `build(..)` then add the +/// logic to `genesis_build`. +/// +/// NOTE: within `decl_storage`: the individual config is executed first, followed by the +/// build and finally the `add_extra_genesis` build. +/// +/// Once this is done you can migrate storages individually, a few notes: +/// - for private storage use `pub(crate) type ` or `pub(super) type` or nothing, +/// - for storages with `get(fn ..)` use [`#[pallet::getter(fn +/// ...)]`](#palletgetterfn-my_getter_fn_name-optional) +/// - for storages with value being `Option<$something>` make generic `Value` being +/// `$something` and generic `QueryKind` being `OptionQuery` (note: this is default). +/// Otherwise make `Value` the complete value type and `QueryKind` being `ValueQuery`. +/// - for storages with default value: `= $expr;` provide some specific `OnEmpty` generic. +/// To do so use of `#[pallet::type_value]` to generate the wanted struct to put. +/// example: `MyStorage: u32 = 3u32` would be written: +/// +/// ```ignore /// #[pallet::type_value] fn MyStorageOnEmpty() -> u32 { 3u32 } /// #[pallet::storage] /// pub(super) type MyStorage = StorageValue<_, u32, ValueQuery, MyStorageOnEmpty>; /// ``` /// -/// NOTE: `decl_storage` also generates functions `assimilate_storage` and `build_storage` -/// directly on GenesisConfig, those are sometimes used in tests. In order not to break they -/// can be implemented manually, one can implement those functions by calling `GenesisBuild` -/// implementation. -/// -/// 10. **migrate origin**: move the origin to the pallet module under `#[pallet::origin]` -/// 11. **migrate validate_unsigned**: move the `ValidateUnsigned` implementation to the pallet -/// module under `#[pallet::validate_unsigned]` -/// 12. **migrate provide_inherent**: move the `ProvideInherent` implementation to the pallet -/// module under `#[pallet::inherent]` +/// NOTE: `decl_storage` also generates the functions `assimilate_storage` and +/// `build_storage` directly on `GenesisConfig`, and these are sometimes used in tests. +/// In order not to break they can be implemented manually, one can implement those +/// functions by calling the `GenesisBuild` implementation. +/// 10. **migrate origin**: move the origin to the pallet module to be under a +/// [`#[pallet::origin]`](#origin-palletorigin-optional) attribute +/// 11. **migrate validate_unsigned**: move the +/// [`ValidateUnsigned`](`pallet_prelude::ValidateUnsigned`) implementation to the pallet +/// module under a +/// [`#[pallet::validate_unsigned]`](#validate-unsigned-palletvalidate_unsigned-optional) +/// attribute +/// 12. **migrate provide_inherent**: move the +/// [`ProvideInherent`](`pallet_prelude::ProvideInherent`) implementation to the pallet +/// module under a [`#[pallet::inherent]`](#inherent-palletinherent-optional) attribute /// 13. rename the usage of `Module` to `Pallet` inside the crate. -/// 14. migration is done, now double check migration with the checking migration guidelines. +/// 14. migration is done, now double check the migration with the checking migration +/// guidelines shown below. /// -/// ## Checking upgrade guidelines: +/// # Checking upgrade guidelines: /// /// * compare metadata. Use [subsee](https://github.com/ascjones/subsee) to fetch the metadata -/// and do a diff of the resulting json before and after migration. This checks for: -/// * call, names, signature, docs -/// * event names, docs -/// * error names, docs -/// * storage names, hasher, prefixes, default value -/// * error , error, constant, +/// and do a diff of the resulting json before and after migration. This checks for: +/// * call, names, signature, docs +/// * event names, docs +/// * error names, docs +/// * storage names, hasher, prefixes, default value +/// * error, error, constant /// * manually check that: -/// * `Origin` is moved inside the macro under `#[pallet::origin]` if it exists -/// * `ValidateUnsigned` is moved inside the macro under `#[pallet::validate_unsigned)]` if it -/// exists -/// * `ProvideInherent` is moved inside macro under `#[pallet::inherent)]` if it exists -/// * `on_initialize`/`on_finalize`/`on_runtime_upgrade`/`offchain_worker` are moved to -/// `Hooks` -/// implementation -/// * storages with `config(..)` are converted to `GenesisConfig` field, and their default is -/// `= $expr;` if the storage have default value -/// * storages with `build($expr)` or `config(..)` are built in `GenesisBuild::build` -/// * `add_extra_genesis` fields are converted to `GenesisConfig` field with their correct -/// default if specified -/// * `add_extra_genesis` build is written into `GenesisBuild::build` +/// * `Origin` was moved inside the macro under +/// [`#[pallet::origin]`](#origin-palletorigin-optional) if it exists +/// * [`ValidateUnsigned`](`pallet_prelude::ValidateUnsigned`) was moved inside the macro +/// under +/// [`#[pallet::validate_unsigned)]`](#validate-unsigned-palletvalidate_unsigned-optional) +/// if it exists +/// * [`ProvideInherent`](`pallet_prelude::ProvideInherent`) was moved inside the macro +/// under [`#[pallet::inherent)]`](#inherent-palletinherent-optional) if it exists +/// * `on_initialize` / `on_finalize` / `on_runtime_upgrade` / `offchain_worker` were moved +/// to the `Hooks` implementation +/// * storages with `config(..)` were converted to `GenesisConfig` field, and their default +/// is `= $expr;` if the storage has a default value +/// * storages with `build($expr)` or `config(..)` were built in `GenesisBuild::build` +/// * `add_extra_genesis` fields were converted to `GenesisConfig` field with their correct +/// default if specified +/// * `add_extra_genesis` build was written into `GenesisBuild::build` /// * storage items defined with [`pallet`] use the name of the pallet provided by -/// [`traits::PalletInfo::name`] as `pallet_prefix` (in `decl_storage`, storage items used the -/// `pallet_prefix` given as input of `decl_storage` with the syntax `as Example`). -/// Thus a runtime using the pallet must be careful with this change. -/// To handle this change: -/// * either ensure that the name of the pallet given to `construct_runtime!` is the same -/// as the name the pallet was giving to `decl_storage`, -/// * or do a storage migration from the old prefix used to the new prefix used. -/// -/// NOTE: The prefixes used by storage items are in the metadata. Thus, ensuring the metadata -/// hasn't changed does ensure that the `pallet_prefix`s used by the storage items haven't -/// changed. +/// [`traits::PalletInfo::name`] as `pallet_prefix` (in `decl_storage`, storage items used +/// the `pallet_prefix` given as input of `decl_storage` with the syntax `as Example`). Thus +/// a runtime using the pallet must be careful with this change. To handle this change: +/// * either ensure that the name of the pallet given to `construct_runtime!` is the same +/// as the name the pallet was giving to `decl_storage`, +/// * or do a storage migration from the old prefix used to the new prefix used. +/// +/// NOTE: The prefixes used by storage items are in metadata. Thus, ensuring the metadata +/// hasn't changed ensures that the `pallet_prefix`s used by the storage items haven't changed. /// /// # Notes when macro fails to show proper error message spans: /// @@ -2547,3 +2695,13 @@ pub mod pallet_prelude { /// ``` /// * use the newest nightly possible. pub use frame_support_procedural::pallet; + +/// Contains macro stubs for all of the pallet:: macros +pub mod pallet_macros { + pub use frame_support_procedural::{ + call_index, compact, config, constant, disable_frame_system_supertrait_check, error, event, + extra_constants, generate_deposit, generate_storage_info, generate_store, genesis_build, + genesis_config, getter, hooks, inherent, origin, storage, storage_prefix, storage_version, + type_value, unbounded, validate_unsigned, weight, whitelist_storage, + }; +} diff --git a/frame/support/src/storage/generator/double_map.rs b/frame/support/src/storage/generator/double_map.rs index 4ffe32651a9cc..c95dcee9d7e5c 100644 --- a/frame/support/src/storage/generator/double_map.rs +++ b/frame/support/src/storage/generator/double_map.rs @@ -512,14 +512,14 @@ mod test_iterators { use codec::{Decode, Encode}; pub trait Config: 'static { - type Origin; + type RuntimeOrigin; type BlockNumber; type PalletInfo: crate::traits::PalletInfo; type DbWeight: crate::traits::Get; } crate::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self {} } #[derive(PartialEq, Eq, Clone, Encode, Decode)] diff --git a/frame/support/src/storage/generator/map.rs b/frame/support/src/storage/generator/map.rs index d190145ea4c00..f6c8eaa270bb3 100644 --- a/frame/support/src/storage/generator/map.rs +++ b/frame/support/src/storage/generator/map.rs @@ -354,14 +354,14 @@ mod test_iterators { use codec::{Decode, Encode}; pub trait Config: 'static { - type Origin; + type RuntimeOrigin; type BlockNumber; type PalletInfo: crate::traits::PalletInfo; type DbWeight: crate::traits::Get; } crate::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self {} } #[derive(PartialEq, Eq, Clone, Encode, Decode)] diff --git a/frame/support/src/storage/generator/mod.rs b/frame/support/src/storage/generator/mod.rs index ca893f44b3cb0..334e9b9e24e86 100644 --- a/frame/support/src/storage/generator/mod.rs +++ b/frame/support/src/storage/generator/mod.rs @@ -47,21 +47,21 @@ mod tests { struct Runtime; pub trait Config: 'static { - type Origin; + type RuntimeOrigin; type BlockNumber; type PalletInfo: crate::traits::PalletInfo; type DbWeight: crate::traits::Get; } impl Config for Runtime { - type Origin = u32; + type RuntimeOrigin = u32; type BlockNumber = u32; type PalletInfo = crate::tests::PanicPalletInfo; type DbWeight = (); } decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self {} } crate::decl_storage! { diff --git a/frame/support/src/storage/generator/nmap.rs b/frame/support/src/storage/generator/nmap.rs index f1d0f9a5f0801..79f3d72044e28 100755 --- a/frame/support/src/storage/generator/nmap.rs +++ b/frame/support/src/storage/generator/nmap.rs @@ -460,14 +460,14 @@ mod test_iterators { use codec::{Decode, Encode}; pub trait Config: 'static { - type Origin; + type RuntimeOrigin; type BlockNumber; type PalletInfo: crate::traits::PalletInfo; type DbWeight: crate::traits::Get; } crate::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self {} } #[derive(PartialEq, Eq, Clone, Encode, Decode)] diff --git a/frame/support/src/storage/mod.rs b/frame/support/src/storage/mod.rs index b70436785af12..333f4382557b1 100644 --- a/frame/support/src/storage/mod.rs +++ b/frame/support/src/storage/mod.rs @@ -27,7 +27,7 @@ use crate::{ use codec::{Decode, Encode, EncodeLike, FullCodec, FullEncode}; use sp_core::storage::ChildInfo; use sp_runtime::generic::{Digest, DigestItem}; -use sp_std::{marker::PhantomData, prelude::*}; +use sp_std::{collections::btree_set::BTreeSet, marker::PhantomData, prelude::*}; pub use self::{ transactional::{ @@ -1303,6 +1303,7 @@ mod private { impl Sealed for WeakBoundedVec {} impl Sealed for bounded_btree_map::BoundedBTreeMap {} impl Sealed for bounded_btree_set::BoundedBTreeSet {} + impl Sealed for BTreeSet {} macro_rules! impl_sealed_for_tuple { ($($elem:ident),+) => { @@ -1335,6 +1336,9 @@ mod private { impl StorageAppend for Vec {} impl StorageDecodeLength for Vec {} +impl StorageAppend for BTreeSet {} +impl StorageDecodeLength for BTreeSet {} + /// We abuse the fact that SCALE does not put any marker into the encoding, i.e. we only encode the /// internal vec and we can append to this vec. We have a test that ensures that if the `Digest` /// format ever changes, we need to remove this here. @@ -1832,4 +1836,22 @@ mod test { ); }); } + + #[crate::storage_alias] + type FooSet = StorageValue>; + + #[test] + fn btree_set_append_and_decode_len_works() { + TestExternalities::default().execute_with(|| { + let btree = BTreeSet::from([1, 2, 3]); + FooSet::put(btree); + + FooSet::append(4); + FooSet::append(5); + FooSet::append(6); + FooSet::append(7); + + assert_eq!(FooSet::decode_len().unwrap(), 7); + }); + } } diff --git a/frame/support/src/storage/storage_noop_guard.rs b/frame/support/src/storage/storage_noop_guard.rs index afcc699d91313..7186c3eaf467a 100644 --- a/frame/support/src/storage/storage_noop_guard.rs +++ b/frame/support/src/storage/storage_noop_guard.rs @@ -16,7 +16,7 @@ // limitations under the License. // Feature gated since it can panic. -#![cfg(any(feature = "std", feature = "runtime-benchmarks", test))] +#![cfg(any(feature = "std", feature = "runtime-benchmarks", feature = "try-runtime", test))] //! Contains the [`crate::StorageNoopGuard`] for conveniently asserting //! that no storage mutation has been made by a whole code block. diff --git a/frame/support/src/storage/types/counted_map.rs b/frame/support/src/storage/types/counted_map.rs index c4027acfe7232..8c19434767f49 100644 --- a/frame/support/src/storage/types/counted_map.rs +++ b/frame/support/src/storage/types/counted_map.rs @@ -143,10 +143,7 @@ where } /// Store a value to be associated with the given key from the map. - pub fn insert + Clone, ValArg: EncodeLike>( - key: KeyArg, - val: ValArg, - ) { + pub fn insert, ValArg: EncodeLike>(key: KeyArg, val: ValArg) { if !::Map::contains_key(Ref::from(&key)) { CounterFor::::mutate(|value| value.saturating_inc()); } @@ -154,7 +151,7 @@ where } /// Remove the value under a key. - pub fn remove + Clone>(key: KeyArg) { + pub fn remove>(key: KeyArg) { if ::Map::contains_key(Ref::from(&key)) { CounterFor::::mutate(|value| value.saturating_dec()); } @@ -162,7 +159,7 @@ where } /// Mutate the value under a key. - pub fn mutate + Clone, R, F: FnOnce(&mut QueryKind::Query) -> R>( + pub fn mutate, R, F: FnOnce(&mut QueryKind::Query) -> R>( key: KeyArg, f: F, ) -> R { @@ -173,7 +170,7 @@ where /// Mutate the item, only if an `Ok` value is returned. pub fn try_mutate(key: KeyArg, f: F) -> Result where - KeyArg: EncodeLike + Clone, + KeyArg: EncodeLike, F: FnOnce(&mut QueryKind::Query) -> Result, { Self::try_mutate_exists(key, |option_value_ref| { @@ -187,7 +184,7 @@ where } /// Mutate the value under a key. Deletes the item if mutated to a `None`. - pub fn mutate_exists + Clone, R, F: FnOnce(&mut Option) -> R>( + pub fn mutate_exists, R, F: FnOnce(&mut Option) -> R>( key: KeyArg, f: F, ) -> R { @@ -200,7 +197,7 @@ where /// or if the storage item does not exist (`None`), independent of the `QueryType`. pub fn try_mutate_exists(key: KeyArg, f: F) -> Result where - KeyArg: EncodeLike + Clone, + KeyArg: EncodeLike, F: FnOnce(&mut Option) -> Result, { ::Map::try_mutate_exists(key, |option_value| { @@ -222,7 +219,7 @@ where } /// Take the value under a key. - pub fn take + Clone>(key: KeyArg) -> QueryKind::Query { + pub fn take>(key: KeyArg) -> QueryKind::Query { let removed_value = ::Map::mutate_exists(key, |value| value.take()); if removed_value.is_some() { CounterFor::::mutate(|value| value.saturating_dec()); @@ -240,7 +237,7 @@ where /// `[item]`. Any default value set for the storage item will be ignored on overwrite. pub fn append(key: EncodeLikeKey, item: EncodeLikeItem) where - EncodeLikeKey: EncodeLike + Clone, + EncodeLikeKey: EncodeLike, Item: Encode, EncodeLikeItem: EncodeLike, Value: StorageAppend, @@ -355,7 +352,7 @@ where /// Is only available if `Value` of the storage implements [`StorageTryAppend`]. pub fn try_append(key: KArg, item: EncodeLikeItem) -> Result<(), ()> where - KArg: EncodeLike + Clone, + KArg: EncodeLike, Item: Encode, EncodeLikeItem: EncodeLike, Value: StorageTryAppend, diff --git a/frame/support/src/traits.rs b/frame/support/src/traits.rs index d4f0e73557c77..302d3354dae5e 100644 --- a/frame/support/src/traits.rs +++ b/frame/support/src/traits.rs @@ -58,10 +58,11 @@ pub use misc::{ Backing, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, ConstU16, ConstU32, ConstU64, ConstU8, DefensiveSaturating, EnsureInherentsAreFirst, EqualPrivilegeOnly, EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, GetBacking, GetDefault, HandleLifetime, - IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, PreimageProvider, - PreimageRecipient, PrivilegeCmp, SameOrOther, Time, TryCollect, TryDrop, TypedGet, UnixTime, - WrapperKeepOpaque, WrapperOpaque, + IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, OnNewAccount, PrivilegeCmp, + SameOrOther, Time, TryCollect, TryDrop, TypedGet, UnixTime, WrapperKeepOpaque, WrapperOpaque, }; +#[allow(deprecated)] +pub use misc::{PreimageProvider, PreimageRecipient}; #[doc(hidden)] pub use misc::{DEFENSIVE_OP_INTERNAL_ERROR, DEFENSIVE_OP_PUBLIC_ERROR}; @@ -89,14 +90,16 @@ pub mod schedule; mod storage; pub use storage::{ Instance, PartialStorageInfoTrait, StorageInfo, StorageInfoTrait, StorageInstance, + TrackedStorageKey, WhitelistedStorageKeys, }; mod dispatch; #[allow(deprecated)] pub use dispatch::EnsureOneOf; pub use dispatch::{ - AsEnsureOriginWithArg, EitherOf, EitherOfDiverse, EnsureOrigin, EnsureOriginWithArg, - MapSuccess, NeverEnsureOrigin, OriginTrait, TryMapSuccess, UnfilteredDispatchable, + AsEnsureOriginWithArg, CallerTrait, EitherOf, EitherOfDiverse, EnsureOrigin, + EnsureOriginWithArg, MapSuccess, NeverEnsureOrigin, OriginTrait, TryMapSuccess, + UnfilteredDispatchable, }; mod voting; @@ -105,7 +108,10 @@ pub use voting::{ U128CurrencyToVote, VoteTally, }; +mod preimages; +pub use preimages::{Bounded, BoundedInline, FetchResult, Hash, QueryPreimage, StorePreimage}; + #[cfg(feature = "try-runtime")] mod try_runtime; #[cfg(feature = "try-runtime")] -pub use try_runtime::{OnRuntimeUpgradeHelpersExt, Select as TryStateSelect, TryState}; +pub use try_runtime::{Select as TryStateSelect, TryState}; diff --git a/frame/support/src/traits/dispatch.rs b/frame/support/src/traits/dispatch.rs index afc819aa454e5..b96cfae4500e2 100644 --- a/frame/support/src/traits/dispatch.rs +++ b/frame/support/src/traits/dispatch.rs @@ -229,24 +229,32 @@ impl< /// Implemented for pallet dispatchable type by `decl_module` and for runtime dispatchable by /// `construct_runtime`. pub trait UnfilteredDispatchable { - /// The origin type of the runtime, (i.e. `frame_system::Config::Origin`). - type Origin; + /// The origin type of the runtime, (i.e. `frame_system::Config::RuntimeOrigin`). + type RuntimeOrigin; /// Dispatch this call but do not check the filter in origin. - fn dispatch_bypass_filter(self, origin: Self::Origin) -> DispatchResultWithPostInfo; + fn dispatch_bypass_filter(self, origin: Self::RuntimeOrigin) -> DispatchResultWithPostInfo; } -/// Methods available on `frame_system::Config::Origin`. +/// The trait implemented by the overarching enumeration of the different pallets' origins. +/// Unlike `OriginTrait` impls, this does not include any kind of dispatch/call filter. Also, this +/// trait is more flexible in terms of how it can be used: it is a `Parameter` and `Member`, so it +/// can be used as dispatchable parameters as well as in storage items. +pub trait CallerTrait: Parameter + Member + From> { + /// Extract the signer from the message if it is a `Signed` origin. + fn into_system(self) -> Option>; + + /// Extract a reference to the system-level `RawOrigin` if it is that. + fn as_system_ref(&self) -> Option<&RawOrigin>; +} + +/// Methods available on `frame_system::Config::RuntimeOrigin`. pub trait OriginTrait: Sized { /// Runtime call type, as in `frame_system::Config::Call` type Call; /// The caller origin, overarching type of all pallets origins. - type PalletsOrigin: Parameter - + Member - + Into - + From> - + MaxEncodedLen; + type PalletsOrigin: Into + CallerTrait + MaxEncodedLen; /// The AccountId used across the system. type AccountId; @@ -266,9 +274,12 @@ pub trait OriginTrait: Sized { /// For root origin caller, the filters are bypassed and true is returned. fn filter_call(&self, call: &Self::Call) -> bool; - /// Get the caller. + /// Get a reference to the caller (`CallerTrait` impl). fn caller(&self) -> &Self::PalletsOrigin; + /// Consume `self` and return the caller. + fn into_caller(self) -> Self::PalletsOrigin; + /// Do something with the caller, consuming self but returning it if the caller was unused. fn try_with_caller( self, @@ -285,7 +296,20 @@ pub trait OriginTrait: Sized { fn signed(by: Self::AccountId) -> Self; /// Extract the signer from the message if it is a `Signed` origin. - fn as_signed(self) -> Option; + fn as_signed(self) -> Option { + self.into_caller().into_system().and_then(|s| { + if let RawOrigin::Signed(who) = s { + Some(who) + } else { + None + } + }) + } + + /// Extract a reference to the sytsem origin, if that's what the caller is. + fn as_system_ref(&self) -> Option<&RawOrigin> { + self.caller().as_system_ref() + } } #[cfg(test)] diff --git a/frame/support/src/traits/hooks.rs b/frame/support/src/traits/hooks.rs index 25ec333a7dbe0..3415682c0b382 100644 --- a/frame/support/src/traits/hooks.rs +++ b/frame/support/src/traits/hooks.rs @@ -22,6 +22,9 @@ use impl_trait_for_tuples::impl_for_tuples; use sp_runtime::traits::AtLeast32BitUnsigned; use sp_std::prelude::*; +#[cfg(all(feature = "try-runtime", test))] +use codec::{Decode, Encode}; + /// The block initialization trait. /// /// Implementing this lets you express what should happen for your pallet when the block is @@ -135,17 +138,25 @@ pub trait OnRuntimeUpgrade { /// Execute some pre-checks prior to a runtime upgrade. /// + /// Return a `Vec` that can contain arbitrary encoded data (usually some pre-upgrade state), + /// which will be passed to `post_upgrade` after upgrading for post-check. An empty vector + /// should be returned if there is no such need. + /// /// This hook is never meant to be executed on-chain but is meant to be used by testing tools. #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { - Ok(()) + fn pre_upgrade() -> Result, &'static str> { + Ok(Vec::new()) } /// Execute some post-checks after a runtime upgrade. /// + /// The `state` parameter is the `Vec` returned by `pre_upgrade` before upgrading, which + /// can be used for post-check. NOTE: if `pre_upgrade` is not implemented an empty vector will + /// be passed in, in such case `post_upgrade` should ignore it. + /// /// This hook is never meant to be executed on-chain but is meant to be used by testing tools. #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { Ok(()) } } @@ -154,6 +165,7 @@ pub trait OnRuntimeUpgrade { #[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] #[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] impl OnRuntimeUpgrade for Tuple { + #[cfg(not(feature = "try-runtime"))] fn on_runtime_upgrade() -> Weight { let mut weight = Weight::zero(); for_tuples!( #( weight = weight.saturating_add(Tuple::on_runtime_upgrade()); )* ); @@ -161,17 +173,43 @@ impl OnRuntimeUpgrade for Tuple { } #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { - let mut result = Ok(()); - for_tuples!( #( result = result.and(Tuple::pre_upgrade()); )* ); - result + /// We are executing pre- and post-checks sequentially in order to be able to test several + /// consecutive migrations for the same pallet without errors. Therefore pre and post upgrade + /// hooks for tuples are a noop. + fn on_runtime_upgrade() -> Weight { + use scale_info::prelude::format; + + let mut weight = Weight::zero(); + // migration index in the tuple, start with 1 for better readability + let mut i = 1; + for_tuples!( #( + let _guard = frame_support::StorageNoopGuard::default(); + // we want to panic if any checks fail right here right now. + let state = Tuple::pre_upgrade().expect(&format!("PreUpgrade failed for migration #{}", i)); + drop(_guard); + + weight = weight.saturating_add(Tuple::on_runtime_upgrade()); + + let _guard = frame_support::StorageNoopGuard::default(); + // we want to panic if any checks fail right here right now. + Tuple::post_upgrade(state).expect(&format!("PostUpgrade failed for migration #{}", i)); + drop(_guard); + + i += 1; + )* ); + weight } #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { - let mut result = Ok(()); - for_tuples!( #( result = result.and(Tuple::post_upgrade()); )* ); - result + /// noop + fn pre_upgrade() -> Result, &'static str> { + Ok(Vec::new()) + } + + #[cfg(feature = "try-runtime")] + /// noop + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { + Ok(()) } } @@ -243,17 +281,25 @@ pub trait Hooks { /// Execute some pre-checks prior to a runtime upgrade. /// + /// Return a `Vec` that can contain arbitrary encoded data (usually some pre-upgrade state), + /// which will be passed to `post_upgrade` after upgrading for post-check. An empty vector + /// should be returned if there is no such need. + /// /// This hook is never meant to be executed on-chain but is meant to be used by testing tools. #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result<(), &'static str> { - Ok(()) + fn pre_upgrade() -> Result, &'static str> { + Ok(Vec::new()) } /// Execute some post-checks after a runtime upgrade. /// + /// The `state` parameter is the `Vec` returned by `pre_upgrade` before upgrading, which + /// can be used for post-check. NOTE: if `pre_upgrade` is not implemented an empty vector will + /// be passed in, in such case `post_upgrade` should ignore it. + /// /// This hook is never meant to be executed on-chain but is meant to be used by testing tools. #[cfg(feature = "try-runtime")] - fn post_upgrade() -> Result<(), &'static str> { + fn post_upgrade(_state: Vec) -> Result<(), &'static str> { Ok(()) } @@ -319,7 +365,9 @@ mod tests { #[test] fn on_initialize_and_on_runtime_upgrade_weight_merge_works() { + use sp_io::TestExternalities; struct Test; + impl OnInitialize for Test { fn on_initialize(_n: u8) -> Weight { Weight::from_ref_time(10) @@ -331,8 +379,10 @@ mod tests { } } - assert_eq!(<(Test, Test)>::on_initialize(0), Weight::from_ref_time(20)); - assert_eq!(<(Test, Test)>::on_runtime_upgrade(), Weight::from_ref_time(40)); + TestExternalities::default().execute_with(|| { + assert_eq!(<(Test, Test)>::on_initialize(0), Weight::from_ref_time(20)); + assert_eq!(<(Test, Test)>::on_runtime_upgrade(), Weight::from_ref_time(40)); + }); } #[test] @@ -390,4 +440,110 @@ mod tests { ON_IDLE_INVOCATION_ORDER.clear(); } } + + #[cfg(feature = "try-runtime")] + #[test] + #[allow(dead_code)] + fn on_runtime_upgrade_tuple() { + use frame_support::parameter_types; + use sp_io::TestExternalities; + + struct Test1; + struct Test2; + struct Test3; + + parameter_types! { + static Test1Assertions: u8 = 0; + static Test2Assertions: u8 = 0; + static Test3Assertions: u8 = 0; + static EnableSequentialTest: bool = false; + static SequentialAssertions: u8 = 0; + } + + impl OnRuntimeUpgrade for Test1 { + fn pre_upgrade() -> Result, &'static str> { + Ok("Test1".encode()) + } + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + let s: String = Decode::decode(&mut state.as_slice()).unwrap(); + Test1Assertions::mutate(|val| *val += 1); + if EnableSequentialTest::get() { + SequentialAssertions::mutate(|val| *val += 1); + } + assert_eq!(s, "Test1"); + Ok(()) + } + } + + impl OnRuntimeUpgrade for Test2 { + fn pre_upgrade() -> Result, &'static str> { + Ok(100u32.encode()) + } + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + let s: u32 = Decode::decode(&mut state.as_slice()).unwrap(); + Test2Assertions::mutate(|val| *val += 1); + if EnableSequentialTest::get() { + assert_eq!(SequentialAssertions::get(), 1); + SequentialAssertions::mutate(|val| *val += 1); + } + assert_eq!(s, 100); + Ok(()) + } + } + + impl OnRuntimeUpgrade for Test3 { + fn pre_upgrade() -> Result, &'static str> { + Ok(true.encode()) + } + fn post_upgrade(state: Vec) -> Result<(), &'static str> { + let s: bool = Decode::decode(&mut state.as_slice()).unwrap(); + Test3Assertions::mutate(|val| *val += 1); + if EnableSequentialTest::get() { + assert_eq!(SequentialAssertions::get(), 2); + SequentialAssertions::mutate(|val| *val += 1); + } + assert_eq!(s, true); + Ok(()) + } + } + + TestExternalities::default().execute_with(|| { + type TestEmpty = (); + let origin_state = ::pre_upgrade().unwrap(); + assert!(origin_state.is_empty()); + ::post_upgrade(origin_state).unwrap(); + + type Test1Tuple = (Test1,); + let origin_state = ::pre_upgrade().unwrap(); + assert!(origin_state.is_empty()); + ::post_upgrade(origin_state).unwrap(); + assert_eq!(Test1Assertions::get(), 0); + ::on_runtime_upgrade(); + assert_eq!(Test1Assertions::take(), 1); + + type Test321 = (Test3, Test2, Test1); + ::on_runtime_upgrade(); + assert_eq!(Test1Assertions::take(), 1); + assert_eq!(Test2Assertions::take(), 1); + assert_eq!(Test3Assertions::take(), 1); + + // enable sequential tests + EnableSequentialTest::mutate(|val| *val = true); + + type Test123 = (Test1, Test2, Test3); + ::on_runtime_upgrade(); + assert_eq!(Test1Assertions::take(), 1); + assert_eq!(Test2Assertions::take(), 1); + assert_eq!(Test3Assertions::take(), 1); + + // reset assertions + SequentialAssertions::take(); + + type TestNested123 = (Test1, (Test2, Test3)); + ::on_runtime_upgrade(); + assert_eq!(Test1Assertions::take(), 1); + assert_eq!(Test2Assertions::take(), 1); + assert_eq!(Test3Assertions::take(), 1); + }); + } } diff --git a/frame/support/src/traits/misc.rs b/frame/support/src/traits/misc.rs index 91999e40afe62..526e28ed32948 100644 --- a/frame/support/src/traits/misc.rs +++ b/frame/support/src/traits/misc.rs @@ -151,10 +151,10 @@ pub trait DefensiveOption { /// Defensively transform this option to a result, mapping `None` to the return value of an /// error closure. - fn defensive_ok_or_else E>(self, err: F) -> Result; + fn defensive_ok_or_else E>(self, err: F) -> Result; /// Defensively transform this option to a result, mapping `None` to a default value. - fn defensive_ok_or(self, err: E) -> Result; + fn defensive_ok_or(self, err: E) -> Result; /// Exactly the same as `map`, but it prints the appropriate warnings if the value being mapped /// is `None`. @@ -318,16 +318,17 @@ impl DefensiveOption for Option { ) } - fn defensive_ok_or_else E>(self, err: F) -> Result { + fn defensive_ok_or_else E>(self, err: F) -> Result { self.ok_or_else(|| { - defensive!(); - err() + let err_value = err(); + defensive!(err_value); + err_value }) } - fn defensive_ok_or(self, err: E) -> Result { + fn defensive_ok_or(self, err: E) -> Result { self.ok_or_else(|| { - defensive!(); + defensive!(err); err }) } @@ -722,13 +723,13 @@ pub trait EstimateCallFee { /// /// The dispatch info and the length is deduced from the call. The post info can optionally be /// provided. - fn estimate_call_fee(call: &Call, post_info: crate::weights::PostDispatchInfo) -> Balance; + fn estimate_call_fee(call: &Call, post_info: crate::dispatch::PostDispatchInfo) -> Balance; } // Useful for building mocks. #[cfg(feature = "std")] impl, const T: u32> EstimateCallFee for ConstU32 { - fn estimate_call_fee(_: &Call, _: crate::weights::PostDispatchInfo) -> Balance { + fn estimate_call_fee(_: &Call, _: crate::dispatch::PostDispatchInfo) -> Balance { T.into() } } @@ -943,7 +944,7 @@ pub trait PreimageRecipient: PreimageProvider { /// Maximum size of a preimage. type MaxSize: Get; - /// Store the bytes of a preimage on chain. + /// Store the bytes of a preimage on chain infallible due to the bounded type. fn note_preimage(bytes: crate::BoundedVec); /// Clear a previously noted preimage. This is infallible and should be treated more like a diff --git a/frame/support/src/traits/preimages.rs b/frame/support/src/traits/preimages.rs new file mode 100644 index 0000000000000..594532ba96903 --- /dev/null +++ b/frame/support/src/traits/preimages.rs @@ -0,0 +1,317 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Stuff for dealing with 32-byte hashed preimages. + +use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; +use sp_core::{RuntimeDebug, H256}; +use sp_io::hashing::blake2_256; +use sp_runtime::{traits::ConstU32, DispatchError}; +use sp_std::borrow::Cow; + +pub type Hash = H256; +pub type BoundedInline = crate::BoundedVec>; + +#[derive( + Encode, Decode, MaxEncodedLen, Clone, Eq, PartialEq, scale_info::TypeInfo, RuntimeDebug, +)] +#[codec(mel_bound())] +pub enum Bounded { + /// A Blake2 256 hash with no preimage length. We + /// do not support creation of this except for transitioning from legacy state. + /// In the future we will make this a pure `Dummy` item storing only the final `dummy` field. + Legacy { hash: Hash, dummy: sp_std::marker::PhantomData }, + /// A an bounded `Call`. Its encoding must be at most 128 bytes. + Inline(BoundedInline), + /// A Blake2-256 hash of the call together with an upper limit for its size. + Lookup { hash: Hash, len: u32 }, +} + +impl Bounded { + /// Casts the wrapped type into something that encodes alike. + /// + /// # Examples + /// ``` + /// use frame_support::traits::Bounded; + /// + /// // Transmute from `String` to `&str`. + /// let x: Bounded = Bounded::Inline(Default::default()); + /// let _: Bounded<&str> = x.transmute(); + /// ``` + pub fn transmute(self) -> Bounded + where + T: Encode + EncodeLike, + { + use Bounded::*; + match self { + Legacy { hash, .. } => Legacy { hash, dummy: sp_std::marker::PhantomData }, + Inline(x) => Inline(x), + Lookup { hash, len } => Lookup { hash, len }, + } + } + + /// Returns the hash of the preimage. + /// + /// The hash is re-calculated every time if the preimage is inlined. + pub fn hash(&self) -> H256 { + use Bounded::*; + match self { + Legacy { hash, .. } => *hash, + Inline(x) => blake2_256(x.as_ref()).into(), + Lookup { hash, .. } => *hash, + } + } +} + +// The maximum we expect a single legacy hash lookup to be. +const MAX_LEGACY_LEN: u32 = 1_000_000; + +impl Bounded { + /// Returns the length of the preimage or `None` if the length is unknown. + pub fn len(&self) -> Option { + match self { + Self::Legacy { .. } => None, + Self::Inline(i) => Some(i.len() as u32), + Self::Lookup { len, .. } => Some(*len), + } + } + + /// Returns whether the image will require a lookup to be peeked. + pub fn lookup_needed(&self) -> bool { + match self { + Self::Inline(..) => false, + Self::Legacy { .. } | Self::Lookup { .. } => true, + } + } + + /// The maximum length of the lookup that is needed to peek `Self`. + pub fn lookup_len(&self) -> Option { + match self { + Self::Inline(..) => None, + Self::Legacy { .. } => Some(MAX_LEGACY_LEN), + Self::Lookup { len, .. } => Some(*len), + } + } + + /// Constructs a `Lookup` bounded item. + pub fn unrequested(hash: Hash, len: u32) -> Self { + Self::Lookup { hash, len } + } + + /// Constructs a `Legacy` bounded item. + #[deprecated = "This API is only for transitioning to Scheduler v3 API"] + pub fn from_legacy_hash(hash: impl Into) -> Self { + Self::Legacy { hash: hash.into(), dummy: sp_std::marker::PhantomData } + } +} + +pub type FetchResult = Result, DispatchError>; + +/// A interface for looking up preimages from their hash on chain. +pub trait QueryPreimage { + /// Returns whether a preimage exists for a given hash and if so its length. + fn len(hash: &Hash) -> Option; + + /// Returns the preimage for a given hash. If given, `len` must be the size of the preimage. + fn fetch(hash: &Hash, len: Option) -> FetchResult; + + /// Returns whether a preimage request exists for a given hash. + fn is_requested(hash: &Hash) -> bool; + + /// Request that someone report a preimage. Providers use this to optimise the economics for + /// preimage reporting. + fn request(hash: &Hash); + + /// Cancel a previous preimage request. + fn unrequest(hash: &Hash); + + /// Request that the data required for decoding the given `bounded` value is made available. + fn hold(bounded: &Bounded) { + use Bounded::*; + match bounded { + Inline(..) => {}, + Legacy { hash, .. } | Lookup { hash, .. } => Self::request(hash), + } + } + + /// No longer request that the data required for decoding the given `bounded` value is made + /// available. + fn drop(bounded: &Bounded) { + use Bounded::*; + match bounded { + Inline(..) => {}, + Legacy { hash, .. } | Lookup { hash, .. } => Self::unrequest(hash), + } + } + + /// Check to see if all data required for the given `bounded` value is available for its + /// decoding. + fn have(bounded: &Bounded) -> bool { + use Bounded::*; + match bounded { + Inline(..) => true, + Legacy { hash, .. } | Lookup { hash, .. } => Self::len(hash).is_some(), + } + } + + /// Create a `Bounded` instance based on the `hash` and `len` of the encoded value. This may not + /// be `peek`-able or `realize`-able. + fn pick(hash: Hash, len: u32) -> Bounded { + Self::request(&hash); + Bounded::Lookup { hash, len } + } + + /// Convert the given `bounded` instance back into its original instance, also returning the + /// exact size of its encoded form if it needed to be looked-up from a stored preimage). + /// + /// NOTE: This does not remove any data needed for realization. If you will no longer use the + /// `bounded`, call `realize` instead or call `drop` afterwards. + fn peek(bounded: &Bounded) -> Result<(T, Option), DispatchError> { + use Bounded::*; + match bounded { + Inline(data) => T::decode(&mut &data[..]).ok().map(|x| (x, None)), + Lookup { hash, len } => { + let data = Self::fetch(hash, Some(*len))?; + T::decode(&mut &data[..]).ok().map(|x| (x, Some(data.len() as u32))) + }, + Legacy { hash, .. } => { + let data = Self::fetch(hash, None)?; + T::decode(&mut &data[..]).ok().map(|x| (x, Some(data.len() as u32))) + }, + } + .ok_or(DispatchError::Corruption) + } + + /// Convert the given `bounded` value back into its original instance. If successful, + /// `drop` any data backing it. This will not break the realisability of independently + /// created instances of `Bounded` which happen to have identical data. + fn realize(bounded: &Bounded) -> Result<(T, Option), DispatchError> { + let r = Self::peek(bounded)?; + Self::drop(bounded); + Ok(r) + } +} + +/// A interface for managing preimages to hashes on chain. +/// +/// Note that this API does not assume any underlying user is calling, and thus +/// does not handle any preimage ownership or fees. Other system level logic that +/// uses this API should implement that on their own side. +pub trait StorePreimage: QueryPreimage { + /// The maximum length of preimage we can store. + /// + /// This is the maximum length of the *encoded* value that can be passed to `bound`. + const MAX_LENGTH: usize; + + /// Request and attempt to store the bytes of a preimage on chain. + /// + /// May return `DispatchError::Exhausted` if the preimage is just too big. + fn note(bytes: Cow<[u8]>) -> Result; + + /// Attempt to clear a previously noted preimage. Exactly the same as `unrequest` but is + /// provided for symmetry. + fn unnote(hash: &Hash) { + Self::unrequest(hash) + } + + /// Convert an otherwise unbounded or large value into a type ready for placing in storage. The + /// result is a type whose `MaxEncodedLen` is 131 bytes. + /// + /// NOTE: Once this API is used, you should use either `drop` or `realize`. + fn bound(t: T) -> Result, DispatchError> { + let data = t.encode(); + let len = data.len() as u32; + Ok(match BoundedInline::try_from(data) { + Ok(bounded) => Bounded::Inline(bounded), + Err(unbounded) => Bounded::Lookup { hash: Self::note(unbounded.into())?, len }, + }) + } +} + +impl QueryPreimage for () { + fn len(_: &Hash) -> Option { + None + } + fn fetch(_: &Hash, _: Option) -> FetchResult { + Err(DispatchError::Unavailable) + } + fn is_requested(_: &Hash) -> bool { + false + } + fn request(_: &Hash) {} + fn unrequest(_: &Hash) {} +} + +impl StorePreimage for () { + const MAX_LENGTH: usize = 0; + fn note(_: Cow<[u8]>) -> Result { + Err(DispatchError::Exhausted) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{bounded_vec, BoundedVec}; + + #[test] + fn bounded_size_is_correct() { + assert_eq!(> as MaxEncodedLen>::max_encoded_len(), 131); + } + + #[test] + fn bounded_basic_works() { + let data: BoundedVec = bounded_vec![b'a', b'b', b'c']; + let len = data.len() as u32; + let hash = blake2_256(&data).into(); + + // Inline works + { + let bound: Bounded> = Bounded::Inline(data.clone()); + assert_eq!(bound.hash(), hash); + assert_eq!(bound.len(), Some(len)); + assert!(!bound.lookup_needed()); + assert_eq!(bound.lookup_len(), None); + } + // Legacy works + { + let bound: Bounded> = Bounded::Legacy { hash, dummy: Default::default() }; + assert_eq!(bound.hash(), hash); + assert_eq!(bound.len(), None); + assert!(bound.lookup_needed()); + assert_eq!(bound.lookup_len(), Some(1_000_000)); + } + // Lookup works + { + let bound: Bounded> = Bounded::Lookup { hash, len: data.len() as u32 }; + assert_eq!(bound.hash(), hash); + assert_eq!(bound.len(), Some(len)); + assert!(bound.lookup_needed()); + assert_eq!(bound.lookup_len(), Some(len)); + } + } + + #[test] + fn bounded_transmuting_works() { + let data: BoundedVec = bounded_vec![b'a', b'b', b'c']; + + // Transmute a `String` into a `&str`. + let x: Bounded = Bounded::Inline(data.clone()); + let y: Bounded<&str> = x.transmute(); + assert_eq!(y, Bounded::Inline(data)); + } +} diff --git a/frame/support/src/traits/schedule.rs b/frame/support/src/traits/schedule.rs index 39ebbb78321d6..b8e6a7f807904 100644 --- a/frame/support/src/traits/schedule.rs +++ b/frame/support/src/traits/schedule.rs @@ -17,6 +17,8 @@ //! Traits and associated utilities for scheduling dispatchables in FRAME. +#[allow(deprecated)] +use super::PreimageProvider; use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen}; use scale_info::TypeInfo; use sp_runtime::{traits::Saturating, DispatchError, RuntimeDebug}; @@ -128,11 +130,12 @@ impl MaybeHashed { } } +// TODO: deprecate pub mod v1 { use super::*; /// A type that can be used as a scheduler. - pub trait Anon { + pub trait Anon { /// An address which can be used for removing a scheduled task. type Address: Codec + Clone + Eq + EncodeLike + Debug + TypeInfo + MaxEncodedLen; @@ -143,7 +146,7 @@ pub mod v1 { when: DispatchTime, maybe_periodic: Option>, priority: Priority, - origin: Origin, + origin: RuntimeOrigin, call: Call, ) -> Result; @@ -177,7 +180,7 @@ pub mod v1 { } /// A type that can be used as a scheduler. - pub trait Named { + pub trait Named { /// An address which can be used for removing a scheduled task. type Address: Codec + Clone + Eq + EncodeLike + sp_std::fmt::Debug + MaxEncodedLen; @@ -189,7 +192,7 @@ pub mod v1 { when: DispatchTime, maybe_periodic: Option>, priority: Priority, - origin: Origin, + origin: RuntimeOrigin, call: Call, ) -> Result; @@ -215,9 +218,9 @@ pub mod v1 { fn next_dispatch_time(id: Vec) -> Result; } - impl Anon for T + impl Anon for T where - T: v2::Anon, + T: v2::Anon, { type Address = T::Address; @@ -225,7 +228,7 @@ pub mod v1 { when: DispatchTime, maybe_periodic: Option>, priority: Priority, - origin: Origin, + origin: RuntimeOrigin, call: Call, ) -> Result { let c = MaybeHashed::::Value(call); @@ -248,9 +251,9 @@ pub mod v1 { } } - impl Named for T + impl Named for T where - T: v2::Named, + T: v2::Named, { type Address = T::Address; @@ -259,7 +262,7 @@ pub mod v1 { when: DispatchTime, maybe_periodic: Option>, priority: Priority, - origin: Origin, + origin: RuntimeOrigin, call: Call, ) -> Result { let c = MaybeHashed::::Value(call); @@ -283,11 +286,12 @@ pub mod v1 { } } +// TODO: deprecate pub mod v2 { use super::*; /// A type that can be used as a scheduler. - pub trait Anon { + pub trait Anon { /// An address which can be used for removing a scheduled task. type Address: Codec + Clone + Eq + EncodeLike + Debug + TypeInfo + MaxEncodedLen; /// A means of expressing a call by the hash of its encoded data. @@ -300,7 +304,7 @@ pub mod v2 { when: DispatchTime, maybe_periodic: Option>, priority: Priority, - origin: Origin, + origin: RuntimeOrigin, call: MaybeHashed, ) -> Result; @@ -334,7 +338,7 @@ pub mod v2 { } /// A type that can be used as a scheduler. - pub trait Named { + pub trait Named { /// An address which can be used for removing a scheduled task. type Address: Codec + Clone + Eq + EncodeLike + sp_std::fmt::Debug + MaxEncodedLen; /// A means of expressing a call by the hash of its encoded data. @@ -348,7 +352,7 @@ pub mod v2 { when: DispatchTime, maybe_periodic: Option>, priority: Priority, - origin: Origin, + origin: RuntimeOrigin, call: MaybeHashed, ) -> Result; @@ -375,6 +379,97 @@ pub mod v2 { } } -pub use v1::*; +pub mod v3 { + use super::*; + use crate::traits::Bounded; -use super::PreimageProvider; + /// A type that can be used as a scheduler. + pub trait Anon { + /// An address which can be used for removing a scheduled task. + type Address: Codec + MaxEncodedLen + Clone + Eq + EncodeLike + Debug + TypeInfo; + + /// Schedule a dispatch to happen at the beginning of some block in the future. + /// + /// This is not named. + fn schedule( + when: DispatchTime, + maybe_periodic: Option>, + priority: Priority, + origin: Origin, + call: Bounded, + ) -> Result; + + /// Cancel a scheduled task. If periodic, then it will cancel all further instances of that, + /// also. + /// + /// Will return an `Unavailable` error if the `address` is invalid. + /// + /// NOTE: This guaranteed to work only *before* the point that it is due to be executed. + /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled. + /// + /// NOTE2: This will not work to cancel periodic tasks after their initial execution. For + /// that, you must name the task explicitly using the `Named` trait. + fn cancel(address: Self::Address) -> Result<(), DispatchError>; + + /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed + /// only if it is executed *before* the currently scheduled block. For periodic tasks, + /// this dispatch is guaranteed to succeed only before the *initial* execution; for + /// others, use `reschedule_named`. + /// + /// Will return an `Unavailable` error if the `address` is invalid. + fn reschedule( + address: Self::Address, + when: DispatchTime, + ) -> Result; + + /// Return the next dispatch time for a given task. + /// + /// Will return an `Unavailable` error if the `address` is invalid. + fn next_dispatch_time(address: Self::Address) -> Result; + } + + pub type TaskName = [u8; 32]; + + /// A type that can be used as a scheduler. + pub trait Named { + /// An address which can be used for removing a scheduled task. + type Address: Codec + MaxEncodedLen + Clone + Eq + EncodeLike + sp_std::fmt::Debug; + + /// Schedule a dispatch to happen at the beginning of some block in the future. + /// + /// - `id`: The identity of the task. This must be unique and will return an error if not. + fn schedule_named( + id: TaskName, + when: DispatchTime, + maybe_periodic: Option>, + priority: Priority, + origin: Origin, + call: Bounded, + ) -> Result; + + /// Cancel a scheduled, named task. If periodic, then it will cancel all further instances + /// of that, also. + /// + /// Will return an `Unavailable` error if the `id` is invalid. + /// + /// NOTE: This guaranteed to work only *before* the point that it is due to be executed. + /// If it ends up being delayed beyond the point of execution, then it cannot be cancelled. + fn cancel_named(id: TaskName) -> Result<(), DispatchError>; + + /// Reschedule a task. For one-off tasks, this dispatch is guaranteed to succeed + /// only if it is executed *before* the currently scheduled block. + /// + /// Will return an `Unavailable` error if the `id` is invalid. + fn reschedule_named( + id: TaskName, + when: DispatchTime, + ) -> Result; + + /// Return the next dispatch time for a given task. + /// + /// Will return an `Unavailable` error if the `id` is invalid. + fn next_dispatch_time(id: TaskName) -> Result; + } +} + +pub use v1::*; diff --git a/frame/support/src/traits/storage.rs b/frame/support/src/traits/storage.rs index d40d82c28e87e..24653d1899836 100644 --- a/frame/support/src/traits/storage.rs +++ b/frame/support/src/traits/storage.rs @@ -17,7 +17,9 @@ //! Traits for encoding data related to pallet's storage items. +use crate::sp_std::collections::btree_set::BTreeSet; use impl_trait_for_tuples::impl_for_tuples; +pub use sp_core::storage::TrackedStorageKey; use sp_std::prelude::*; /// An instance of a pallet in the storage. @@ -90,3 +92,29 @@ impl StorageInfoTrait for Tuple { pub trait PartialStorageInfoTrait { fn partial_storage_info() -> Vec; } + +/// Allows a pallet to specify storage keys to whitelist during benchmarking. +/// This means those keys will be excluded from the benchmarking performance +/// calculation. +pub trait WhitelistedStorageKeys { + /// Returns a [`Vec`] indicating the storage keys that + /// should be whitelisted during benchmarking. This means that those keys + /// will be excluded from the benchmarking performance calculation. + fn whitelisted_storage_keys() -> Vec; +} + +#[cfg_attr(all(not(feature = "tuples-96"), not(feature = "tuples-128")), impl_for_tuples(64))] +#[cfg_attr(all(feature = "tuples-96", not(feature = "tuples-128")), impl_for_tuples(96))] +#[cfg_attr(feature = "tuples-128", impl_for_tuples(128))] +impl WhitelistedStorageKeys for Tuple { + fn whitelisted_storage_keys() -> Vec { + // de-duplicate the storage keys + let mut combined_keys: BTreeSet = BTreeSet::new(); + for_tuples!( #( + for storage_key in Tuple::whitelisted_storage_keys() { + combined_keys.insert(storage_key); + } + )* ); + combined_keys.into_iter().collect::>() + } +} diff --git a/frame/support/src/traits/tokens/currency.rs b/frame/support/src/traits/tokens/currency.rs index 715758a959448..0bff46790117e 100644 --- a/frame/support/src/traits/tokens/currency.rs +++ b/frame/support/src/traits/tokens/currency.rs @@ -25,11 +25,15 @@ use crate::{ dispatch::{DispatchError, DispatchResult}, traits::Get, }; + use codec::{FullCodec, MaxEncodedLen}; use frame_support::Parameter; use mangata_types::{Balance as BalancePrimitive, TokenId}; use scale_info::TypeInfo; -use sp_runtime::traits::{AtLeast32BitUnsigned, MaybeSerializeDeserialize, Member}; +use sp_runtime::{ + traits::{AtLeast32BitUnsigned, MaybeSerializeDeserialize, Member}, + FixedPointOperand, +}; use sp_std::{fmt::Debug, result}; mod reservable; @@ -314,7 +318,7 @@ pub trait MultiTokenLockableCurrency: MultiTokenCurrency { /// Abstraction over a fungible assets system. pub trait Currency { /// The balance of an account. - type Balance: Balance + MaybeSerializeDeserialize + Debug + MaxEncodedLen; + type Balance: Balance + MaybeSerializeDeserialize + Debug + MaxEncodedLen + FixedPointOperand; /// The opaque token type for an imbalance. This is returned by unbalanced operations /// and must be dealt with. It may be dropped but cannot be cloned. diff --git a/frame/support/src/traits/tokens/fungibles.rs b/frame/support/src/traits/tokens/fungibles.rs index dab50d56962f6..e4108b7f80a98 100644 --- a/frame/support/src/traits/tokens/fungibles.rs +++ b/frame/support/src/traits/tokens/fungibles.rs @@ -31,6 +31,7 @@ pub mod metadata; pub use balanced::{Balanced, Unbalanced}; mod imbalance; pub use imbalance::{CreditOf, DebtOf, HandleImbalanceDrop, Imbalance}; +pub mod roles; /// Trait for providing balance-inspection access to a set of named fungible assets. pub trait Inspect { diff --git a/frame/transaction-payment-mangata/rpc/runtime-api/src/lib.rs b/frame/support/src/traits/tokens/fungibles/roles.rs similarity index 56% rename from frame/transaction-payment-mangata/rpc/runtime-api/src/lib.rs rename to frame/support/src/traits/tokens/fungibles/roles.rs index 3b1fffe3f720d..18fd1cc801210 100644 --- a/frame/transaction-payment-mangata/rpc/runtime-api/src/lib.rs +++ b/frame/support/src/traits/tokens/fungibles/roles.rs @@ -15,20 +15,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Runtime API definition for transaction payment pallet. +//! Inspect traits for Asset roles -#![cfg_attr(not(feature = "std"), no_std)] - -use codec::Codec; -use sp_runtime::traits::MaybeDisplay; - -pub use pallet_transaction_payment_mangata::{FeeDetails, InclusionFee, RuntimeDispatchInfo}; - -sp_api::decl_runtime_apis! { - pub trait TransactionPaymentApi where - Balance: Codec + MaybeDisplay, - { - fn query_info(uxt: Block::Extrinsic, len: u32) -> RuntimeDispatchInfo; - fn query_fee_details(uxt: Block::Extrinsic, len: u32) -> FeeDetails; - } +pub trait Inspect: super::Inspect { + // Get owner for an AssetId. + fn owner(asset: Self::AssetId) -> Option; + // Get issuer for an AssetId. + fn issuer(asset: Self::AssetId) -> Option; + // Get admin for an AssetId. + fn admin(asset: Self::AssetId) -> Option; + // Get freezer for an AssetId. + fn freezer(asset: Self::AssetId) -> Option; } diff --git a/frame/support/src/traits/try_runtime.rs b/frame/support/src/traits/try_runtime.rs index c5ddd1cae42be..640bb566a65af 100644 --- a/frame/support/src/traits/try_runtime.rs +++ b/frame/support/src/traits/try_runtime.rs @@ -17,46 +17,10 @@ //! Try-runtime specific traits and types. -use super::*; use impl_trait_for_tuples::impl_for_tuples; use sp_arithmetic::traits::AtLeast32BitUnsigned; use sp_std::prelude::*; -/// Prefix to be used (optionally) for implementing [`OnRuntimeUpgradeHelpersExt::storage_key`]. -const ON_RUNTIME_UPGRADE_PREFIX: &[u8] = b"__ON_RUNTIME_UPGRADE__"; - -/// Some helper functions for [`OnRuntimeUpgrade`] during `try-runtime` testing. -pub trait OnRuntimeUpgradeHelpersExt { - /// Generate a storage key unique to this runtime upgrade. - /// - /// This can be used to communicate data from pre-upgrade to post-upgrade state and check - /// them. See [`Self::set_temp_storage`] and [`Self::get_temp_storage`]. - fn storage_key(ident: &str) -> [u8; 32] { - crate::storage::storage_prefix(ON_RUNTIME_UPGRADE_PREFIX, ident.as_bytes()) - } - - /// Get temporary storage data written by [`Self::set_temp_storage`]. - /// - /// Returns `None` if either the data is unavailable or un-decodable. - /// - /// A `at` storage identifier must be provided to indicate where the storage is being read from. - fn get_temp_storage(at: &str) -> Option { - sp_io::storage::get(&Self::storage_key(at)) - .and_then(|bytes| codec::Decode::decode(&mut &*bytes).ok()) - } - - /// Write some temporary data to a specific storage that can be read (potentially in - /// post-upgrade hook) via [`Self::get_temp_storage`]. - /// - /// A `at` storage identifier must be provided to indicate where the storage is being written - /// to. - fn set_temp_storage(data: T, at: &str) { - sp_io::storage::set(&Self::storage_key(at), &data.encode()); - } -} - -impl OnRuntimeUpgradeHelpersExt for U {} - // Which state tests to execute. #[derive(codec::Encode, codec::Decode, Clone)] pub enum Select { @@ -68,7 +32,7 @@ pub enum Select { RoundRobin(u32), /// Run only pallets who's name matches the given list. /// - /// Pallet names are obtained from [`PalletInfoAccess`]. + /// Pallet names are obtained from [`super::PalletInfoAccess`]. Only(Vec>), } diff --git a/frame/support/src/weights.rs b/frame/support/src/weights.rs index b4fd896e865dc..9ff49b97bf21f 100644 --- a/frame/support/src/weights.rs +++ b/frame/support/src/weights.rs @@ -15,102 +15,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! # Primitives for transaction weighting. -//! -//! Every dispatchable function is responsible for providing `#[weight = $x]` attribute. In this -//! snipped, `$x` can be any user provided struct that implements the following traits: -//! -//! - [`WeighData`]: the weight amount. -//! - [`ClassifyDispatch`]: class of the dispatch. -//! - [`PaysFee`]: whether this weight should be translated to fee and deducted upon dispatch. -//! -//! Substrate then bundles the output information of the three traits into [`DispatchInfo`] struct -//! and provides it by implementing the [`GetDispatchInfo`] for all `Call` both inner and outer call -//! types. -//! -//! Substrate provides two pre-defined ways to annotate weight: -//! -//! ### 1. Fixed values -//! -//! This can only be used when all 3 traits can be resolved statically. You have 3 degrees of -//! configuration: -//! -//! 1. Define only weight, **in which case `ClassifyDispatch` will be `Normal` and `PaysFee` will be -//! `Yes`**. -//! -//! ``` -//! # use frame_system::Config; -//! frame_support::decl_module! { -//! pub struct Module for enum Call where origin: T::Origin { -//! #[weight = 1000] -//! fn dispatching(origin) { unimplemented!() } -//! } -//! } -//! # fn main() {} -//! ``` -//! -//! 2.1 Define weight and class, **in which case `PaysFee` would be `Yes`**. -//! -//! ``` -//! # use frame_system::Config; -//! # use frame_support::weights::DispatchClass; -//! frame_support::decl_module! { -//! pub struct Module for enum Call where origin: T::Origin { -//! #[weight = (1000, DispatchClass::Operational)] -//! fn dispatching(origin) { unimplemented!() } -//! } -//! } -//! # fn main() {} -//! ``` -//! -//! 2.2 Define weight and `PaysFee`, **in which case `ClassifyDispatch` would be `Normal`**. -//! -//! ``` -//! # use frame_system::Config; -//! # use frame_support::weights::Pays; -//! frame_support::decl_module! { -//! pub struct Module for enum Call where origin: T::Origin { -//! #[weight = (1000, Pays::No)] -//! fn dispatching(origin) { unimplemented!() } -//! } -//! } -//! # fn main() {} -//! ``` -//! -//! 3. Define all 3 parameters. -//! -//! ``` -//! # use frame_system::Config; -//! # use frame_support::weights::{DispatchClass, Pays}; -//! frame_support::decl_module! { -//! pub struct Module for enum Call where origin: T::Origin { -//! #[weight = (1000, DispatchClass::Operational, Pays::No)] -//! fn dispatching(origin) { unimplemented!() } -//! } -//! } -//! # fn main() {} -//! ``` -//! -//! ### 2. Define weights as a function of input arguments. -//! -//! The arguments of the dispatch are available in the weight expressions as a borrowed value. -//! -//! ``` -//! # use frame_system::Config; -//! # use frame_support::weights::{DispatchClass, Pays}; -//! frame_support::decl_module! { -//! pub struct Module for enum Call where origin: T::Origin { -//! #[weight = ( -//! *a as u64 + *b, -//! DispatchClass::Operational, -//! if *a > 1000 { Pays::Yes } else { Pays::No } -//! )] -//! fn dispatching(origin, a: u32, b: u64) { unimplemented!() } -//! } -//! } -//! # fn main() {} -//! ``` -//! FRAME assumes a weight of `1_000_000_000_000` equals 1 second of compute on a standard machine. +//! Re-exports `sp-weights` public API, and contains benchmarked weight constants specific to +//! FRAME. //! //! Latest machine specification used to benchmark are: //! - Digital Ocean: ubuntu-s-2vcpu-4gb-ams3-01 @@ -123,41 +29,14 @@ mod block_weights; mod extrinsic_weights; mod paritydb_weights; mod rocksdb_weights; -mod weight_v2; - -use crate::{ - dispatch::{DispatchError, DispatchErrorWithPostInfo, DispatchResultWithPostInfo}, - traits::Get, -}; -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; -#[cfg(feature = "std")] -use serde::{Deserialize, Serialize}; -use smallvec::SmallVec; -use sp_arithmetic::{ - traits::{BaseArithmetic, Saturating, Unsigned}, - Perbill, -}; -use sp_runtime::{ - generic::{CheckedExtrinsic, UncheckedExtrinsic}, - traits::{SaturatedConversion, SignedExtension}, - RuntimeDebug, -}; - -/// Re-export priority as type -pub use sp_runtime::transaction_validity::TransactionPriority; -pub use weight_v2::*; +use crate::dispatch; +pub use sp_weights::*; /// These constants are specific to FRAME, and the current implementation of its various components. /// For example: FRAME System, FRAME Executive, our FRAME support libraries, etc... pub mod constants { - use super::Weight; - - pub const WEIGHT_PER_SECOND: Weight = Weight::from_ref_time(1_000_000_000_000); - pub const WEIGHT_PER_MILLIS: Weight = Weight::from_ref_time(1_000_000_000); - pub const WEIGHT_PER_MICROS: Weight = Weight::from_ref_time(1_000_000); - pub const WEIGHT_PER_NANOS: Weight = Weight::from_ref_time(1_000); + pub use sp_weights::constants::*; // Expose the Block and Extrinsic base weights. pub use super::{block_weights::BlockExecutionWeight, extrinsic_weights::ExtrinsicBaseWeight}; @@ -168,786 +47,69 @@ pub mod constants { }; } -/// Means of weighing some particular kind of data (`T`). -pub trait WeighData { - /// Weigh the data `T` given by `target`. When implementing this for a dispatchable, `T` will be - /// a tuple of all arguments given to the function (except origin). - fn weigh_data(&self, target: T) -> Weight; -} - -/// Means of classifying a dispatchable function. -pub trait ClassifyDispatch { - /// Classify the dispatch function based on input data `target` of type `T`. When implementing - /// this for a dispatchable, `T` will be a tuple of all arguments given to the function (except - /// origin). - fn classify_dispatch(&self, target: T) -> DispatchClass; -} - -/// Indicates if dispatch function should pay fees or not. -/// If set to `Pays::No`, the block resource limits are applied, yet no fee is deducted. -pub trait PaysFee { - fn pays_fee(&self, _target: T) -> Pays; -} - -/// Explicit enum to denote if a transaction pays fee or not. -#[derive(Clone, Copy, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo)] -pub enum Pays { - /// Transactor will pay related fees. - Yes, - /// Transactor will NOT pay related fees. - No, -} - -impl Default for Pays { - fn default() -> Self { - Self::Yes - } -} - -impl From for PostDispatchInfo { - fn from(pays_fee: Pays) -> Self { - Self { actual_weight: None, pays_fee } - } -} - -/// A generalized group of dispatch types. -/// -/// NOTE whenever upgrading the enum make sure to also update -/// [DispatchClass::all] and [DispatchClass::non_mandatory] helper functions. -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] -#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug, TypeInfo)] -pub enum DispatchClass { - /// A normal dispatch. - Normal, - /// An operational dispatch. - Operational, - /// A mandatory dispatch. These kinds of dispatch are always included regardless of their - /// weight, therefore it is critical that they are separately validated to ensure that a - /// malicious validator cannot craft a valid but impossibly heavy block. Usually this just - /// means ensuring that the extrinsic can only be included once and that it is always very - /// light. - /// - /// Do *NOT* use it for extrinsics that can be heavy. - /// - /// The only real use case for this is inherent extrinsics that are required to execute in a - /// block for the block to be valid, and it solves the issue in the case that the block - /// initialization is sufficiently heavy to mean that those inherents do not fit into the - /// block. Essentially, we assume that in these exceptional circumstances, it is better to - /// allow an overweight block to be created than to not allow any block at all to be created. - Mandatory, -} - -impl Default for DispatchClass { - fn default() -> Self { - Self::Normal - } -} - -impl DispatchClass { - /// Returns an array containing all dispatch classes. - pub fn all() -> &'static [DispatchClass] { - &[DispatchClass::Normal, DispatchClass::Operational, DispatchClass::Mandatory] - } - - /// Returns an array of all dispatch classes except `Mandatory`. - pub fn non_mandatory() -> &'static [DispatchClass] { - &[DispatchClass::Normal, DispatchClass::Operational] - } -} - -/// A trait that represents one or many values of given type. -/// -/// Useful to accept as parameter type to let the caller pass either a single value directly -/// or an iterator. -pub trait OneOrMany { - /// The iterator type. - type Iter: Iterator; - /// Convert this item into an iterator. - fn into_iter(self) -> Self::Iter; -} - -impl OneOrMany for DispatchClass { - type Iter = sp_std::iter::Once; - fn into_iter(self) -> Self::Iter { - sp_std::iter::once(self) - } -} - -impl<'a> OneOrMany for &'a [DispatchClass] { - type Iter = sp_std::iter::Cloned>; - fn into_iter(self) -> Self::Iter { - self.iter().cloned() - } -} - -/// A bundle of static information collected from the `#[weight = $x]` attributes. -#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] -pub struct DispatchInfo { - /// Weight of this transaction. - pub weight: Weight, - /// Class of this transaction. - pub class: DispatchClass, - /// Does this transaction pay fees. - pub pays_fee: Pays, -} - -/// A `Dispatchable` function (aka transaction) that can carry some static information along with -/// it, using the `#[weight]` attribute. -pub trait GetDispatchInfo { - /// Return a `DispatchInfo`, containing relevant information of this dispatch. - /// - /// This is done independently of its encoded size. - fn get_dispatch_info(&self) -> DispatchInfo; -} - -impl GetDispatchInfo for () { - fn get_dispatch_info(&self) -> DispatchInfo { - DispatchInfo::default() - } -} - -/// Weight information that is only available post dispatch. -/// NOTE: This can only be used to reduce the weight or fee, not increase it. -#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] -pub struct PostDispatchInfo { - /// Actual weight consumed by a call or `None` which stands for the worst case static weight. - pub actual_weight: Option, - /// Whether this transaction should pay fees when all is said and done. - pub pays_fee: Pays, -} - -impl PostDispatchInfo { - /// Calculate how much (if any) weight was not used by the `Dispatchable`. - pub fn calc_unspent(&self, info: &DispatchInfo) -> Weight { - info.weight - self.calc_actual_weight(info) - } - - /// Calculate how much weight was actually spent by the `Dispatchable`. - pub fn calc_actual_weight(&self, info: &DispatchInfo) -> Weight { - if let Some(actual_weight) = self.actual_weight { - actual_weight.min(info.weight) - } else { - info.weight - } - } - - /// Determine if user should actually pay fees at the end of the dispatch. - pub fn pays_fee(&self, info: &DispatchInfo) -> Pays { - // If they originally were not paying fees, or the post dispatch info - // says they should not pay fees, then they don't pay fees. - // This is because the pre dispatch information must contain the - // worst case for weight and fees paid. - if info.pays_fee == Pays::No || self.pays_fee == Pays::No { - Pays::No - } else { - // Otherwise they pay. - Pays::Yes - } - } -} - -/// Extract the actual weight from a dispatch result if any or fall back to the default weight. -pub fn extract_actual_weight(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Weight { - match result { - Ok(post_info) => post_info, - Err(err) => &err.post_info, - } - .calc_actual_weight(info) -} - -/// Extract the actual pays_fee from a dispatch result if any or fall back to the default weight. -pub fn extract_actual_pays_fee(result: &DispatchResultWithPostInfo, info: &DispatchInfo) -> Pays { - match result { - Ok(post_info) => post_info, - Err(err) => &err.post_info, - } - .pays_fee(info) -} - -impl From<()> for PostDispatchInfo { - fn from(_: ()) -> Self { - Self { actual_weight: None, pays_fee: Default::default() } - } -} - -impl sp_runtime::traits::Printable for PostDispatchInfo { - fn print(&self) { - "actual_weight=".print(); - match self.actual_weight { - Some(weight) => weight.print(), - None => "max-weight".print(), - }; - "pays_fee=".print(); - match self.pays_fee { - Pays::Yes => "Yes".print(), - Pays::No => "No".print(), - } - } -} - -/// Allows easy conversion from `DispatchError` to `DispatchErrorWithPostInfo` for dispatchables -/// that want to return a custom a posterior weight on error. -pub trait WithPostDispatchInfo { - /// Call this on your modules custom errors type in order to return a custom weight on error. - /// - /// # Example - /// - /// ```ignore - /// let who = ensure_signed(origin).map_err(|e| e.with_weight(Weight::from_ref_time(100)))?; - /// ensure!(who == me, Error::::NotMe.with_weight(200_000)); - /// ``` - fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo; -} - -impl WithPostDispatchInfo for T -where - T: Into, -{ - fn with_weight(self, actual_weight: Weight) -> DispatchErrorWithPostInfo { - DispatchErrorWithPostInfo { - post_info: PostDispatchInfo { - actual_weight: Some(actual_weight), - pays_fee: Default::default(), - }, - error: self.into(), - } - } -} - -/// Implementation for unchecked extrinsic. -impl GetDispatchInfo - for UncheckedExtrinsic -where - Call: GetDispatchInfo, - Extra: SignedExtension, -{ - fn get_dispatch_info(&self) -> DispatchInfo { - self.function.get_dispatch_info() - } -} - -/// Implementation for checked extrinsic. -impl GetDispatchInfo for CheckedExtrinsic -where - Call: GetDispatchInfo, -{ - fn get_dispatch_info(&self) -> DispatchInfo { - self.function.get_dispatch_info() - } -} - -/// Implementation for test extrinsic. -#[cfg(feature = "std")] -impl GetDispatchInfo for sp_runtime::testing::TestXt { - fn get_dispatch_info(&self) -> DispatchInfo { - // for testing: weight == size. - DispatchInfo { - weight: Weight::from_ref_time(self.encode().len() as _), - pays_fee: Pays::Yes, - ..Default::default() - } - } -} - -/// The weight of database operations that the runtime can invoke. -/// -/// NOTE: This is currently only measured in computational time, and will probably -/// be updated all together once proof size is accounted for. -#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] -pub struct RuntimeDbWeight { - pub read: u64, - pub write: u64, -} - -impl RuntimeDbWeight { - pub fn reads(self, r: u64) -> Weight { - Weight::from_ref_time(self.read.saturating_mul(r)) - } - - pub fn writes(self, w: u64) -> Weight { - Weight::from_ref_time(self.write.saturating_mul(w)) - } - - pub fn reads_writes(self, r: u64, w: u64) -> Weight { - let read_weight = self.read.saturating_mul(r); - let write_weight = self.write.saturating_mul(w); - Weight::from_ref_time(read_weight.saturating_add(write_weight)) - } -} - -/// One coefficient and its position in the `WeightToFee`. -/// -/// One term of polynomial is calculated as: -/// -/// ```ignore -/// coeff_integer * x^(degree) + coeff_frac * x^(degree) -/// ``` -/// -/// The `negative` value encodes whether the term is added or substracted from the -/// overall polynomial result. -#[derive(Clone, Encode, Decode, TypeInfo)] -pub struct WeightToFeeCoefficient { - /// The integral part of the coefficient. - pub coeff_integer: Balance, - /// The fractional part of the coefficient. - pub coeff_frac: Perbill, - /// True iff the coefficient should be interpreted as negative. - pub negative: bool, - /// Degree/exponent of the term. - pub degree: u8, -} - -/// A list of coefficients that represent one polynomial. -pub type WeightToFeeCoefficients = SmallVec<[WeightToFeeCoefficient; 4]>; - -/// A trait that describes the weight to fee calculation. -pub trait WeightToFee { - /// The type that is returned as result from calculation. - type Balance: BaseArithmetic + From + Copy + Unsigned; - - /// Calculates the fee from the passed `weight`. - fn weight_to_fee(weight: &Weight) -> Self::Balance; -} - -/// A trait that describes the weight to fee calculation as polynomial. -/// -/// An implementor should only implement the `polynomial` function. -pub trait WeightToFeePolynomial { - /// The type that is returned as result from polynomial evaluation. - type Balance: BaseArithmetic + From + Copy + Unsigned; - - /// Returns a polynomial that describes the weight to fee conversion. - /// - /// This is the only function that should be manually implemented. Please note - /// that all calculation is done in the probably unsigned `Balance` type. This means - /// that the order of coefficients is important as putting the negative coefficients - /// first will most likely saturate the result to zero mid evaluation. - fn polynomial() -> WeightToFeeCoefficients; -} - -impl WeightToFee for T -where - T: WeightToFeePolynomial, -{ - type Balance = ::Balance; - - /// Calculates the fee from the passed `weight` according to the `polynomial`. - /// - /// This should not be overridden in most circumstances. Calculation is done in the - /// `Balance` type and never overflows. All evaluation is saturating. - fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::polynomial() - .iter() - .fold(Self::Balance::saturated_from(0u32), |mut acc, args| { - let w = Self::Balance::saturated_from(weight.ref_time()) - .saturating_pow(args.degree.into()); - - // The sum could get negative. Therefore we only sum with the accumulator. - // The Perbill Mul implementation is non overflowing. - let frac = args.coeff_frac * w; - let integer = args.coeff_integer.saturating_mul(w); - - if args.negative { - acc = acc.saturating_sub(frac); - acc = acc.saturating_sub(integer); - } else { - acc = acc.saturating_add(frac); - acc = acc.saturating_add(integer); - } - - acc - }) - } -} - -/// Implementor of `WeightToFee` that maps one unit of weight to one unit of fee. -pub struct IdentityFee(sp_std::marker::PhantomData); - -impl WeightToFee for IdentityFee -where - T: BaseArithmetic + From + Copy + Unsigned, -{ - type Balance = T; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(weight.ref_time()) - } -} - -/// Implementor of [`WeightToFee`] that uses a constant multiplier. -/// # Example -/// -/// ``` -/// # use frame_support::traits::ConstU128; -/// # use frame_support::weights::ConstantMultiplier; -/// // Results in a multiplier of 10 for each unit of weight (or length) -/// type LengthToFee = ConstantMultiplier::>; -/// ``` -pub struct ConstantMultiplier(sp_std::marker::PhantomData<(T, M)>); - -impl WeightToFee for ConstantMultiplier -where - T: BaseArithmetic + From + Copy + Unsigned, - M: Get, -{ - type Balance = T; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(weight.ref_time()).saturating_mul(M::get()) - } -} - -/// A struct holding value for each `DispatchClass`. -#[derive(Clone, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] -pub struct PerDispatchClass { - /// Value for `Normal` extrinsics. - normal: T, - /// Value for `Operational` extrinsics. - operational: T, - /// Value for `Mandatory` extrinsics. - mandatory: T, -} - -impl PerDispatchClass { - /// Create new `PerDispatchClass` with the same value for every class. - pub fn new(val: impl Fn(DispatchClass) -> T) -> Self { - Self { - normal: val(DispatchClass::Normal), - operational: val(DispatchClass::Operational), - mandatory: val(DispatchClass::Mandatory), - } - } - - /// Get a mutable reference to current value of given class. - pub fn get_mut(&mut self, class: DispatchClass) -> &mut T { - match class { - DispatchClass::Operational => &mut self.operational, - DispatchClass::Normal => &mut self.normal, - DispatchClass::Mandatory => &mut self.mandatory, - } - } - - /// Get current value for given class. - pub fn get(&self, class: DispatchClass) -> &T { - match class { - DispatchClass::Normal => &self.normal, - DispatchClass::Operational => &self.operational, - DispatchClass::Mandatory => &self.mandatory, - } - } -} - -impl PerDispatchClass { - /// Set the value of given class. - pub fn set(&mut self, new: T, class: impl OneOrMany) { - for class in class.into_iter() { - *self.get_mut(class) = new.clone(); - } - } -} - -impl PerDispatchClass { - /// Returns the total weight consumed by all extrinsics in the block. - pub fn total(&self) -> Weight { - let mut sum = Weight::zero(); - for class in DispatchClass::all() { - sum = sum.saturating_add(*self.get(*class)); - } - sum - } - - /// Add some weight of a specific dispatch class, saturating at the numeric bounds of `Weight`. - pub fn add(&mut self, weight: Weight, class: DispatchClass) { - let value = self.get_mut(class); - *value = value.saturating_add(weight); - } - - /// Try to add some weight of a specific dispatch class, returning Err(()) if overflow would - /// occur. - pub fn checked_add(&mut self, weight: Weight, class: DispatchClass) -> Result<(), ()> { - let value = self.get_mut(class); - *value = value.checked_add(&weight).ok_or(())?; - Ok(()) - } - - /// Subtract some weight of a specific dispatch class, saturating at the numeric bounds of - /// `Weight`. - pub fn sub(&mut self, weight: Weight, class: DispatchClass) { - let value = self.get_mut(class); - *value = value.saturating_sub(weight); - } -} - -#[cfg(test)] -#[allow(dead_code)] -mod tests { - use super::*; - use crate::{decl_module, parameter_types, traits::Get}; - use smallvec::smallvec; - - pub trait Config: 'static { - type Origin; - type Balance; - type BlockNumber; - type DbWeight: Get; - type PalletInfo: crate::traits::PalletInfo; - } - - pub struct TraitImpl {} - - parameter_types! { - pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { - read: 100, - write: 1000, - }; - } - - impl Config for TraitImpl { - type Origin = u32; - type BlockNumber = u32; - type Balance = u32; - type DbWeight = DbWeight; - type PalletInfo = crate::tests::PanicPalletInfo; - } - - decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self { - // no arguments, fixed weight - #[weight = 1000] - fn f00(_origin) { unimplemented!(); } - - #[weight = (1000, DispatchClass::Mandatory)] - fn f01(_origin) { unimplemented!(); } - - #[weight = (1000, Pays::No)] - fn f02(_origin) { unimplemented!(); } - - #[weight = (1000, DispatchClass::Operational, Pays::No)] - fn f03(_origin) { unimplemented!(); } - - // weight = a x 10 + b - #[weight = ((_a * 10 + _eb * 1) as u64, DispatchClass::Normal, Pays::Yes)] - fn f11(_origin, _a: u32, _eb: u32) { unimplemented!(); } - - #[weight = (0, DispatchClass::Operational, Pays::Yes)] - fn f12(_origin, _a: u32, _eb: u32) { unimplemented!(); } - - #[weight = T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + Weight::from_ref_time(10_000)] - fn f20(_origin) { unimplemented!(); } - - #[weight = T::DbWeight::get().reads_writes(6, 5) + Weight::from_ref_time(40_000)] - fn f21(_origin) { unimplemented!(); } - - } - } - - #[test] - fn weights_are_correct() { - // #[weight = 1000] - let info = Call::::f00 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_ref_time(1000)); - assert_eq!(info.class, DispatchClass::Normal); - assert_eq!(info.pays_fee, Pays::Yes); - - // #[weight = (1000, DispatchClass::Mandatory)] - let info = Call::::f01 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_ref_time(1000)); - assert_eq!(info.class, DispatchClass::Mandatory); - assert_eq!(info.pays_fee, Pays::Yes); - - // #[weight = (1000, Pays::No)] - let info = Call::::f02 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_ref_time(1000)); - assert_eq!(info.class, DispatchClass::Normal); - assert_eq!(info.pays_fee, Pays::No); - - // #[weight = (1000, DispatchClass::Operational, Pays::No)] - let info = Call::::f03 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_ref_time(1000)); - assert_eq!(info.class, DispatchClass::Operational); - assert_eq!(info.pays_fee, Pays::No); - - // #[weight = ((_a * 10 + _eb * 1) as Weight, DispatchClass::Normal, Pays::Yes)] - let info = Call::::f11 { _a: 13, _eb: 20 }.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_ref_time(150)); // 13*10 + 20 - assert_eq!(info.class, DispatchClass::Normal); - assert_eq!(info.pays_fee, Pays::Yes); - - // #[weight = (0, DispatchClass::Operational, Pays::Yes)] - let info = Call::::f12 { _a: 10, _eb: 20 }.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_ref_time(0)); - assert_eq!(info.class, DispatchClass::Operational); - assert_eq!(info.pays_fee, Pays::Yes); - - // #[weight = T::DbWeight::get().reads(3) + T::DbWeight::get().writes(2) + 10_000] - let info = Call::::f20 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_ref_time(12300)); // 100*3 + 1000*2 + 10_1000 - assert_eq!(info.class, DispatchClass::Normal); - assert_eq!(info.pays_fee, Pays::Yes); - - // #[weight = T::DbWeight::get().reads_writes(6, 5) + 40_000] - let info = Call::::f21 {}.get_dispatch_info(); - assert_eq!(info.weight, Weight::from_ref_time(45600)); // 100*6 + 1000*5 + 40_1000 - assert_eq!(info.class, DispatchClass::Normal); - assert_eq!(info.pays_fee, Pays::Yes); - } - - #[test] - fn extract_actual_weight_works() { - let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; - assert_eq!(extract_actual_weight(&Ok(Some(7).into()), &pre), Weight::from_ref_time(7)); - assert_eq!( - extract_actual_weight(&Ok(Some(1000).into()), &pre), - Weight::from_ref_time(1000) - ); - assert_eq!( - extract_actual_weight( - &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(9))), - &pre - ), - Weight::from_ref_time(9) - ); - } - - #[test] - fn extract_actual_weight_caps_at_pre_weight() { - let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; - assert_eq!( - extract_actual_weight(&Ok(Some(1250).into()), &pre), - Weight::from_ref_time(1000) - ); - assert_eq!( - extract_actual_weight( - &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(1300))), - &pre - ), - Weight::from_ref_time(1000), - ); - } - - #[test] - fn extract_actual_pays_fee_works() { - let pre = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; - assert_eq!(extract_actual_pays_fee(&Ok(Some(7).into()), &pre), Pays::Yes); - assert_eq!(extract_actual_pays_fee(&Ok(Some(1000).into()), &pre), Pays::Yes); - assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::Yes); - assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::No).into()), &pre), Pays::No); - assert_eq!( - extract_actual_pays_fee( - &Err(DispatchError::BadOrigin.with_weight(Weight::from_ref_time(9))), - &pre - ), - Pays::Yes - ); - assert_eq!( - extract_actual_pays_fee( - &Err(DispatchErrorWithPostInfo { - post_info: PostDispatchInfo { actual_weight: None, pays_fee: Pays::No }, - error: DispatchError::BadOrigin, - }), - &pre - ), - Pays::No - ); - - let pre = DispatchInfo { - weight: Weight::from_ref_time(1000), - pays_fee: Pays::No, - ..Default::default() - }; - assert_eq!(extract_actual_pays_fee(&Ok(Some(7).into()), &pre), Pays::No); - assert_eq!(extract_actual_pays_fee(&Ok(Some(1000).into()), &pre), Pays::No); - assert_eq!(extract_actual_pays_fee(&Ok((Some(1000), Pays::Yes).into()), &pre), Pays::No); - } - - type Balance = u64; - - // 0.5x^3 + 2.333x^2 + 7x - 10_000 - struct Poly; - impl WeightToFeePolynomial for Poly { - type Balance = Balance; - - fn polynomial() -> WeightToFeeCoefficients { - smallvec![ - WeightToFeeCoefficient { - coeff_integer: 0, - coeff_frac: Perbill::from_float(0.5), - negative: false, - degree: 3 - }, - WeightToFeeCoefficient { - coeff_integer: 2, - coeff_frac: Perbill::from_rational(1u32, 3u32), - negative: false, - degree: 2 - }, - WeightToFeeCoefficient { - coeff_integer: 7, - coeff_frac: Perbill::zero(), - negative: false, - degree: 1 - }, - WeightToFeeCoefficient { - coeff_integer: 10_000, - coeff_frac: Perbill::zero(), - negative: true, - degree: 0 - }, - ] - } - } - - #[test] - fn polynomial_works() { - // 100^3/2=500000 100^2*(2+1/3)=23333 700 -10000 - assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(100)), 514033); - // 10123^3/2=518677865433 10123^2*(2+1/3)=239108634 70861 -10000 - assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(10_123)), 518917034928); - } - - #[test] - fn polynomial_does_not_underflow() { - assert_eq!(Poly::weight_to_fee(&Weight::zero()), 0); - assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(10)), 0); - } - - #[test] - fn polynomial_does_not_overflow() { - assert_eq!(Poly::weight_to_fee(&Weight::MAX), Balance::max_value() - 10_000); - } - - #[test] - fn identity_fee_works() { - assert_eq!(IdentityFee::::weight_to_fee(&Weight::zero()), 0); - assert_eq!(IdentityFee::::weight_to_fee(&Weight::from_ref_time(50)), 50); - assert_eq!(IdentityFee::::weight_to_fee(&Weight::MAX), Balance::max_value()); - } - - #[test] - fn constant_fee_works() { - use crate::traits::ConstU128; - assert_eq!( - ConstantMultiplier::>::weight_to_fee(&Weight::zero()), - 0 - ); - assert_eq!( - ConstantMultiplier::>::weight_to_fee(&Weight::from_ref_time( - 50 - )), - 500 - ); - assert_eq!( - ConstantMultiplier::>::weight_to_fee(&Weight::from_ref_time( - 16 - )), - 16384 - ); - assert_eq!( - ConstantMultiplier::>::weight_to_fee( - &Weight::from_ref_time(2) - ), - u128::MAX - ); +#[deprecated = "Function has moved to `frame_support::dispatch`"] +pub fn extract_actual_pays_fee( + res: &dispatch::DispatchResultWithPostInfo, + info: &dispatch::DispatchInfo, +) -> dispatch::Pays { + dispatch::extract_actual_pays_fee(res, info) +} +#[deprecated = "Function has moved to `frame_support::dispatch`"] +pub fn extract_actual_weight( + res: &dispatch::DispatchResultWithPostInfo, + info: &dispatch::DispatchInfo, +) -> Weight { + dispatch::extract_actual_weight(res, info) +} +#[deprecated = "Trait has moved to `frame_support::dispatch`"] +pub trait ClassifyDispatch: dispatch::ClassifyDispatch { + fn classify_dispatch(&self, target: T) -> dispatch::DispatchClass { + >::classify_dispatch(self, target) + } +} +#[deprecated = "Enum has moved to `frame_support::dispatch`"] +pub type DispatchClass = dispatch::DispatchClass; +#[deprecated = "Struct has moved to `frame_support::dispatch`"] +pub type DispatchInfo = dispatch::DispatchInfo; +#[deprecated = "Trait has moved to `frame_support::dispatch`"] +pub trait GetDispatchInfo: dispatch::GetDispatchInfo { + fn get_dispatch_info(&self) -> dispatch::DispatchInfo { + ::get_dispatch_info(self) + } +} +#[deprecated = "Trait has moved to `frame_support::dispatch`"] +pub trait OneOrMany: dispatch::OneOrMany { + fn into_iter(self) -> Self::Iter + where + Self: Sized, + { + >::into_iter(self) + } +} +#[deprecated = "Enum has moved to `frame_support::dispatch`"] +pub type Pays = dispatch::Pays; +#[deprecated = "Trait has moved to `frame_support::dispatch`"] +pub trait PaysFee: dispatch::PaysFee { + fn pays_fee(&self, target: T) -> dispatch::Pays { + >::pays_fee(self, target) + } +} +#[deprecated = "Struct has moved to `frame_support::dispatch`"] +pub type PerDispatchClass = dispatch::PerDispatchClass; +#[deprecated = "Struct has moved to `frame_support::dispatch`"] +pub type PostDispatchInfo = dispatch::PostDispatchInfo; +#[deprecated = "Trait has moved to `frame_support::dispatch`"] +pub trait WeighData: dispatch::WeighData { + fn weigh_data(&self, target: T) -> Weight { + >::weigh_data(self, target) + } +} +#[deprecated = "Trait has moved to `frame_support::dispatch`"] +pub trait WithPostDispatchInfo: dispatch::WithPostDispatchInfo { + fn with_weight(self, actual_weight: Weight) -> dispatch::DispatchErrorWithPostInfo + where + Self: Sized, + { + ::with_weight(self, actual_weight) } } diff --git a/frame/support/src/weights/block_weights.rs b/frame/support/src/weights/block_weights.rs index 51f707b2b0df5..240b80460aa09 100644 --- a/frame/support/src/weights/block_weights.rs +++ b/frame/support/src/weights/block_weights.rs @@ -34,10 +34,8 @@ // --warmup=10 // --repeat=100 -use frame_support::{ - parameter_types, - weights::{constants::WEIGHT_PER_NANOS, Weight}, -}; +use sp_core::parameter_types; +use sp_weights::{constants::WEIGHT_PER_NANOS, Weight}; parameter_types! { /// Time to execute an empty block. @@ -58,7 +56,7 @@ parameter_types! { #[cfg(test)] mod test_weights { - use frame_support::weights::constants; + use sp_weights::constants; /// Checks that the weight exists and is sane. // NOTE: If this test fails but you are sure that the generated values are fine, @@ -68,8 +66,14 @@ mod test_weights { let w = super::BlockExecutionWeight::get(); // At least 100 µs. - assert!(w >= 100u32 * constants::WEIGHT_PER_MICROS, "Weight should be at least 100 µs."); + assert!( + w.ref_time() >= 100u64 * constants::WEIGHT_PER_MICROS.ref_time(), + "Weight should be at least 100 µs." + ); // At most 50 ms. - assert!(w <= 50u32 * constants::WEIGHT_PER_MILLIS, "Weight should be at most 50 ms."); + assert!( + w.ref_time() <= 50u64 * constants::WEIGHT_PER_MILLIS.ref_time(), + "Weight should be at most 50 ms." + ); } } diff --git a/frame/support/src/weights/extrinsic_weights.rs b/frame/support/src/weights/extrinsic_weights.rs index 2bee1059b0dad..913dbc4e91fc1 100644 --- a/frame/support/src/weights/extrinsic_weights.rs +++ b/frame/support/src/weights/extrinsic_weights.rs @@ -34,10 +34,8 @@ // --warmup=10 // --repeat=100 -use frame_support::{ - parameter_types, - weights::{constants::WEIGHT_PER_NANOS, Weight}, -}; +use sp_core::parameter_types; +use sp_weights::{constants::WEIGHT_PER_NANOS, Weight}; parameter_types! { /// Time to execute a NO-OP extrinsic, for example `System::remark`. @@ -58,7 +56,7 @@ parameter_types! { #[cfg(test)] mod test_weights { - use frame_support::weights::constants; + use sp_weights::constants; /// Checks that the weight exists and is sane. // NOTE: If this test fails but you are sure that the generated values are fine, @@ -68,8 +66,14 @@ mod test_weights { let w = super::ExtrinsicBaseWeight::get(); // At least 10 µs. - assert!(w >= 10u32 * constants::WEIGHT_PER_MICROS, "Weight should be at least 10 µs."); + assert!( + w.ref_time() >= 10u64 * constants::WEIGHT_PER_MICROS.ref_time(), + "Weight should be at least 10 µs." + ); // At most 1 ms. - assert!(w <= constants::WEIGHT_PER_MILLIS, "Weight should be at most 1 ms."); + assert!( + w.ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), + "Weight should be at most 1 ms." + ); } } diff --git a/frame/support/src/weights/paritydb_weights.rs b/frame/support/src/weights/paritydb_weights.rs index f498991729d7a..344e6cf0ddb6e 100644 --- a/frame/support/src/weights/paritydb_weights.rs +++ b/frame/support/src/weights/paritydb_weights.rs @@ -16,10 +16,9 @@ // limitations under the License. pub mod constants { - use frame_support::{ - parameter_types, - weights::{constants, RuntimeDbWeight}, - }; + use frame_support::weights::constants; + use sp_core::parameter_types; + use sp_weights::RuntimeDbWeight; parameter_types! { /// ParityDB can be enabled with a feature flag, but is still experimental. These weights @@ -33,7 +32,7 @@ pub mod constants { #[cfg(test)] mod test_db_weights { use super::constants::ParityDbWeight as W; - use frame_support::weights::constants; + use sp_weights::constants; /// Checks that all weights exist and have sane values. // NOTE: If this test fails but you are sure that the generated values are fine, @@ -42,20 +41,20 @@ pub mod constants { fn sane() { // At least 1 µs. assert!( - W::get().reads(1) >= constants::WEIGHT_PER_MICROS, + W::get().reads(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), "Read weight should be at least 1 µs." ); assert!( - W::get().writes(1) >= constants::WEIGHT_PER_MICROS, + W::get().writes(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), "Write weight should be at least 1 µs." ); // At most 1 ms. assert!( - W::get().reads(1) <= constants::WEIGHT_PER_MILLIS, + W::get().reads(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), "Read weight should be at most 1 ms." ); assert!( - W::get().writes(1) <= constants::WEIGHT_PER_MILLIS, + W::get().writes(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), "Write weight should be at most 1 ms." ); } diff --git a/frame/support/src/weights/rocksdb_weights.rs b/frame/support/src/weights/rocksdb_weights.rs index 67571c4723f94..4dec2d8c877ea 100644 --- a/frame/support/src/weights/rocksdb_weights.rs +++ b/frame/support/src/weights/rocksdb_weights.rs @@ -16,10 +16,9 @@ // limitations under the License. pub mod constants { - use frame_support::{ - parameter_types, - weights::{constants, RuntimeDbWeight}, - }; + use frame_support::weights::constants; + use sp_core::parameter_types; + use sp_weights::RuntimeDbWeight; parameter_types! { /// By default, Substrate uses RocksDB, so this will be the weight used throughout @@ -33,7 +32,7 @@ pub mod constants { #[cfg(test)] mod test_db_weights { use super::constants::RocksDbWeight as W; - use frame_support::weights::constants; + use sp_weights::constants; /// Checks that all weights exist and have sane values. // NOTE: If this test fails but you are sure that the generated values are fine, @@ -42,20 +41,20 @@ pub mod constants { fn sane() { // At least 1 µs. assert!( - W::get().reads(1) >= constants::WEIGHT_PER_MICROS, + W::get().reads(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), "Read weight should be at least 1 µs." ); assert!( - W::get().writes(1) >= constants::WEIGHT_PER_MICROS, + W::get().writes(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), "Write weight should be at least 1 µs." ); // At most 1 ms. assert!( - W::get().reads(1) <= constants::WEIGHT_PER_MILLIS, + W::get().reads(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), "Read weight should be at most 1 ms." ); assert!( - W::get().writes(1) <= constants::WEIGHT_PER_MILLIS, + W::get().writes(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), "Write weight should be at most 1 ms." ); } diff --git a/frame/support/src/weights/weight_v2.rs b/frame/support/src/weights/weight_v2.rs deleted file mode 100644 index 4bfab36663394..0000000000000 --- a/frame/support/src/weights/weight_v2.rs +++ /dev/null @@ -1,472 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use codec::{CompactAs, Decode, Encode, MaxEncodedLen}; -use core::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign}; -use sp_runtime::{ - traits::{Bounded, CheckedAdd, CheckedSub, Zero}, - RuntimeDebug, -}; - -use super::*; - -#[derive( - Encode, - Decode, - MaxEncodedLen, - TypeInfo, - Eq, - PartialEq, - Copy, - Clone, - RuntimeDebug, - Default, - Ord, - PartialOrd, - CompactAs, -)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct Weight { - /// The weight of computational time used based on some reference hardware. - ref_time: u64, -} - -impl Weight { - /// Set the reference time part of the weight. - pub const fn set_ref_time(mut self, c: u64) -> Self { - self.ref_time = c; - self - } - - /// Return the reference time part of the weight. - pub const fn ref_time(&self) -> u64 { - self.ref_time - } - - /// Return a mutable reference time part of the weight. - pub fn ref_time_mut(&mut self) -> &mut u64 { - &mut self.ref_time - } - - pub const MAX: Self = Self { ref_time: u64::MAX }; - - /// Get the conservative min of `self` and `other` weight. - pub fn min(&self, other: Self) -> Self { - Self { ref_time: self.ref_time.min(other.ref_time) } - } - - /// Get the aggressive max of `self` and `other` weight. - pub fn max(&self, other: Self) -> Self { - Self { ref_time: self.ref_time.max(other.ref_time) } - } - - /// Try to add some `other` weight while upholding the `limit`. - pub fn try_add(&self, other: &Self, limit: &Self) -> Option { - let total = self.checked_add(other)?; - if total.ref_time > limit.ref_time { - None - } else { - Some(total) - } - } - - /// Construct [`Weight`] with reference time weight. - pub const fn from_ref_time(ref_time: u64) -> Self { - Self { ref_time } - } - - /// Saturating [`Weight`] addition. Computes `self + rhs`, saturating at the numeric bounds of - /// all fields instead of overflowing. - pub const fn saturating_add(self, rhs: Self) -> Self { - Self { ref_time: self.ref_time.saturating_add(rhs.ref_time) } - } - - /// Saturating [`Weight`] subtraction. Computes `self - rhs`, saturating at the numeric bounds - /// of all fields instead of overflowing. - pub const fn saturating_sub(self, rhs: Self) -> Self { - Self { ref_time: self.ref_time.saturating_sub(rhs.ref_time) } - } - - /// Saturating [`Weight`] scalar multiplication. Computes `self.field * scalar` for all fields, - /// saturating at the numeric bounds of all fields instead of overflowing. - pub const fn saturating_mul(self, scalar: u64) -> Self { - Self { ref_time: self.ref_time.saturating_mul(scalar) } - } - - /// Saturating [`Weight`] scalar division. Computes `self.field / scalar` for all fields, - /// saturating at the numeric bounds of all fields instead of overflowing. - pub const fn saturating_div(self, scalar: u64) -> Self { - Self { ref_time: self.ref_time.saturating_div(scalar) } - } - - /// Saturating [`Weight`] scalar exponentiation. Computes `self.field.pow(exp)` for all fields, - /// saturating at the numeric bounds of all fields instead of overflowing. - pub const fn saturating_pow(self, exp: u32) -> Self { - Self { ref_time: self.ref_time.saturating_pow(exp) } - } - - /// Increment [`Weight`] by `amount` via saturating addition. - pub fn saturating_accrue(&mut self, amount: Self) { - *self = self.saturating_add(amount); - } - - /// Checked [`Weight`] addition. Computes `self + rhs`, returning `None` if overflow occurred. - pub const fn checked_add(&self, rhs: &Self) -> Option { - match self.ref_time.checked_add(rhs.ref_time) { - Some(ref_time) => Some(Self { ref_time }), - None => None, - } - } - - /// Checked [`Weight`] subtraction. Computes `self - rhs`, returning `None` if overflow - /// occurred. - pub const fn checked_sub(&self, rhs: &Self) -> Option { - match self.ref_time.checked_sub(rhs.ref_time) { - Some(ref_time) => Some(Self { ref_time }), - None => None, - } - } - - /// Checked [`Weight`] scalar multiplication. Computes `self.field * scalar` for each field, - /// returning `None` if overflow occurred. - pub const fn checked_mul(self, scalar: u64) -> Option { - match self.ref_time.checked_mul(scalar) { - Some(ref_time) => Some(Self { ref_time }), - None => None, - } - } - - /// Checked [`Weight`] scalar division. Computes `self.field / scalar` for each field, returning - /// `None` if overflow occurred. - pub const fn checked_div(self, scalar: u64) -> Option { - match self.ref_time.checked_div(scalar) { - Some(ref_time) => Some(Self { ref_time }), - None => None, - } - } - - /// Return a [`Weight`] where all fields are zero. - pub const fn zero() -> Self { - Self { ref_time: 0 } - } -} - -impl Zero for Weight { - fn zero() -> Self { - Self::zero() - } - - fn is_zero(&self) -> bool { - self.ref_time == 0 - } -} - -impl Add for Weight { - type Output = Self; - fn add(self, rhs: Self) -> Self { - Self { ref_time: self.ref_time + rhs.ref_time } - } -} - -impl Sub for Weight { - type Output = Self; - fn sub(self, rhs: Self) -> Self { - Self { ref_time: self.ref_time - rhs.ref_time } - } -} - -impl Mul for Weight -where - T: Mul + Copy, -{ - type Output = Self; - fn mul(self, b: T) -> Self { - Self { ref_time: b * self.ref_time } - } -} - -macro_rules! weight_mul_per_impl { - ($($t:ty),* $(,)?) => { - $( - impl Mul for $t { - type Output = Weight; - fn mul(self, b: Weight) -> Weight { - Weight { ref_time: self * b.ref_time } - } - } - )* - } -} -weight_mul_per_impl!( - sp_runtime::Percent, - sp_runtime::PerU16, - sp_runtime::Permill, - sp_runtime::Perbill, - sp_runtime::Perquintill, -); - -macro_rules! weight_mul_primitive_impl { - ($($t:ty),* $(,)?) => { - $( - impl Mul for $t { - type Output = Weight; - fn mul(self, b: Weight) -> Weight { - Weight { ref_time: u64::from(self) * b.ref_time } - } - } - )* - } -} -weight_mul_primitive_impl!(u8, u16, u32, u64); - -impl Div for Weight -where - u64: Div, - T: Copy, -{ - type Output = Self; - fn div(self, b: T) -> Self { - Self { ref_time: self.ref_time / b } - } -} - -impl CheckedAdd for Weight { - fn checked_add(&self, rhs: &Self) -> Option { - self.checked_add(rhs) - } -} - -impl CheckedSub for Weight { - fn checked_sub(&self, rhs: &Self) -> Option { - self.checked_sub(rhs) - } -} - -impl PaysFee for (Weight, DispatchClass, Pays) { - fn pays_fee(&self, _: T) -> Pays { - self.2 - } -} - -impl WeighData for (Weight, DispatchClass) { - fn weigh_data(&self, args: T) -> Weight { - return self.0.weigh_data(args) - } -} - -impl WeighData for (Weight, DispatchClass, Pays) { - fn weigh_data(&self, args: T) -> Weight { - return self.0.weigh_data(args) - } -} - -impl ClassifyDispatch for (Weight, DispatchClass) { - fn classify_dispatch(&self, _: T) -> DispatchClass { - self.1 - } -} - -impl PaysFee for (Weight, DispatchClass) { - fn pays_fee(&self, _: T) -> Pays { - Pays::Yes - } -} - -impl WeighData for (Weight, Pays) { - fn weigh_data(&self, args: T) -> Weight { - return self.0.weigh_data(args) - } -} - -impl ClassifyDispatch for (Weight, Pays) { - fn classify_dispatch(&self, _: T) -> DispatchClass { - DispatchClass::Normal - } -} - -impl PaysFee for (Weight, Pays) { - fn pays_fee(&self, _: T) -> Pays { - self.1 - } -} - -impl From<(Option, Pays)> for PostDispatchInfo { - fn from(post_weight_info: (Option, Pays)) -> Self { - let (actual_weight, pays_fee) = post_weight_info; - Self { actual_weight, pays_fee } - } -} - -impl From> for PostDispatchInfo { - fn from(actual_weight: Option) -> Self { - Self { actual_weight, pays_fee: Default::default() } - } -} - -impl WeighData for Weight { - fn weigh_data(&self, _: T) -> Weight { - return *self - } -} - -impl ClassifyDispatch for Weight { - fn classify_dispatch(&self, _: T) -> DispatchClass { - DispatchClass::Normal - } -} - -impl PaysFee for Weight { - fn pays_fee(&self, _: T) -> Pays { - Pays::Yes - } -} - -impl ClassifyDispatch for (Weight, DispatchClass, Pays) { - fn classify_dispatch(&self, _: T) -> DispatchClass { - self.1 - } -} - -impl core::fmt::Display for Weight { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "Weight(ref_time: {})", self.ref_time) - } -} - -impl Bounded for Weight { - fn min_value() -> Self { - Zero::zero() - } - fn max_value() -> Self { - Self::MAX - } -} - -impl AddAssign for Weight { - fn add_assign(&mut self, other: Self) { - *self = Self { ref_time: self.ref_time + other.ref_time }; - } -} - -impl SubAssign for Weight { - fn sub_assign(&mut self, other: Self) { - *self = Self { ref_time: self.ref_time - other.ref_time }; - } -} - -impl sp_runtime::traits::Printable for Weight { - fn print(&self) { - self.ref_time().print() - } -} - -// TODO: Eventually remove these - -impl From> for PostDispatchInfo { - fn from(maybe_actual_computation: Option) -> Self { - let actual_weight = match maybe_actual_computation { - Some(actual_computation) => Some(Weight::zero().set_ref_time(actual_computation)), - None => None, - }; - Self { actual_weight, pays_fee: Default::default() } - } -} - -impl From<(Option, Pays)> for PostDispatchInfo { - fn from(post_weight_info: (Option, Pays)) -> Self { - let (maybe_actual_time, pays_fee) = post_weight_info; - let actual_weight = match maybe_actual_time { - Some(actual_time) => Some(Weight::zero().set_ref_time(actual_time)), - None => None, - }; - Self { actual_weight, pays_fee } - } -} - -impl WeighData for u64 { - fn weigh_data(&self, _: T) -> Weight { - return Weight::zero().set_ref_time(*self) - } -} - -impl ClassifyDispatch for u64 { - fn classify_dispatch(&self, _: T) -> DispatchClass { - DispatchClass::Normal - } -} - -impl PaysFee for u64 { - fn pays_fee(&self, _: T) -> Pays { - Pays::Yes - } -} - -impl WeighData for (u64, DispatchClass, Pays) { - fn weigh_data(&self, args: T) -> Weight { - return self.0.weigh_data(args) - } -} - -impl ClassifyDispatch for (u64, DispatchClass, Pays) { - fn classify_dispatch(&self, _: T) -> DispatchClass { - self.1 - } -} - -impl PaysFee for (u64, DispatchClass, Pays) { - fn pays_fee(&self, _: T) -> Pays { - self.2 - } -} - -impl WeighData for (u64, DispatchClass) { - fn weigh_data(&self, args: T) -> Weight { - return self.0.weigh_data(args) - } -} - -impl ClassifyDispatch for (u64, DispatchClass) { - fn classify_dispatch(&self, _: T) -> DispatchClass { - self.1 - } -} - -impl PaysFee for (u64, DispatchClass) { - fn pays_fee(&self, _: T) -> Pays { - Pays::Yes - } -} - -impl WeighData for (u64, Pays) { - fn weigh_data(&self, args: T) -> Weight { - return self.0.weigh_data(args) - } -} - -impl ClassifyDispatch for (u64, Pays) { - fn classify_dispatch(&self, _: T) -> DispatchClass { - DispatchClass::Normal - } -} - -impl PaysFee for (u64, Pays) { - fn pays_fee(&self, _: T) -> Pays { - self.1 - } -} - -// END TODO diff --git a/frame/support/test/Cargo.toml b/frame/support/test/Cargo.toml index dd23d7e6b0d96..d7d3bfc98f3d7 100644 --- a/frame/support/test/Cargo.toml +++ b/frame/support/test/Cargo.toml @@ -47,9 +47,10 @@ std = [ "sp-version/std", ] try-runtime = ["frame-support/try-runtime"] -# WARNING: CI only execute pallet test with this feature, -# if the feature intended to be used outside, CI and this message need to be updated. -conditional-storage = [] +# WARNING: +# Only CI runs with this feature enabled. This feature is for testing stuff related to the FRAME macros +# in conjunction with rust features. +frame-feature-testing = [] # Disable ui tests disable-ui-tests = [] no-metadata-docs = ["frame-support/no-metadata-docs"] diff --git a/frame/support/test/compile_pass/src/lib.rs b/frame/support/test/compile_pass/src/lib.rs index 7850726048546..b46f6c48a6d99 100644 --- a/frame/support/test/compile_pass/src/lib.rs +++ b/frame/support/test/compile_pass/src/lib.rs @@ -65,12 +65,12 @@ impl frame_system::Config for Runtime { type BlockHashCount = ConstU64<2400>; type Version = Version; type AccountData = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type BlockNumber = BlockNumber; type AccountId = AccountId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PalletInfo = PalletInfo; - type Call = Call; + type RuntimeCall = RuntimeCall; type DbWeight = (); type OnNewAccount = (); type OnKilledAccount = (); @@ -82,7 +82,7 @@ impl frame_system::Config for Runtime { pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; construct_runtime!( pub enum Runtime where diff --git a/frame/support/test/src/lib.rs b/frame/support/test/src/lib.rs index dd3fbd1f3020d..0ceeed42ff982 100644 --- a/frame/support/test/src/lib.rs +++ b/frame/support/test/src/lib.rs @@ -25,7 +25,7 @@ /// The configuration trait pub trait Config: 'static { /// The runtime origin type. - type Origin: codec::Codec + codec::EncodeLike + Default + scale_info::TypeInfo; + type RuntimeOrigin: codec::Codec + codec::EncodeLike + Default + scale_info::TypeInfo; /// The block number type. type BlockNumber: codec::Codec + codec::EncodeLike + Default + scale_info::TypeInfo; /// The information about the pallet setup in the runtime. @@ -36,7 +36,7 @@ pub trait Config: 'static { frame_support::decl_module! { /// Some test module - pub struct Module for enum Call where origin: T::Origin, system=self {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self {} } /// A PalletInfo implementation which just panics. diff --git a/frame/support/test/tests/construct_runtime.rs b/frame/support/test/tests/construct_runtime.rs index aed98579a0fd8..b1ace12936241 100644 --- a/frame/support/test/tests/construct_runtime.rs +++ b/frame/support/test/tests/construct_runtime.rs @@ -22,7 +22,10 @@ #![recursion_limit = "128"] use codec::MaxEncodedLen; -use frame_support::traits::{CrateVersion, PalletInfo as _}; +use frame_support::{ + parameter_types, + traits::{CrateVersion, PalletInfo as _}, +}; use scale_info::TypeInfo; use sp_core::{sr25519, H256}; use sp_runtime::{ @@ -30,14 +33,13 @@ use sp_runtime::{ traits::{BlakeTwo256, Verify}, DispatchError, ModuleError, }; -use sp_std::cell::RefCell; mod system; pub trait Currency {} -thread_local! { - pub static INTEGRITY_TEST_EXEC: RefCell = RefCell::new(0); +parameter_types! { + pub static IntegrityTestExec: u32 = 0; } mod module1 { @@ -47,7 +49,7 @@ mod module1 { frame_support::decl_module! { pub struct Module, I: Instance = DefaultInstance> for enum Call - where origin: ::Origin, system=system + where origin: ::RuntimeOrigin, system=system { #[weight = 0] pub fn fail(_origin) -> frame_support::dispatch::DispatchResult { @@ -87,7 +89,7 @@ mod module2 { frame_support::decl_module! { pub struct Module for enum Call - where origin: ::Origin, system=system + where origin: ::RuntimeOrigin, system=system { #[weight = 0] pub fn fail(_origin) -> frame_support::dispatch::DispatchResult { @@ -95,7 +97,7 @@ mod module2 { } fn integrity_test() { - INTEGRITY_TEST_EXEC.with(|i| *i.borrow_mut() += 1); + IntegrityTestExec::mutate(|i| *i += 1); } } } @@ -132,7 +134,7 @@ mod nested { frame_support::decl_module! { pub struct Module for enum Call - where origin: ::Origin, system=system + where origin: ::RuntimeOrigin, system=system { #[weight = 0] pub fn fail(_origin) -> frame_support::dispatch::DispatchResult { @@ -140,7 +142,7 @@ mod nested { } fn integrity_test() { - INTEGRITY_TEST_EXEC.with(|i| *i.borrow_mut() += 1); + IntegrityTestExec::mutate(|i| *i += 1); } } } @@ -178,7 +180,7 @@ pub mod module3 { frame_support::decl_module! { pub struct Module for enum Call - where origin: ::Origin, system=system + where origin: ::RuntimeOrigin, system=system { #[weight = 0] pub fn fail(_origin) -> frame_support::dispatch::DispatchResult { @@ -198,7 +200,7 @@ pub mod module3 { } #[weight = 3] fn aux_4(_origin) -> frame_support::dispatch::DispatchResult { unreachable!() } - #[weight = (5, frame_support::weights::DispatchClass::Operational)] + #[weight = (5, frame_support::dispatch::DispatchClass::Operational)] fn operational(_origin) { unreachable!() } } } @@ -245,12 +247,12 @@ fn test_pub() -> AccountId { impl system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type Hash = H256; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type BlockNumber = BlockNumber; type AccountId = AccountId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PalletInfo = PalletInfo; - type Call = Call; + type RuntimeCall = RuntimeCall; type DbWeight = (); } @@ -278,7 +280,7 @@ frame_support::construct_runtime!( pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; #[test] fn check_modules_error_type() { @@ -371,13 +373,13 @@ fn check_modules_error_type() { message: Some("Something") })), ); - }); + }) } #[test] fn integrity_test_works() { __construct_runtime_integrity_test::runtime_integrity_tests(); - assert_eq!(INTEGRITY_TEST_EXEC.with(|i| *i.borrow()), 2); + assert_eq!(IntegrityTestExec::get(), 2); } #[test] @@ -420,53 +422,53 @@ fn event_codec() { use codec::Encode; let event = system::Event::::ExtrinsicSuccess; - assert_eq!(Event::from(event).encode()[0], 30); + assert_eq!(RuntimeEvent::from(event).encode()[0], 30); let event = module1::Event::::A(test_pub()); - assert_eq!(Event::from(event).encode()[0], 31); + assert_eq!(RuntimeEvent::from(event).encode()[0], 31); let event = module2::Event::A; - assert_eq!(Event::from(event).encode()[0], 32); + assert_eq!(RuntimeEvent::from(event).encode()[0], 32); let event = module1::Event::::A(test_pub()); - assert_eq!(Event::from(event).encode()[0], 33); + assert_eq!(RuntimeEvent::from(event).encode()[0], 33); let event = nested::module3::Event::A; - assert_eq!(Event::from(event).encode()[0], 34); + assert_eq!(RuntimeEvent::from(event).encode()[0], 34); let event = module3::Event::A; - assert_eq!(Event::from(event).encode()[0], 35); + assert_eq!(RuntimeEvent::from(event).encode()[0], 35); let event = module1::Event::::A(test_pub()); - assert_eq!(Event::from(event).encode()[0], 4); + assert_eq!(RuntimeEvent::from(event).encode()[0], 4); let event = module1::Event::::A(test_pub()); - assert_eq!(Event::from(event).encode()[0], 1); + assert_eq!(RuntimeEvent::from(event).encode()[0], 1); let event = module1::Event::::A(test_pub()); - assert_eq!(Event::from(event).encode()[0], 2); + assert_eq!(RuntimeEvent::from(event).encode()[0], 2); let event = module1::Event::::A(test_pub()); - assert_eq!(Event::from(event).encode()[0], 12); + assert_eq!(RuntimeEvent::from(event).encode()[0], 12); let event = module1::Event::::A(test_pub()); - assert_eq!(Event::from(event).encode()[0], 13); + assert_eq!(RuntimeEvent::from(event).encode()[0], 13); } #[test] fn call_codec() { use codec::Encode; - assert_eq!(Call::System(system::Call::noop {}).encode()[0], 30); - assert_eq!(Call::Module1_1(module1::Call::fail {}).encode()[0], 31); - assert_eq!(Call::Module2(module2::Call::fail {}).encode()[0], 32); - assert_eq!(Call::Module1_2(module1::Call::fail {}).encode()[0], 33); - assert_eq!(Call::NestedModule3(nested::module3::Call::fail {}).encode()[0], 34); - assert_eq!(Call::Module3(module3::Call::fail {}).encode()[0], 35); - assert_eq!(Call::Module1_4(module1::Call::fail {}).encode()[0], 3); - assert_eq!(Call::Module1_6(module1::Call::fail {}).encode()[0], 1); - assert_eq!(Call::Module1_7(module1::Call::fail {}).encode()[0], 2); - assert_eq!(Call::Module1_8(module1::Call::fail {}).encode()[0], 12); - assert_eq!(Call::Module1_9(module1::Call::fail {}).encode()[0], 13); + assert_eq!(RuntimeCall::System(system::Call::noop {}).encode()[0], 30); + assert_eq!(RuntimeCall::Module1_1(module1::Call::fail {}).encode()[0], 31); + assert_eq!(RuntimeCall::Module2(module2::Call::fail {}).encode()[0], 32); + assert_eq!(RuntimeCall::Module1_2(module1::Call::fail {}).encode()[0], 33); + assert_eq!(RuntimeCall::NestedModule3(nested::module3::Call::fail {}).encode()[0], 34); + assert_eq!(RuntimeCall::Module3(module3::Call::fail {}).encode()[0], 35); + assert_eq!(RuntimeCall::Module1_4(module1::Call::fail {}).encode()[0], 3); + assert_eq!(RuntimeCall::Module1_6(module1::Call::fail {}).encode()[0], 1); + assert_eq!(RuntimeCall::Module1_7(module1::Call::fail {}).encode()[0], 2); + assert_eq!(RuntimeCall::Module1_8(module1::Call::fail {}).encode()[0], 12); + assert_eq!(RuntimeCall::Module1_9(module1::Call::fail {}).encode()[0], 13); } #[test] @@ -502,8 +504,8 @@ fn call_encode_is_correct_and_decode_works() { #[test] fn call_weight_should_attach_to_call_enum() { use frame_support::{ - dispatch::{DispatchInfo, GetDispatchInfo}, - weights::{DispatchClass, Pays, Weight}, + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}, + weights::Weight, }; // operational. assert_eq!( @@ -535,7 +537,7 @@ fn call_name() { #[test] fn call_metadata() { use frame_support::dispatch::{CallMetadata, GetCallMetadata}; - let call = Call::Module3(module3::Call::::aux_4 {}); + let call = RuntimeCall::Module3(module3::Call::::aux_4 {}); let metadata = call.get_call_metadata(); let expected = CallMetadata { function_name: "aux_4".into(), pallet_name: "Module3".into() }; assert_eq!(metadata, expected); @@ -551,7 +553,7 @@ fn get_call_names() { #[test] fn get_module_names() { use frame_support::dispatch::GetCallMetadata; - let module_names = Call::get_module_names(); + let module_names = RuntimeCall::get_module_names(); assert_eq!( [ "System", @@ -573,13 +575,13 @@ fn get_module_names() { #[test] fn call_subtype_conversion() { use frame_support::{dispatch::CallableCallFor, traits::IsSubType}; - let call = Call::Module3(module3::Call::::fail {}); + let call = RuntimeCall::Module3(module3::Call::::fail {}); let subcall: Option<&CallableCallFor> = call.is_sub_type(); let subcall_none: Option<&CallableCallFor> = call.is_sub_type(); assert_eq!(Some(&module3::Call::::fail {}), subcall); assert_eq!(None, subcall_none); - let from = Call::from(subcall.unwrap().clone()); + let from = RuntimeCall::from(subcall.unwrap().clone()); assert_eq!(from, call); } diff --git a/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.rs b/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.rs index 98cd1f197f619..7a074db9986a2 100644 --- a/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.rs +++ b/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.rs @@ -15,7 +15,7 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u64; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} diff --git a/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.stderr b/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.stderr index 608d57d6a97fc..5f1fccd43c549 100644 --- a/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.stderr +++ b/frame/support/test/tests/construct_runtime_ui/both_use_and_excluded_parts.stderr @@ -1,28 +1,19 @@ error: Unexpected tokens, expected one of `=`, `,` - --> $DIR/both_use_and_excluded_parts.rs:29:43 + --> tests/construct_runtime_ui/both_use_and_excluded_parts.rs:29:43 | 29 | Pallet: pallet exclude_parts { Pallet } use_parts { Pallet }, | ^^^^^^^^^ -error[E0412]: cannot find type `Call` in this scope - --> $DIR/both_use_and_excluded_parts.rs:18:64 - | -18 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; - | ^^^^ not found in this scope - | -help: consider importing one of these items - | -1 | use crate::pallet::Call; - | -1 | use frame_support_test::Call; - | -1 | use frame_system::Call; - | -1 | use test_pallet::Call; +error[E0412]: cannot find type `RuntimeCall` in this scope + --> tests/construct_runtime_ui/both_use_and_excluded_parts.rs:18:64 | +18 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + | - ^^^^^^^^^^^ not found in this scope + | | + | help: you might be missing a type parameter: `` error[E0412]: cannot find type `Runtime` in this scope - --> $DIR/both_use_and_excluded_parts.rs:20:25 + --> tests/construct_runtime_ui/both_use_and_excluded_parts.rs:20:25 | 20 | impl pallet::Config for Runtime {} | ^^^^^^^ not found in this scope diff --git a/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.rs b/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.rs index 51be7e30bd3eb..302b5af7ecd26 100644 --- a/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.rs @@ -20,7 +20,7 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u64; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} diff --git a/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.stderr b/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.stderr index 4e31cfb75c074..c623ecfbf4cdf 100644 --- a/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/exclude_undefined_part.stderr @@ -1,28 +1,19 @@ error: Invalid pallet part specified, the pallet `Pallet` doesn't have the `Call` part. Available parts are: `Pallet`, `Storage`. - --> $DIR/exclude_undefined_part.rs:34:34 + --> tests/construct_runtime_ui/exclude_undefined_part.rs:34:34 | 34 | Pallet: pallet exclude_parts { Call }, | ^^^^ -error[E0412]: cannot find type `Call` in this scope - --> $DIR/exclude_undefined_part.rs:23:64 - | -23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; - | ^^^^ not found in this scope - | -help: consider importing one of these items - | -1 | use crate::pallet::Call; - | -1 | use frame_support_test::Call; - | -1 | use frame_system::Call; - | -1 | use test_pallet::Call; +error[E0412]: cannot find type `RuntimeCall` in this scope + --> tests/construct_runtime_ui/exclude_undefined_part.rs:23:64 | +23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + | - ^^^^^^^^^^^ not found in this scope + | | + | help: you might be missing a type parameter: `` error[E0412]: cannot find type `Runtime` in this scope - --> $DIR/exclude_undefined_part.rs:25:25 + --> tests/construct_runtime_ui/exclude_undefined_part.rs:25:25 | 25 | impl pallet::Config for Runtime {} | ^^^^^^^ not found in this scope diff --git a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.rs b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.rs index c06333795e3c5..2ca9676406579 100644 --- a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.rs +++ b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.rs @@ -6,22 +6,22 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl test_pallet::Config for Runtime {} impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU32<250>; type BlockWeights = (); type BlockLength = (); diff --git a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr index 1f08ab87c1f79..26c0717c0ad37 100644 --- a/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr +++ b/frame/support/test/tests/construct_runtime_ui/no_std_genesis_config.stderr @@ -10,7 +10,7 @@ error: `Pallet` does not have the std feature enabled, this will cause the `test 49 | | } | |_^ | - = note: this error originates in the macro `test_pallet::__substrate_genesis_config_check::is_std_enabled_for_genesis` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `test_pallet::__substrate_genesis_config_check::is_std_enabled_for_genesis` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `GenesisConfig` in crate `test_pallet` --> tests/construct_runtime_ui/no_std_genesis_config.rs:40:1 diff --git a/frame/support/test/tests/construct_runtime_ui/old_unsupported_pallet_decl.rs b/frame/support/test/tests/construct_runtime_ui/old_unsupported_pallet_decl.rs index 706d444f23590..5691549c20f34 100644 --- a/frame/support/test/tests/construct_runtime_ui/old_unsupported_pallet_decl.rs +++ b/frame/support/test/tests/construct_runtime_ui/old_unsupported_pallet_decl.rs @@ -8,7 +8,7 @@ mod pallet_old { } decl_module! { - pub struct Module for enum Call where origin: T::Origin {} + pub struct Module for enum Call where origin: T::RuntimeOrigin {} } } diff --git a/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs b/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs index 827d8a58af733..b7ccadb5e3e58 100644 --- a/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs +++ b/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.rs @@ -40,22 +40,22 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU32<250>; type BlockWeights = (); type BlockLength = (); diff --git a/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr b/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr index 161873866b6f3..99a543eef7a8a 100644 --- a/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr +++ b/frame/support/test/tests/construct_runtime_ui/pallet_error_too_large.stderr @@ -10,4 +10,4 @@ error[E0080]: evaluation of constant value failed 83 | | } | |_^ the evaluated program panicked at 'The maximum encoded size of the error type in the `Pallet` pallet exceeds `MAX_MODULE_ERROR_ENCODED_SIZE`', $DIR/tests/construct_runtime_ui/pallet_error_too_large.rs:74:1 | - = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs index 1653e830f0b4f..abe5c4cfeb343 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.rs @@ -15,22 +15,22 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU32<250>; type BlockWeights = (); type BlockLength = (); diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr index c162a22bb87b0..6baf01e866f64 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_call_part.stderr @@ -13,4 +13,4 @@ error: `Pallet` does not have #[pallet::call] defined, perhaps you should remove 58 | | } | |_- in this macro invocation | - = note: this error originates in the macro `pallet::__substrate_call_check::is_call_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_call_check::is_call_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs index b8f91cf4bc690..9a6ac5c6251fb 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.rs @@ -15,22 +15,22 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU32<250>; type BlockWeights = (); type BlockLength = (); diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr index 2af4d3fb15000..8f2bf7be15749 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_event_part.stderr @@ -13,7 +13,7 @@ error: `Pallet` does not have #[pallet::event] defined, perhaps you should remov 58 | | } | |_- in this macro invocation | - = note: this error originates in the macro `pallet::__substrate_event_check::is_event_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_event_check::is_event_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `Event` in module `pallet` --> tests/construct_runtime_ui/undefined_event_part.rs:49:1 @@ -45,36 +45,3 @@ help: if you import `Event`, refer to it directly 57 - } 58 - } | - -error[E0412]: cannot find type `Event` in module `pallet` - --> tests/construct_runtime_ui/undefined_event_part.rs:49:1 - | -49 | / construct_runtime! { -50 | | pub enum Runtime where -51 | | Block = Block, -52 | | NodeBlock = Block, -... | -57 | | } -58 | | } - | |_^ not found in `pallet` - | - = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing one of these items - | -1 | use crate::Event; - | -1 | use frame_system::Event; - | -help: if you import `Event`, refer to it directly - | -49 - construct_runtime! { -50 - pub enum Runtime where -51 - Block = Block, -52 - NodeBlock = Block, -53 - UncheckedExtrinsic = UncheckedExtrinsic -54 - { -55 - System: frame_system::{Pallet, Call, Storage, Config, Event}, -56 - Pallet: pallet::{Pallet, Event}, -57 - } -58 - } - | diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs index a61d545b3279e..4facf85e280c0 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.rs @@ -15,22 +15,22 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU32<250>; type BlockWeights = (); type BlockLength = (); diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr index 1bc109a45ac57..aae3aaa80c865 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_genesis_config_part.stderr @@ -13,7 +13,7 @@ error: `Pallet` does not have #[pallet::genesis_config] defined, perhaps you sho 58 | | } | |_- in this macro invocation | - = note: this error originates in the macro `pallet::__substrate_genesis_config_check::is_genesis_config_defined` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_genesis_config_check::is_genesis_config_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `GenesisConfig` in module `pallet` --> tests/construct_runtime_ui/undefined_genesis_config_part.rs:49:1 diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs index 6e4764286ab41..322fa2c297285 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.rs @@ -15,22 +15,22 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU32<250>; type BlockWeights = (); type BlockLength = (); diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr index 9f646469d86a8..74af0c264cd5e 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_inherent_part.stderr @@ -13,13 +13,13 @@ error: `Pallet` does not have #[pallet::inherent] defined, perhaps you should re 58 | | } | |_- in this macro invocation | - = note: this error originates in the macro `pallet::__substrate_inherent_check::is_inherent_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_inherent_check::is_inherent_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no function or associated item named `create_inherent` found for struct `pallet::Pallet` in the current scope --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | 11 | pub struct Pallet(_); - | ------------------------ function or associated item `create_inherent` not found for this + | -------------------- function or associated item `create_inherent` not found for this struct ... 49 | / construct_runtime! { 50 | | pub enum Runtime where @@ -39,7 +39,7 @@ error[E0599]: no function or associated item named `is_inherent` found for struc --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | 11 | pub struct Pallet(_); - | ------------------------ function or associated item `is_inherent` not found for this + | -------------------- function or associated item `is_inherent` not found for this struct ... 49 | / construct_runtime! { 50 | | pub enum Runtime where @@ -59,7 +59,7 @@ error[E0599]: no function or associated item named `check_inherent` found for st --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | 11 | pub struct Pallet(_); - | ------------------------ function or associated item `check_inherent` not found for this + | -------------------- function or associated item `check_inherent` not found for this struct ... 49 | / construct_runtime! { 50 | | pub enum Runtime where @@ -79,7 +79,7 @@ error[E0599]: no associated item named `INHERENT_IDENTIFIER` found for struct `p --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | 11 | pub struct Pallet(_); - | ------------------------ associated item `INHERENT_IDENTIFIER` not found for this + | -------------------- associated item `INHERENT_IDENTIFIER` not found for this struct ... 49 | / construct_runtime! { 50 | | pub enum Runtime where @@ -99,7 +99,7 @@ error[E0599]: no function or associated item named `is_inherent_required` found --> tests/construct_runtime_ui/undefined_inherent_part.rs:49:1 | 11 | pub struct Pallet(_); - | ------------------------ function or associated item `is_inherent_required` not found for this + | -------------------- function or associated item `is_inherent_required` not found for this struct ... 49 | / construct_runtime! { 50 | | pub enum Runtime where diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs index 9233404a865b9..55cd5b545d6ba 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.rs @@ -15,22 +15,22 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU32<250>; type BlockWeights = (); type BlockLength = (); diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr index c692cd61bae8b..1a8fe64da1758 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_origin_part.stderr @@ -13,7 +13,7 @@ error: `Pallet` does not have #[pallet::origin] defined, perhaps you should remo 58 | | } | |_- in this macro invocation | - = note: this error originates in the macro `pallet::__substrate_origin_check::is_origin_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_origin_check::is_origin_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0412]: cannot find type `Origin` in module `pallet` --> tests/construct_runtime_ui/undefined_origin_part.rs:49:1 @@ -46,39 +46,6 @@ help: if you import `Origin`, refer to it directly 58 - } | -error[E0412]: cannot find type `Origin` in module `pallet` - --> tests/construct_runtime_ui/undefined_origin_part.rs:49:1 - | -49 | / construct_runtime! { -50 | | pub enum Runtime where -51 | | Block = Block, -52 | | NodeBlock = Block, -... | -57 | | } -58 | | } - | |_^ not found in `pallet` - | - = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider importing one of these items - | -1 | use crate::Origin; - | -1 | use frame_system::Origin; - | -help: if you import `Origin`, refer to it directly - | -49 - construct_runtime! { -50 - pub enum Runtime where -51 - Block = Block, -52 - NodeBlock = Block, -53 - UncheckedExtrinsic = UncheckedExtrinsic -54 - { -55 - System: frame_system::{Pallet, Call, Storage, Config, Event}, -56 - Pallet: pallet::{Pallet, Origin}, -57 - } -58 - } - | - error[E0282]: type annotations needed --> tests/construct_runtime_ui/undefined_origin_part.rs:49:1 | @@ -89,6 +56,10 @@ error[E0282]: type annotations needed ... | 57 | | } 58 | | } - | |_^ cannot infer type for type parameter `AccountId` declared on the enum `RawOrigin` + | |_^ cannot infer type of the type parameter `AccountId` declared on the enum `RawOrigin` | = note: this error originates in the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider specifying the generic argument + | +58 | }:: + | +++++++++++++ diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs index 621683aca3754..0cf305a7dc055 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.rs @@ -15,22 +15,22 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u32; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = frame_support::traits::ConstU32<250>; type BlockWeights = (); type BlockLength = (); diff --git a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr index 94226075d9a4b..6f0b13c58933e 100644 --- a/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/undefined_validate_unsigned_part.stderr @@ -13,22 +13,27 @@ error: `Pallet` does not have #[pallet::validate_unsigned] defined, perhaps you 58 | | } | |_- in this macro invocation | - = note: this error originates in the macro `pallet::__substrate_validate_unsigned_check::is_validate_unsigned_part_defined` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pallet::__substrate_validate_unsigned_check::is_validate_unsigned_part_defined` which comes from the expansion of the macro `construct_runtime` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0599]: no variant or associated item named `Pallet` found for enum `Call` in the current scope +error[E0599]: no variant or associated item named `Pallet` found for enum `RuntimeCall` in the current scope --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:56:3 | -49 | construct_runtime! { - | ------------------ variant or associated item `Pallet` not found here -... -56 | Pallet: pallet::{Pallet, ValidateUnsigned}, - | ^^^^^^ variant or associated item not found in `Call` +49 | / construct_runtime! { +50 | | pub enum Runtime where +51 | | Block = Block, +52 | | NodeBlock = Block, +... | +56 | | Pallet: pallet::{Pallet, ValidateUnsigned}, + | | ^^^^^^ variant or associated item not found in `RuntimeCall` +57 | | } +58 | | } + | |_- variant or associated item `Pallet` not found for this enum error[E0599]: no function or associated item named `pre_dispatch` found for struct `pallet::Pallet` in the current scope --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:49:1 | 11 | pub struct Pallet(_); - | ------------------------ function or associated item `pre_dispatch` not found for this + | -------------------- function or associated item `pre_dispatch` not found for this struct ... 49 | / construct_runtime! { 50 | | pub enum Runtime where @@ -49,7 +54,7 @@ error[E0599]: no function or associated item named `validate_unsigned` found for --> tests/construct_runtime_ui/undefined_validate_unsigned_part.rs:49:1 | 11 | pub struct Pallet(_); - | ------------------------ function or associated item `validate_unsigned` not found for this + | -------------------- function or associated item `validate_unsigned` not found for this struct ... 49 | / construct_runtime! { 50 | | pub enum Runtime where diff --git a/frame/support/test/tests/construct_runtime_ui/use_undefined_part.rs b/frame/support/test/tests/construct_runtime_ui/use_undefined_part.rs index 1664dcc42b755..c74e29bc05469 100644 --- a/frame/support/test/tests/construct_runtime_ui/use_undefined_part.rs +++ b/frame/support/test/tests/construct_runtime_ui/use_undefined_part.rs @@ -20,7 +20,7 @@ pub type Signature = sr25519::Signature; pub type BlockNumber = u64; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl pallet::Config for Runtime {} diff --git a/frame/support/test/tests/construct_runtime_ui/use_undefined_part.stderr b/frame/support/test/tests/construct_runtime_ui/use_undefined_part.stderr index ed41f0ce673a4..e289c75fb008a 100644 --- a/frame/support/test/tests/construct_runtime_ui/use_undefined_part.stderr +++ b/frame/support/test/tests/construct_runtime_ui/use_undefined_part.stderr @@ -1,28 +1,19 @@ error: Invalid pallet part specified, the pallet `Pallet` doesn't have the `Call` part. Available parts are: `Pallet`, `Storage`. - --> $DIR/use_undefined_part.rs:34:30 + --> tests/construct_runtime_ui/use_undefined_part.rs:34:30 | 34 | Pallet: pallet use_parts { Call }, | ^^^^ -error[E0412]: cannot find type `Call` in this scope - --> $DIR/use_undefined_part.rs:23:64 - | -23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; - | ^^^^ not found in this scope - | -help: consider importing one of these items - | -1 | use crate::pallet::Call; - | -1 | use frame_support_test::Call; - | -1 | use frame_system::Call; - | -1 | use test_pallet::Call; +error[E0412]: cannot find type `RuntimeCall` in this scope + --> tests/construct_runtime_ui/use_undefined_part.rs:23:64 | +23 | pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + | - ^^^^^^^^^^^ not found in this scope + | | + | help: you might be missing a type parameter: `` error[E0412]: cannot find type `Runtime` in this scope - --> $DIR/use_undefined_part.rs:25:25 + --> tests/construct_runtime_ui/use_undefined_part.rs:25:25 | 25 | impl pallet::Config for Runtime {} | ^^^^^^^ not found in this scope diff --git a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.rs b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.rs index cc7c1ff219d8b..0f662b96e2b13 100644 --- a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.rs +++ b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.rs @@ -1,5 +1,5 @@ frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self { + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self { fn integrity_test() {} fn integrity_test() {} diff --git a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr index 880695d9b77e2..4212707599d41 100644 --- a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr +++ b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_integrity_test.stderr @@ -2,7 +2,7 @@ error: `integrity_test` can only be passed once as input. --> tests/decl_module_ui/reserved_keyword_two_times_integrity_test.rs:1:1 | 1 | / frame_support::decl_module! { -2 | | pub struct Module for enum Call where origin: T::Origin, system=self { +2 | | pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self { 3 | | fn integrity_test() {} 4 | | 5 | | fn integrity_test() {} @@ -10,7 +10,7 @@ error: `integrity_test` can only be passed once as input. 7 | | } | |_^ | - = note: this error originates in the macro `$crate::decl_module` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::decl_module` which comes from the expansion of the macro `frame_support::decl_module` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0601]: `main` function not found in crate `$CRATE` --> tests/decl_module_ui/reserved_keyword_two_times_integrity_test.rs:7:2 diff --git a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.rs b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.rs index 18aaec12c5f39..ea0746b1c501c 100644 --- a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.rs +++ b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.rs @@ -1,5 +1,5 @@ frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self { + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self { fn on_initialize() -> Weight { 0 } diff --git a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.stderr b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.stderr index 369be77b8d249..94bde853e4cc8 100644 --- a/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.stderr +++ b/frame/support/test/tests/decl_module_ui/reserved_keyword_two_times_on_initialize.stderr @@ -1,8 +1,8 @@ error: `on_initialize` can only be passed once as input. - --> $DIR/reserved_keyword_two_times_on_initialize.rs:1:1 + --> tests/decl_module_ui/reserved_keyword_two_times_on_initialize.rs:1:1 | 1 | / frame_support::decl_module! { -2 | | pub struct Module for enum Call where origin: T::Origin, system=self { +2 | | pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self { 3 | | fn on_initialize() -> Weight { 4 | | 0 ... | @@ -10,4 +10,4 @@ error: `on_initialize` can only be passed once as input. 11 | | } | |_^ | - = note: this error originates in the macro `$crate::decl_module` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::decl_module` which comes from the expansion of the macro `frame_support::decl_module` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/frame/support/test/tests/decl_storage.rs b/frame/support/test/tests/decl_storage.rs index 7ce43cd5d44d1..a4e420eb454b6 100644 --- a/frame/support/test/tests/decl_storage.rs +++ b/frame/support/test/tests/decl_storage.rs @@ -23,7 +23,7 @@ mod tests { use sp_io::TestExternalities; frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } pub trait Config: frame_support_test::Config { @@ -94,7 +94,7 @@ mod tests { struct TraitImpl {} impl frame_support_test::Config for TraitImpl { - type Origin = u32; + type RuntimeOrigin = u32; type BlockNumber = u32; type PalletInfo = frame_support_test::PanicPalletInfo; type DbWeight = (); @@ -617,7 +617,7 @@ mod test2 { pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } type PairOf = (T, T); @@ -639,7 +639,7 @@ mod test2 { struct TraitImpl {} impl frame_support_test::Config for TraitImpl { - type Origin = u32; + type RuntimeOrigin = u32; type BlockNumber = u32; type PalletInfo = frame_support_test::PanicPalletInfo; type DbWeight = (); @@ -695,7 +695,7 @@ mod test3 { pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } frame_support::decl_storage! { trait Store for Module as Test { @@ -708,7 +708,7 @@ mod test3 { struct TraitImpl {} impl frame_support_test::Config for TraitImpl { - type Origin = u32; + type RuntimeOrigin = u32; type BlockNumber = u32; type PalletInfo = frame_support_test::PanicPalletInfo; type DbWeight = (); @@ -726,7 +726,7 @@ mod test_append_and_len { pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } #[derive(PartialEq, Eq, Clone, Encode, Decode, scale_info::TypeInfo)] @@ -753,7 +753,7 @@ mod test_append_and_len { struct Test {} impl frame_support_test::Config for Test { - type Origin = u32; + type RuntimeOrigin = u32; type BlockNumber = u32; type PalletInfo = frame_support_test::PanicPalletInfo; type DbWeight = (); diff --git a/frame/support/test/tests/decl_storage_ui/config_duplicate.rs b/frame/support/test/tests/decl_storage_ui/config_duplicate.rs index db2cdbdc65492..af74823f64ca6 100644 --- a/frame/support/test/tests/decl_storage_ui/config_duplicate.rs +++ b/frame/support/test/tests/decl_storage_ui/config_duplicate.rs @@ -18,7 +18,7 @@ pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } frame_support::decl_storage!{ diff --git a/frame/support/test/tests/decl_storage_ui/config_get_duplicate.rs b/frame/support/test/tests/decl_storage_ui/config_get_duplicate.rs index b804bf8980383..8805effd9e725 100644 --- a/frame/support/test/tests/decl_storage_ui/config_get_duplicate.rs +++ b/frame/support/test/tests/decl_storage_ui/config_get_duplicate.rs @@ -18,7 +18,7 @@ pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } frame_support::decl_storage!{ diff --git a/frame/support/test/tests/decl_storage_ui/get_duplicate.rs b/frame/support/test/tests/decl_storage_ui/get_duplicate.rs index bc03ff6b4a4f9..5e05887110537 100644 --- a/frame/support/test/tests/decl_storage_ui/get_duplicate.rs +++ b/frame/support/test/tests/decl_storage_ui/get_duplicate.rs @@ -18,7 +18,7 @@ pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } frame_support::decl_storage!{ diff --git a/frame/support/test/tests/derive_no_bound.rs b/frame/support/test/tests/derive_no_bound.rs index e1cf539f2ac58..1ce4a94f46b9b 100644 --- a/frame/support/test/tests/derive_no_bound.rs +++ b/frame/support/test/tests/derive_no_bound.rs @@ -72,7 +72,7 @@ fn test_struct_named() { assert_eq!(a_2, a_1); assert_eq!( format!("{:?}", a_1), - String::from("StructNamed { a: 1, b: 2, c: 3, phantom: PhantomData }") + String::from("StructNamed { a: 1, b: 2, c: 3, phantom: PhantomData<(derive_no_bound::ImplNone, derive_no_bound::ImplNone)> }") ); let b = StructNamed:: { @@ -103,7 +103,7 @@ fn test_struct_unnamed() { assert_eq!(a_2.1, 2); assert_eq!(a_2.2, 3); assert_eq!(a_2, a_1); - assert_eq!(format!("{:?}", a_1), String::from("StructUnnamed(1, 2, 3, PhantomData)")); + assert_eq!(format!("{:?}", a_1), String::from("StructUnnamed(1, 2, 3, PhantomData<(derive_no_bound::ImplNone, derive_no_bound::ImplNone)>)")); let b = StructUnnamed::(1, 2, 4, Default::default()); @@ -178,11 +178,11 @@ fn test_enum() { assert_eq!( format!("{:?}", variant_0), - String::from("Enum::VariantUnnamed(1, 2, 3, PhantomData)"), + String::from("Enum::VariantUnnamed(1, 2, 3, PhantomData<(derive_no_bound::ImplNone, derive_no_bound::ImplNone)>)"), ); assert_eq!( format!("{:?}", variant_1), - String::from("Enum::VariantNamed { a: 1, b: 2, c: 3, phantom: PhantomData }"), + String::from("Enum::VariantNamed { a: 1, b: 2, c: 3, phantom: PhantomData<(derive_no_bound::ImplNone, derive_no_bound::ImplNone)> }"), ); assert_eq!(format!("{:?}", variant_2), String::from("Enum::VariantUnit")); assert_eq!(format!("{:?}", variant_3), String::from("Enum::VariantUnit2")); diff --git a/frame/support/test/tests/derive_no_bound_ui/debug.stderr b/frame/support/test/tests/derive_no_bound_ui/debug.stderr index 7580cab2ea0b3..acc7f80b37663 100644 --- a/frame/support/test/tests/derive_no_bound_ui/debug.stderr +++ b/frame/support/test/tests/derive_no_bound_ui/debug.stderr @@ -1,8 +1,8 @@ error[E0277]: `::C` doesn't implement `std::fmt::Debug` - --> $DIR/debug.rs:7:2 + --> tests/derive_no_bound_ui/debug.rs:7:2 | 7 | c: T::C, | ^ `::C` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::C` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = note: required for the cast from `::C` to the object type `dyn std::fmt::Debug` diff --git a/frame/support/test/tests/final_keys.rs b/frame/support/test/tests/final_keys.rs index c1723c6ad7a1b..a7ad88c801001 100644 --- a/frame/support/test/tests/final_keys.rs +++ b/frame/support/test/tests/final_keys.rs @@ -28,7 +28,7 @@ mod no_instance { pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } frame_support::decl_storage! { @@ -53,7 +53,7 @@ mod instance { frame_support::decl_module! { pub struct Module, I: Instance = DefaultInstance> - for enum Call where origin: T::Origin, system=frame_support_test {} + for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } frame_support::decl_storage! { diff --git a/frame/support/test/tests/genesisconfig.rs b/frame/support/test/tests/genesisconfig.rs index 367c7236d0158..f0094b3188ae1 100644 --- a/frame/support/test/tests/genesisconfig.rs +++ b/frame/support/test/tests/genesisconfig.rs @@ -18,7 +18,7 @@ pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test {} } frame_support::decl_storage! { @@ -31,7 +31,7 @@ struct Test; impl frame_support_test::Config for Test { type BlockNumber = u32; - type Origin = (); + type RuntimeOrigin = (); type PalletInfo = frame_support_test::PanicPalletInfo; type DbWeight = (); } diff --git a/frame/support/test/tests/instance.rs b/frame/support/test/tests/instance.rs index 75a96f628245a..043959b67ee6e 100644 --- a/frame/support/test/tests/instance.rs +++ b/frame/support/test/tests/instance.rs @@ -50,15 +50,15 @@ mod module1 { where ::BlockNumber: From, { - type Event: From> + Into<::Event>; - type Origin: From>; + type RuntimeEvent: From> + Into<::RuntimeEvent>; + type RuntimeOrigin: From>; type SomeParameter: Get; type GenericType: Default + Clone + Codec + EncodeLike + TypeInfo; } frame_support::decl_module! { pub struct Module, I: Instance> for enum Call where - origin: ::Origin, + origin: ::RuntimeOrigin, system = system, T::BlockNumber: From { @@ -154,15 +154,15 @@ mod module2 { pub trait Config: system::Config { type Amount: Parameter + Default; - type Event: From> + Into<::Event>; - type Origin: From>; + type RuntimeEvent: From> + Into<::RuntimeEvent>; + type RuntimeOrigin: From>; } impl, I: Instance> Currency for Module {} frame_support::decl_module! { pub struct Module, I: Instance=DefaultInstance> for enum Call where - origin: ::Origin, + origin: ::RuntimeOrigin, system = system { fn deposit_event() = default; @@ -228,41 +228,41 @@ mod module3 { } frame_support::decl_module! { - pub struct Module for enum Call where origin: ::Origin, system=system {} + pub struct Module for enum Call where origin: ::RuntimeOrigin, system=system {} } } impl module1::Config for Runtime { - type Event = Event; - type Origin = Origin; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; type SomeParameter = ConstU32<100>; type GenericType = u32; } impl module1::Config for Runtime { - type Event = Event; - type Origin = Origin; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; type SomeParameter = ConstU32<100>; type GenericType = u32; } impl module2::Config for Runtime { type Amount = u16; - type Event = Event; - type Origin = Origin; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; } impl module2::Config for Runtime { type Amount = u32; - type Event = Event; - type Origin = Origin; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; } impl module2::Config for Runtime { type Amount = u32; - type Event = Event; - type Origin = Origin; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; } impl module2::Config for Runtime { type Amount = u64; - type Event = Event; - type Origin = Origin; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; } impl module3::Config for Runtime { type Currency = Module2_2; @@ -277,12 +277,12 @@ pub type Index = u64; impl system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type Hash = H256; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type BlockNumber = BlockNumber; type AccountId = AccountId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PalletInfo = PalletInfo; - type Call = Call; + type RuntimeCall = RuntimeCall; type DbWeight = (); } @@ -315,7 +315,7 @@ frame_support::construct_runtime!( pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; fn new_test_ext() -> sp_io::TestExternalities { GenesisConfig { diff --git a/frame/support/test/tests/issue2219.rs b/frame/support/test/tests/issue2219.rs index d7e3d2cb5b135..5d24d54165c1f 100644 --- a/frame/support/test/tests/issue2219.rs +++ b/frame/support/test/tests/issue2219.rs @@ -86,7 +86,7 @@ mod module { pub trait Config: system::Config + TypeInfo {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=system {} + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=system {} } #[derive(Encode, Decode, Copy, Clone, Serialize, Deserialize)] @@ -155,17 +155,17 @@ pub type BlockNumber = u64; pub type Index = u64; pub type Header = generic::Header; pub type Block = generic::Block; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; impl system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type Hash = H256; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type BlockNumber = BlockNumber; type AccountId = AccountId; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PalletInfo = PalletInfo; - type Call = Call; + type RuntimeCall = RuntimeCall; type DbWeight = (); } diff --git a/frame/support/test/tests/origin.rs b/frame/support/test/tests/origin.rs index cff531ff2e529..f794cd8be1ce0 100644 --- a/frame/support/test/tests/origin.rs +++ b/frame/support/test/tests/origin.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Origin tests for construct_runtime macro +//! RuntimeOrigin tests for construct_runtime macro #![recursion_limit = "128"] @@ -38,7 +38,7 @@ mod nested { frame_support::decl_module! { pub struct Module for enum Call - where origin: ::Origin, system=system + where origin: ::RuntimeOrigin, system=system { #[weight = 0] pub fn fail(_origin) -> frame_support::dispatch::DispatchResult { @@ -80,7 +80,7 @@ pub mod module { frame_support::decl_module! { pub struct Module for enum Call - where origin: ::Origin, system=system + where origin: ::RuntimeOrigin, system=system { #[weight = 0] pub fn fail(_origin) -> frame_support::dispatch::DispatchResult { @@ -100,7 +100,7 @@ pub mod module { } #[weight = 3] fn aux_4(_origin) -> frame_support::dispatch::DispatchResult { unreachable!() } - #[weight = (5, frame_support::weights::DispatchClass::Operational)] + #[weight = (5, frame_support::dispatch::DispatchClass::Operational)] fn operational(_origin) { unreachable!() } } } @@ -134,10 +134,10 @@ impl nested::module::Config for RuntimeOriginTest {} impl module::Config for RuntimeOriginTest {} pub struct BaseCallFilter; -impl Contains for BaseCallFilter { - fn contains(c: &Call) -> bool { +impl Contains for BaseCallFilter { + fn contains(c: &RuntimeCall) -> bool { match c { - Call::NestedModule(_) => true, + RuntimeCall::NestedModule(_) => true, _ => false, } } @@ -146,12 +146,12 @@ impl Contains for BaseCallFilter { impl system::Config for RuntimeOriginTest { type BaseCallFilter = BaseCallFilter; type Hash = H256; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type BlockNumber = BlockNumber; type AccountId = u32; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type PalletInfo = PalletInfo; - type Call = Call; + type RuntimeCall = RuntimeCall; type DbWeight = (); } @@ -170,7 +170,7 @@ frame_support::construct_runtime!( pub type Signature = sr25519::Signature; pub type BlockNumber = u64; pub type Header = generic::Header; -pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; pub type Block = generic::Block; #[test] @@ -178,40 +178,40 @@ fn origin_default_filter() { let accepted_call = nested::module::Call::fail {}.into(); let rejected_call = module::Call::fail {}.into(); - assert_eq!(Origin::root().filter_call(&accepted_call), true); - assert_eq!(Origin::root().filter_call(&rejected_call), true); - assert_eq!(Origin::none().filter_call(&accepted_call), true); - assert_eq!(Origin::none().filter_call(&rejected_call), false); - assert_eq!(Origin::signed(0).filter_call(&accepted_call), true); - assert_eq!(Origin::signed(0).filter_call(&rejected_call), false); - assert_eq!(Origin::from(Some(0)).filter_call(&accepted_call), true); - assert_eq!(Origin::from(Some(0)).filter_call(&rejected_call), false); - assert_eq!(Origin::from(None).filter_call(&accepted_call), true); - assert_eq!(Origin::from(None).filter_call(&rejected_call), false); - assert_eq!(Origin::from(nested::module::Origin).filter_call(&accepted_call), true); - assert_eq!(Origin::from(nested::module::Origin).filter_call(&rejected_call), false); - - let mut origin = Origin::from(Some(0)); - origin.add_filter(|c| matches!(c, Call::Module(_))); + assert_eq!(RuntimeOrigin::root().filter_call(&accepted_call), true); + assert_eq!(RuntimeOrigin::root().filter_call(&rejected_call), true); + assert_eq!(RuntimeOrigin::none().filter_call(&accepted_call), true); + assert_eq!(RuntimeOrigin::none().filter_call(&rejected_call), false); + assert_eq!(RuntimeOrigin::signed(0).filter_call(&accepted_call), true); + assert_eq!(RuntimeOrigin::signed(0).filter_call(&rejected_call), false); + assert_eq!(RuntimeOrigin::from(Some(0)).filter_call(&accepted_call), true); + assert_eq!(RuntimeOrigin::from(Some(0)).filter_call(&rejected_call), false); + assert_eq!(RuntimeOrigin::from(None).filter_call(&accepted_call), true); + assert_eq!(RuntimeOrigin::from(None).filter_call(&rejected_call), false); + assert_eq!(RuntimeOrigin::from(nested::module::Origin).filter_call(&accepted_call), true); + assert_eq!(RuntimeOrigin::from(nested::module::Origin).filter_call(&rejected_call), false); + + let mut origin = RuntimeOrigin::from(Some(0)); + origin.add_filter(|c| matches!(c, RuntimeCall::Module(_))); assert_eq!(origin.filter_call(&accepted_call), false); assert_eq!(origin.filter_call(&rejected_call), false); // Now test for root origin and filters: - let mut origin = Origin::from(Some(0)); - origin.set_caller_from(Origin::root()); + let mut origin = RuntimeOrigin::from(Some(0)); + origin.set_caller_from(RuntimeOrigin::root()); assert!(matches!(origin.caller, OriginCaller::system(system::RawOrigin::Root))); // Root origin bypass all filter. assert_eq!(origin.filter_call(&accepted_call), true); assert_eq!(origin.filter_call(&rejected_call), true); - origin.set_caller_from(Origin::from(Some(0))); + origin.set_caller_from(RuntimeOrigin::from(Some(0))); // Back to another signed origin, the filtered are now effective again assert_eq!(origin.filter_call(&accepted_call), true); assert_eq!(origin.filter_call(&rejected_call), false); - origin.set_caller_from(Origin::root()); + origin.set_caller_from(RuntimeOrigin::root()); origin.reset_filter(); // Root origin bypass all filter, even when they are reset. diff --git a/frame/support/test/tests/pallet.rs b/frame/support/test/tests/pallet.rs index 907a52f1184cc..05c1f14601862 100644 --- a/frame/support/test/tests/pallet.rs +++ b/frame/support/test/tests/pallet.rs @@ -16,14 +16,16 @@ // limitations under the License. use frame_support::{ - dispatch::{Parameter, UnfilteredDispatchable}, + dispatch::{ + DispatchClass, DispatchInfo, GetDispatchInfo, Parameter, Pays, UnfilteredDispatchable, + }, pallet_prelude::ValueQuery, storage::unhashed, traits::{ ConstU32, GetCallName, GetStorageVersion, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade, PalletError, PalletInfoAccess, StorageVersion, }, - weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays, RuntimeDbWeight, Weight}, + weights::{RuntimeDbWeight, Weight}, }; use scale_info::{meta_type, TypeInfo}; use sp_io::{ @@ -125,7 +127,7 @@ pub mod pallet { type Balance: Parameter + Default + TypeInfo; - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; } #[pallet::extra_constants] @@ -334,22 +336,22 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn conditional_value)] - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] pub type ConditionalValue = StorageValue<_, u32>; - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] #[pallet::storage] #[pallet::getter(fn conditional_map)] pub type ConditionalMap = StorageMap<_, Twox64Concat, u16, u32, OptionQuery, GetDefault, ConstU32<12>>; - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] #[pallet::storage] #[pallet::getter(fn conditional_double_map)] pub type ConditionalDoubleMap = StorageDoubleMap<_, Blake2_128Concat, u8, Twox64Concat, u16, u32>; - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] #[pallet::storage] #[pallet::getter(fn conditional_nmap)] pub type ConditionalNMap = @@ -477,7 +479,7 @@ pub mod pallet2 { where ::AccountId: From + SomeAssociation1, { - type Event: From + IsType<::Event>; + type RuntimeEvent: From + IsType<::RuntimeEvent>; } #[pallet::pallet] @@ -550,7 +552,11 @@ pub mod pallet2 { #[frame_support::pallet] pub mod pallet3 { #[pallet::config] - pub trait Config: frame_system::Config {} + pub trait Config: + frame_system::Config::RuntimeOrigin> + { + type RuntimeOrigin; + } #[pallet::pallet] pub struct Pallet(_); @@ -574,16 +580,16 @@ frame_support::parameter_types!( impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU32<250>; type BlockWeights = (); type BlockLength = (); @@ -599,7 +605,7 @@ impl frame_system::Config for Runtime { type MaxConsumers = ConstU32<16>; } impl pallet::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type MyGetParam = ConstU32<10>; type MyGetParam2 = ConstU32<11>; type MyGetParam3 = MyGetParam3; @@ -607,14 +613,19 @@ impl pallet::Config for Runtime { } impl pallet2::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; } impl pallet4::Config for Runtime {} +#[cfg(feature = "frame-feature-testing")] +impl pallet3::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; +} + pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Runtime where @@ -626,16 +637,16 @@ frame_support::construct_runtime!( System: frame_system exclude_parts { Pallet, Storage }, Example: pallet, Example2: pallet2 exclude_parts { Call }, - #[cfg(feature = "example3")] + #[cfg(feature = "frame-feature-testing")] Example3: pallet3, Example4: pallet4 use_parts { Call }, } ); -// Test that the part `Call` is excluded from Example2 and included in Example4. -fn _ensure_call_is_correctly_excluded_and_included(call: Call) { +// Test that the part `RuntimeCall` is excluded from Example2 and included in Example4. +fn _ensure_call_is_correctly_excluded_and_included(call: RuntimeCall) { match call { - Call::System(_) | Call::Example(_) | Call::Example4(_) => (), + RuntimeCall::System(_) | RuntimeCall::Example(_) | RuntimeCall::Example4(_) => (), } } @@ -658,7 +669,7 @@ fn transactional_works() { .iter() .map(|e| &e.event) .collect::>(), - vec![&Event::Example(pallet::Event::Something(0))], + vec![&RuntimeEvent::Example(pallet::Event::Something(0))], ); }) } @@ -723,7 +734,7 @@ fn inherent_expand() { let inherents = InherentData::new().create_extrinsics(); let expected = vec![UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_no_post_info {}), + function: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), signature: None, }]; assert_eq!(expected, inherents); @@ -738,11 +749,11 @@ fn inherent_expand() { ), vec![ UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_no_post_info {}), + function: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), signature: None, }, UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo { foo: 1, bar: 0 }), + function: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 0 }), signature: None, }, ], @@ -760,11 +771,11 @@ fn inherent_expand() { ), vec![ UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_no_post_info {}), + function: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), signature: None, }, UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo { foo: 0, bar: 0 }), + function: RuntimeCall::Example(pallet::Call::foo { foo: 0, bar: 0 }), signature: None, }, ], @@ -781,7 +792,7 @@ fn inherent_expand() { Digest::default(), ), vec![UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_storage_layer { foo: 0 }), + function: RuntimeCall::Example(pallet::Call::foo_storage_layer { foo: 0 }), signature: None, }], ); @@ -799,7 +810,7 @@ fn inherent_expand() { Digest::default(), ), vec![UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_no_post_info {}), + function: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), signature: Some((1, (), ())), }], ); @@ -818,11 +829,11 @@ fn inherent_expand() { ), vec![ UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo { foo: 1, bar: 1 }), + function: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 1 }), signature: None, }, UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_storage_layer { foo: 0 }), + function: RuntimeCall::Example(pallet::Call::foo_storage_layer { foo: 0 }), signature: None, }, ], @@ -840,15 +851,15 @@ fn inherent_expand() { ), vec![ UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo { foo: 1, bar: 1 }), + function: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 1 }), signature: None, }, UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_storage_layer { foo: 0 }), + function: RuntimeCall::Example(pallet::Call::foo_storage_layer { foo: 0 }), signature: None, }, UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_no_post_info {}), + function: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), signature: None, }, ], @@ -866,15 +877,15 @@ fn inherent_expand() { ), vec![ UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo { foo: 1, bar: 1 }), + function: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 1 }), signature: None, }, UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo { foo: 1, bar: 0 }), + function: RuntimeCall::Example(pallet::Call::foo { foo: 1, bar: 0 }), signature: Some((1, (), ())), }, UncheckedExtrinsic { - function: Call::Example(pallet::Call::foo_no_post_info {}), + function: RuntimeCall::Example(pallet::Call::foo_no_post_info {}), signature: None, }, ], @@ -918,7 +929,7 @@ fn pallet_expand_deposit_event() { .unwrap(); assert_eq!( frame_system::Pallet::::events()[0].event, - Event::Example(pallet::Event::Something(3)), + RuntimeEvent::Example(pallet::Event::Something(3)), ); }) } @@ -1024,7 +1035,7 @@ fn storage_expand() { Err(pallet::Error::::NonExistentStorageValue), ); - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] { pallet::ConditionalValue::::put(1); pallet::ConditionalMap::::insert(1, 2); @@ -1057,27 +1068,27 @@ fn pallet_hooks_expand() { assert_eq!( frame_system::Pallet::::events()[0].event, - Event::Example(pallet::Event::Something(10)), + RuntimeEvent::Example(pallet::Event::Something(10)), ); assert_eq!( frame_system::Pallet::::events()[1].event, - Event::Example2(pallet2::Event::Something(11)), + RuntimeEvent::Example2(pallet2::Event::Something(11)), ); assert_eq!( frame_system::Pallet::::events()[2].event, - Event::Example(pallet::Event::Something(20)), + RuntimeEvent::Example(pallet::Event::Something(20)), ); assert_eq!( frame_system::Pallet::::events()[3].event, - Event::Example2(pallet2::Event::Something(21)), + RuntimeEvent::Example2(pallet2::Event::Something(21)), ); assert_eq!( frame_system::Pallet::::events()[4].event, - Event::Example(pallet::Event::Something(30)), + RuntimeEvent::Example(pallet::Event::Something(30)), ); assert_eq!( frame_system::Pallet::::events()[5].event, - Event::Example2(pallet2::Event::Something(31)), + RuntimeEvent::Example2(pallet2::Event::Something(31)), ); }) } @@ -1103,27 +1114,27 @@ fn all_pallets_type_reversed_order_is_correct() { assert_eq!( frame_system::Pallet::::events()[0].event, - Event::Example2(pallet2::Event::Something(11)), + RuntimeEvent::Example2(pallet2::Event::Something(11)), ); assert_eq!( frame_system::Pallet::::events()[1].event, - Event::Example(pallet::Event::Something(10)), + RuntimeEvent::Example(pallet::Event::Something(10)), ); assert_eq!( frame_system::Pallet::::events()[2].event, - Event::Example2(pallet2::Event::Something(21)), + RuntimeEvent::Example2(pallet2::Event::Something(21)), ); assert_eq!( frame_system::Pallet::::events()[3].event, - Event::Example(pallet::Event::Something(20)), + RuntimeEvent::Example(pallet::Event::Something(20)), ); assert_eq!( frame_system::Pallet::::events()[4].event, - Event::Example2(pallet2::Event::Something(31)), + RuntimeEvent::Example2(pallet2::Event::Something(31)), ); assert_eq!( frame_system::Pallet::::events()[5].event, - Event::Example(pallet::Event::Something(30)), + RuntimeEvent::Example(pallet::Event::Something(30)), ); }) } @@ -1164,8 +1175,10 @@ fn migrate_from_pallet_version_to_storage_version() { AllPalletsWithSystem, >(&db_weight); - // 4 pallets, 2 writes and every write costs 5 weight. - assert_eq!(Weight::from_ref_time(4 * 2 * 5), weight); + let pallet_num = if cfg!(feature = "frame-feature-testing") { 5 } else { 4 }; + + // `pallet_num` pallets, 2 writes and every write costs 5 weight. + assert_eq!(Weight::from_ref_time(pallet_num * 2 * 5), weight); // All pallet versions should be removed assert!(sp_io::storage::get(&pallet_version_key(Example::name())).is_none()); @@ -1332,7 +1345,7 @@ fn metadata() { default: vec![1, 1], docs: vec![], }, - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] StorageEntryMetadata { name: "ConditionalValue", modifier: StorageEntryModifier::Optional, @@ -1340,7 +1353,7 @@ fn metadata() { default: vec![0], docs: vec![], }, - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] StorageEntryMetadata { name: "ConditionalMap", modifier: StorageEntryModifier::Optional, @@ -1352,7 +1365,7 @@ fn metadata() { default: vec![0], docs: vec![], }, - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] StorageEntryMetadata { name: "ConditionalDoubleMap", modifier: StorageEntryModifier::Optional, @@ -1367,7 +1380,7 @@ fn metadata() { default: vec![0], docs: vec![], }, - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] StorageEntryMetadata { name: "ConditionalNMap", modifier: StorageEntryModifier::Optional, @@ -1489,6 +1502,16 @@ fn metadata() { constants: vec![], error: None, }, + #[cfg(feature = "frame-feature-testing")] + PalletMetadata { + index: 3, + name: "Example3", + storage: None, + calls: None, + event: None, + constants: vec![], + error: None, + }, ]; let empty_doc = pallets[0].event.as_ref().unwrap().ty.type_info().docs().is_empty() && @@ -1633,7 +1656,7 @@ fn test_storage_info() { max_values: None, max_size: Some(16 + 1 + 8 + 2 + 16), }, - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] { StorageInfo { pallet_name: b"Example".to_vec(), @@ -1643,7 +1666,7 @@ fn test_storage_info() { max_size: Some(4), } }, - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] { StorageInfo { pallet_name: b"Example".to_vec(), @@ -1653,7 +1676,7 @@ fn test_storage_info() { max_size: Some(8 + 2 + 4), } }, - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] { StorageInfo { pallet_name: b"Example".to_vec(), @@ -1663,7 +1686,7 @@ fn test_storage_info() { max_size: Some(16 + 1 + 8 + 2 + 4), } }, - #[cfg(feature = "conditional-storage")] + #[cfg(feature = "frame-feature-testing")] { StorageInfo { pallet_name: b"Example".to_vec(), @@ -1730,27 +1753,42 @@ fn assert_type_all_pallets_reversed_with_system_first_is_correct() { // Just ensure the 2 types are same. #[allow(deprecated)] fn _a(_t: AllPalletsReversedWithSystemFirst) {} + #[cfg(not(feature = "frame-feature-testing"))] fn _b(t: (System, Example4, Example2, Example)) { _a(t) } + #[cfg(feature = "frame-feature-testing")] + fn _b(t: (System, Example4, Example3, Example2, Example)) { + _a(t) + } } #[test] fn assert_type_all_pallets_with_system_is_correct() { // Just ensure the 2 types are same. fn _a(_t: AllPalletsWithSystem) {} + #[cfg(not(feature = "frame-feature-testing"))] fn _b(t: (System, Example, Example2, Example4)) { _a(t) } + #[cfg(feature = "frame-feature-testing")] + fn _b(t: (System, Example, Example2, Example3, Example4)) { + _a(t) + } } #[test] fn assert_type_all_pallets_without_system_is_correct() { // Just ensure the 2 types are same. fn _a(_t: AllPalletsWithoutSystem) {} + #[cfg(not(feature = "frame-feature-testing"))] fn _b(t: (Example, Example2, Example4)) { _a(t) } + #[cfg(feature = "frame-feature-testing")] + fn _b(t: (Example, Example2, Example3, Example4)) { + _a(t) + } } #[test] @@ -1758,9 +1796,14 @@ fn assert_type_all_pallets_with_system_reversed_is_correct() { // Just ensure the 2 types are same. #[allow(deprecated)] fn _a(_t: AllPalletsWithSystemReversed) {} + #[cfg(not(feature = "frame-feature-testing"))] fn _b(t: (Example4, Example2, Example, System)) { _a(t) } + #[cfg(feature = "frame-feature-testing")] + fn _b(t: (Example4, Example3, Example2, Example, System)) { + _a(t) + } } #[test] @@ -1768,9 +1811,14 @@ fn assert_type_all_pallets_without_system_reversed_is_correct() { // Just ensure the 2 types are same. #[allow(deprecated)] fn _a(_t: AllPalletsWithoutSystemReversed) {} + #[cfg(not(feature = "frame-feature-testing"))] fn _b(t: (Example4, Example2, Example)) { _a(t) } + #[cfg(feature = "frame-feature-testing")] + fn _b(t: (Example4, Example3, Example2, Example)) { + _a(t) + } } #[test] diff --git a/frame/support/test/tests/pallet_compatibility.rs b/frame/support/test/tests/pallet_compatibility.rs index dc107b345c2b8..398137d644ee4 100644 --- a/frame/support/test/tests/pallet_compatibility.rs +++ b/frame/support/test/tests/pallet_compatibility.rs @@ -43,7 +43,7 @@ mod pallet_old { + Into + Default + SomeAssociation; - type Event: From> + Into<::Event>; + type RuntimeEvent: From> + Into<::RuntimeEvent>; } decl_storage! { @@ -70,7 +70,7 @@ mod pallet_old { ); decl_module! { - pub struct Module for enum Call where origin: T::Origin { + pub struct Module for enum Call where origin: T::RuntimeOrigin { type Error = Error; fn deposit_event() = default; const SomeConst: T::Balance = T::SomeConst::get(); @@ -120,7 +120,7 @@ pub mod pallet { + scale_info::StaticTypeInfo; #[pallet::constant] type SomeConst: Get; - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; } #[pallet::pallet] @@ -226,16 +226,16 @@ pub mod pallet { impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU32<250>; type BlockWeights = (); type BlockLength = (); @@ -251,19 +251,19 @@ impl frame_system::Config for Runtime { type MaxConsumers = ConstU32<16>; } impl pallet::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet_old::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SomeConst = ConstU64<10>; type Balance = u64; } pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Runtime where diff --git a/frame/support/test/tests/pallet_compatibility_instance.rs b/frame/support/test/tests/pallet_compatibility_instance.rs index 428de08864f29..e8b5fe9fa33d4 100644 --- a/frame/support/test/tests/pallet_compatibility_instance.rs +++ b/frame/support/test/tests/pallet_compatibility_instance.rs @@ -30,7 +30,7 @@ mod pallet_old { pub trait Config: frame_system::Config { type SomeConst: Get; type Balance: Parameter + codec::HasCompact + From + Into + Default; - type Event: From> + Into<::Event>; + type RuntimeEvent: From> + Into<::RuntimeEvent>; } decl_storage! { @@ -56,7 +56,7 @@ mod pallet_old { decl_module! { pub struct Module, I: Instance = DefaultInstance> for enum Call - where origin: T::Origin + where origin: T::RuntimeOrigin { type Error = Error; fn deposit_event() = default; @@ -105,7 +105,8 @@ pub mod pallet { + scale_info::StaticTypeInfo; #[pallet::constant] type SomeConst: Get; - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; } #[pallet::pallet] @@ -209,16 +210,16 @@ impl frame_system::Config for Runtime { type BlockLength = (); type DbWeight = (); type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU32<250>; type Version = (); type PalletInfo = PalletInfo; @@ -231,39 +232,39 @@ impl frame_system::Config for Runtime { type MaxConsumers = ConstU32<16>; } impl pallet::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet_old::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet_old::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SomeConst = ConstU64<10>; type Balance = u64; } impl pallet_old::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type SomeConst = ConstU64<10>; type Balance = u64; } pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Runtime where diff --git a/frame/support/test/tests/pallet_instance.rs b/frame/support/test/tests/pallet_instance.rs index 2ae910e73d87e..7e05e2ecf783b 100644 --- a/frame/support/test/tests/pallet_instance.rs +++ b/frame/support/test/tests/pallet_instance.rs @@ -16,11 +16,10 @@ // limitations under the License. use frame_support::{ - dispatch::UnfilteredDispatchable, + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays, UnfilteredDispatchable}, pallet_prelude::ValueQuery, storage::unhashed, traits::{ConstU32, GetCallName, OnFinalize, OnGenesis, OnInitialize, OnRuntimeUpgrade}, - weights::{DispatchClass, DispatchInfo, GetDispatchInfo, Pays}, }; use sp_io::{ hashing::{blake2_128, twox_128, twox_64}, @@ -42,7 +41,8 @@ pub mod pallet { #[pallet::constant] type MyGetParam: Get; type Balance: Parameter + Default + scale_info::StaticTypeInfo; - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; } #[pallet::pallet] @@ -253,7 +253,8 @@ pub mod pallet2 { #[pallet::config] pub trait Config: frame_system::Config { - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; } #[pallet::pallet] @@ -285,16 +286,16 @@ pub mod pallet2 { impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU32<250>; type BlockWeights = (); type BlockLength = (); @@ -310,25 +311,25 @@ impl frame_system::Config for Runtime { type MaxConsumers = ConstU32<16>; } impl pallet::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type MyGetParam = ConstU32<10>; type Balance = u64; } impl pallet::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type MyGetParam = ConstU32<10>; type Balance = u64; } impl pallet2::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; } impl pallet2::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; } pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; frame_support::construct_runtime!( pub enum Runtime where @@ -433,7 +434,7 @@ fn pallet_expand_deposit_event() { .unwrap(); assert_eq!( frame_system::Pallet::::events()[0].event, - Event::Example(pallet::Event::Something(3)), + RuntimeEvent::Example(pallet::Event::Something(3)), ); }); @@ -444,7 +445,7 @@ fn pallet_expand_deposit_event() { .unwrap(); assert_eq!( frame_system::Pallet::::events()[0].event, - Event::Instance1Example(pallet::Event::Something(3)), + RuntimeEvent::Instance1Example(pallet::Event::Something(3)), ); }); } @@ -668,27 +669,27 @@ fn pallet_hooks_expand() { assert_eq!( frame_system::Pallet::::events()[0].event, - Event::Example(pallet::Event::Something(10)), + RuntimeEvent::Example(pallet::Event::Something(10)), ); assert_eq!( frame_system::Pallet::::events()[1].event, - Event::Instance1Example(pallet::Event::Something(11)), + RuntimeEvent::Instance1Example(pallet::Event::Something(11)), ); assert_eq!( frame_system::Pallet::::events()[2].event, - Event::Example(pallet::Event::Something(20)), + RuntimeEvent::Example(pallet::Event::Something(20)), ); assert_eq!( frame_system::Pallet::::events()[3].event, - Event::Instance1Example(pallet::Event::Something(21)), + RuntimeEvent::Instance1Example(pallet::Event::Something(21)), ); assert_eq!( frame_system::Pallet::::events()[4].event, - Event::Example(pallet::Event::Something(30)), + RuntimeEvent::Example(pallet::Event::Something(30)), ); assert_eq!( frame_system::Pallet::::events()[5].event, - Event::Instance1Example(pallet::Event::Something(31)), + RuntimeEvent::Instance1Example(pallet::Event::Something(31)), ); }) } diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr index 1d581ea7ed572..86e8d33c8dad1 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound.stderr @@ -6,7 +6,7 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::Bar` = note: required because of the requirements on the impl of `std::fmt::Debug` for `&::Bar` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = note: required for the cast from `&::Bar` to the object type `dyn std::fmt::Debug` error[E0277]: the trait bound `::Bar: Clone` is not satisfied --> tests/pallet_ui/call_argument_invalid_bound.rs:20:36 diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr index b1487776eac50..c6acccaaba7d4 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_2.stderr @@ -6,7 +6,7 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::Bar` = note: required because of the requirements on the impl of `std::fmt::Debug` for `&::Bar` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = note: required for the cast from `&::Bar` to the object type `dyn std::fmt::Debug` error[E0277]: the trait bound `::Bar: Clone` is not satisfied --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 @@ -21,21 +21,23 @@ error[E0369]: binary operation `==` cannot be applied to type `&::Bar: WrapperTypeEncode` is not satisfied - --> tests/pallet_ui/call_argument_invalid_bound_2.rs:20:36 + --> tests/pallet_ui/call_argument_invalid_bound_2.rs:1:1 | -1 | / #[frame_support::pallet] +1 | #[frame_support::pallet] + | ^----------------------- + | | + | _in this procedural macro expansion + | | 2 | | mod pallet { 3 | | use frame_support::pallet_prelude::{Hooks, DispatchResultWithPostInfo}; 4 | | use frame_system::pallet_prelude::{BlockNumberFor, OriginFor}; ... | 16 | | 17 | | #[pallet::call] - | |__________________- required by a bound introduced by this call -... -20 | pub fn foo(origin: OriginFor, bar: T::Bar) -> DispatchResultWithPostInfo { - | ^^^ the trait `WrapperTypeEncode` is not implemented for `::Bar` + | |__________________^ the trait `WrapperTypeEncode` is not implemented for `::Bar` | = note: required because of the requirements on the impl of `Encode` for `::Bar` + = note: this error originates in the derive macro `frame_support::codec::Encode` which comes from the expansion of the attribute macro `frame_support::pallet` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `::Bar: WrapperTypeDecode` is not satisfied --> tests/pallet_ui/call_argument_invalid_bound_2.rs:17:12 diff --git a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr index a0418760ba7e2..4a0b2ea67c7d6 100644 --- a/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr +++ b/frame/support/test/tests/pallet_ui/call_argument_invalid_bound_3.stderr @@ -7,7 +7,7 @@ error[E0277]: `Bar` doesn't implement `std::fmt::Debug` = help: the trait `std::fmt::Debug` is not implemented for `Bar` = note: add `#[derive(Debug)]` to `Bar` or manually `impl std::fmt::Debug for Bar` = note: required because of the requirements on the impl of `std::fmt::Debug` for `&Bar` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = note: required for the cast from `&Bar` to the object type `dyn std::fmt::Debug` help: consider annotating `Bar` with `#[derive(Debug)]` | 17 | #[derive(Debug)] diff --git a/frame/support/test/tests/pallet_ui/event_field_not_member.rs b/frame/support/test/tests/pallet_ui/event_field_not_member.rs index 0ecde4c130878..2b45a971788fb 100644 --- a/frame/support/test/tests/pallet_ui/event_field_not_member.rs +++ b/frame/support/test/tests/pallet_ui/event_field_not_member.rs @@ -6,7 +6,7 @@ mod pallet { #[pallet::config] pub trait Config: frame_system::Config { type Bar; - type Event: IsType<::Event> + From>; + type RuntimeEvent: IsType<::RuntimeEvent> + From>; } #[pallet::pallet] diff --git a/frame/support/test/tests/pallet_ui/event_field_not_member.stderr b/frame/support/test/tests/pallet_ui/event_field_not_member.stderr index 92623e0329fe3..f95da9deef90a 100644 --- a/frame/support/test/tests/pallet_ui/event_field_not_member.stderr +++ b/frame/support/test/tests/pallet_ui/event_field_not_member.stderr @@ -18,4 +18,4 @@ error[E0277]: `::Bar` doesn't implement `std::fmt::Debug` | = help: the trait `std::fmt::Debug` is not implemented for `::Bar` = note: required because of the requirements on the impl of `std::fmt::Debug` for `&::Bar` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = note: required for the cast from `&::Bar` to the object type `dyn std::fmt::Debug` diff --git a/frame/support/test/tests/pallet_ui/event_not_in_trait.stderr b/frame/support/test/tests/pallet_ui/event_not_in_trait.stderr index e3126ad6a85dc..2eda72eb5f72f 100644 --- a/frame/support/test/tests/pallet_ui/event_not_in_trait.stderr +++ b/frame/support/test/tests/pallet_ui/event_not_in_trait.stderr @@ -1,4 +1,4 @@ -error: Invalid usage of Event, `Config` contains no associated type `Event`, but enum `Event` is declared (in use of `#[pallet::event]`). An Event associated type must be declare on trait `Config`. +error: Invalid usage of RuntimeEvent, `Config` contains no associated type `RuntimeEvent`, but enum `Event` is declared (in use of `#[pallet::event]`). An RuntimeEvent associated type must be declare on trait `Config`. --> $DIR/event_not_in_trait.rs:1:1 | 1 | #[frame_support::pallet] diff --git a/frame/support/test/tests/pallet_ui/event_type_invalid_bound.rs b/frame/support/test/tests/pallet_ui/event_type_invalid_bound.rs index fa3bf04d3530d..a02cc9b9de883 100644 --- a/frame/support/test/tests/pallet_ui/event_type_invalid_bound.rs +++ b/frame/support/test/tests/pallet_ui/event_type_invalid_bound.rs @@ -6,7 +6,7 @@ mod pallet { #[pallet::config] pub trait Config: frame_system::Config { type Bar; - type Event; + type RuntimeEvent; } #[pallet::pallet] diff --git a/frame/support/test/tests/pallet_ui/event_type_invalid_bound.stderr b/frame/support/test/tests/pallet_ui/event_type_invalid_bound.stderr index 1f58a37576d0d..d54149d719a3b 100644 --- a/frame/support/test/tests/pallet_ui/event_type_invalid_bound.stderr +++ b/frame/support/test/tests/pallet_ui/event_type_invalid_bound.stderr @@ -1,5 +1,5 @@ -error: Invalid `type Event`, associated type `Event` is reserved and must bound: `IsType<::Event>` +error: Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must bound: `IsType<::RuntimeEvent>` --> $DIR/event_type_invalid_bound.rs:9:3 | -9 | type Event; +9 | type RuntimeEvent; | ^^^^ diff --git a/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.rs b/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.rs index 564a539b89f57..99df89d67278c 100644 --- a/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.rs +++ b/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.rs @@ -6,7 +6,7 @@ mod pallet { #[pallet::config] pub trait Config: frame_system::Config { type Bar; - type Event: IsType<::Event>; + type RuntimeEvent: IsType<::RuntimeEvent>; } #[pallet::pallet] diff --git a/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.stderr b/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.stderr index 8b8946f3b25eb..ea8b2ff000ceb 100644 --- a/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.stderr +++ b/frame/support/test/tests/pallet_ui/event_type_invalid_bound_2.stderr @@ -1,5 +1,5 @@ -error: Invalid `type Event`, associated type `Event` is reserved and must bound: `From` or `From>` or `From>` +error: Invalid `type RuntimeEvent`, associated type `RuntimeEvent` is reserved and must bound: `From` or `From>` or `From>` --> $DIR/event_type_invalid_bound_2.rs:9:3 | -9 | type Event: IsType<::Event>; +9 | type RuntimeEvent: IsType<::RuntimeEvent>; | ^^^^ diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr index e674e49eddbe5..cced83f207c41 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen.stderr @@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 279 others + and 278 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -69,7 +69,7 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied (A, B, C, D) (A, B, C, D, E) (A, B, C, D, E, F) - and 159 others + and 161 others = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 279 others + and 278 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr index ecdc18263432e..ab377e05d3901 100644 --- a/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr +++ b/frame/support/test/tests/pallet_ui/storage_ensure_span_are_ok_on_wrong_gen_unnamed.stderr @@ -28,7 +28,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 279 others + and 278 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `PartialStorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -69,7 +69,7 @@ error[E0277]: the trait bound `Bar: TypeInfo` is not satisfied (A, B, C, D) (A, B, C, D, E) (A, B, C, D, E, F) - and 159 others + and 161 others = note: required because of the requirements on the impl of `StaticTypeInfo` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` @@ -103,7 +103,7 @@ error[E0277]: the trait bound `Bar: EncodeLike` is not satisfied <&[(T,)] as EncodeLike>> <&[(T,)] as EncodeLike>> <&[T] as EncodeLike>> - and 279 others + and 278 others = note: required because of the requirements on the impl of `FullEncode` for `Bar` = note: required because of the requirements on the impl of `FullCodec` for `Bar` = note: required because of the requirements on the impl of `StorageEntryMetadataBuilder` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr index d9cd20711403d..8d3d7a71a313e 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied.stderr @@ -13,5 +13,5 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) - and 76 others + and 78 others = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageValue<_GeneratedPrefixForStorageFoo, Bar>` diff --git a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index 9a4e8d740cb2c..ebf24a1232e3c 100644 --- a/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -13,6 +13,6 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6) (TupleElement0, TupleElement1, TupleElement2, TupleElement3, TupleElement4, TupleElement5, TupleElement6, TupleElement7) - and 76 others + and 78 others = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key` = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` diff --git a/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr b/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr index 6313bd691f943..80c6526bbf888 100644 --- a/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr +++ b/frame/support/test/tests/pallet_ui/storage_invalid_attribute.stderr @@ -1,4 +1,4 @@ -error: expected one of: `getter`, `storage_prefix`, `unbounded` +error: expected one of: `getter`, `storage_prefix`, `unbounded`, `whitelist_storage` --> $DIR/storage_invalid_attribute.rs:16:12 | 16 | #[pallet::generate_store(pub trait Store)] diff --git a/frame/support/test/tests/pallet_ui/storage_not_storage_type.stderr b/frame/support/test/tests/pallet_ui/storage_not_storage_type.stderr index 4fd59183282d0..223e9cfa3e9f8 100644 --- a/frame/support/test/tests/pallet_ui/storage_not_storage_type.stderr +++ b/frame/support/test/tests/pallet_ui/storage_not_storage_type.stderr @@ -1,4 +1,4 @@ -error: Invalid pallet::storage, expected ident: `StorageValue` or `StorageMap` or `StorageDoubleMap` or `StorageNMap` in order to expand metadata, found `u8`. +error: Invalid pallet::storage, expected ident: `StorageValue` or `StorageMap` or `CountedStorageMap` or `StorageDoubleMap` or `StorageNMap` in order to expand metadata, found `u8`. --> $DIR/storage_not_storage_type.rs:19:16 | 19 | type Foo = u8; diff --git a/frame/support/test/tests/pallet_with_name_trait_is_valid.rs b/frame/support/test/tests/pallet_with_name_trait_is_valid.rs index 6415c3c0d2c07..0066420566fe8 100644 --- a/frame/support/test/tests/pallet_with_name_trait_is_valid.rs +++ b/frame/support/test/tests/pallet_with_name_trait_is_valid.rs @@ -18,7 +18,7 @@ pub trait Trait: frame_system::Config { type Balance: frame_support::dispatch::Parameter; /// The overarching event type. - type Event: From> + Into<::Event>; + type RuntimeEvent: From> + Into<::RuntimeEvent>; } frame_support::decl_storage! { @@ -43,7 +43,7 @@ frame_support::decl_error!( ); frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin { + pub struct Module for enum Call where origin: T::RuntimeOrigin { fn deposit_event() = default; type Error = Error; const Foo: u32 = u32::MAX; @@ -108,7 +108,7 @@ mod tests { type TestHeader = sp_runtime::generic::Header; type TestUncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic< ::AccountId, - ::Call, + ::RuntimeCall, (), SignedExtra, >; @@ -126,16 +126,16 @@ mod tests { impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = sp_core::H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = TestHeader; - type Event = (); + type RuntimeEvent = (); type BlockHashCount = ConstU64<250>; type DbWeight = (); type BlockWeights = (); @@ -153,6 +153,6 @@ mod tests { impl pallet_test::Trait for Runtime { type Balance = u32; - type Event = (); + type RuntimeEvent = (); } } diff --git a/frame/support/test/tests/storage_layers.rs b/frame/support/test/tests/storage_layers.rs index 7404ccace2c09..6fbbb8ac67bd7 100644 --- a/frame/support/test/tests/storage_layers.rs +++ b/frame/support/test/tests/storage_layers.rs @@ -59,7 +59,7 @@ pub mod decl_pallet { pub trait Config: frame_system::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin { + pub struct Module for enum Call where origin: T::RuntimeOrigin { #[weight = 0] pub fn set_value(_origin, value: u32) { DeclValue::put(value); @@ -79,23 +79,23 @@ pub type BlockNumber = u64; pub type Index = u64; pub type Header = sp_runtime::generic::Header; pub type Block = sp_runtime::generic::Block; -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; +pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; impl frame_system::Config for Runtime { type BlockWeights = (); type BlockLength = (); type DbWeight = (); type BaseCallFilter = frame_support::traits::Everything; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u32; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_runtime::testing::H256; type Hashing = sp_runtime::traits::BlakeTwo256; type AccountId = u64; type Lookup = sp_runtime::traits::IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU32<250>; type Version = (); type PalletInfo = PalletInfo; @@ -255,12 +255,12 @@ fn storage_layer_commit_then_rollback() { fn storage_layer_in_pallet_call() { TestExternalities::default().execute_with(|| { use sp_runtime::traits::Dispatchable; - let call1 = Call::MyPallet(pallet::Call::set_value { value: 2 }); - assert_ok!(call1.dispatch(Origin::signed(0))); + let call1 = RuntimeCall::MyPallet(pallet::Call::set_value { value: 2 }); + assert_ok!(call1.dispatch(RuntimeOrigin::signed(0))); assert_eq!(Value::::get(), 2); - let call2 = Call::MyPallet(pallet::Call::set_value { value: 1 }); - assert_noop!(call2.dispatch(Origin::signed(0)), Error::::Revert); + let call2 = RuntimeCall::MyPallet(pallet::Call::set_value { value: 1 }); + assert_noop!(call2.dispatch(RuntimeOrigin::signed(0)), Error::::Revert); }); } @@ -270,13 +270,16 @@ fn storage_layer_in_decl_pallet_call() { use frame_support::StorageValue; use sp_runtime::traits::Dispatchable; - let call1 = Call::DeclPallet(decl_pallet::Call::set_value { value: 2 }); - assert_ok!(call1.dispatch(Origin::signed(0))); + let call1 = RuntimeCall::DeclPallet(decl_pallet::Call::set_value { value: 2 }); + assert_ok!(call1.dispatch(RuntimeOrigin::signed(0))); assert_eq!(decl_pallet::DeclValue::get(), 2); - let call2 = Call::DeclPallet(decl_pallet::Call::set_value { value: 1 }); - assert_noop!(call2.dispatch(Origin::signed(0)), "Revert!"); + let call2 = RuntimeCall::DeclPallet(decl_pallet::Call::set_value { value: 1 }); + assert_noop!(call2.dispatch(RuntimeOrigin::signed(0)), "Revert!"); // Calling the function directly also works with storage layers. - assert_noop!(decl_pallet::Module::::set_value(Origin::signed(1), 1), "Revert!"); + assert_noop!( + decl_pallet::Module::::set_value(RuntimeOrigin::signed(1), 1), + "Revert!" + ); }); } diff --git a/frame/support/test/tests/storage_transaction.rs b/frame/support/test/tests/storage_transaction.rs index 9e597969d6c89..6fedd75019e37 100644 --- a/frame/support/test/tests/storage_transaction.rs +++ b/frame/support/test/tests/storage_transaction.rs @@ -31,7 +31,7 @@ use sp_std::result; pub trait Config: frame_support_test::Config {} frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=frame_support_test { + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=frame_support_test { #[weight = 0] #[transactional] fn value_commits(_origin, v: u32) { @@ -57,7 +57,7 @@ frame_support::decl_storage! { struct Runtime; impl frame_support_test::Config for Runtime { - type Origin = u32; + type RuntimeOrigin = u32; type BlockNumber = u32; type PalletInfo = frame_support_test::PanicPalletInfo; type DbWeight = (); diff --git a/frame/support/test/tests/system.rs b/frame/support/test/tests/system.rs index b30fd8d5ec561..eff41242917a0 100644 --- a/frame/support/test/tests/system.rs +++ b/frame/support/test/tests/system.rs @@ -22,28 +22,28 @@ use frame_support::{ }; pub trait Config: 'static + Eq + Clone { - type Origin: Into, Self::Origin>> + type RuntimeOrigin: Into, Self::RuntimeOrigin>> + From>; - type BaseCallFilter: frame_support::traits::Contains; + type BaseCallFilter: frame_support::traits::Contains; type BlockNumber: Decode + Encode + EncodeLike + Clone + Default + scale_info::TypeInfo; type Hash; type AccountId: Encode + EncodeLike + Decode + scale_info::TypeInfo; - type Call; - type Event: From>; + type RuntimeCall; + type RuntimeEvent: From>; type PalletInfo: frame_support::traits::PalletInfo; type DbWeight: Get; } frame_support::decl_module! { - pub struct Module for enum Call where origin: T::Origin, system=self { + pub struct Module for enum Call where origin: T::RuntimeOrigin, system=self { #[weight = 0] fn noop(_origin) {} } } impl Module { - pub fn deposit_event(_event: impl Into) {} + pub fn deposit_event(_event: impl Into) {} } frame_support::decl_event!( diff --git a/frame/system/Cargo.toml b/frame/system/Cargo.toml index db0fdc21540bc..b9b848ca0182f 100644 --- a/frame/system/Cargo.toml +++ b/frame/system/Cargo.toml @@ -23,9 +23,11 @@ sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/ sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } sp-version = { version = "5.0.0", default-features = false, path = "../../primitives/version" } +sp-weights = { version = "4.0.0", default-features = false, path = "../../primitives/weights" } sp-ver = { version = "4.0.0-dev", default-features = false, path = "../../primitives/ver" } extrinsic-shuffler = { version = "4.0.0-dev", default-features = false, path = "../../primitives/shuffler" } + [dev-dependencies] criterion = "0.3.3" sp-externalities = { version = "0.12.0", path = "../../primitives/externalities" } @@ -45,13 +47,14 @@ std = [ "sp-std/std", "sp-ver/std", "sp-version/std", + "sp-weights/std", "extrinsic-shuffler/std", ] runtime-benchmarks = [ "frame-support/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] -try-runtime = ["frame-support/try-runtime", "frame-support/try-runtime"] +try-runtime = ["frame-support/try-runtime"] [[bench]] name = "bench" diff --git a/frame/system/benches/bench.rs b/frame/system/benches/bench.rs index 017298dab3928..0881b81eaca7d 100644 --- a/frame/system/benches/bench.rs +++ b/frame/system/benches/bench.rs @@ -37,7 +37,7 @@ mod module { #[pallet::config] pub trait Config: frame_system::Config { - type Event: From + IsType<::Event>; + type RuntimeEvent: From + IsType<::RuntimeEvent>; } #[pallet::event] @@ -76,16 +76,16 @@ impl frame_system::Config for Runtime { type BlockWeights = (); type BlockLength = BlockLength; type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -99,7 +99,7 @@ impl frame_system::Config for Runtime { } impl module::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; } fn new_test_ext() -> sp_io::TestExternalities { diff --git a/frame/system/benchmarking/Cargo.toml b/frame/system/benchmarking/Cargo.toml index 437d06a17c781..9ec9ed2ae6d21 100644 --- a/frame/system/benchmarking/Cargo.toml +++ b/frame/system/benchmarking/Cargo.toml @@ -37,3 +37,9 @@ std = [ "sp-runtime/std", "sp-std/std", ] + +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", +] diff --git a/frame/system/benchmarking/src/lib.rs b/frame/system/benchmarking/src/lib.rs index 367e6c73c4134..0f7603fe1dd9f 100644 --- a/frame/system/benchmarking/src/lib.rs +++ b/frame/system/benchmarking/src/lib.rs @@ -21,7 +21,7 @@ use codec::Encode; use frame_benchmarking::{benchmarks, whitelisted_caller}; -use frame_support::{storage, traits::Get, weights::DispatchClass}; +use frame_support::{dispatch::DispatchClass, storage, traits::Get}; use frame_system::{Call, Pallet as System, RawOrigin}; use sp_core::storage::well_known_keys; use sp_runtime::traits::Hash; @@ -64,7 +64,7 @@ benchmarks! { #[skip_meta] set_storage { - let i in 1 .. 1000; + let i in 0 .. 1000; // Set up i items to add let mut items = Vec::new(); @@ -72,56 +72,69 @@ benchmarks! { let hash = (i, j).using_encoded(T::Hashing::hash).as_ref().to_vec(); items.push((hash.clone(), hash.clone())); } + + let items_to_verify = items.clone(); }: _(RawOrigin::Root, items) verify { - let last_hash = (i, i - 1).using_encoded(T::Hashing::hash); - let value = storage::unhashed::get_raw(last_hash.as_ref()).ok_or("No value stored")?; - assert_eq!(value, last_hash.as_ref().to_vec()); + // Verify that they're actually in the storage. + for (item, _) in items_to_verify { + let value = storage::unhashed::get_raw(&item).ok_or("No value stored")?; + assert_eq!(value, *item); + } } #[skip_meta] kill_storage { - let i in 1 .. 1000; + let i in 0 .. 1000; // Add i items to storage - let mut items = Vec::new(); + let mut items = Vec::with_capacity(i as usize); for j in 0 .. i { let hash = (i, j).using_encoded(T::Hashing::hash).as_ref().to_vec(); storage::unhashed::put_raw(&hash, &hash); items.push(hash); } - // We will verify this value is removed - let last_hash = (i, i - 1).using_encoded(T::Hashing::hash); - let value = storage::unhashed::get_raw(last_hash.as_ref()).ok_or("No value stored")?; - assert_eq!(value, last_hash.as_ref().to_vec()); + // Verify that they're actually in the storage. + for item in &items { + let value = storage::unhashed::get_raw(item).ok_or("No value stored")?; + assert_eq!(value, *item); + } + let items_to_verify = items.clone(); }: _(RawOrigin::Root, items) verify { - assert_eq!(storage::unhashed::get_raw(last_hash.as_ref()), None); + // Verify that they're not in the storage anymore. + for item in items_to_verify { + assert!(storage::unhashed::get_raw(&item).is_none()); + } } #[skip_meta] kill_prefix { - let p in 1 .. 1000; + let p in 0 .. 1000; let prefix = p.using_encoded(T::Hashing::hash).as_ref().to_vec(); + let mut items = Vec::with_capacity(p as usize); // add p items that share a prefix for i in 0 .. p { let hash = (p, i).using_encoded(T::Hashing::hash).as_ref().to_vec(); let key = [&prefix[..], &hash[..]].concat(); storage::unhashed::put_raw(&key, &key); + items.push(key); } - // We will verify this value is removed - let last_hash = (p, p - 1).using_encoded(T::Hashing::hash).as_ref().to_vec(); - let last_key = [&prefix[..], &last_hash[..]].concat(); - let value = storage::unhashed::get_raw(&last_key).ok_or("No value stored")?; - assert_eq!(value, last_key); - + // Verify that they're actually in the storage. + for item in &items { + let value = storage::unhashed::get_raw(item).ok_or("No value stored")?; + assert_eq!(value, *item); + } }: _(RawOrigin::Root, prefix, p) verify { - assert_eq!(storage::unhashed::get_raw(&last_key), None); + // Verify that they're not in the storage anymore. + for item in items { + assert!(storage::unhashed::get_raw(&item).is_none()); + } } impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/frame/system/benchmarking/src/mock.rs b/frame/system/benchmarking/src/mock.rs index 08b043ae62741..a7f28ca30fe87 100644 --- a/frame/system/benchmarking/src/mock.rs +++ b/frame/system/benchmarking/src/mock.rs @@ -43,16 +43,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = AccountIndex; type BlockNumber = BlockNumber; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = sp_core::H256; type Hashing = ::sp_runtime::traits::BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = sp_runtime::testing::Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = (); type Version = (); type PalletInfo = PalletInfo; diff --git a/frame/system/src/extensions/check_genesis.rs b/frame/system/src/extensions/check_genesis.rs index a0679b11487f6..f5811f306cfe3 100644 --- a/frame/system/src/extensions/check_genesis.rs +++ b/frame/system/src/extensions/check_genesis.rs @@ -54,7 +54,7 @@ impl CheckGenesis { impl SignedExtension for CheckGenesis { type AccountId = T::AccountId; - type Call = ::Call; + type Call = ::RuntimeCall; type AdditionalSigned = T::Hash; type Pre = (); const IDENTIFIER: &'static str = "CheckGenesis"; diff --git a/frame/system/src/extensions/check_mortality.rs b/frame/system/src/extensions/check_mortality.rs index 59a6e14aca175..635ab4ef1d9a9 100644 --- a/frame/system/src/extensions/check_mortality.rs +++ b/frame/system/src/extensions/check_mortality.rs @@ -56,7 +56,7 @@ impl sp_std::fmt::Debug for CheckMortality { impl SignedExtension for CheckMortality { type AccountId = T::AccountId; - type Call = T::Call; + type Call = T::RuntimeCall; type AdditionalSigned = T::Hash; type Pre = (); const IDENTIFIER: &'static str = "CheckMortality"; @@ -101,7 +101,10 @@ impl SignedExtension for CheckMortality { mod tests { use super::*; use crate::mock::{new_test_ext, System, Test, CALL}; - use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight}; + use frame_support::{ + dispatch::{DispatchClass, DispatchInfo, Pays}, + weights::Weight, + }; use sp_core::H256; #[test] diff --git a/frame/system/src/extensions/check_non_zero_sender.rs b/frame/system/src/extensions/check_non_zero_sender.rs index 9a6c4007b3779..036f70c2fdd48 100644 --- a/frame/system/src/extensions/check_non_zero_sender.rs +++ b/frame/system/src/extensions/check_non_zero_sender.rs @@ -17,7 +17,7 @@ use crate::Config; use codec::{Decode, Encode}; -use frame_support::weights::DispatchInfo; +use frame_support::dispatch::DispatchInfo; use scale_info::TypeInfo; use sp_runtime::{ traits::{DispatchInfoOf, Dispatchable, SignedExtension}, @@ -53,10 +53,10 @@ impl CheckNonZeroSender { impl SignedExtension for CheckNonZeroSender where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { type AccountId = T::AccountId; - type Call = T::Call; + type Call = T::RuntimeCall; type AdditionalSigned = (); type Pre = (); const IDENTIFIER: &'static str = "CheckNonZeroSender"; diff --git a/frame/system/src/extensions/check_nonce.rs b/frame/system/src/extensions/check_nonce.rs index 68b4e11d47fa1..73cb787f51c4c 100644 --- a/frame/system/src/extensions/check_nonce.rs +++ b/frame/system/src/extensions/check_nonce.rs @@ -17,7 +17,7 @@ use crate::Config; use codec::{Decode, Encode}; -use frame_support::weights::DispatchInfo; +use frame_support::dispatch::DispatchInfo; use scale_info::TypeInfo; use sp_runtime::{ traits::{DispatchInfoOf, Dispatchable, One, SignedExtension}, @@ -60,10 +60,10 @@ impl sp_std::fmt::Debug for CheckNonce { impl SignedExtension for CheckNonce where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { type AccountId = T::AccountId; - type Call = T::Call; + type Call = T::RuntimeCall; type AdditionalSigned = (); type Pre = (); const IDENTIFIER: &'static str = "CheckNonce"; diff --git a/frame/system/src/extensions/check_spec_version.rs b/frame/system/src/extensions/check_spec_version.rs index 0280d31f657ae..ef5f40402692c 100644 --- a/frame/system/src/extensions/check_spec_version.rs +++ b/frame/system/src/extensions/check_spec_version.rs @@ -54,7 +54,7 @@ impl CheckSpecVersion { impl SignedExtension for CheckSpecVersion { type AccountId = T::AccountId; - type Call = ::Call; + type Call = ::RuntimeCall; type AdditionalSigned = u32; type Pre = (); const IDENTIFIER: &'static str = "CheckSpecVersion"; diff --git a/frame/system/src/extensions/check_tx_version.rs b/frame/system/src/extensions/check_tx_version.rs index b92d8978bde01..be0b8fe2354aa 100644 --- a/frame/system/src/extensions/check_tx_version.rs +++ b/frame/system/src/extensions/check_tx_version.rs @@ -54,7 +54,7 @@ impl CheckTxVersion { impl SignedExtension for CheckTxVersion { type AccountId = T::AccountId; - type Call = ::Call; + type Call = ::RuntimeCall; type AdditionalSigned = u32; type Pre = (); const IDENTIFIER: &'static str = "CheckTxVersion"; diff --git a/frame/system/src/extensions/check_weight.rs b/frame/system/src/extensions/check_weight.rs index d6434b6c63d8a..5c3b80f59bfa8 100644 --- a/frame/system/src/extensions/check_weight.rs +++ b/frame/system/src/extensions/check_weight.rs @@ -18,8 +18,8 @@ use crate::{limits::BlockWeights, Config, Pallet}; use codec::{Decode, Encode}; use frame_support::{ + dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}, traits::Get, - weights::{DispatchClass, DispatchInfo, PostDispatchInfo, Weight}, }; use scale_info::TypeInfo; use sp_runtime::{ @@ -27,6 +27,7 @@ use sp_runtime::{ transaction_validity::{InvalidTransaction, TransactionValidity, TransactionValidityError}, DispatchResult, }; +use sp_weights::Weight; /// Block resource (weight) limit check. /// @@ -40,16 +41,17 @@ pub struct CheckWeight(sp_std::marker::PhantomData); impl CheckWeight where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { /// Checks if the current extrinsic does not exceed the maximum weight a single extrinsic /// with given `DispatchClass` can have. fn check_extrinsic_weight( - info: &DispatchInfoOf, + info: &DispatchInfoOf, ) -> Result<(), TransactionValidityError> { let max = T::BlockWeights::get().get(info.class).max_extrinsic; match max { - Some(max) if info.weight > max => Err(InvalidTransaction::ExhaustsResources.into()), + Some(max) if info.weight.any_gt(max) => + Err(InvalidTransaction::ExhaustsResources.into()), _ => Ok(()), } } @@ -58,18 +60,18 @@ where /// /// Upon successes, it returns the new block weight as a `Result`. fn check_block_weight( - info: &DispatchInfoOf, + info: &DispatchInfoOf, ) -> Result { let maximum_weight = T::BlockWeights::get(); let all_weight = Pallet::::block_weight(); - calculate_consumed_weight::(maximum_weight, all_weight, info) + calculate_consumed_weight::(maximum_weight, all_weight, info) } /// Checks if the current extrinsic can fit into the block with respect to block length limits. /// /// Upon successes, it returns the new block length as a `Result`. fn check_block_length( - info: &DispatchInfoOf, + info: &DispatchInfoOf, len: usize, ) -> Result { let length_limit = T::BlockLength::get(); @@ -92,7 +94,7 @@ where /// /// It checks and notes the new weight and length. pub fn do_pre_dispatch( - info: &DispatchInfoOf, + info: &DispatchInfoOf, len: usize, ) -> Result<(), TransactionValidityError> { let next_len = Self::check_block_length(info, len)?; @@ -107,7 +109,7 @@ where /// Do the validate checks. This can be applied to both signed and unsigned. /// /// It only checks that the block weight and length limit will not exceed. - pub fn do_validate(info: &DispatchInfoOf, len: usize) -> TransactionValidity { + pub fn do_validate(info: &DispatchInfoOf, len: usize) -> TransactionValidity { // ignore the next length. If they return `Ok`, then it is below the limit. let _ = Self::check_block_length(info, len)?; // during validation we skip block limit check. Since the `validate_transaction` @@ -144,7 +146,8 @@ where // Check if we don't exceed per-class allowance match limit_per_class.max_total { - Some(max) if per_class > max => return Err(InvalidTransaction::ExhaustsResources.into()), + Some(max) if per_class.any_gt(max) => + return Err(InvalidTransaction::ExhaustsResources.into()), // There is no `max_total` limit (`None`), // or we are below the limit. _ => {}, @@ -152,10 +155,10 @@ where // In cases total block weight is exceeded, we need to fall back // to `reserved` pool if there is any. - if all_weight.total() > maximum_weight.max_block { + if all_weight.total().any_gt(maximum_weight.max_block) { match limit_per_class.reserved { // We are over the limit in reserved pool. - Some(reserved) if per_class > reserved => + Some(reserved) if per_class.any_gt(reserved) => return Err(InvalidTransaction::ExhaustsResources.into()), // There is either no limit in reserved pool (`None`), // or we are below the limit. @@ -168,10 +171,10 @@ where impl SignedExtension for CheckWeight where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { type AccountId = T::AccountId; - type Call = T::Call; + type Call = T::RuntimeCall; type AdditionalSigned = (); type Pre = (); const IDENTIFIER: &'static str = "CheckWeight"; @@ -238,7 +241,7 @@ where } let unspent = post_info.calc_unspent(info); - if unspent > Weight::zero() { + if unspent.any_gt(Weight::zero()) { crate::BlockWeight::::mutate(|current_weight| { current_weight.sub(unspent, info.class); }) @@ -267,10 +270,7 @@ mod tests { mock::{new_test_ext, System, Test, CALL}, AllExtrinsicsLen, BlockWeight, }; - use frame_support::{ - assert_err, assert_ok, - weights::{Pays, Weight}, - }; + use frame_support::{assert_err, assert_ok, dispatch::Pays, weights::Weight}; use sp_std::marker::PhantomData; fn block_weights() -> crate::limits::BlockWeights { @@ -310,7 +310,7 @@ mod tests { check(|max, len| { assert_ok!(CheckWeight::::do_pre_dispatch(max, len)); assert_eq!(System::block_weight().total(), Weight::MAX); - assert!(System::block_weight().total() > block_weight_limit()); + assert!(System::block_weight().total().ref_time() > block_weight_limit().ref_time()); }); check(|max, len| { assert_ok!(CheckWeight::::do_validate(max, len)); @@ -342,7 +342,7 @@ mod tests { .get(DispatchClass::Operational) .max_total .unwrap_or_else(|| weights.max_block); - let base_weight = weights.get(DispatchClass::Normal).base_extrinsic; + let base_weight = weights.get(DispatchClass::Operational).base_extrinsic; let weight = operational_limit - base_weight; let okay = @@ -367,7 +367,7 @@ mod tests { new_test_ext().execute_with(|| { System::register_extra_weight_unchecked(Weight::MAX, DispatchClass::Normal); assert_eq!(System::block_weight().total(), Weight::MAX); - assert!(System::block_weight().total() > block_weight_limit()); + assert!(System::block_weight().total().ref_time() > block_weight_limit().ref_time()); }); } @@ -378,11 +378,11 @@ mod tests { // Max normal is 768 (75%) // 10 is taken for block execution weight // So normal extrinsic can be 758 weight (-5 for base extrinsic weight) - // And Operational can be 256 to produce a full block (-5 for base) + // And Operational can be 246 to produce a full block (-10 for base) let max_normal = DispatchInfo { weight: Weight::from_ref_time(753), ..Default::default() }; let rest_operational = DispatchInfo { - weight: Weight::from_ref_time(251), + weight: Weight::from_ref_time(246), class: DispatchClass::Operational, ..Default::default() }; @@ -392,8 +392,8 @@ mod tests { assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); assert_eq!(System::block_weight().total(), Weight::from_ref_time(768)); assert_ok!(CheckWeight::::do_pre_dispatch(&rest_operational, len)); - assert_eq!(block_weight_limit(), Weight::from_ref_time(1024)); - assert_eq!(System::block_weight().total(), block_weight_limit()); + assert_eq!(block_weight_limit(), Weight::from_ref_time(1024).set_proof_size(u64::MAX)); + assert_eq!(System::block_weight().total(), block_weight_limit().set_proof_size(0)); // Checking single extrinsic should not take current block weight into account. assert_eq!(CheckWeight::::check_extrinsic_weight(&rest_operational), Ok(())); }); @@ -406,7 +406,7 @@ mod tests { let max_normal = DispatchInfo { weight: Weight::from_ref_time(753), ..Default::default() }; let rest_operational = DispatchInfo { - weight: Weight::from_ref_time(251), + weight: Weight::from_ref_time(246), class: DispatchClass::Operational, ..Default::default() }; @@ -414,11 +414,11 @@ mod tests { let len = 0_usize; assert_ok!(CheckWeight::::do_pre_dispatch(&rest_operational, len)); - // Extra 15 here from block execution + base extrinsic weight + // Extra 20 here from block execution + base extrinsic weight assert_eq!(System::block_weight().total(), Weight::from_ref_time(266)); assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); - assert_eq!(block_weight_limit(), Weight::from_ref_time(1024)); - assert_eq!(System::block_weight().total(), block_weight_limit()); + assert_eq!(block_weight_limit(), Weight::from_ref_time(1024).set_proof_size(u64::MAX)); + assert_eq!(System::block_weight().total(), block_weight_limit().set_proof_size(0)); }); } @@ -433,7 +433,7 @@ mod tests { ..Default::default() }; let dispatch_operational = DispatchInfo { - weight: Weight::from_ref_time(251), + weight: Weight::from_ref_time(246), class: DispatchClass::Operational, ..Default::default() }; @@ -669,7 +669,7 @@ mod tests { assert_ok!(CheckWeight::::do_pre_dispatch(&max_normal, len)); assert_eq!(System::block_weight().total(), Weight::from_ref_time(768)); assert_ok!(CheckWeight::::do_pre_dispatch(&mandatory, len)); - assert_eq!(block_weight_limit(), Weight::from_ref_time(1024)); + assert_eq!(block_weight_limit(), Weight::from_ref_time(1024).set_proof_size(u64::MAX)); assert_eq!(System::block_weight().total(), Weight::from_ref_time(1024 + 768)); assert_eq!(CheckWeight::::check_extrinsic_weight(&mandatory), Ok(())); }); @@ -682,11 +682,11 @@ mod tests { .base_block(Weight::zero()) .for_class(DispatchClass::non_mandatory(), |w| { w.base_extrinsic = Weight::zero(); - w.max_total = Some(Weight::from_ref_time(20)); + w.max_total = Some(Weight::from_ref_time(20).set_proof_size(u64::MAX)); }) .for_class(DispatchClass::Mandatory, |w| { w.base_extrinsic = Weight::zero(); - w.reserved = Some(Weight::from_ref_time(5)); + w.reserved = Some(Weight::from_ref_time(5).set_proof_size(u64::MAX)); w.max_total = None; }) .build_or_panic(); @@ -695,7 +695,7 @@ mod tests { DispatchClass::Operational => Weight::from_ref_time(10), DispatchClass::Mandatory => Weight::zero(), }); - assert_eq!(maximum_weight.max_block, all_weight.total()); + assert_eq!(maximum_weight.max_block, all_weight.total().set_proof_size(u64::MAX)); // fits into reserved let mandatory1 = DispatchInfo { @@ -711,13 +711,13 @@ mod tests { }; // when - assert_ok!(calculate_consumed_weight::<::Call>( + assert_ok!(calculate_consumed_weight::<::RuntimeCall>( maximum_weight.clone(), all_weight.clone(), &mandatory1 )); assert_err!( - calculate_consumed_weight::<::Call>( + calculate_consumed_weight::<::RuntimeCall>( maximum_weight, all_weight, &mandatory2 diff --git a/frame/system/src/lib.rs b/frame/system/src/lib.rs index 605357b751839..ae1d3416728c2 100644 --- a/frame/system/src/lib.rs +++ b/frame/system/src/lib.rs @@ -85,21 +85,21 @@ use sp_version::RuntimeVersion; use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen}; use frame_support::{ - dispatch::{DispatchResult, DispatchResultWithPostInfo}, + dispatch::{ + extract_actual_pays_fee, extract_actual_weight, DispatchClass, DispatchInfo, + DispatchResult, DispatchResultWithPostInfo, PerDispatchClass, + }, ensure, storage, storage::bounded_vec::BoundedVec, traits::{ ConstU32, Contains, EnsureOrigin, Get, HandleLifetime, OnKilledAccount, OnNewAccount, OriginTrait, PalletInfo, SortedMembers, StoredMap, TypedGet, }, - weights::{ - extract_actual_pays_fee, extract_actual_weight, DispatchClass, DispatchInfo, - PerDispatchClass, RuntimeDbWeight, Weight, - }, Parameter, }; use scale_info::TypeInfo; use sp_core::storage::well_known_keys; +use sp_weights::{RuntimeDbWeight, Weight}; #[cfg(feature = "std")] use frame_support::traits::GenesisBuild; @@ -213,7 +213,7 @@ pub mod pallet { pub trait Config: 'static + Eq + Clone { /// The basic call filter to use in Origin. All origins are built with this filter as base, /// except Root. - type BaseCallFilter: Contains; + type BaseCallFilter: Contains; /// Block & extrinsics weights: base values and limits. #[pallet::constant] @@ -223,14 +223,17 @@ pub mod pallet { #[pallet::constant] type BlockLength: Get; - /// The `Origin` type used by dispatchable calls. - type Origin: Into, Self::Origin>> + /// The `RuntimeOrigin` type used by dispatchable calls. + type RuntimeOrigin: Into, Self::RuntimeOrigin>> + From> + Clone - + OriginTrait; + + OriginTrait; - /// The aggregated `Call` type. - type Call: Dispatchable + Debug; + /// The aggregated `RuntimeCall` type. + type RuntimeCall: Parameter + + Dispatchable + + Debug + + From>; /// Account index (aka nonce) type. This stores the number of previous transactions /// associated with a sender account. @@ -301,11 +304,11 @@ pub mod pallet { type Header: Parameter + traits::Header; /// The aggregated event type of the runtime. - type Event: Parameter + type RuntimeEvent: Parameter + Member + From> + Debug - + IsType<::Event>; + + IsType<::RuntimeEvent>; /// Maximum number of block number to block hash mappings to keep (oldest pruned first). #[pallet::constant] @@ -604,6 +607,7 @@ pub mod pallet { /// The current weight for the block. #[pallet::storage] + #[pallet::whitelist_storage] #[pallet::getter(fn block_weight)] pub(super) type BlockWeight = StorageValue<_, ConsumedWeight, ValueQuery>; @@ -671,6 +675,7 @@ pub mod pallet { /// The current block number being processed. Set by `execute_block`. #[pallet::storage] + #[pallet::whitelist_storage] #[pallet::getter(fn block_number)] pub(super) type Number = StorageValue<_, T::BlockNumber, ValueQuery>; @@ -693,12 +698,14 @@ pub mod pallet { /// Events have a large in-memory size. Box the events to not go out-of-memory /// just in case someone still reads them from within the runtime. #[pallet::storage] + #[pallet::whitelist_storage] #[pallet::unbounded] pub(super) type Events = - StorageValue<_, Vec>>, ValueQuery>; + StorageValue<_, Vec>>, ValueQuery>; /// The number of events in the `Events` list. #[pallet::storage] + #[pallet::whitelist_storage] #[pallet::getter(fn event_count)] pub(super) type EventCount = StorageValue<_, EventIndex, ValueQuery>; @@ -734,6 +741,7 @@ pub mod pallet { /// The execution phase of the block. #[pallet::storage] + #[pallet::whitelist_storage] pub(super) type ExecutionPhase = StorageValue<_, Phase>; #[cfg_attr(feature = "std", derive(Default))] @@ -1304,7 +1312,7 @@ impl Pallet { } /// Deposits an event into this block's event record. - pub fn deposit_event(event: impl Into) { + pub fn deposit_event(event: impl Into) { Self::deposit_event_indexed(&[], event.into()); } @@ -1313,7 +1321,7 @@ impl Pallet { /// /// This will update storage entries that correspond to the specified topics. /// It is expected that light-clients could subscribe to this topics. - pub fn deposit_event_indexed(topics: &[T::Hash], event: T::Event) { + pub fn deposit_event_indexed(topics: &[T::Hash], event: T::RuntimeEvent) { let block_number = Self::block_number(); // Don't populate events on genesis. if block_number.is_zero() { @@ -1622,7 +1630,7 @@ impl Pallet { /// impact on the PoV size of a block. Users should use alternative and well bounded storage /// items for any behavior like this. #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] - pub fn events() -> Vec> { + pub fn events() -> Vec> { // Dereferencing the events here is fine since we are not in the // memory-restricted runtime. Self::read_events_no_consensus().into_iter().map(|e| *e).collect() @@ -1632,7 +1640,7 @@ impl Pallet { /// /// Should only be called if you know what you are doing and outside of the runtime block /// execution else it can have a large impact on the PoV size of a block. - pub fn read_events_no_consensus() -> Vec>> { + pub fn read_events_no_consensus() -> Vec>> { Events::::get() } @@ -1677,13 +1685,13 @@ impl Pallet { /// Assert the given `event` exists. #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] - pub fn assert_has_event(event: T::Event) { + pub fn assert_has_event(event: T::RuntimeEvent) { assert!(Self::events().iter().any(|record| record.event == event)) } /// Assert the last event equal to the given `event`. #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] - pub fn assert_last_event(event: T::Event) { + pub fn assert_last_event(event: T::RuntimeEvent) { assert_eq!(Self::events().last().expect("events expected").event, event); } @@ -1711,9 +1719,15 @@ impl Pallet { } /// To be called immediately after an extrinsic has been applied. + /// + /// Emits an `ExtrinsicSuccess` or `ExtrinsicFailed` event depending on the outcome. + /// The emitted event contains the post-dispatch corrected weight including + /// the base-weight for its dispatch class. pub fn note_applied_extrinsic(r: &DispatchResultWithPostInfo, mut info: DispatchInfo) { - info.weight = extract_actual_weight(r, &info); + info.weight = extract_actual_weight(r, &info) + .saturating_add(T::BlockWeights::get().get(info.class).base_extrinsic); info.pays_fee = extract_actual_pays_fee(r, &info); + Self::deposit_event(match r { Ok(_) => Event::ExtrinsicSuccess { dispatch_info: info }, Err(err) => { @@ -1903,7 +1917,7 @@ pub mod pallet_prelude { pub use crate::{ensure_none, ensure_root, ensure_signed, ensure_signed_or_root}; /// Type alias for the `Origin` associated type of system config. - pub type OriginFor = ::Origin; + pub type OriginFor = ::RuntimeOrigin; /// Type alias for the `BlockNumber` associated type of system config. pub type BlockNumberFor = ::BlockNumber; diff --git a/frame/system/src/limits.rs b/frame/system/src/limits.rs index 7626c7e8665e6..eb95b699eba32 100644 --- a/frame/system/src/limits.rs +++ b/frame/system/src/limits.rs @@ -25,7 +25,10 @@ //! `DispatchClass`. This module contains configuration object for both resources, //! which should be passed to `frame_system` configuration when runtime is being set up. -use frame_support::weights::{constants, DispatchClass, OneOrMany, PerDispatchClass, Weight}; +use frame_support::{ + dispatch::{DispatchClass, OneOrMany, PerDispatchClass}, + weights::{constants, Weight}, +}; use scale_info::TypeInfo; use sp_runtime::{traits::Bounded, Perbill, RuntimeDebug}; @@ -204,7 +207,10 @@ pub struct BlockWeights { impl Default for BlockWeights { fn default() -> Self { - Self::with_sensible_defaults(1u32 * constants::WEIGHT_PER_SECOND, DEFAULT_NORMAL_RATIO) + Self::with_sensible_defaults( + Weight::from_parts(constants::WEIGHT_PER_SECOND.ref_time(), u64::MAX), + DEFAULT_NORMAL_RATIO, + ) } } @@ -229,7 +235,7 @@ impl BlockWeights { // Make sure that if total is set it's greater than base_block && // base_for_class error_assert!( - (max_for_class > self.base_block && max_for_class > base_for_class) + (max_for_class.all_gt(self.base_block) && max_for_class.all_gt(base_for_class)) || max_for_class == Weight::zero(), &mut error, "[{:?}] {:?} (total) has to be greater than {:?} (base block) & {:?} (base extrinsic)", @@ -237,8 +243,10 @@ impl BlockWeights { ); // Max extrinsic can't be greater than max_for_class. error_assert!( - weights.max_extrinsic.unwrap_or(Weight::zero()) <= - max_for_class.saturating_sub(base_for_class), + weights + .max_extrinsic + .unwrap_or(Weight::zero()) + .all_lte(max_for_class.saturating_sub(base_for_class)), &mut error, "[{:?}] {:?} (max_extrinsic) can't be greater than {:?} (max for class)", class, @@ -247,14 +255,14 @@ impl BlockWeights { ); // Max extrinsic should not be 0 error_assert!( - weights.max_extrinsic.unwrap_or_else(Weight::max_value) > Weight::zero(), + weights.max_extrinsic.unwrap_or_else(Weight::max_value).all_gt(Weight::zero()), &mut error, "[{:?}] {:?} (max_extrinsic) must not be 0. Check base cost and average initialization cost.", class, weights.max_extrinsic, ); // Make sure that if reserved is set it's greater than base_for_class. error_assert!( - reserved > base_for_class || reserved == Weight::zero(), + reserved.all_gt(base_for_class) || reserved == Weight::zero(), &mut error, "[{:?}] {:?} (reserved) has to be greater than {:?} (base extrinsic) if set", class, @@ -263,7 +271,7 @@ impl BlockWeights { ); // Make sure max block is greater than max_total if it's set. error_assert!( - self.max_block >= weights.max_total.unwrap_or(Weight::zero()), + self.max_block.all_gte(weights.max_total.unwrap_or(Weight::zero())), &mut error, "[{:?}] {:?} (max block) has to be greater than {:?} (max for class)", class, @@ -272,7 +280,7 @@ impl BlockWeights { ); // Make sure we can fit at least one extrinsic. error_assert!( - self.max_block > base_for_class + self.base_block, + self.max_block.all_gt(base_for_class + self.base_block), &mut error, "[{:?}] {:?} (max block) must fit at least one extrinsic {:?} (base weight)", class, @@ -400,7 +408,7 @@ impl BlockWeightsBuilder { // compute max block size. for class in DispatchClass::all() { weights.max_block = match weights.per_class.get(*class).max_total { - Some(max) if max > weights.max_block => max, + Some(max) => max.max(weights.max_block), _ => weights.max_block, }; } diff --git a/frame/system/src/mock.rs b/frame/system/src/mock.rs index 23ab3c2af20b0..d31a1b08667e5 100644 --- a/frame/system/src/mock.rs +++ b/frame/system/src/mock.rs @@ -26,7 +26,6 @@ use sp_runtime::{ traits::{BlakeTwo256, IdentityLookup}, BuildStorage, }; -use sp_std::cell::RefCell; type UncheckedExtrinsic = mocking::MockUncheckedExtrinsic; type Block = mocking::MockBlock; @@ -42,7 +41,7 @@ frame_support::construct_runtime!( ); const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); -const MAX_BLOCK_WEIGHT: Weight = Weight::from_ref_time(1024); +const MAX_BLOCK_WEIGHT: Weight = Weight::from_ref_time(1024).set_proof_size(u64::MAX); parameter_types! { pub Version: RuntimeVersion = RuntimeVersion { @@ -68,6 +67,7 @@ parameter_types! { weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAX_BLOCK_WEIGHT); }) .for_class(DispatchClass::Operational, |weights| { + weights.base_extrinsic = Weight::from_ref_time(10); weights.max_total = Some(MAX_BLOCK_WEIGHT); weights.reserved = Some( MAX_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAX_BLOCK_WEIGHT @@ -79,14 +79,14 @@ parameter_types! { limits::BlockLength::max_with_normal_ratio(1024, NORMAL_DISPATCH_RATIO); } -thread_local! { - pub static KILLED: RefCell> = RefCell::new(vec![]); +parameter_types! { + pub static Killed: Vec = vec![]; } pub struct RecordKilled; impl OnKilledAccount for RecordKilled { fn on_killed_account(who: &u64) { - KILLED.with(|r| r.borrow_mut().push(*who)) + Killed::mutate(|r| r.push(*who)) } } @@ -94,8 +94,8 @@ impl Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = RuntimeBlockWeights; type BlockLength = RuntimeBlockLength; - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -103,7 +103,7 @@ impl Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<10>; type DbWeight = DbWeight; type Version = Version; @@ -120,8 +120,8 @@ impl Config for Test { pub type SysEvent = frame_system::Event; /// A simple call, which one doesn't matter. -pub const CALL: &::Call = - &Call::System(frame_system::Call::set_heap_pages { pages: 0u64 }); +pub const CALL: &::RuntimeCall = + &RuntimeCall::System(frame_system::Call::set_heap_pages { pages: 0u64 }); /// Create new externalities for `System` module tests. pub fn new_test_ext() -> sp_io::TestExternalities { diff --git a/frame/system/src/mocking.rs b/frame/system/src/mocking.rs index ccb63f9bb236c..d8cfcb9baf268 100644 --- a/frame/system/src/mocking.rs +++ b/frame/system/src/mocking.rs @@ -22,7 +22,7 @@ use sp_runtime::generic; /// An unchecked extrinsic type to be used in tests. pub type MockUncheckedExtrinsic = generic::UncheckedExtrinsic< ::AccountId, - ::Call, + ::RuntimeCall, Signature, Extra, >; diff --git a/frame/system/src/offchain.rs b/frame/system/src/offchain.rs index 86440188a765c..99a4c1541d30f 100644 --- a/frame/system/src/offchain.rs +++ b/frame/system/src/offchain.rs @@ -617,7 +617,7 @@ pub trait SignedPayload: Encode { #[cfg(test)] mod tests { use super::*; - use crate::mock::{Call, Test as TestRuntime, CALL}; + use crate::mock::{RuntimeCall, Test as TestRuntime, CALL}; use codec::Decode; use sp_core::offchain::{testing, TransactionPoolExt}; use sp_runtime::testing::{TestSignature, TestXt, UintAuthorityId}; @@ -627,11 +627,11 @@ mod tests { type Signature = TestSignature; } - type Extrinsic = TestXt; + type Extrinsic = TestXt; - impl SendTransactionTypes for TestRuntime { + impl SendTransactionTypes for TestRuntime { type Extrinsic = Extrinsic; - type OverarchingCall = Call; + type OverarchingCall = RuntimeCall; } #[derive(codec::Encode, codec::Decode)] diff --git a/frame/system/src/tests.rs b/frame/system/src/tests.rs index cf1319f1bb125..39dc321e83a2b 100644 --- a/frame/system/src/tests.rs +++ b/frame/system/src/tests.rs @@ -18,10 +18,9 @@ use crate::*; use frame_support::{ assert_err, assert_noop, assert_ok, - dispatch::PostDispatchInfo, - weights::{Pays, WithPostDispatchInfo}, + dispatch::{Pays, PostDispatchInfo, WithPostDispatchInfo}, }; -use mock::{Origin, *}; +use mock::{RuntimeOrigin, *}; use sp_core::H256; use sp_runtime::{ traits::{BlakeTwo256, Header}, @@ -30,8 +29,8 @@ use sp_runtime::{ #[test] fn origin_works() { - let o = Origin::from(RawOrigin::::Signed(1u64)); - let x: Result, Origin> = o.into(); + let o = RuntimeOrigin::from(RawOrigin::::Signed(1u64)); + let x: Result, RuntimeOrigin> = o.into(); assert_eq!(x.unwrap(), RawOrigin::::Signed(1u64)); } @@ -55,9 +54,9 @@ fn stored_map_works() { System::dec_consumers(&0); assert!(!System::is_provider_required(&0)); - assert!(KILLED.with(|r| r.borrow().is_empty())); + assert!(Killed::get().is_empty()); assert_ok!(System::remove(&0)); - assert_eq!(KILLED.with(|r| r.borrow().clone()), vec![0u64]); + assert_eq!(Killed::get(), vec![0u64]); }); } @@ -170,6 +169,10 @@ fn deposit_event_should_work() { }] ); + let normal_base = ::BlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic; + System::reset_events(); System::initialize(&2, &[0u8; 32].into(), &Default::default()); System::deposit_event(SysEvent::NewAccount { account: 32 }); @@ -195,14 +198,17 @@ fn deposit_event_should_work() { }, EventRecord { phase: Phase::ApplyExtrinsic(0), - event: SysEvent::ExtrinsicSuccess { dispatch_info: Default::default() }.into(), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { weight: normal_base, ..Default::default() } + } + .into(), topics: vec![] }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: SysEvent::ExtrinsicFailed { dispatch_error: DispatchError::BadOrigin.into(), - dispatch_info: Default::default() + dispatch_info: DispatchInfo { weight: normal_base, ..Default::default() } } .into(), topics: vec![] @@ -224,6 +230,9 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { System::initialize(&1, &[0u8; 32].into(), &Default::default()); System::note_finished_initialize(); + let normal_base = ::BlockWeights::get() + .get(DispatchClass::Normal) + .base_extrinsic; let pre_info = DispatchInfo { weight: Weight::from_ref_time(1000), ..Default::default() }; System::note_applied_extrinsic(&Ok(Some(300).into()), pre_info); System::note_applied_extrinsic(&Ok(Some(1000).into()), pre_info); @@ -268,144 +277,168 @@ fn deposit_event_uses_actual_weight_and_pays_fee() { }), pre_info, ); + // Also works for operational. + let operational_base = ::BlockWeights::get() + .get(DispatchClass::Operational) + .base_extrinsic; + assert!(normal_base != operational_base, "Test pre-condition violated"); + let pre_info = DispatchInfo { + weight: Weight::from_ref_time(1000), + class: DispatchClass::Operational, + ..Default::default() + }; + System::note_applied_extrinsic(&Ok(Some(300).into()), pre_info); - assert_eq!( - System::events(), - vec![ - EventRecord { - phase: Phase::ApplyExtrinsic(0), - event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(300), - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(1), - event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000), - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(2), - event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000), - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(3), - event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000), - pays_fee: Pays::Yes, - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(4), - event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000), - pays_fee: Pays::No, - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(5), - event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000), - pays_fee: Pays::No, - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(6), - event: SysEvent::ExtrinsicSuccess { - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(500), - pays_fee: Pays::No, - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(7), - event: SysEvent::ExtrinsicFailed { - dispatch_error: DispatchError::BadOrigin.into(), - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(999), - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(8), - event: SysEvent::ExtrinsicFailed { - dispatch_error: DispatchError::BadOrigin.into(), - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(1000), - pays_fee: Pays::Yes, - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(9), - event: SysEvent::ExtrinsicFailed { - dispatch_error: DispatchError::BadOrigin.into(), - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(800), - pays_fee: Pays::Yes, - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - EventRecord { - phase: Phase::ApplyExtrinsic(10), - event: SysEvent::ExtrinsicFailed { - dispatch_error: DispatchError::BadOrigin.into(), - dispatch_info: DispatchInfo { - weight: Weight::from_ref_time(800), - pays_fee: Pays::No, - ..Default::default() - }, - } - .into(), - topics: vec![] - }, - ] - ); + let got = System::events(); + let want = vec![ + EventRecord { + phase: Phase::ApplyExtrinsic(0), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(300).saturating_add(normal_base), + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(1), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(1000).saturating_add(normal_base), + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(2), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(1000).saturating_add(normal_base), + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(3), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(1000).saturating_add(normal_base), + pays_fee: Pays::Yes, + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(4), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(1000).saturating_add(normal_base), + pays_fee: Pays::No, + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(5), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(1000).saturating_add(normal_base), + pays_fee: Pays::No, + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(6), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(500).saturating_add(normal_base), + pays_fee: Pays::No, + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(7), + event: SysEvent::ExtrinsicFailed { + dispatch_error: DispatchError::BadOrigin.into(), + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(999).saturating_add(normal_base), + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(8), + event: SysEvent::ExtrinsicFailed { + dispatch_error: DispatchError::BadOrigin.into(), + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(1000).saturating_add(normal_base), + pays_fee: Pays::Yes, + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(9), + event: SysEvent::ExtrinsicFailed { + dispatch_error: DispatchError::BadOrigin.into(), + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(800).saturating_add(normal_base), + pays_fee: Pays::Yes, + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(10), + event: SysEvent::ExtrinsicFailed { + dispatch_error: DispatchError::BadOrigin.into(), + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(800).saturating_add(normal_base), + pays_fee: Pays::No, + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(11), + event: SysEvent::ExtrinsicSuccess { + dispatch_info: DispatchInfo { + weight: Weight::from_ref_time(300).saturating_add(operational_base), + class: DispatchClass::Operational, + ..Default::default() + }, + } + .into(), + topics: vec![], + }, + ]; + for (i, event) in want.into_iter().enumerate() { + assert_eq!(got[i], event, "Event mismatch at index {}", i); + } }); } @@ -639,16 +672,16 @@ fn ensure_signed_stuff_works() { } } - let signed_origin = Origin::signed(0u64); + let signed_origin = RuntimeOrigin::signed(0u64); assert_ok!(EnsureSigned::try_origin(signed_origin.clone())); assert_ok!(EnsureSignedBy::::try_origin(signed_origin)); #[cfg(feature = "runtime-benchmarks")] { - let successful_origin: Origin = EnsureSigned::successful_origin(); + let successful_origin: RuntimeOrigin = EnsureSigned::successful_origin(); assert_ok!(EnsureSigned::try_origin(successful_origin)); - let successful_origin: Origin = EnsureSignedBy::::successful_origin(); + let successful_origin: RuntimeOrigin = EnsureSignedBy::::successful_origin(); assert_ok!(EnsureSignedBy::::try_origin(successful_origin)); } } @@ -766,20 +799,20 @@ fn do_not_allow_for_storing_txs_when_queue_is_full() { for i in 1u32..>::get() + 1 { println!("iter"); assert!(System::can_enqueue_txs()); - System::enqueue_txs(Origin::none(), dummy_txs.clone()).unwrap(); + System::enqueue_txs(RuntimeOrigin::none(), dummy_txs.clone()).unwrap(); System::finalize(); System::set_block_number(i.into()); System::set_block_seed(&dummy_seed); } assert!(!System::can_enqueue_txs()); assert_err!( - System::enqueue_txs(Origin::none(), dummy_txs.clone()), + System::enqueue_txs(RuntimeOrigin::none(), dummy_txs.clone()), Error::::StorageQueueFull ); assert!(!System::pop_txs(1).is_empty()); assert!(System::can_enqueue_txs()); System::finalize(); - System::enqueue_txs(Origin::none(), dummy_txs.clone()).unwrap(); + System::enqueue_txs(RuntimeOrigin::none(), dummy_txs.clone()).unwrap(); }); } diff --git a/frame/timestamp/Cargo.toml b/frame/timestamp/Cargo.toml index 5d2f933a5d5fc..a4979b7e84dbd 100644 --- a/frame/timestamp/Cargo.toml +++ b/frame/timestamp/Cargo.toml @@ -33,8 +33,9 @@ sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ + "sp-io?/std", "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/timestamp/src/mock.rs b/frame/timestamp/src/mock.rs index b4c377cfa30ef..2208510f24fe5 100644 --- a/frame/timestamp/src/mock.rs +++ b/frame/timestamp/src/mock.rs @@ -19,7 +19,6 @@ use super::*; use crate as pallet_timestamp; -use sp_std::cell::RefCell; use frame_support::{ parameter_types, @@ -56,16 +55,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -78,14 +77,14 @@ impl frame_system::Config for Test { type MaxConsumers = ConstU32<16>; } -thread_local! { - pub static CAPTURED_MOMENT: RefCell> = RefCell::new(None); +parameter_types! { + pub static CapturedMoment: Option = None; } pub struct MockOnTimestampSet; impl OnTimestampSet for MockOnTimestampSet { fn on_timestamp_set(moment: Moment) { - CAPTURED_MOMENT.with(|x| *x.borrow_mut() = Some(moment)); + CapturedMoment::mutate(|x| *x = Some(moment)); } } @@ -97,11 +96,11 @@ impl Config for Test { } pub(crate) fn clear_captured_moment() { - CAPTURED_MOMENT.with(|x| *x.borrow_mut() = None); + CapturedMoment::mutate(|x| *x = None); } pub(crate) fn get_captured_moment() -> Option { - CAPTURED_MOMENT.with(|x| *x.borrow()) + CapturedMoment::get() } pub(crate) fn new_test_ext() -> TestExternalities { diff --git a/frame/timestamp/src/tests.rs b/frame/timestamp/src/tests.rs index ef9fd6e39d4b5..6a76fbc4820e6 100644 --- a/frame/timestamp/src/tests.rs +++ b/frame/timestamp/src/tests.rs @@ -24,7 +24,7 @@ use frame_support::assert_ok; fn timestamp_works() { new_test_ext().execute_with(|| { crate::Now::::put(46); - assert_ok!(Timestamp::set(Origin::none(), 69)); + assert_ok!(Timestamp::set(RuntimeOrigin::none(), 69)); assert_eq!(Timestamp::now(), 69); assert_eq!(Some(69), get_captured_moment()); }); @@ -35,7 +35,7 @@ fn timestamp_works() { fn double_timestamp_should_fail() { new_test_ext().execute_with(|| { Timestamp::set_timestamp(42); - assert_ok!(Timestamp::set(Origin::none(), 69)); + assert_ok!(Timestamp::set(RuntimeOrigin::none(), 69)); }); } @@ -46,6 +46,6 @@ fn double_timestamp_should_fail() { fn block_period_minimum_enforced() { new_test_ext().execute_with(|| { crate::Now::::put(44); - let _ = Timestamp::set(Origin::none(), 46); + let _ = Timestamp::set(RuntimeOrigin::none(), 46); }); } diff --git a/frame/tips/Cargo.toml b/frame/tips/Cargo.toml index e2ca152148db6..b00a684c1c83b 100644 --- a/frame/tips/Cargo.toml +++ b/frame/tips/Cargo.toml @@ -33,6 +33,7 @@ sp-storage = { version = "6.0.0", path = "../../primitives/storage" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/tips/src/benchmarking.rs b/frame/tips/src/benchmarking.rs index 4956e2a095688..312424e5799ec 100644 --- a/frame/tips/src/benchmarking.rs +++ b/frame/tips/src/benchmarking.rs @@ -197,7 +197,7 @@ benchmarks_instance_pallet! { let hash = T::Hashing::hash_of(&(&reason_hash, &beneficiary)); ensure!(Tips::::contains_key(hash), "tip does not exist"); let reject_origin = T::RejectOrigin::successful_origin(); - }: _(reject_origin, hash) + }: _(reject_origin, hash) impl_benchmark_test_suite!(TipsMod, crate::tests::new_test_ext(), crate::tests::Test); } diff --git a/frame/tips/src/lib.rs b/frame/tips/src/lib.rs index a4697284e38a0..9313a26e52e00 100644 --- a/frame/tips/src/lib.rs +++ b/frame/tips/src/lib.rs @@ -127,7 +127,8 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + pallet_treasury::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Maximum acceptable reason length. /// diff --git a/frame/tips/src/tests.rs b/frame/tips/src/tests.rs index bcaa99285d2e7..cb0b4458c7fba 100644 --- a/frame/tips/src/tests.rs +++ b/frame/tips/src/tests.rs @@ -19,8 +19,6 @@ #![cfg(test)] -use std::cell::RefCell; - use sp_core::H256; use sp_runtime::{ testing::Header, @@ -67,16 +65,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u128; // u64 is not enough to hold bytes used to generate bounty account type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -94,24 +92,23 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } -thread_local! { - static TEN_TO_FOURTEEN: RefCell> = RefCell::new(vec![10,11,12,13,14]); +parameter_types! { + static TenToFourteenTestValue: Vec = vec![10,11,12,13,14]; } pub struct TenToFourteen; impl SortedMembers for TenToFourteen { fn sorted_members() -> Vec { - TEN_TO_FOURTEEN.with(|v| v.borrow().clone()) + TenToFourteenTestValue::get().clone() } #[cfg(feature = "runtime-benchmarks")] fn add(new: &u128) { - TEN_TO_FOURTEEN.with(|v| { - let mut members = v.borrow_mut(); + TenToFourteenTestValue::mutate(|members| { members.push(*new); members.sort(); }) @@ -119,7 +116,7 @@ impl SortedMembers for TenToFourteen { } impl ContainsLengthBound for TenToFourteen { fn max_len() -> usize { - TEN_TO_FOURTEEN.with(|v| v.borrow().len()) + TenToFourteenTestValue::get().len() } fn min_len() -> usize { 0 @@ -136,7 +133,7 @@ impl pallet_treasury::Config for Test { type Currency = pallet_balances::Pallet; type ApproveOrigin = frame_system::EnsureRoot; type RejectOrigin = frame_system::EnsureRoot; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ConstU64<1>; @@ -155,7 +152,7 @@ impl pallet_treasury::Config for Test { type Currency = pallet_balances::Pallet; type ApproveOrigin = frame_system::EnsureRoot; type RejectOrigin = frame_system::EnsureRoot; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ConstU64<1>; @@ -179,7 +176,7 @@ impl Config for Test { type TipFindersFee = TipFindersFee; type TipReportDepositBase = ConstU64<1>; type DataDepositPerByte = ConstU64<1>; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } @@ -190,7 +187,7 @@ impl Config for Test { type TipFindersFee = TipFindersFee; type TipReportDepositBase = ConstU64<1>; type DataDepositPerByte = ConstU64<1>; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } @@ -212,7 +209,7 @@ fn last_event() -> TipEvent { System::events() .into_iter() .map(|r| r.event) - .filter_map(|e| if let Event::Tips(inner) = e { Some(inner) } else { None }) + .filter_map(|e| if let RuntimeEvent::Tips(inner) = e { Some(inner) } else { None }) .last() .unwrap() } @@ -233,9 +230,9 @@ fn tip_hash() -> H256 { fn tip_new_cannot_be_used_twice() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10)); + assert_ok!(Tips::tip_new(RuntimeOrigin::signed(10), b"awesome.dot".to_vec(), 3, 10)); assert_noop!( - Tips::tip_new(Origin::signed(11), b"awesome.dot".to_vec(), 3, 10), + Tips::tip_new(RuntimeOrigin::signed(11), b"awesome.dot".to_vec(), 3, 10), Error::::AlreadyKnown ); }); @@ -245,23 +242,23 @@ fn tip_new_cannot_be_used_twice() { fn report_awesome_and_tip_works() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Tips::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3)); + assert_ok!(Tips::report_awesome(RuntimeOrigin::signed(0), b"awesome.dot".to_vec(), 3)); assert_eq!(Balances::reserved_balance(0), 12); assert_eq!(Balances::free_balance(0), 88); // other reports don't count. assert_noop!( - Tips::report_awesome(Origin::signed(1), b"awesome.dot".to_vec(), 3), + Tips::report_awesome(RuntimeOrigin::signed(1), b"awesome.dot".to_vec(), 3), Error::::AlreadyKnown ); let h = tip_hash(); - assert_ok!(Tips::tip(Origin::signed(10), h, 10)); - assert_ok!(Tips::tip(Origin::signed(11), h, 10)); - assert_ok!(Tips::tip(Origin::signed(12), h, 10)); - assert_noop!(Tips::tip(Origin::signed(9), h, 10), BadOrigin); + assert_ok!(Tips::tip(RuntimeOrigin::signed(10), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(11), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(12), h, 10)); + assert_noop!(Tips::tip(RuntimeOrigin::signed(9), h, 10), BadOrigin); System::set_block_number(2); - assert_ok!(Tips::close_tip(Origin::signed(100), h.into())); + assert_ok!(Tips::close_tip(RuntimeOrigin::signed(100), h.into())); assert_eq!(Balances::reserved_balance(0), 0); assert_eq!(Balances::free_balance(0), 102); assert_eq!(Balances::free_balance(3), 8); @@ -272,15 +269,15 @@ fn report_awesome_and_tip_works() { fn report_awesome_from_beneficiary_and_tip_works() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Tips::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 0)); + assert_ok!(Tips::report_awesome(RuntimeOrigin::signed(0), b"awesome.dot".to_vec(), 0)); assert_eq!(Balances::reserved_balance(0), 12); assert_eq!(Balances::free_balance(0), 88); let h = BlakeTwo256::hash_of(&(BlakeTwo256::hash(b"awesome.dot"), 0u128)); - assert_ok!(Tips::tip(Origin::signed(10), h, 10)); - assert_ok!(Tips::tip(Origin::signed(11), h, 10)); - assert_ok!(Tips::tip(Origin::signed(12), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(10), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(11), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(12), h, 10)); System::set_block_number(2); - assert_ok!(Tips::close_tip(Origin::signed(100), h.into())); + assert_ok!(Tips::close_tip(RuntimeOrigin::signed(100), h.into())); assert_eq!(Balances::reserved_balance(0), 0); assert_eq!(Balances::free_balance(0), 110); }); @@ -294,30 +291,33 @@ fn close_tip_works() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10)); + assert_ok!(Tips::tip_new(RuntimeOrigin::signed(10), b"awesome.dot".to_vec(), 3, 10)); let h = tip_hash(); assert_eq!(last_event(), TipEvent::NewTip { tip_hash: h }); - assert_ok!(Tips::tip(Origin::signed(11), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(11), h, 10)); - assert_noop!(Tips::close_tip(Origin::signed(0), h.into()), Error::::StillOpen); + assert_noop!(Tips::close_tip(RuntimeOrigin::signed(0), h.into()), Error::::StillOpen); - assert_ok!(Tips::tip(Origin::signed(12), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(12), h, 10)); assert_eq!(last_event(), TipEvent::TipClosing { tip_hash: h }); - assert_noop!(Tips::close_tip(Origin::signed(0), h.into()), Error::::Premature); + assert_noop!(Tips::close_tip(RuntimeOrigin::signed(0), h.into()), Error::::Premature); System::set_block_number(2); - assert_noop!(Tips::close_tip(Origin::none(), h.into()), BadOrigin); - assert_ok!(Tips::close_tip(Origin::signed(0), h.into())); + assert_noop!(Tips::close_tip(RuntimeOrigin::none(), h.into()), BadOrigin); + assert_ok!(Tips::close_tip(RuntimeOrigin::signed(0), h.into())); assert_eq!(Balances::free_balance(3), 10); assert_eq!(last_event(), TipEvent::TipClosed { tip_hash: h, who: 3, payout: 10 }); - assert_noop!(Tips::close_tip(Origin::signed(100), h.into()), Error::::UnknownTip); + assert_noop!( + Tips::close_tip(RuntimeOrigin::signed(100), h.into()), + Error::::UnknownTip + ); }); } @@ -331,7 +331,7 @@ fn slash_tip_works() { assert_eq!(Balances::reserved_balance(0), 0); assert_eq!(Balances::free_balance(0), 100); - assert_ok!(Tips::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3)); + assert_ok!(Tips::report_awesome(RuntimeOrigin::signed(0), b"awesome.dot".to_vec(), 3)); assert_eq!(Balances::reserved_balance(0), 12); assert_eq!(Balances::free_balance(0), 88); @@ -340,10 +340,10 @@ fn slash_tip_works() { assert_eq!(last_event(), TipEvent::NewTip { tip_hash: h }); // can't remove from any origin - assert_noop!(Tips::slash_tip(Origin::signed(0), h), BadOrigin); + assert_noop!(Tips::slash_tip(RuntimeOrigin::signed(0), h), BadOrigin); // can remove from root. - assert_ok!(Tips::slash_tip(Origin::root(), h)); + assert_ok!(Tips::slash_tip(RuntimeOrigin::root(), h)); assert_eq!(last_event(), TipEvent::TipSlashed { tip_hash: h, finder: 0, deposit: 12 }); // tipper slashed @@ -357,26 +357,32 @@ fn retract_tip_works() { new_test_ext().execute_with(|| { // with report awesome Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Tips::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3)); + assert_ok!(Tips::report_awesome(RuntimeOrigin::signed(0), b"awesome.dot".to_vec(), 3)); let h = tip_hash(); - assert_ok!(Tips::tip(Origin::signed(10), h, 10)); - assert_ok!(Tips::tip(Origin::signed(11), h, 10)); - assert_ok!(Tips::tip(Origin::signed(12), h, 10)); - assert_noop!(Tips::retract_tip(Origin::signed(10), h), Error::::NotFinder); - assert_ok!(Tips::retract_tip(Origin::signed(0), h)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(10), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(11), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(12), h, 10)); + assert_noop!(Tips::retract_tip(RuntimeOrigin::signed(10), h), Error::::NotFinder); + assert_ok!(Tips::retract_tip(RuntimeOrigin::signed(0), h)); System::set_block_number(2); - assert_noop!(Tips::close_tip(Origin::signed(0), h.into()), Error::::UnknownTip); + assert_noop!( + Tips::close_tip(RuntimeOrigin::signed(0), h.into()), + Error::::UnknownTip + ); // with tip new Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10)); + assert_ok!(Tips::tip_new(RuntimeOrigin::signed(10), b"awesome.dot".to_vec(), 3, 10)); let h = tip_hash(); - assert_ok!(Tips::tip(Origin::signed(11), h, 10)); - assert_ok!(Tips::tip(Origin::signed(12), h, 10)); - assert_noop!(Tips::retract_tip(Origin::signed(0), h), Error::::NotFinder); - assert_ok!(Tips::retract_tip(Origin::signed(10), h)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(11), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(12), h, 10)); + assert_noop!(Tips::retract_tip(RuntimeOrigin::signed(0), h), Error::::NotFinder); + assert_ok!(Tips::retract_tip(RuntimeOrigin::signed(10), h)); System::set_block_number(2); - assert_noop!(Tips::close_tip(Origin::signed(10), h.into()), Error::::UnknownTip); + assert_noop!( + Tips::close_tip(RuntimeOrigin::signed(10), h.into()), + Error::::UnknownTip + ); }); } @@ -384,12 +390,12 @@ fn retract_tip_works() { fn tip_median_calculation_works() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 0)); + assert_ok!(Tips::tip_new(RuntimeOrigin::signed(10), b"awesome.dot".to_vec(), 3, 0)); let h = tip_hash(); - assert_ok!(Tips::tip(Origin::signed(11), h, 10)); - assert_ok!(Tips::tip(Origin::signed(12), h, 1000000)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(11), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(12), h, 1000000)); System::set_block_number(2); - assert_ok!(Tips::close_tip(Origin::signed(0), h.into())); + assert_ok!(Tips::close_tip(RuntimeOrigin::signed(0), h.into())); assert_eq!(Balances::free_balance(3), 10); }); } @@ -398,17 +404,17 @@ fn tip_median_calculation_works() { fn tip_changing_works() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Tips::tip_new(Origin::signed(10), b"awesome.dot".to_vec(), 3, 10000)); + assert_ok!(Tips::tip_new(RuntimeOrigin::signed(10), b"awesome.dot".to_vec(), 3, 10000)); let h = tip_hash(); - assert_ok!(Tips::tip(Origin::signed(11), h, 10000)); - assert_ok!(Tips::tip(Origin::signed(12), h, 10000)); - assert_ok!(Tips::tip(Origin::signed(13), h, 0)); - assert_ok!(Tips::tip(Origin::signed(14), h, 0)); - assert_ok!(Tips::tip(Origin::signed(12), h, 1000)); - assert_ok!(Tips::tip(Origin::signed(11), h, 100)); - assert_ok!(Tips::tip(Origin::signed(10), h, 10)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(11), h, 10000)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(12), h, 10000)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(13), h, 0)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(14), h, 0)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(12), h, 1000)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(11), h, 100)); + assert_ok!(Tips::tip(RuntimeOrigin::signed(10), h, 10)); System::set_block_number(2); - assert_ok!(Tips::close_tip(Origin::signed(0), h.into())); + assert_ok!(Tips::close_tip(RuntimeOrigin::signed(0), h.into())); assert_eq!(Balances::free_balance(3), 10); }); } @@ -585,24 +591,24 @@ fn report_awesome_and_tip_works_second_instance() { assert_eq!(Balances::free_balance(&Treasury::account_id()), 101); assert_eq!(Balances::free_balance(&Treasury1::account_id()), 201); - assert_ok!(Tips1::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3)); + assert_ok!(Tips1::report_awesome(RuntimeOrigin::signed(0), b"awesome.dot".to_vec(), 3)); // duplicate report in tips1 reports don't count. assert_noop!( - Tips1::report_awesome(Origin::signed(1), b"awesome.dot".to_vec(), 3), + Tips1::report_awesome(RuntimeOrigin::signed(1), b"awesome.dot".to_vec(), 3), Error::::AlreadyKnown ); // but tips is separate - assert_ok!(Tips::report_awesome(Origin::signed(0), b"awesome.dot".to_vec(), 3)); + assert_ok!(Tips::report_awesome(RuntimeOrigin::signed(0), b"awesome.dot".to_vec(), 3)); let h = tip_hash(); - assert_ok!(Tips1::tip(Origin::signed(10), h, 10)); - assert_ok!(Tips1::tip(Origin::signed(11), h, 10)); - assert_ok!(Tips1::tip(Origin::signed(12), h, 10)); - assert_noop!(Tips1::tip(Origin::signed(9), h, 10), BadOrigin); + assert_ok!(Tips1::tip(RuntimeOrigin::signed(10), h, 10)); + assert_ok!(Tips1::tip(RuntimeOrigin::signed(11), h, 10)); + assert_ok!(Tips1::tip(RuntimeOrigin::signed(12), h, 10)); + assert_noop!(Tips1::tip(RuntimeOrigin::signed(9), h, 10), BadOrigin); System::set_block_number(2); - assert_ok!(Tips1::close_tip(Origin::signed(100), h.into())); + assert_ok!(Tips1::close_tip(RuntimeOrigin::signed(100), h.into())); // Treasury 1 unchanged assert_eq!(Balances::free_balance(&Treasury::account_id()), 101); // Treasury 2 gave the funds diff --git a/frame/transaction-payment-mangata/Cargo.toml b/frame/transaction-payment-mangata/Cargo.toml deleted file mode 100644 index 987750b1b2d6a..0000000000000 --- a/frame/transaction-payment-mangata/Cargo.toml +++ /dev/null @@ -1,45 +0,0 @@ -[package] -name = "pallet-transaction-payment-mangata" -version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" -license = "Apache-2.0" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" -description = "FRAME pallet to manage transaction payments" -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ - "derive", -] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } -serde = { version = "1.0.136", optional = true } -frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" } -sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } - -[dev-dependencies] -serde_json = "1.0.79" -pallet-balances = { version = "4.0.0-dev", path = "../balances" } - -[features] -default = ["std"] -std = [ - "codec/std", - "frame-support/std", - "frame-system/std", - "scale-info/std", - "serde", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", - "sp-std/std", -] -try-runtime = ["frame-support/try-runtime"] diff --git a/frame/transaction-payment-mangata/README.md b/frame/transaction-payment-mangata/README.md deleted file mode 100644 index bf114246e60fa..0000000000000 --- a/frame/transaction-payment-mangata/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Transaction Payment Pallet - -This pallet provides the basic logic needed to pay the absolute minimum amount needed for a -transaction to be included. This includes: - - _weight fee_: A fee proportional to amount of weight a transaction consumes. - - _length fee_: A fee proportional to the encoded length of the transaction. - - _tip_: An optional tip. Tip increases the priority of the transaction, giving it a higher - chance to be included by the transaction queue. - -Additionally, this pallet allows one to configure: - - The mapping between one unit of weight to one unit of fee via [`Config::WeightToFee`]. - - A means of updating the fee for the next block, via defining a multiplier, based on the - final state of the chain at the end of the previous block. This can be configured via - [`Config::FeeMultiplierUpdate`] - -License: Apache-2.0 diff --git a/frame/transaction-payment-mangata/asset-tx-payment/Cargo.toml b/frame/transaction-payment-mangata/asset-tx-payment/Cargo.toml deleted file mode 100644 index e2ee594b2f0c5..0000000000000 --- a/frame/transaction-payment-mangata/asset-tx-payment/Cargo.toml +++ /dev/null @@ -1,54 +0,0 @@ -[package] -name = "pallet-asset-tx-payment-mangata" -version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" -license = "Apache-2.0" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" -description = "pallet to manage transaction payments in assets" -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -# Substrate dependencies -sp-core = { version = "6.0.0", default-features = false, path = "../../../primitives/core" } -sp-io = { version = "6.0.0", default-features = false, path = "../../../primitives/io" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../primitives/runtime" } -sp-std = { version = "4.0.0", default-features = false, path = "../../../primitives/std" } - -frame-support = { version = "4.0.0-dev", default-features = false, path = "../../support" } -frame-system = { version = "4.0.0-dev", default-features = false, path = "../../system" } -pallet-transaction-payment-mangata = { version = "4.0.0-dev", default-features = false, path = ".." } - -# Other dependencies -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } -serde = { version = "1.0.136", optional = true } - -[dev-dependencies] -serde_json = "1.0.79" - -sp-storage = { version = "6.0.0", default-features = false, path = "../../../primitives/storage" } - -pallet-assets = { version = "4.0.0-dev", path = "../../assets" } -pallet-authorship = { version = "4.0.0-dev", path = "../../authorship" } -pallet-balances = { version = "4.0.0-dev", path = "../../balances" } - - -[features] -default = ["std"] -std = [ - "serde", - "codec/std", - "sp-std/std", - "sp-runtime/std", - "frame-support/std", - "frame-system/std", - "sp-io/std", - "sp-core/std", - "pallet-transaction-payment-mangata/std", -] -try-runtime = ["frame-support/try-runtime"] diff --git a/frame/transaction-payment-mangata/asset-tx-payment/README.md b/frame/transaction-payment-mangata/asset-tx-payment/README.md deleted file mode 100644 index beda765101f0e..0000000000000 --- a/frame/transaction-payment-mangata/asset-tx-payment/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# pallet-asset-tx-payment - -## Asset Transaction Payment Pallet - -This pallet allows runtimes that include it to pay for transactions in assets other than the -native token of the chain. - -### Overview -It does this by extending transactions to include an optional `AssetId` that specifies the asset -to be used for payment (defaulting to the native token on `None`). It expects an -[`OnChargeAssetTransaction`] implementation analogously to [`pallet-transaction-payment-mangata`]. The -included [`FungiblesAdapter`] (implementing [`OnChargeAssetTransaction`]) determines the fee -amount by converting the fee calculated by [`pallet-transaction-payment-mangata`] into the desired -asset. - -### Integration -This pallet wraps FRAME's transaction payment pallet and functions as a replacement. This means -you should include both pallets in your `construct_runtime` macro, but only include this -pallet's [`SignedExtension`] ([`ChargeAssetTxPayment`]). - -License: Apache-2.0 diff --git a/frame/transaction-payment-mangata/asset-tx-payment/src/lib.rs b/frame/transaction-payment-mangata/asset-tx-payment/src/lib.rs deleted file mode 100644 index f60c4aee2d3a0..0000000000000 --- a/frame/transaction-payment-mangata/asset-tx-payment/src/lib.rs +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! # Asset Transaction Payment Pallet -//! -//! This pallet allows runtimes that include it to pay for transactions in assets other than the -//! main token of the chain. -//! -//! ## Overview - -//! It does this by extending transactions to include an optional `AssetId` that specifies the asset -//! to be used for payment (defaulting to the native token on `None`). It expects an -//! [`OnChargeAssetTransaction`] implementation analogously to -//! [`pallet-transaction-payment-mangata`]. The included [`FungiblesAdapter`] (implementing -//! [`OnChargeAssetTransaction`]) determines the fee amount by converting the fee calculated by -//! [`pallet-transaction-payment-mangata`] into the desired asset. -//! -//! ## Integration - -//! This pallet wraps FRAME's transaction payment pallet and functions as a replacement. This means -//! you should include both pallets in your `construct_runtime` macro, but only include this -//! pallet's [`SignedExtension`] ([`ChargeAssetTxPayment`]). - -#![cfg_attr(not(feature = "std"), no_std)] - -use sp_std::prelude::*; - -use codec::{Decode, Encode}; -use frame_support::{ - dispatch::DispatchResult, - traits::{ - tokens::{ - fungibles::{Balanced, CreditOf, Inspect}, - WithdrawConsequence, - }, - IsType, - }, - weights::{DispatchInfo, PostDispatchInfo}, - DefaultNoBound, -}; -use pallet_transaction_payment_mangata::OnChargeTransaction; -use scale_info::TypeInfo; -use sp_runtime::{ - traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension, Zero}, - transaction_validity::{ - InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, - }, - FixedPointOperand, -}; - -#[cfg(test)] -mod tests; - -mod payment; -pub use payment::*; - -// Type aliases used for interaction with `OnChargeTransaction`. -pub(crate) type OnChargeTransactionOf = - ::OnChargeTransaction; -// Balance type alias. -pub(crate) type BalanceOf = as OnChargeTransaction>::Balance; -// Liquity info type alias. -pub(crate) type LiquidityInfoOf = - as OnChargeTransaction>::LiquidityInfo; - -// Type alias used for interaction with fungibles (assets). -// Balance type alias. -pub(crate) type AssetBalanceOf = - <::Fungibles as Inspect<::AccountId>>::Balance; -/// Asset id type alias. -pub(crate) type AssetIdOf = - <::Fungibles as Inspect<::AccountId>>::AssetId; - -// Type aliases used for interaction with `OnChargeAssetTransaction`. -// Balance type alias. -pub(crate) type ChargeAssetBalanceOf = - <::OnChargeAssetTransaction as OnChargeAssetTransaction>::Balance; -// Asset id type alias. -pub(crate) type ChargeAssetIdOf = - <::OnChargeAssetTransaction as OnChargeAssetTransaction>::AssetId; -// Liquity info type alias. -pub(crate) type ChargeAssetLiquidityOf = - <::OnChargeAssetTransaction as OnChargeAssetTransaction>::LiquidityInfo; - -/// Used to pass the initial payment info from pre- to post-dispatch. -#[derive(Encode, Decode, DefaultNoBound, TypeInfo)] -pub enum InitialPayment { - /// No initial fee was payed. - Nothing, - /// The initial fee was payed in the native currency. - Native(LiquidityInfoOf), - /// The initial fee was payed in an asset. - Asset(CreditOf), -} - -pub use pallet::*; - -#[frame_support::pallet] -pub mod pallet { - use super::*; - - #[pallet::config] - pub trait Config: frame_system::Config + pallet_transaction_payment_mangata::Config { - /// The fungibles instance used to pay for transactions in assets. - type Fungibles: Balanced; - /// The actual transaction charging logic that charges the fees. - type OnChargeAssetTransaction: OnChargeAssetTransaction; - } - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(_); -} - -/// Require the transactor pay for themselves and maybe include a tip to gain additional priority -/// in the queue. Allows paying via both `Currency` as well as `fungibles::Balanced`. -/// -/// Wraps the transaction logic in [`pallet_transaction_payment_mangata`] and extends it with -/// assets. An asset id of `None` falls back to the underlying transaction payment via the native -/// currency. -#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] -#[scale_info(skip_type_params(T))] -pub struct ChargeAssetTxPayment { - #[codec(compact)] - tip: BalanceOf, - asset_id: Option>, -} - -impl ChargeAssetTxPayment -where - T::Call: Dispatchable, - AssetBalanceOf: Send + Sync + FixedPointOperand, - BalanceOf: Send + Sync + FixedPointOperand + IsType>, - ChargeAssetIdOf: Send + Sync, - CreditOf: IsType>, -{ - /// Utility constructor. Used only in client/factory code. - pub fn from(tip: BalanceOf, asset_id: Option>) -> Self { - Self { tip, asset_id } - } - - /// Fee withdrawal logic that dispatches to either `OnChargeAssetTransaction` or - /// `OnChargeTransaction`. - fn withdraw_fee( - &self, - who: &T::AccountId, - call: &T::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result<(BalanceOf, InitialPayment), TransactionValidityError> { - let fee = pallet_transaction_payment_mangata::Pallet::::compute_fee( - len as u32, info, self.tip, - ); - debug_assert!(self.tip <= fee, "tip should be included in the computed fee"); - if fee.is_zero() { - Ok((fee, InitialPayment::Nothing)) - } else if let Some(asset_id) = self.asset_id { - T::OnChargeAssetTransaction::withdraw_fee( - who, - call, - info, - asset_id, - fee.into(), - self.tip.into(), - ) - .map(|i| (fee, InitialPayment::Asset(i.into()))) - } else { - as OnChargeTransaction>::withdraw_fee( - who, call, info, fee, self.tip, - ) - .map(|i| (fee, InitialPayment::Native(i))) - .map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() }) - } - } -} - -impl sp_std::fmt::Debug for ChargeAssetTxPayment { - #[cfg(feature = "std")] - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - write!(f, "ChargeAssetTxPayment<{:?}, {:?}>", self.tip, self.asset_id.encode()) - } - #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - Ok(()) - } -} - -impl SignedExtension for ChargeAssetTxPayment -where - T::Call: Dispatchable, - AssetBalanceOf: Send + Sync + FixedPointOperand, - BalanceOf: Send + Sync + From + FixedPointOperand + IsType>, - ChargeAssetIdOf: Send + Sync, - CreditOf: IsType>, -{ - const IDENTIFIER: &'static str = "ChargeAssetTxPayment"; - type AccountId = T::AccountId; - type Call = T::Call; - type AdditionalSigned = (); - type Pre = ( - // tip - BalanceOf, - // who paid the fee - Self::AccountId, - // imbalance resulting from withdrawing the fee - InitialPayment, - ); - - fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { - Ok(()) - } - - fn validate( - &self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> TransactionValidity { - use pallet_transaction_payment_mangata::ChargeTransactionPayment; - let (fee, _) = self.withdraw_fee(who, call, info, len)?; - let priority = ChargeTransactionPayment::::get_priority(info, len, self.tip, fee); - Ok(ValidTransaction { priority, ..Default::default() }) - } - - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - let (_fee, initial_payment) = self.withdraw_fee(who, call, info, len)?; - Ok((self.tip, who.clone(), initial_payment)) - } - - fn post_dispatch( - pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, - len: usize, - result: &DispatchResult, - ) -> Result<(), TransactionValidityError> { - if let Some((tip, who, initial_payment)) = pre { - match initial_payment { - InitialPayment::Native(already_withdrawn) => { - pallet_transaction_payment_mangata::ChargeTransactionPayment::::post_dispatch( - Some((tip, who, already_withdrawn)), - info, - post_info, - len, - result, - )?; - }, - InitialPayment::Asset(already_withdrawn) => { - let actual_fee = - pallet_transaction_payment_mangata::Pallet::::compute_actual_fee( - len as u32, info, post_info, tip, - ); - T::OnChargeAssetTransaction::correct_and_deposit_fee( - &who, - info, - post_info, - actual_fee.into(), - tip.into(), - already_withdrawn.into(), - )?; - }, - InitialPayment::Nothing => { - // `actual_fee` should be zero here for any signed extrinsic. It would be - // non-zero here in case of unsigned extrinsics as they don't pay fees but - // `compute_actual_fee` is not aware of them. In both cases it's fine to just - // move ahead without adjusting the fee, though, so we do nothing. - debug_assert!(tip.is_zero(), "tip should be zero if initial fee was zero."); - }, - } - } - - Ok(()) - } -} diff --git a/frame/transaction-payment-mangata/asset-tx-payment/src/payment.rs b/frame/transaction-payment-mangata/asset-tx-payment/src/payment.rs deleted file mode 100644 index 394696cc18929..0000000000000 --- a/frame/transaction-payment-mangata/asset-tx-payment/src/payment.rs +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -///! Traits and default implementation for paying transaction fees in assets. -use super::*; -use crate::Config; - -use codec::FullCodec; -use frame_support::{ - traits::{ - fungibles::{Balanced, CreditOf, Inspect}, - tokens::BalanceConversion, - }, - unsigned::TransactionValidityError, -}; -use scale_info::TypeInfo; -use sp_runtime::{ - traits::{ - AtLeast32BitUnsigned, DispatchInfoOf, MaybeSerializeDeserialize, One, PostDispatchInfoOf, - }, - transaction_validity::InvalidTransaction, -}; -use sp_std::{fmt::Debug, marker::PhantomData}; - -/// Handle withdrawing, refunding and depositing of transaction fees. -pub trait OnChargeAssetTransaction { - /// The underlying integer type in which fees are calculated. - type Balance: AtLeast32BitUnsigned - + FullCodec - + Copy - + MaybeSerializeDeserialize - + Debug - + Default - + TypeInfo; - /// The type used to identify the assets used for transaction payment. - type AssetId: FullCodec + Copy + MaybeSerializeDeserialize + Debug + Default + Eq + TypeInfo; - /// The type used to store the intermediate values between pre- and post-dispatch. - type LiquidityInfo; - - /// Before the transaction is executed the payment of the transaction fees needs to be secured. - /// - /// Note: The `fee` already includes the `tip`. - fn withdraw_fee( - who: &T::AccountId, - call: &T::Call, - dispatch_info: &DispatchInfoOf, - asset_id: Self::AssetId, - fee: Self::Balance, - tip: Self::Balance, - ) -> Result; - - /// After the transaction was executed the actual fee can be calculated. - /// This function should refund any overpaid fees and optionally deposit - /// the corrected amount. - /// - /// Note: The `fee` already includes the `tip`. - fn correct_and_deposit_fee( - who: &T::AccountId, - dispatch_info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, - corrected_fee: Self::Balance, - tip: Self::Balance, - already_withdrawn: Self::LiquidityInfo, - ) -> Result<(), TransactionValidityError>; -} - -/// Allows specifying what to do with the withdrawn asset fees. -pub trait HandleCredit> { - /// Implement to determine what to do with the withdrawn asset fees. - /// Default for `CreditOf` from the assets pallet is to burn and - /// decrease total issuance. - fn handle_credit(credit: CreditOf); -} - -/// Default implementation that just drops the credit according to the `OnDrop` in the underlying -/// imbalance type. -impl> HandleCredit for () { - fn handle_credit(_credit: CreditOf) {} -} - -/// Implements the asset transaction for a balance to asset converter (implementing -/// [`BalanceConversion`]) and a credit handler (implementing [`HandleCredit`]). -/// -/// The credit handler is given the complete fee in terms of the asset used for the transaction. -pub struct FungiblesAdapter(PhantomData<(CON, HC)>); - -/// Default implementation for a runtime instantiating this pallet, a balance to asset converter and -/// a credit handler. -impl OnChargeAssetTransaction for FungiblesAdapter -where - T: Config, - CON: BalanceConversion, AssetIdOf, AssetBalanceOf>, - HC: HandleCredit, - AssetIdOf: FullCodec + Copy + MaybeSerializeDeserialize + Debug + Default + Eq + TypeInfo, -{ - type Balance = BalanceOf; - type AssetId = AssetIdOf; - type LiquidityInfo = CreditOf; - - /// Withdraw the predicted fee from the transaction origin. - /// - /// Note: The `fee` already includes the `tip`. - fn withdraw_fee( - who: &T::AccountId, - _call: &T::Call, - _info: &DispatchInfoOf, - asset_id: Self::AssetId, - fee: Self::Balance, - _tip: Self::Balance, - ) -> Result { - // We don't know the precision of the underlying asset. Because the converted fee could be - // less than one (e.g. 0.5) but gets rounded down by integer division we introduce a minimum - // fee. - let min_converted_fee = if fee.is_zero() { Zero::zero() } else { One::one() }; - let converted_fee = CON::to_asset_balance(fee, asset_id) - .map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment))? - .max(min_converted_fee); - let can_withdraw = - >::can_withdraw(asset_id, who, converted_fee); - if !matches!(can_withdraw, WithdrawConsequence::Success) { - return Err(InvalidTransaction::Payment.into()) - } - >::withdraw(asset_id, who, converted_fee) - .map_err(|_| TransactionValidityError::from(InvalidTransaction::Payment)) - } - - /// Hand the fee and the tip over to the `[HandleCredit]` implementation. - /// Since the predicted fee might have been too high, parts of the fee may be refunded. - /// - /// Note: The `corrected_fee` already includes the `tip`. - fn correct_and_deposit_fee( - who: &T::AccountId, - _dispatch_info: &DispatchInfoOf, - _post_info: &PostDispatchInfoOf, - corrected_fee: Self::Balance, - _tip: Self::Balance, - paid: Self::LiquidityInfo, - ) -> Result<(), TransactionValidityError> { - let min_converted_fee = if corrected_fee.is_zero() { Zero::zero() } else { One::one() }; - // Convert the corrected fee into the asset used for payment. - let converted_fee = CON::to_asset_balance(corrected_fee, paid.asset()) - .map_err(|_| -> TransactionValidityError { InvalidTransaction::Payment.into() })? - .max(min_converted_fee); - // Calculate how much refund we should return. - let (final_fee, refund) = paid.split(converted_fee); - // Refund to the account that paid the fees. If this fails, the account might have dropped - // below the existential balance. In that case we don't refund anything. - let _ = >::resolve(who, refund); - // Handle the final fee, e.g. by transferring to the block author or burning. - HC::handle_credit(final_fee); - Ok(()) - } -} diff --git a/frame/transaction-payment-mangata/asset-tx-payment/src/tests.rs b/frame/transaction-payment-mangata/asset-tx-payment/src/tests.rs deleted file mode 100644 index 9a3691cc1918c..0000000000000 --- a/frame/transaction-payment-mangata/asset-tx-payment/src/tests.rs +++ /dev/null @@ -1,732 +0,0 @@ -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use super::*; -use crate as pallet_asset_tx_payment; - -use frame_support::{ - assert_ok, - pallet_prelude::*, - parameter_types, - traits::{fungibles::Mutate, ConstU32, ConstU64, ConstU8, FindAuthor}, - weights::{DispatchClass, DispatchInfo, PostDispatchInfo, Weight, WeightToFee as WeightToFeeT}, - ConsensusEngineId, -}; -use frame_system as system; -use frame_system::EnsureRoot; -use pallet_balances::Call as BalancesCall; -use pallet_transaction_payment_mangata::CurrencyAdapter; -use sp_core::H256; -use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, ConvertInto, IdentityLookup, SaturatedConversion, StaticLookup}, -}; -use std::cell::RefCell; - -type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; -type Block = frame_system::mocking::MockBlock; -type Balance = u64; -type AccountId = u64; - -frame_support::construct_runtime!( - pub enum Runtime where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - TransactionPayment: pallet_transaction_payment_mangata::{Pallet, Storage}, - Assets: pallet_assets::{Pallet, Call, Storage, Event}, - Authorship: pallet_authorship::{Pallet, Call, Storage}, - AssetTxPayment: pallet_asset_tx_payment::{Pallet}, - } -); - -const CALL: &::Call = - &Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); - -thread_local! { - static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(0); -} - -pub struct BlockWeights; -impl Get for BlockWeights { - fn get() -> frame_system::limits::BlockWeights { - frame_system::limits::BlockWeights::builder() - .base_block(0) - .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow()).into(); - }) - .for_class(DispatchClass::non_mandatory(), |weights| { - weights.max_total = 1024.into(); - }) - .build_or_panic() - } -} - -parameter_types! { - pub static WeightToFee: u64 = 1; - pub static TransactionByteFee: u64 = 1; -} - -impl frame_system::Config for Runtime { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; - type BlockLength = (); - type DbWeight = (); - type Origin = Origin; - type Index = u64; - type BlockNumber = u64; - type Call = Call; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Header = Header; - type Event = Event; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; -} - -parameter_types! { - pub const ExistentialDeposit: u64 = 10; -} - -impl pallet_balances::Config for Runtime { - type Balance = Balance; - type Event = Event; - type DustRemoval = (); - type ExistentialDeposit = ConstU64<10>; - type AccountStore = System; - type MaxLocks = (); - type WeightInfo = (); - type MaxReserves = ConstU32<50>; - type ReserveIdentifier = [u8; 8]; -} - -impl WeightToFeeT for WeightToFee { - type Balance = u64; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(*weight).saturating_mul(WEIGHT_TO_FEE.with(|v| *v.borrow())) - } -} - -impl WeightToFeeT for TransactionByteFee { - type Balance = u64; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(*weight) - .saturating_mul(TRANSACTION_BYTE_FEE.with(|v| *v.borrow())) - } -} - -impl pallet_transaction_payment_mangata::Config for Runtime { - type OnChargeTransaction = CurrencyAdapter; - type WeightToFee = WeightToFee; - type LengthToFee = TransactionByteFee; - type FeeMultiplierUpdate = (); - type OperationalFeeMultiplier = ConstU8<5>; -} - -impl pallet_assets::Config for Runtime { - type Event = Event; - type Balance = Balance; - type AssetId = u32; - type Currency = Balances; - type ForceOrigin = EnsureRoot; - type AssetDeposit = ConstU64<2>; - type AssetAccountDeposit = ConstU64<2>; - type MetadataDepositBase = ConstU64<0>; - type MetadataDepositPerByte = ConstU64<0>; - type ApprovalDeposit = ConstU64<0>; - type StringLimit = ConstU32<20>; - type Freezer = (); - type Extra = (); - type WeightInfo = (); -} - -pub struct HardcodedAuthor; -const BLOCK_AUTHOR: AccountId = 1234; -impl FindAuthor for HardcodedAuthor { - fn find_author<'a, I>(_: I) -> Option - where - I: 'a + IntoIterator, - { - Some(BLOCK_AUTHOR) - } -} - -impl pallet_authorship::Config for Runtime { - type FindAuthor = HardcodedAuthor; - type UncleGenerations = (); - type FilterUncle = (); - type EventHandler = (); -} - -pub struct CreditToBlockAuthor; -impl HandleCredit for CreditToBlockAuthor { - fn handle_credit(credit: CreditOf) { - if let Some(author) = pallet_authorship::Pallet::::author() { - // What to do in case paying the author fails (e.g. because `fee < min_balance`) - // default: drop the result which will trigger the `OnDrop` of the imbalance. - let _ = >::resolve(&author, credit); - } - } -} - -impl Config for Runtime { - type Fungibles = Assets; - type OnChargeAssetTransaction = FungiblesAdapter< - pallet_assets::BalanceToAssetBalance, - CreditToBlockAuthor, - >; -} - -pub struct ExtBuilder { - balance_factor: u64, - base_weight: u64, - byte_fee: u64, - weight_to_fee: u64, -} - -impl Default for ExtBuilder { - fn default() -> Self { - Self { balance_factor: 1, base_weight: 0, byte_fee: 1, weight_to_fee: 1 } - } -} - -impl ExtBuilder { - pub fn base_weight(mut self, base_weight: u64) -> Self { - self.base_weight = base_weight; - self - } - pub fn balance_factor(mut self, factor: u64) -> Self { - self.balance_factor = factor; - self - } - fn set_constants(&self) { - EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow_mut() = self.base_weight); - TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.byte_fee); - WEIGHT_TO_FEE.with(|v| *v.borrow_mut() = self.weight_to_fee); - } - pub fn build(self) -> sp_io::TestExternalities { - self.set_constants(); - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - pallet_balances::GenesisConfig:: { - balances: if self.balance_factor > 0 { - vec![ - (1, 10 * self.balance_factor), - (2, 20 * self.balance_factor), - (3, 30 * self.balance_factor), - (4, 40 * self.balance_factor), - (5, 50 * self.balance_factor), - (6, 60 * self.balance_factor), - ] - } else { - vec![] - }, - } - .assimilate_storage(&mut t) - .unwrap(); - t.into() - } -} - -/// create a transaction info struct from weight. Handy to avoid building the whole struct. -pub fn info_from_weight(w: Weight) -> DispatchInfo { - // pays_fee: Pays::Yes -- class: DispatchClass::Normal - DispatchInfo { weight: w, ..Default::default() } -} - -fn post_info_from_weight(w: Weight) -> PostDispatchInfo { - PostDispatchInfo { actual_weight: Some(w), pays_fee: Default::default() } -} - -fn info_from_pays(p: Pays) -> DispatchInfo { - DispatchInfo { pays_fee: p, ..Default::default() } -} - -fn post_info_from_pays(p: Pays) -> PostDispatchInfo { - PostDispatchInfo { actual_weight: None, pays_fee: p } -} - -fn default_post_info() -> PostDispatchInfo { - PostDispatchInfo { actual_weight: None, pays_fee: Default::default() } -} - -#[test] -fn transaction_payment_in_native_possible() { - let balance_factor = 100; - ExtBuilder::default() - .balance_factor(balance_factor) - .base_weight(5) - .build() - .execute_with(|| { - let len = 10; - let pre = ChargeAssetTxPayment::::from(0, None) - .pre_dispatch(&1, CALL, &info_from_weight(5), len) - .unwrap(); - let initial_balance = 10 * balance_factor; - assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); - - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), - &info_from_weight(5), - &default_post_info(), - len, - &Ok(()) - )); - assert_eq!(Balances::free_balance(1), initial_balance - 5 - 5 - 10); - - let pre = ChargeAssetTxPayment::::from(5 /* tipped */, None) - .pre_dispatch(&2, CALL, &info_from_weight(100), len) - .unwrap(); - let initial_balance_for_2 = 20 * balance_factor; - assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 100 - 5); - - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), - &info_from_weight(100), - &post_info_from_weight(50), - len, - &Ok(()) - )); - assert_eq!(Balances::free_balance(2), initial_balance_for_2 - 5 - 10 - 50 - 5); - }); -} - -#[test] -fn transaction_payment_in_asset_possible() { - let base_weight = 5; - let balance_factor = 100; - ExtBuilder::default() - .balance_factor(balance_factor) - .base_weight(base_weight) - .build() - .execute_with(|| { - // create the asset - let asset_id = 1; - let min_balance = 2; - assert_ok!(Assets::force_create( - Origin::root(), - asset_id, - 42, /* owner */ - true, /* is_sufficient */ - min_balance - )); - - // mint into the caller account - let caller = 1; - let beneficiary = ::Lookup::unlookup(caller); - let balance = 100; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); - assert_eq!(Assets::balance(asset_id, caller), balance); - let weight = 5; - let len = 10; - // we convert the from weight to fee based on the ratio between asset min balance and - // existential deposit - let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) - .unwrap(); - // assert that native balance is not used - assert_eq!(Balances::free_balance(caller), 10 * balance_factor); - // check that fee was charged in the given asset - assert_eq!(Assets::balance(asset_id, caller), balance - fee); - assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0); - - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), - &info_from_weight(weight), - &default_post_info(), - len, - &Ok(()) - )); - assert_eq!(Assets::balance(asset_id, caller), balance - fee); - // check that the block author gets rewarded - assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), fee); - }); -} - -#[test] -fn transaction_payment_without_fee() { - let base_weight = 5; - let balance_factor = 100; - ExtBuilder::default() - .balance_factor(balance_factor) - .base_weight(base_weight) - .build() - .execute_with(|| { - // create the asset - let asset_id = 1; - let min_balance = 2; - assert_ok!(Assets::force_create( - Origin::root(), - asset_id, - 42, /* owner */ - true, /* is_sufficient */ - min_balance - )); - - // mint into the caller account - let caller = 1; - let beneficiary = ::Lookup::unlookup(caller); - let balance = 100; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); - assert_eq!(Assets::balance(asset_id, caller), balance); - let weight = 5; - let len = 10; - // we convert the from weight to fee based on the ratio between asset min balance and - // existential deposit - let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) - .unwrap(); - // assert that native balance is not used - assert_eq!(Balances::free_balance(caller), 10 * balance_factor); - // check that fee was charged in the given asset - assert_eq!(Assets::balance(asset_id, caller), balance - fee); - assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0); - - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), - &info_from_weight(weight), - &post_info_from_pays(Pays::No), - len, - &Ok(()) - )); - // caller should be refunded - assert_eq!(Assets::balance(asset_id, caller), balance); - // check that the block author did not get rewarded - assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), 0); - }); -} - -#[test] -fn asset_transaction_payment_with_tip_and_refund() { - let base_weight = 5; - ExtBuilder::default() - .balance_factor(100) - .base_weight(base_weight) - .build() - .execute_with(|| { - // create the asset - let asset_id = 1; - let min_balance = 2; - assert_ok!(Assets::force_create( - Origin::root(), - asset_id, - 42, /* owner */ - true, /* is_sufficient */ - min_balance - )); - - // mint into the caller account - let caller = 2; - let beneficiary = ::Lookup::unlookup(caller); - let balance = 1000; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); - assert_eq!(Assets::balance(asset_id, caller), balance); - let weight = 100; - let tip = 5; - let len = 10; - // we convert the from weight to fee based on the ratio between asset min balance and - // existential deposit - let fee_with_tip = - (base_weight + weight + len as u64 + tip) * min_balance / ExistentialDeposit::get(); - let pre = ChargeAssetTxPayment::::from(tip, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) - .unwrap(); - assert_eq!(Assets::balance(asset_id, caller), balance - fee_with_tip); - - let final_weight = 50; - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), - &info_from_weight(weight), - &post_info_from_weight(final_weight), - len, - &Ok(()) - )); - let final_fee = - fee_with_tip - (weight - final_weight) * min_balance / ExistentialDeposit::get(); - assert_eq!(Assets::balance(asset_id, caller), balance - (final_fee)); - assert_eq!(Assets::balance(asset_id, BLOCK_AUTHOR), final_fee); - }); -} - -#[test] -fn payment_from_account_with_only_assets() { - let base_weight = 5; - ExtBuilder::default() - .balance_factor(100) - .base_weight(base_weight) - .build() - .execute_with(|| { - // create the asset - let asset_id = 1; - let min_balance = 2; - assert_ok!(Assets::force_create( - Origin::root(), - asset_id, - 42, /* owner */ - true, /* is_sufficient */ - min_balance - )); - - // mint into the caller account - let caller = 333; - let beneficiary = ::Lookup::unlookup(caller); - let balance = 100; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); - assert_eq!(Assets::balance(asset_id, caller), balance); - // assert that native balance is not necessary - assert_eq!(Balances::free_balance(caller), 0); - let weight = 5; - let len = 10; - // we convert the from weight to fee based on the ratio between asset min balance and - // existential deposit - let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) - .unwrap(); - assert_eq!(Balances::free_balance(caller), 0); - // check that fee was charged in the given asset - assert_eq!(Assets::balance(asset_id, caller), balance - fee); - - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), - &info_from_weight(weight), - &default_post_info(), - len, - &Ok(()) - )); - assert_eq!(Assets::balance(asset_id, caller), balance - fee); - assert_eq!(Balances::free_balance(caller), 0); - }); -} - -#[test] -fn payment_only_with_existing_sufficient_asset() { - let base_weight = 5; - ExtBuilder::default() - .balance_factor(100) - .base_weight(base_weight) - .build() - .execute_with(|| { - let asset_id = 1; - let caller = 1; - let weight = 5; - let len = 10; - // pre_dispatch fails for non-existent asset - assert!(ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) - .is_err()); - - // create the non-sufficient asset - let min_balance = 2; - assert_ok!(Assets::force_create( - Origin::root(), - asset_id, - 42, /* owner */ - false, /* is_sufficient */ - min_balance - )); - // pre_dispatch fails for non-sufficient asset - assert!(ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) - .is_err()); - }); -} - -#[test] -fn converted_fee_is_never_zero_if_input_fee_is_not() { - let base_weight = 1; - ExtBuilder::default() - .balance_factor(100) - .base_weight(base_weight) - .build() - .execute_with(|| { - // create the asset - let asset_id = 1; - let min_balance = 1; - assert_ok!(Assets::force_create( - Origin::root(), - asset_id, - 42, /* owner */ - true, /* is_sufficient */ - min_balance - )); - - // mint into the caller account - let caller = 333; - let beneficiary = ::Lookup::unlookup(caller); - let balance = 100; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); - assert_eq!(Assets::balance(asset_id, caller), balance); - let weight = 1; - let len = 1; - // we convert the from weight to fee based on the ratio between asset min balance and - // existential deposit - let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); - // naive fee calculation would round down to zero - assert_eq!(fee, 0); - { - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_pays(Pays::No), len) - .unwrap(); - // `Pays::No` still implies no fees - assert_eq!(Assets::balance(asset_id, caller), balance); - - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), - &info_from_pays(Pays::No), - &post_info_from_pays(Pays::No), - len, - &Ok(()) - )); - assert_eq!(Assets::balance(asset_id, caller), balance); - } - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_weight(weight), len) - .unwrap(); - // check that at least one coin was charged in the given asset - assert_eq!(Assets::balance(asset_id, caller), balance - 1); - - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), - &info_from_weight(weight), - &default_post_info(), - len, - &Ok(()) - )); - assert_eq!(Assets::balance(asset_id, caller), balance - 1); - }); -} - -#[test] -fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { - let base_weight = 1; - ExtBuilder::default() - .balance_factor(100) - .base_weight(base_weight) - .build() - .execute_with(|| { - // create the asset - let asset_id = 1; - let min_balance = 100; - assert_ok!(Assets::force_create( - Origin::root(), - asset_id, - 42, /* owner */ - true, /* is_sufficient */ - min_balance - )); - - // mint into the caller account - let caller = 333; - let beneficiary = ::Lookup::unlookup(caller); - let balance = 100; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); - assert_eq!(Assets::balance(asset_id, caller), balance); - let weight = 1; - let len = 1; - // we convert the from weight to fee based on the ratio between asset min balance and - // existential deposit - let fee = (base_weight + weight + len as u64) * min_balance / ExistentialDeposit::get(); - // calculated fee is greater than 0 - assert!(fee > 0); - let pre = ChargeAssetTxPayment::::from(0, Some(asset_id)) - .pre_dispatch(&caller, CALL, &info_from_pays(Pays::No), len) - .unwrap(); - // `Pays::No` implies no pre-dispatch fees - assert_eq!(Assets::balance(asset_id, caller), balance); - let (_tip, _who, initial_payment) = ⪯ - let not_paying = match initial_payment { - &InitialPayment::Nothing => true, - _ => false, - }; - assert!(not_paying, "initial payment should be Nothing if we pass Pays::No"); - - // `Pays::Yes` on post-dispatch does not mean we pay (we never charge more than the - // initial fee) - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - Some(pre), - &info_from_pays(Pays::No), - &post_info_from_pays(Pays::Yes), - len, - &Ok(()) - )); - assert_eq!(Assets::balance(asset_id, caller), balance); - }); -} - -#[test] -fn post_dispatch_fee_is_zero_if_unsigned_pre_dispatch_fee_is_zero() { - let base_weight = 1; - ExtBuilder::default() - .balance_factor(100) - .base_weight(base_weight) - .build() - .execute_with(|| { - // create the asset - let asset_id = 1; - let min_balance = 100; - assert_ok!(Assets::force_create( - Origin::root(), - asset_id, - 42, /* owner */ - true, /* is_sufficient */ - min_balance - )); - - // mint into the caller account - let caller = 333; - let beneficiary = ::Lookup::unlookup(caller); - let balance = 100; - assert_ok!(Assets::mint_into(asset_id, &beneficiary, balance)); - assert_eq!(Assets::balance(asset_id, caller), balance); - let weight = 1; - let len = 1; - ChargeAssetTxPayment::::pre_dispatch_unsigned( - CALL, - &info_from_weight(weight), - len, - ) - .unwrap(); - - assert_eq!(Assets::balance(asset_id, caller), balance); - - // `Pays::Yes` on post-dispatch does not mean we pay (we never charge more than the - // initial fee) - assert_ok!(ChargeAssetTxPayment::::post_dispatch( - None, - &info_from_weight(weight), - &post_info_from_pays(Pays::Yes), - len, - &Ok(()) - )); - assert_eq!(Assets::balance(asset_id, caller), balance); - }); -} diff --git a/frame/transaction-payment-mangata/rpc/Cargo.toml b/frame/transaction-payment-mangata/rpc/Cargo.toml deleted file mode 100644 index 53e45bcfb19a0..0000000000000 --- a/frame/transaction-payment-mangata/rpc/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "pallet-transaction-payment-rpc-mangata" -version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" -license = "Apache-2.0" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" -description = "RPC interface for the transaction payment pallet." -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0" } -jsonrpsee = { version = "0.15.1", features = ["server", "macros"] } -pallet-transaction-payment-rpc-runtime-api-mangata = { version = "4.0.0-dev", path = "./runtime-api" } -sp-api = { version = "4.0.0-dev", path = "../../../primitives/api" } -sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } -sp-core = { version = "6.0.0", path = "../../../primitives/core" } -sp-rpc = { version = "6.0.0", path = "../../../primitives/rpc" } -sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } diff --git a/frame/transaction-payment-mangata/rpc/README.md b/frame/transaction-payment-mangata/rpc/README.md deleted file mode 100644 index bf2ada1ff0ab3..0000000000000 --- a/frame/transaction-payment-mangata/rpc/README.md +++ /dev/null @@ -1,3 +0,0 @@ -RPC interface for the transaction payment pallet. - -License: Apache-2.0 diff --git a/frame/transaction-payment-mangata/rpc/runtime-api/Cargo.toml b/frame/transaction-payment-mangata/rpc/runtime-api/Cargo.toml deleted file mode 100644 index 76ef2c302c2d5..0000000000000 --- a/frame/transaction-payment-mangata/rpc/runtime-api/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "pallet-transaction-payment-rpc-runtime-api-mangata" -version = "4.0.0-dev" -authors = ["Parity Technologies "] -edition = "2021" -license = "Apache-2.0" -homepage = "https://substrate.io" -repository = "https://github.com/paritytech/substrate/" -description = "RPC runtime API for transaction payment FRAME pallet" -readme = "README.md" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -pallet-transaction-payment-mangata = { version = "4.0.0-dev", default-features = false, path = "../../../transaction-payment-mangata" } -sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../../primitives/api" } -sp-runtime = { version = "6.0.0", default-features = false, path = "../../../../primitives/runtime" } - -[features] -default = ["std"] -std = [ - "codec/std", - "pallet-transaction-payment-mangata/std", - "sp-api/std", - "sp-runtime/std", -] diff --git a/frame/transaction-payment-mangata/rpc/runtime-api/README.md b/frame/transaction-payment-mangata/rpc/runtime-api/README.md deleted file mode 100644 index 0d81abdb1eeb3..0000000000000 --- a/frame/transaction-payment-mangata/rpc/runtime-api/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Runtime API definition for transaction payment pallet. - -License: Apache-2.0 diff --git a/frame/transaction-payment-mangata/rpc/src/lib.rs b/frame/transaction-payment-mangata/rpc/src/lib.rs deleted file mode 100644 index 4e06da77382e6..0000000000000 --- a/frame/transaction-payment-mangata/rpc/src/lib.rs +++ /dev/null @@ -1,171 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! RPC interface for the transaction payment pallet. - -use std::{convert::TryInto, sync::Arc}; - -use codec::{Codec, Decode}; -use jsonrpsee::{ - core::{async_trait, Error as JsonRpseeError, RpcResult}, - proc_macros::rpc, - types::error::{CallError, ErrorCode, ErrorObject}, -}; -use pallet_transaction_payment_rpc_runtime_api_mangata::{ - FeeDetails, InclusionFee, RuntimeDispatchInfo, -}; -use sp_api::ProvideRuntimeApi; -use sp_blockchain::HeaderBackend; -use sp_core::Bytes; -use sp_rpc::number::NumberOrHex; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, MaybeDisplay}, -}; - -pub use pallet_transaction_payment_rpc_runtime_api_mangata::TransactionPaymentApi as TransactionPaymentRuntimeApi; - -#[rpc(client, server)] -pub trait TransactionPaymentApi { - #[method(name = "payment_queryInfo")] - fn query_info(&self, encoded_xt: Bytes, at: Option) -> RpcResult; - - #[method(name = "payment_queryFeeDetails")] - fn query_fee_details( - &self, - encoded_xt: Bytes, - at: Option, - ) -> RpcResult>; -} - -/// Provides RPC methods to query a dispatchable's class, weight and fee. -pub struct TransactionPayment { - /// Shared reference to the client. - client: Arc, - _marker: std::marker::PhantomData

, -} - -impl TransactionPayment { - /// Creates a new instance of the TransactionPayment Rpc helper. - pub fn new(client: Arc) -> Self { - Self { client, _marker: Default::default() } - } -} - -/// Error type of this RPC api. -pub enum Error { - /// The transaction was not decodable. - DecodeError, - /// The call to runtime failed. - RuntimeError, -} - -impl From for i32 { - fn from(e: Error) -> i32 { - match e { - Error::RuntimeError => 1, - Error::DecodeError => 2, - } - } -} - -#[async_trait] -impl - TransactionPaymentApiServer<::Hash, RuntimeDispatchInfo> - for TransactionPayment -where - Block: BlockT, - C: ProvideRuntimeApi + HeaderBackend + Send + Sync + 'static, - C::Api: TransactionPaymentRuntimeApi, - Balance: Codec + MaybeDisplay + Copy + TryInto + Send + Sync + 'static, -{ - fn query_info( - &self, - encoded_xt: Bytes, - at: Option, - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); - - let encoded_len = encoded_xt.len() as u32; - - let uxt: Block::Extrinsic = Decode::decode(&mut &*encoded_xt).map_err(|e| { - CallError::Custom(ErrorObject::owned( - Error::DecodeError.into(), - "Unable to query dispatch info.", - Some(format!("{:?}", e)), - )) - })?; - api.query_info(&at, uxt, encoded_len).map_err(|e| { - CallError::Custom(ErrorObject::owned( - Error::RuntimeError.into(), - "Unable to query dispatch info.", - Some(e.to_string()), - )) - .into() - }) - } - - fn query_fee_details( - &self, - encoded_xt: Bytes, - at: Option, - ) -> RpcResult> { - let api = self.client.runtime_api(); - let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); - - let encoded_len = encoded_xt.len() as u32; - - let uxt: Block::Extrinsic = Decode::decode(&mut &*encoded_xt).map_err(|e| { - CallError::Custom(ErrorObject::owned( - Error::DecodeError.into(), - "Unable to query fee details.", - Some(format!("{:?}", e)), - )) - })?; - let fee_details = api.query_fee_details(&at, uxt, encoded_len).map_err(|e| { - CallError::Custom(ErrorObject::owned( - Error::RuntimeError.into(), - "Unable to query fee details.", - Some(e.to_string()), - )) - })?; - - let try_into_rpc_balance = |value: Balance| { - value.try_into().map_err(|_| { - JsonRpseeError::Call(CallError::Custom(ErrorObject::owned( - ErrorCode::InvalidParams.code(), - format!("{} doesn't fit in NumberOrHex representation", value), - None::<()>, - ))) - }) - }; - - Ok(FeeDetails { - inclusion_fee: if let Some(inclusion_fee) = fee_details.inclusion_fee { - Some(InclusionFee { - base_fee: try_into_rpc_balance(inclusion_fee.base_fee)?, - len_fee: try_into_rpc_balance(inclusion_fee.len_fee)?, - adjusted_weight_fee: try_into_rpc_balance(inclusion_fee.adjusted_weight_fee)?, - }) - } else { - None - }, - tip: Default::default(), - }) - } -} diff --git a/frame/transaction-payment-mangata/src/lib.rs b/frame/transaction-payment-mangata/src/lib.rs deleted file mode 100644 index 05469c20fba58..0000000000000 --- a/frame/transaction-payment-mangata/src/lib.rs +++ /dev/null @@ -1,1613 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! # Transaction Payment Pallet -//! -//! This pallet provides the basic logic needed to pay the absolute minimum amount needed for a -//! transaction to be included. This includes: -//! - _base fee_: This is the minimum amount a user pays for a transaction. It is declared -//! as a base _weight_ in the runtime and converted to a fee using `WeightToFee`. -//! - _weight fee_: A fee proportional to amount of weight a transaction consumes. -//! - _length fee_: A fee proportional to the encoded length of the transaction. -//! - _tip_: An optional tip. Tip increases the priority of the transaction, giving it a higher -//! chance to be included by the transaction queue. -//! -//! The base fee and adjusted weight and length fees constitute the _inclusion fee_, which is -//! the minimum fee for a transaction to be included in a block. -//! -//! The formula of final fee: -//! ```ignore -//! inclusion_fee = base_fee + length_fee + [targeted_fee_adjustment * weight_fee]; -//! final_fee = inclusion_fee + tip; -//! ``` -//! -//! - `targeted_fee_adjustment`: This is a multiplier that can tune the final fee based on -//! the congestion of the network. -//! -//! Additionally, this pallet allows one to configure: -//! - The mapping between one unit of weight to one unit of fee via [`Config::WeightToFee`]. -//! - A means of updating the fee for the next block, via defining a multiplier, based on the -//! final state of the chain at the end of the previous block. This can be configured via -//! [`Config::FeeMultiplierUpdate`] -//! - How the fees are paid via [`Config::OnChargeTransaction`]. - -#![cfg_attr(not(feature = "std"), no_std)] - -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; - -use sp_runtime::{ - traits::{ - Convert, DispatchInfoOf, Dispatchable, One, PostDispatchInfoOf, SaturatedConversion, - Saturating, SignedExtension, Zero, - }, - transaction_validity::{ - TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransaction, - }, - FixedPointNumber, FixedPointOperand, FixedU128, Perquintill, RuntimeDebug, -}; -use sp_std::prelude::*; - -use frame_support::{ - dispatch::DispatchResult, - traits::{EstimateCallFee, Get}, - weights::{ - DispatchClass, DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo, Weight, WeightToFee, - }, -}; - -mod payment; -mod types; - -pub use pallet::*; -pub use payment::*; -pub use types::{FeeDetails, InclusionFee, RuntimeDispatchInfo}; - -/// Fee multiplier. -pub type Multiplier = FixedU128; - -type BalanceOf = <::OnChargeTransaction as OnChargeTransaction>::Balance; - -/// A struct to update the weight multiplier per block. It implements `Convert`, meaning that it can convert the previous multiplier to the next one. This should -/// be called on `on_finalize` of a block, prior to potentially cleaning the weight data from the -/// system pallet. -/// -/// given: -/// s = previous block weight -/// s'= ideal block weight -/// m = maximum block weight -/// diff = (s - s')/m -/// v = 0.00001 -/// t1 = (v * diff) -/// t2 = (v * diff)^2 / 2 -/// then: -/// next_multiplier = prev_multiplier * (1 + t1 + t2) -/// -/// Where `(s', v)` must be given as the `Get` implementation of the `T` generic type. Moreover, `M` -/// must provide the minimum allowed value for the multiplier. Note that a runtime should ensure -/// with tests that the combination of this `M` and `V` is not such that the multiplier can drop to -/// zero and never recover. -/// -/// note that `s'` is interpreted as a portion in the _normal transaction_ capacity of the block. -/// For example, given `s' == 0.25` and `AvailableBlockRatio = 0.75`, then the target fullness is -/// _0.25 of the normal capacity_ and _0.1875 of the entire block_. -/// -/// This implementation implies the bound: -/// - `v ≤ p / k * (s − s')` -/// - or, solving for `p`: `p >= v * k * (s - s')` -/// -/// where `p` is the amount of change over `k` blocks. -/// -/// Hence: -/// - in a fully congested chain: `p >= v * k * (1 - s')`. -/// - in an empty chain: `p >= v * k * (-s')`. -/// -/// For example, when all blocks are full and there are 28800 blocks per day (default in -/// `substrate-node`) and v == 0.00001, s' == 0.1875, we'd have: -/// -/// p >= 0.00001 * 28800 * 0.8125 -/// p >= 0.234 -/// -/// Meaning that fees can change by around ~23% per day, given extreme congestion. -/// -/// More info can be found at: -/// -pub struct TargetedFeeAdjustment(sp_std::marker::PhantomData<(T, S, V, M)>); - -/// Something that can convert the current multiplier to the next one. -pub trait MultiplierUpdate: Convert { - /// Minimum multiplier - fn min() -> Multiplier; - /// Target block saturation level - fn target() -> Perquintill; - /// Variability factor - fn variability() -> Multiplier; -} - -impl MultiplierUpdate for () { - fn min() -> Multiplier { - Default::default() - } - fn target() -> Perquintill { - Default::default() - } - fn variability() -> Multiplier { - Default::default() - } -} - -impl MultiplierUpdate for TargetedFeeAdjustment -where - T: frame_system::Config, - S: Get, - V: Get, - M: Get, -{ - fn min() -> Multiplier { - M::get() - } - fn target() -> Perquintill { - S::get() - } - fn variability() -> Multiplier { - V::get() - } -} - -impl Convert for TargetedFeeAdjustment -where - T: frame_system::Config, - S: Get, - V: Get, - M: Get, -{ - fn convert(previous: Multiplier) -> Multiplier { - // Defensive only. The multiplier in storage should always be at most positive. Nonetheless - // we recover here in case of errors, because any value below this would be stale and can - // never change. - let min_multiplier = M::get(); - let previous = previous.max(min_multiplier); - - let weights = T::BlockWeights::get(); - // the computed ratio is only among the normal class. - let normal_max_weight = - weights.get(DispatchClass::Normal).max_total.unwrap_or(weights.max_block); - let current_block_weight = >::block_weight(); - let normal_block_weight = - current_block_weight.get(DispatchClass::Normal).min(normal_max_weight); - - // TODO: Handle all weight dimensions - let normal_max_weight = normal_max_weight.ref_time(); - let normal_block_weight = normal_block_weight.ref_time(); - - let s = S::get(); - let v = V::get(); - - let target_weight = (s * normal_max_weight) as u128; - let block_weight = normal_block_weight as u128; - - // determines if the first_term is positive - let positive = block_weight >= target_weight; - let diff_abs = block_weight.max(target_weight) - block_weight.min(target_weight); - - // defensive only, a test case assures that the maximum weight diff can fit in Multiplier - // without any saturation. - let diff = Multiplier::saturating_from_rational(diff_abs, normal_max_weight.max(1)); - let diff_squared = diff.saturating_mul(diff); - - let v_squared_2 = v.saturating_mul(v) / Multiplier::saturating_from_integer(2); - - let first_term = v.saturating_mul(diff); - let second_term = v_squared_2.saturating_mul(diff_squared); - - if positive { - let excess = first_term.saturating_add(second_term).saturating_mul(previous); - previous.saturating_add(excess).max(min_multiplier) - } else { - // Defensive-only: first_term > second_term. Safe subtraction. - let negative = first_term.saturating_sub(second_term).saturating_mul(previous); - previous.saturating_sub(negative).max(min_multiplier) - } - } -} - -/// Storage releases of the pallet. -#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -enum Releases { - /// Original version of the pallet. - V1Ancient, - /// One that bumps the usage to FixedU128 from FixedI128. - V2, -} - -impl Default for Releases { - fn default() -> Self { - Releases::V1Ancient - } -} - -#[frame_support::pallet] -pub mod pallet { - use super::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(_); - - #[pallet::config] - pub trait Config: frame_system::Config { - /// Handler for withdrawing, refunding and depositing the transaction fee. - /// Transaction fees are withdrawn before the transaction is executed. - /// After the transaction was executed the transaction weight can be - /// adjusted, depending on the used resources by the transaction. If the - /// transaction weight is lower than expected, parts of the transaction fee - /// might be refunded. In the end the fees can be deposited. - type OnChargeTransaction: OnChargeTransaction; - - /// A fee mulitplier for `Operational` extrinsics to compute "virtual tip" to boost their - /// `priority` - /// - /// This value is multipled by the `final_fee` to obtain a "virtual tip" that is later - /// added to a tip component in regular `priority` calculations. - /// It means that a `Normal` transaction can front-run a similarly-sized `Operational` - /// extrinsic (with no tip), by including a tip value greater than the virtual tip. - /// - /// ```rust,ignore - /// // For `Normal` - /// let priority = priority_calc(tip); - /// - /// // For `Operational` - /// let virtual_tip = (inclusion_fee + tip) * OperationalFeeMultiplier; - /// let priority = priority_calc(tip + virtual_tip); - /// ``` - /// - /// Note that since we use `final_fee` the multiplier applies also to the regular `tip` - /// sent with the transaction. So, not only does the transaction get a priority bump based - /// on the `inclusion_fee`, but we also amplify the impact of tips applied to `Operational` - /// transactions. - #[pallet::constant] - type OperationalFeeMultiplier: Get; - - /// Convert a weight value into a deductible fee based on the currency type. - type WeightToFee: WeightToFee>; - - /// Convert a length value into a deductible fee based on the currency type. - type LengthToFee: WeightToFee>; - - /// Update the multiplier of the next block, based on the previous block's weight. - type FeeMultiplierUpdate: MultiplierUpdate; - } - - #[pallet::type_value] - pub fn NextFeeMultiplierOnEmpty() -> Multiplier { - Multiplier::saturating_from_integer(1) - } - - #[pallet::storage] - #[pallet::getter(fn next_fee_multiplier)] - pub type NextFeeMultiplier = - StorageValue<_, Multiplier, ValueQuery, NextFeeMultiplierOnEmpty>; - - #[pallet::storage] - pub(super) type StorageVersion = StorageValue<_, Releases, ValueQuery>; - - #[pallet::genesis_config] - pub struct GenesisConfig; - - #[cfg(feature = "std")] - impl Default for GenesisConfig { - fn default() -> Self { - Self - } - } - - #[pallet::genesis_build] - impl GenesisBuild for GenesisConfig { - fn build(&self) { - StorageVersion::::put(Releases::V2); - } - } - - #[pallet::hooks] - impl Hooks> for Pallet { - fn on_finalize(_: T::BlockNumber) { - >::mutate(|fm| { - *fm = T::FeeMultiplierUpdate::convert(*fm); - }); - } - - fn integrity_test() { - // given weight == u64, we build multipliers from `diff` of two weight values, which can - // at most be maximum block weight. Make sure that this can fit in a multiplier without - // loss. - assert!( - ::max_value() >= - Multiplier::checked_from_integer::( - T::BlockWeights::get().max_block.ref_time().try_into().unwrap() - ) - .unwrap(), - ); - - let target = T::FeeMultiplierUpdate::target() * - T::BlockWeights::get().get(DispatchClass::Normal).max_total.expect( - "Setting `max_total` for `Normal` dispatch class is not compatible with \ - `transaction-payment-mangata` pallet.", - ); - // add 1 percent; - let addition = target / 100; - if addition == Weight::zero() { - // this is most likely because in a test setup we set everything to (). - return - } - - // We disable this test as our variability is 0, and min multiplier is set to 1. - - // #[cfg(any(feature = "std", test))] - // sp_io::TestExternalities::new_empty().execute_with(|| { - // // This is the minimum value of the multiplier. Make sure that if we collapse to - // // this value, we can recover with a reasonable amount of traffic. For this test we - // // assert that if we collapse to minimum, the trend will be positive with a weight - // // value which is 1% more than the target. - // let min_value = T::FeeMultiplierUpdate::min(); - - // let target = target + addition; - - // >::set_block_consumed_resources(target, 0); - // let next = T::FeeMultiplierUpdate::convert(min_value); - // assert!( - // next > min_value, - // "The minimum bound of the multiplier is too low. When \ - // block saturation is more than target by 1% and multiplier is minimal then \ - // the multiplier doesn't increase." - // ); - // }); - } - } -} - -impl Pallet -where - BalanceOf: FixedPointOperand, -{ - /// Query the data that we know about the fee of a given `call`. - /// - /// This pallet is not and cannot be aware of the internals of a signed extension, for example - /// a tip. It only interprets the extrinsic as some encoded value and accounts for its weight - /// and length, the runtime's extrinsic base weight, and the current fee multiplier. - /// - /// All dispatchables must be annotated with weight and will have some fee info. This function - /// always returns. - pub fn query_info( - unchecked_extrinsic: Extrinsic, - len: u32, - ) -> RuntimeDispatchInfo> - where - T::Call: Dispatchable, - { - // NOTE: we can actually make it understand `ChargeTransactionPayment`, but would be some - // hassle for sure. We have to make it aware of the index of `ChargeTransactionPayment` in - // `Extra`. Alternatively, we could actually execute the tx's per-dispatch and record the - // balance of the sender before and after the pipeline.. but this is way too much hassle for - // a very very little potential gain in the future. - let dispatch_info = ::get_dispatch_info(&unchecked_extrinsic); - - let partial_fee = if unchecked_extrinsic.is_signed().unwrap_or(false) { - Self::compute_fee(len, &dispatch_info, 0u32.into()) - } else { - // Unsigned extrinsics have no partial fee. - 0u32.into() - }; - - let DispatchInfo { weight, class, .. } = dispatch_info; - - RuntimeDispatchInfo { weight, class, partial_fee } - } - - /// Query the detailed fee of a given `call`. - pub fn query_fee_details( - unchecked_extrinsic: Extrinsic, - len: u32, - ) -> FeeDetails> - where - T::Call: Dispatchable, - { - let dispatch_info = ::get_dispatch_info(&unchecked_extrinsic); - - let tip = 0u32.into(); - - if unchecked_extrinsic.is_signed().unwrap_or(false) { - Self::compute_fee_details(len, &dispatch_info, tip) - } else { - // Unsigned extrinsics have no inclusion fee. - FeeDetails { inclusion_fee: None, tip } - } - } - - /// Compute the final fee value for a particular transaction. - pub fn compute_fee(len: u32, info: &DispatchInfoOf, tip: BalanceOf) -> BalanceOf - where - T::Call: Dispatchable, - { - Self::compute_fee_details(len, info, tip).final_fee() - } - - /// Compute the fee details for a particular transaction. - pub fn compute_fee_details( - len: u32, - info: &DispatchInfoOf, - tip: BalanceOf, - ) -> FeeDetails> - where - T::Call: Dispatchable, - { - Self::compute_fee_raw(len, info.weight, tip, info.pays_fee, info.class) - } - - /// Compute the actual post dispatch fee for a particular transaction. - /// - /// Identical to `compute_fee` with the only difference that the post dispatch corrected - /// weight is used for the weight fee calculation. - pub fn compute_actual_fee( - len: u32, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, - tip: BalanceOf, - ) -> BalanceOf - where - T::Call: Dispatchable, - { - Self::compute_actual_fee_details(len, info, post_info, tip).final_fee() - } - - /// Compute the actual post dispatch fee details for a particular transaction. - pub fn compute_actual_fee_details( - len: u32, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, - tip: BalanceOf, - ) -> FeeDetails> - where - T::Call: Dispatchable, - { - Self::compute_fee_raw( - len, - post_info.calc_actual_weight(info), - tip, - post_info.pays_fee(info), - info.class, - ) - } - - fn compute_fee_raw( - len: u32, - weight: Weight, - tip: BalanceOf, - pays_fee: Pays, - class: DispatchClass, - ) -> FeeDetails> { - if pays_fee == Pays::Yes { - // the adjustable part of the fee. - let unadjusted_weight_fee = Self::weight_to_fee(weight); - let multiplier = Self::next_fee_multiplier(); - // final adjusted weight fee. - let adjusted_weight_fee = multiplier.saturating_mul_int(unadjusted_weight_fee); - - // length fee. this is adjusted via `LengthToFee`. - let len_fee = Self::length_to_fee(len); - - let base_fee = Self::weight_to_fee(T::BlockWeights::get().get(class).base_extrinsic); - FeeDetails { - inclusion_fee: Some(InclusionFee { base_fee, len_fee, adjusted_weight_fee }), - tip, - } - } else { - FeeDetails { inclusion_fee: None, tip } - } - } - - fn length_to_fee(length: u32) -> BalanceOf { - T::LengthToFee::weight_to_fee(&Weight::from_ref_time(length as u64)) - } - - fn weight_to_fee(weight: Weight) -> BalanceOf { - // cap the weight to the maximum defined in runtime, otherwise it will be the - // `Bounded` maximum of its data type, which is not desired. - let capped_weight = weight.min(T::BlockWeights::get().max_block); - T::WeightToFee::weight_to_fee(&capped_weight) - } -} - -impl Convert> for Pallet -where - T: Config, - BalanceOf: FixedPointOperand, -{ - /// Compute the fee for the specified weight. - /// - /// This fee is already adjusted by the per block fee adjustment factor and is therefore the - /// share that the weight contributes to the overall fee of a transaction. It is mainly - /// for informational purposes and not used in the actual fee calculation. - fn convert(weight: Weight) -> BalanceOf { - >::get().saturating_mul_int(Self::weight_to_fee(weight)) - } -} - -/// Require the transactor pay for themselves and maybe include a tip to gain additional priority -/// in the queue. -/// -/// # Transaction Validity -/// -/// This extension sets the `priority` field of `TransactionValidity` depending on the amount -/// of tip being paid per weight unit. -/// -/// Operational transactions will receive an additional priority bump, so that they are normally -/// considered before regular transactions. -#[derive(Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] -#[scale_info(skip_type_params(T))] -pub struct ChargeTransactionPayment(#[codec(compact)] BalanceOf); - -impl ChargeTransactionPayment -where - T::Call: Dispatchable, - BalanceOf: Send + Sync + FixedPointOperand, -{ - /// utility constructor. Used only in client/factory code. - pub fn from(fee: BalanceOf) -> Self { - Self(fee) - } - - /// Returns the tip as being choosen by the transaction sender. - pub fn tip(&self) -> BalanceOf { - self.0 - } - - fn withdraw_fee( - &self, - who: &T::AccountId, - call: &T::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result< - ( - BalanceOf, - <::OnChargeTransaction as OnChargeTransaction>::LiquidityInfo, - ), - TransactionValidityError, - > { - let tip = self.0; - let fee = Pallet::::compute_fee(len as u32, info, tip); - - <::OnChargeTransaction as OnChargeTransaction>::withdraw_fee( - who, call, info, fee, tip, - ) - .map(|i| (fee, i)) - } - - /// Get an appropriate priority for a transaction with the given `DispatchInfo`, encoded length - /// and user-included tip. - /// - /// The priority is based on the amount of `tip` the user is willing to pay per unit of either - /// `weight` or `length`, depending which one is more limitting. For `Operational` extrinsics - /// we add a "virtual tip" to the calculations. - /// - /// The formula should simply be `tip / bounded_{weight|length}`, but since we are using - /// integer division, we have no guarantees it's going to give results in any reasonable - /// range (might simply end up being zero). Hence we use a scaling factor: - /// `tip * (max_block_{weight|length} / bounded_{weight|length})`, since given current - /// state of-the-art blockchains, number of per-block transactions is expected to be in a - /// range reasonable enough to not saturate the `Balance` type while multiplying by the tip. - pub fn get_priority( - info: &DispatchInfoOf, - len: usize, - tip: BalanceOf, - final_fee: BalanceOf, - ) -> TransactionPriority { - // Calculate how many such extrinsics we could fit into an empty block and take - // the limitting factor. - let max_block_weight = T::BlockWeights::get().max_block; - let max_block_length = *T::BlockLength::get().max.get(info.class) as u64; - - // TODO: Take into account all dimensions of weight - let max_block_weight = max_block_weight.ref_time(); - let info_weight = info.weight.ref_time(); - - let bounded_weight = info_weight.max(1).min(max_block_weight); - let bounded_length = (len as u64).max(1).min(max_block_length); - - let max_tx_per_block_weight = max_block_weight / bounded_weight; - let max_tx_per_block_length = max_block_length / bounded_length; - // Given our current knowledge this value is going to be in a reasonable range - i.e. - // less than 10^9 (2^30), so multiplying by the `tip` value is unlikely to overflow the - // balance type. We still use saturating ops obviously, but the point is to end up with some - // `priority` distribution instead of having all transactions saturate the priority. - let max_tx_per_block = max_tx_per_block_length - .min(max_tx_per_block_weight) - .saturated_into::>(); - let max_reward = |val: BalanceOf| val.saturating_mul(max_tx_per_block); - - // To distribute no-tip transactions a little bit, we increase the tip value by one. - // This means that given two transactions without a tip, smaller one will be preferred. - let tip = tip.saturating_add(One::one()); - let scaled_tip = max_reward(tip); - - match info.class { - DispatchClass::Normal => { - // For normal class we simply take the `tip_per_weight`. - scaled_tip - }, - DispatchClass::Mandatory => { - // Mandatory extrinsics should be prohibited (e.g. by the [`CheckWeight`] - // extensions), but just to be safe let's return the same priority as `Normal` here. - scaled_tip - }, - DispatchClass::Operational => { - // A "virtual tip" value added to an `Operational` extrinsic. - // This value should be kept high enough to allow `Operational` extrinsics - // to get in even during congestion period, but at the same time low - // enough to prevent a possible spam attack by sending invalid operational - // extrinsics which push away regular transactions from the pool. - let fee_multiplier = T::OperationalFeeMultiplier::get().saturated_into(); - let virtual_tip = final_fee.saturating_mul(fee_multiplier); - let scaled_virtual_tip = max_reward(virtual_tip); - - scaled_tip.saturating_add(scaled_virtual_tip) - }, - } - .saturated_into::() - } -} - -impl sp_std::fmt::Debug for ChargeTransactionPayment { - #[cfg(feature = "std")] - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - write!(f, "ChargeTransactionPayment<{:?}>", self.0) - } - #[cfg(not(feature = "std"))] - fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - Ok(()) - } -} - -impl SignedExtension for ChargeTransactionPayment -where - BalanceOf: Send + Sync + From + FixedPointOperand, - T::Call: Dispatchable, -{ - const IDENTIFIER: &'static str = "ChargeTransactionPayment"; - type AccountId = T::AccountId; - type Call = T::Call; - type AdditionalSigned = (); - type Pre = ( - // tip - BalanceOf, - // who paid the fee - this is an option to allow for a Default impl. - Self::AccountId, - // imbalance resulting from withdrawing the fee - <::OnChargeTransaction as OnChargeTransaction>::LiquidityInfo, - ); - fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> { - Ok(()) - } - - fn validate( - &self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> TransactionValidity { - let (final_fee, _) = self.withdraw_fee(who, call, info, len)?; - let tip = self.0; - Ok(ValidTransaction { - priority: Self::get_priority(info, len, tip, final_fee), - ..Default::default() - }) - } - - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?; - Ok((self.0, who.clone(), imbalance)) - } - - fn post_dispatch( - maybe_pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, - len: usize, - _result: &DispatchResult, - ) -> Result<(), TransactionValidityError> { - if let Some((tip, who, imbalance)) = maybe_pre { - let actual_fee = Pallet::::compute_actual_fee(len as u32, info, post_info, tip); - T::OnChargeTransaction::correct_and_deposit_fee( - &who, info, post_info, actual_fee, tip, imbalance, - )?; - } - Ok(()) - } -} - -impl EstimateCallFee> - for Pallet -where - BalanceOf: FixedPointOperand, - T::Call: Dispatchable, -{ - fn estimate_call_fee(call: &AnyCall, post_info: PostDispatchInfo) -> BalanceOf { - let len = call.encoded_size() as u32; - let info = call.get_dispatch_info(); - Self::compute_actual_fee(len, &info, &post_info, Zero::zero()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate as pallet_transaction_payment_mangata; - - use std::cell::RefCell; - - use codec::Encode; - - use sp_core::H256; - use sp_runtime::{ - testing::{Header, TestXt}, - traits::{BlakeTwo256, IdentityLookup, One}, - transaction_validity::InvalidTransaction, - }; - - use frame_support::{ - assert_noop, assert_ok, parameter_types, - traits::{ConstU32, ConstU64, Currency, Imbalance, OnUnbalanced}, - weights::{ - DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo, Weight, - WeightToFee as WeightToFeeT, - }, - }; - use frame_system as system; - use pallet_balances::Call as BalancesCall; - - type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; - type Block = frame_system::mocking::MockBlock; - - frame_support::construct_runtime!( - pub enum Runtime where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - TransactionPayment: pallet_transaction_payment_mangata::{Pallet, Storage}, - } - ); - - const CALL: &::Call = - &Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); - - thread_local! { - static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(0); - } - - pub struct BlockWeights; - impl Get for BlockWeights { - fn get() -> frame_system::limits::BlockWeights { - frame_system::limits::BlockWeights::builder() - .base_block(0) - .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow()).into(); - }) - .for_class(DispatchClass::non_mandatory(), |weights| { - weights.max_total = 1024.into(); - }) - .build_or_panic() - } - } - - parameter_types! { - pub static WeightToFee: u64 = 1; - pub static TransactionByteFee: u64 = 1; - pub static OperationalFeeMultiplier: u8 = 5; - } - - impl frame_system::Config for Runtime { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = BlockWeights; - type BlockLength = (); - type DbWeight = (); - type Origin = Origin; - type Index = u64; - type BlockNumber = u64; - type Call = Call; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Header = Header; - type Event = Event; - type BlockHashCount = ConstU64<250>; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; - } - - impl pallet_balances::Config for Runtime { - type Balance = u64; - type Event = Event; - type DustRemoval = (); - type ExistentialDeposit = ConstU64<1>; - type AccountStore = System; - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type WeightInfo = (); - } - - impl WeightToFeeT for WeightToFee { - type Balance = u64; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(*weight) - .saturating_mul(WEIGHT_TO_FEE.with(|v| *v.borrow())) - } - } - - impl WeightToFeeT for TransactionByteFee { - type Balance = u64; - - fn weight_to_fee(weight: &Weight) -> Self::Balance { - Self::Balance::saturated_from(*weight) - .saturating_mul(TRANSACTION_BYTE_FEE.with(|v| *v.borrow())) - } - } - - thread_local! { - static TIP_UNBALANCED_AMOUNT: RefCell = RefCell::new(0); - static FEE_UNBALANCED_AMOUNT: RefCell = RefCell::new(0); - } - - pub struct DealWithFees; - impl OnUnbalanced> for DealWithFees { - fn on_unbalanceds( - mut fees_then_tips: impl Iterator>, - ) { - if let Some(fees) = fees_then_tips.next() { - FEE_UNBALANCED_AMOUNT.with(|a| *a.borrow_mut() += fees.peek()); - if let Some(tips) = fees_then_tips.next() { - TIP_UNBALANCED_AMOUNT.with(|a| *a.borrow_mut() += tips.peek()); - } - } - } - } - - impl Config for Runtime { - type OnChargeTransaction = CurrencyAdapter; - type OperationalFeeMultiplier = OperationalFeeMultiplier; - type WeightToFee = WeightToFee; - type LengthToFee = TransactionByteFee; - type FeeMultiplierUpdate = (); - } - - pub struct ExtBuilder { - balance_factor: u64, - base_weight: u64, - byte_fee: u64, - weight_to_fee: u64, - } - - impl Default for ExtBuilder { - fn default() -> Self { - Self { balance_factor: 1, base_weight: 0, byte_fee: 1, weight_to_fee: 1 } - } - } - - impl ExtBuilder { - pub fn base_weight(mut self, base_weight: u64) -> Self { - self.base_weight = base_weight; - self - } - pub fn byte_fee(mut self, byte_fee: u64) -> Self { - self.byte_fee = byte_fee; - self - } - pub fn weight_fee(mut self, weight_to_fee: u64) -> Self { - self.weight_to_fee = weight_to_fee; - self - } - pub fn balance_factor(mut self, factor: u64) -> Self { - self.balance_factor = factor; - self - } - fn set_constants(&self) { - EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow_mut() = self.base_weight); - TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.byte_fee); - WEIGHT_TO_FEE.with(|v| *v.borrow_mut() = self.weight_to_fee); - } - pub fn build(self) -> sp_io::TestExternalities { - self.set_constants(); - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - pallet_balances::GenesisConfig:: { - balances: if self.balance_factor > 0 { - vec![ - (1, 10 * self.balance_factor), - (2, 20 * self.balance_factor), - (3, 30 * self.balance_factor), - (4, 40 * self.balance_factor), - (5, 50 * self.balance_factor), - (6, 60 * self.balance_factor), - ] - } else { - vec![] - }, - } - .assimilate_storage(&mut t) - .unwrap(); - t.into() - } - } - - /// create a transaction info struct from weight. Handy to avoid building the whole struct. - pub fn info_from_weight(w: Weight) -> DispatchInfo { - // pays_fee: Pays::Yes -- class: DispatchClass::Normal - DispatchInfo { weight: w, ..Default::default() } - } - - fn post_info_from_weight(w: Weight) -> PostDispatchInfo { - PostDispatchInfo { actual_weight: Some(w), pays_fee: Default::default() } - } - - fn post_info_from_pays(p: Pays) -> PostDispatchInfo { - PostDispatchInfo { actual_weight: None, pays_fee: p } - } - - fn default_post_info() -> PostDispatchInfo { - PostDispatchInfo { actual_weight: None, pays_fee: Default::default() } - } - - #[test] - fn signed_extension_transaction_payment_work() { - ExtBuilder::default() - .balance_factor(10) - .base_weight(5) - .build() - .execute_with(|| { - let len = 10; - let pre = ChargeTransactionPayment::::from(0) - .pre_dispatch(&1, CALL, &info_from_weight(5), len) - .unwrap(); - assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10); - - assert_ok!(ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info_from_weight(5), - &default_post_info(), - len, - &Ok(()) - )); - assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10); - assert_eq!(FEE_UNBALANCED_AMOUNT.with(|a| a.borrow().clone()), 5 + 5 + 10); - assert_eq!(TIP_UNBALANCED_AMOUNT.with(|a| a.borrow().clone()), 0); - - FEE_UNBALANCED_AMOUNT.with(|a| *a.borrow_mut() = 0); - - let pre = ChargeTransactionPayment::::from(5 /* tipped */) - .pre_dispatch(&2, CALL, &info_from_weight(100), len) - .unwrap(); - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); - - assert_ok!(ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info_from_weight(100), - &post_info_from_weight(50), - len, - &Ok(()) - )); - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 50 - 5); - assert_eq!(FEE_UNBALANCED_AMOUNT.with(|a| a.borrow().clone()), 5 + 10 + 50); - assert_eq!(TIP_UNBALANCED_AMOUNT.with(|a| a.borrow().clone()), 5); - }); - } - - #[test] - fn signed_extension_transaction_payment_multiplied_refund_works() { - ExtBuilder::default() - .balance_factor(10) - .base_weight(5) - .build() - .execute_with(|| { - let len = 10; - >::put(Multiplier::saturating_from_rational(3, 2)); - - let pre = ChargeTransactionPayment::::from(5 /* tipped */) - .pre_dispatch(&2, CALL, &info_from_weight(100), len) - .unwrap(); - // 5 base fee, 10 byte fee, 3/2 * 100 weight fee, 5 tip - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 150 - 5); - - assert_ok!(ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info_from_weight(100), - &post_info_from_weight(50), - len, - &Ok(()) - )); - // 75 (3/2 of the returned 50 units of weight) is refunded - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 75 - 5); - }); - } - - #[test] - fn signed_extension_transaction_payment_is_bounded() { - ExtBuilder::default().balance_factor(1000).byte_fee(0).build().execute_with(|| { - // maximum weight possible - assert_ok!(ChargeTransactionPayment::::from(0).pre_dispatch( - &1, - CALL, - &info_from_weight(Weight::max_value()), - 10 - )); - // fee will be proportional to what is the actual maximum weight in the runtime. - assert_eq!( - Balances::free_balance(&1), - (10000 - ::BlockWeights::get().max_block) as u64 - ); - }); - } - - #[test] - fn signed_extension_allows_free_transactions() { - ExtBuilder::default() - .base_weight(100) - .balance_factor(0) - .build() - .execute_with(|| { - // 1 ain't have a penny. - assert_eq!(Balances::free_balance(1), 0); - - let len = 100; - - // This is a completely free (and thus wholly insecure/DoS-ridden) transaction. - let operational_transaction = DispatchInfo { - weight: 0, - class: DispatchClass::Operational, - pays_fee: Pays::No, - }; - assert_ok!(ChargeTransactionPayment::::from(0).validate( - &1, - CALL, - &operational_transaction, - len - )); - - // like a InsecureFreeNormal - let free_transaction = - DispatchInfo { weight: 0, class: DispatchClass::Normal, pays_fee: Pays::Yes }; - assert_noop!( - ChargeTransactionPayment::::from(0).validate( - &1, - CALL, - &free_transaction, - len - ), - TransactionValidityError::Invalid(InvalidTransaction::Payment), - ); - }); - } - - #[test] - fn signed_ext_length_fee_is_also_updated_per_congestion() { - ExtBuilder::default() - .base_weight(5) - .balance_factor(10) - .build() - .execute_with(|| { - // all fees should be x1.5 - >::put(Multiplier::saturating_from_rational(3, 2)); - let len = 10; - - assert_ok!(ChargeTransactionPayment::::from(10) // tipped - .pre_dispatch(&1, CALL, &info_from_weight(3), len)); - assert_eq!( - Balances::free_balance(1), - 100 // original - - 10 // tip - - 5 // base - - 10 // len - - (3 * 3 / 2) // adjusted weight - ); - }) - } - - #[test] - fn query_info_and_fee_details_works() { - let call = Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); - let origin = 111111; - let extra = (); - let xt = TestXt::new(call.clone(), Some((origin, extra))); - let info = xt.get_dispatch_info(); - let ext = xt.encode(); - let len = ext.len() as u32; - - let unsigned_xt = TestXt::<_, ()>::new(call, None); - let unsigned_xt_info = unsigned_xt.get_dispatch_info(); - - ExtBuilder::default().base_weight(5).weight_fee(2).build().execute_with(|| { - // all fees should be x1.5 - >::put(Multiplier::saturating_from_rational(3, 2)); - - assert_eq!( - TransactionPayment::query_info(xt.clone(), len), - RuntimeDispatchInfo { - weight: info.weight, - class: info.class, - partial_fee: 5 * 2 /* base * weight_fee */ - + len as u64 /* len * 1 */ - + info.weight.min(BlockWeights::get().max_block) as u64 * 2 * 3 / 2 /* weight */ - }, - ); - - assert_eq!( - TransactionPayment::query_info(unsigned_xt.clone(), len), - RuntimeDispatchInfo { - weight: unsigned_xt_info.weight, - class: unsigned_xt_info.class, - partial_fee: 0, - }, - ); - - assert_eq!( - TransactionPayment::query_fee_details(xt, len), - FeeDetails { - inclusion_fee: Some(InclusionFee { - base_fee: 5 * 2, - len_fee: len as u64, - adjusted_weight_fee: info.weight.min(BlockWeights::get().max_block) as u64 * - 2 * 3 / 2 - }), - tip: 0, - }, - ); - - assert_eq!( - TransactionPayment::query_fee_details(unsigned_xt, len), - FeeDetails { inclusion_fee: None, tip: 0 }, - ); - }); - } - - #[test] - fn compute_fee_works_without_multiplier() { - ExtBuilder::default() - .base_weight(100) - .byte_fee(10) - .balance_factor(0) - .build() - .execute_with(|| { - // Next fee multiplier is zero - assert_eq!(>::get(), Multiplier::one()); - - // Tip only, no fees works - let dispatch_info = DispatchInfo { - weight: 0, - class: DispatchClass::Operational, - pays_fee: Pays::No, - }; - assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 10), 10); - // No tip, only base fee works - let dispatch_info = DispatchInfo { - weight: 0, - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 0), 100); - // Tip + base fee works - assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 69), 169); - // Len (byte fee) + base fee works - assert_eq!(Pallet::::compute_fee(42, &dispatch_info, 0), 520); - // Weight fee + base fee works - let dispatch_info = DispatchInfo { - weight: 1000, - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 0), 1100); - }); - } - - #[test] - fn compute_fee_works_with_multiplier() { - ExtBuilder::default() - .base_weight(100) - .byte_fee(10) - .balance_factor(0) - .build() - .execute_with(|| { - // Add a next fee multiplier. Fees will be x3/2. - >::put(Multiplier::saturating_from_rational(3, 2)); - // Base fee is unaffected by multiplier - let dispatch_info = DispatchInfo { - weight: 0, - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 0), 100); - - // Everything works together :) - let dispatch_info = DispatchInfo { - weight: 123, - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - // 123 weight, 456 length, 100 base - assert_eq!( - Pallet::::compute_fee(456, &dispatch_info, 789), - 100 + (3 * 123 / 2) + 4560 + 789, - ); - }); - } - - #[test] - fn compute_fee_works_with_negative_multiplier() { - ExtBuilder::default() - .base_weight(100) - .byte_fee(10) - .balance_factor(0) - .build() - .execute_with(|| { - // Add a next fee multiplier. All fees will be x1/2. - >::put(Multiplier::saturating_from_rational(1, 2)); - - // Base fee is unaffected by multiplier. - let dispatch_info = DispatchInfo { - weight: 0, - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - assert_eq!(Pallet::::compute_fee(0, &dispatch_info, 0), 100); - - // Everything works together. - let dispatch_info = DispatchInfo { - weight: 123, - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - // 123 weight, 456 length, 100 base - assert_eq!( - Pallet::::compute_fee(456, &dispatch_info, 789), - 100 + (123 / 2) + 4560 + 789, - ); - }); - } - - #[test] - fn compute_fee_does_not_overflow() { - ExtBuilder::default() - .base_weight(100) - .byte_fee(10) - .balance_factor(0) - .build() - .execute_with(|| { - // Overflow is handled - let dispatch_info = DispatchInfo { - weight: Weight::max_value(), - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - assert_eq!( - Pallet::::compute_fee(u32::MAX, &dispatch_info, u64::MAX), - u64::MAX - ); - }); - } - - #[test] - fn refund_does_not_recreate_account() { - ExtBuilder::default() - .balance_factor(10) - .base_weight(5) - .build() - .execute_with(|| { - // So events are emitted - System::set_block_number(10); - let len = 10; - let pre = ChargeTransactionPayment::::from(5 /* tipped */) - .pre_dispatch(&2, CALL, &info_from_weight(100), len) - .unwrap(); - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); - - // kill the account between pre and post dispatch - assert_ok!(Balances::transfer(Some(2).into(), 3, Balances::free_balance(2))); - assert_eq!(Balances::free_balance(2), 0); - - assert_ok!(ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info_from_weight(100), - &post_info_from_weight(50), - len, - &Ok(()) - )); - assert_eq!(Balances::free_balance(2), 0); - // Transfer Event - System::assert_has_event(Event::Balances(pallet_balances::Event::Transfer { - from: 2, - to: 3, - amount: 80, - })); - // Killed Event - System::assert_has_event(Event::System(system::Event::KilledAccount { - account: 2, - })); - }); - } - - #[test] - fn actual_weight_higher_than_max_refunds_nothing() { - ExtBuilder::default() - .balance_factor(10) - .base_weight(5) - .build() - .execute_with(|| { - let len = 10; - let pre = ChargeTransactionPayment::::from(5 /* tipped */) - .pre_dispatch(&2, CALL, &info_from_weight(100), len) - .unwrap(); - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); - - assert_ok!(ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info_from_weight(100), - &post_info_from_weight(101), - len, - &Ok(()) - )); - assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 100 - 5); - }); - } - - #[test] - fn zero_transfer_on_free_transaction() { - ExtBuilder::default() - .balance_factor(10) - .base_weight(5) - .build() - .execute_with(|| { - // So events are emitted - System::set_block_number(10); - let len = 10; - let dispatch_info = - DispatchInfo { weight: 100, pays_fee: Pays::No, class: DispatchClass::Normal }; - let user = 69; - let pre = ChargeTransactionPayment::::from(0) - .pre_dispatch(&user, CALL, &dispatch_info, len) - .unwrap(); - assert_eq!(Balances::total_balance(&user), 0); - assert_ok!(ChargeTransactionPayment::::post_dispatch( - Some(pre), - &dispatch_info, - &default_post_info(), - len, - &Ok(()) - )); - assert_eq!(Balances::total_balance(&user), 0); - // No events for such a scenario - assert_eq!(System::events().len(), 0); - }); - } - - #[test] - fn refund_consistent_with_actual_weight() { - ExtBuilder::default() - .balance_factor(10) - .base_weight(7) - .build() - .execute_with(|| { - let info = info_from_weight(100); - let post_info = post_info_from_weight(33); - let prev_balance = Balances::free_balance(2); - let len = 10; - let tip = 5; - - >::put(Multiplier::saturating_from_rational(5, 4)); - - let pre = ChargeTransactionPayment::::from(tip) - .pre_dispatch(&2, CALL, &info, len) - .unwrap(); - - ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info, - &post_info, - len, - &Ok(()), - ) - .unwrap(); - - let refund_based_fee = prev_balance - Balances::free_balance(2); - let actual_fee = - Pallet::::compute_actual_fee(len as u32, &info, &post_info, tip); - - // 33 weight, 10 length, 7 base, 5 tip - assert_eq!(actual_fee, 7 + 10 + (33 * 5 / 4) + 5); - assert_eq!(refund_based_fee, actual_fee); - }); - } - - #[test] - fn should_alter_operational_priority() { - let tip = 5; - let len = 10; - - ExtBuilder::default().balance_factor(100).build().execute_with(|| { - let normal = - DispatchInfo { weight: 100, class: DispatchClass::Normal, pays_fee: Pays::Yes }; - let priority = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &normal, len) - .unwrap() - .priority; - - assert_eq!(priority, 60); - - let priority = ChargeTransactionPayment::(2 * tip) - .validate(&2, CALL, &normal, len) - .unwrap() - .priority; - - assert_eq!(priority, 110); - }); - - ExtBuilder::default().balance_factor(100).build().execute_with(|| { - let op = DispatchInfo { - weight: 100, - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - let priority = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &op, len) - .unwrap() - .priority; - assert_eq!(priority, 5810); - - let priority = ChargeTransactionPayment::(2 * tip) - .validate(&2, CALL, &op, len) - .unwrap() - .priority; - assert_eq!(priority, 6110); - }); - } - - #[test] - fn no_tip_has_some_priority() { - let tip = 0; - let len = 10; - - ExtBuilder::default().balance_factor(100).build().execute_with(|| { - let normal = - DispatchInfo { weight: 100, class: DispatchClass::Normal, pays_fee: Pays::Yes }; - let priority = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &normal, len) - .unwrap() - .priority; - - assert_eq!(priority, 10); - }); - - ExtBuilder::default().balance_factor(100).build().execute_with(|| { - let op = DispatchInfo { - weight: 100, - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - let priority = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &op, len) - .unwrap() - .priority; - assert_eq!(priority, 5510); - }); - } - - #[test] - fn higher_tip_have_higher_priority() { - let get_priorities = |tip: u64| { - let mut priority1 = 0; - let mut priority2 = 0; - let len = 10; - ExtBuilder::default().balance_factor(100).build().execute_with(|| { - let normal = - DispatchInfo { weight: 100, class: DispatchClass::Normal, pays_fee: Pays::Yes }; - priority1 = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &normal, len) - .unwrap() - .priority; - }); - - ExtBuilder::default().balance_factor(100).build().execute_with(|| { - let op = DispatchInfo { - weight: 100, - class: DispatchClass::Operational, - pays_fee: Pays::Yes, - }; - priority2 = ChargeTransactionPayment::(tip) - .validate(&2, CALL, &op, len) - .unwrap() - .priority; - }); - - (priority1, priority2) - }; - - let mut prev_priorities = get_priorities(0); - - for tip in 1..3 { - let priorities = get_priorities(tip); - assert!(prev_priorities.0 < priorities.0); - assert!(prev_priorities.1 < priorities.1); - prev_priorities = priorities; - } - } - - #[test] - fn post_info_can_change_pays_fee() { - ExtBuilder::default() - .balance_factor(10) - .base_weight(7) - .build() - .execute_with(|| { - let info = info_from_weight(100); - let post_info = post_info_from_pays(Pays::No); - let prev_balance = Balances::free_balance(2); - let len = 10; - let tip = 5; - - >::put(Multiplier::saturating_from_rational(5, 4)); - - let pre = ChargeTransactionPayment::::from(tip) - .pre_dispatch(&2, CALL, &info, len) - .unwrap(); - - ChargeTransactionPayment::::post_dispatch( - Some(pre), - &info, - &post_info, - len, - &Ok(()), - ) - .unwrap(); - - let refund_based_fee = prev_balance - Balances::free_balance(2); - let actual_fee = - Pallet::::compute_actual_fee(len as u32, &info, &post_info, tip); - - // Only 5 tip is paid - assert_eq!(actual_fee, 5); - assert_eq!(refund_based_fee, actual_fee); - }); - } -} diff --git a/frame/transaction-payment-mangata/src/payment.rs b/frame/transaction-payment-mangata/src/payment.rs deleted file mode 100644 index 3a5fad0d66a52..0000000000000 --- a/frame/transaction-payment-mangata/src/payment.rs +++ /dev/null @@ -1,148 +0,0 @@ -/// ! Traits and default implementation for paying transaction fees. -use crate::Config; - -use codec::FullCodec; -use sp_runtime::{ - traits::{ - AtLeast32BitUnsigned, DispatchInfoOf, MaybeSerializeDeserialize, PostDispatchInfoOf, - Saturating, Zero, - }, - transaction_validity::InvalidTransaction, -}; -use sp_std::{fmt::Debug, marker::PhantomData}; - -use frame_support::{ - traits::{Currency, ExistenceRequirement, Imbalance, OnUnbalanced, WithdrawReasons}, - unsigned::TransactionValidityError, -}; - -type NegativeImbalanceOf = - ::AccountId>>::NegativeImbalance; - -/// Handle withdrawing, refunding and depositing of transaction fees. -pub trait OnChargeTransaction { - /// The underlying integer type in which fees are calculated. - type Balance: AtLeast32BitUnsigned - + FullCodec - + Copy - + MaybeSerializeDeserialize - + Debug - + Default - + scale_info::TypeInfo; - type LiquidityInfo: Default; - - /// Before the transaction is executed the payment of the transaction fees - /// need to be secured. - /// - /// Note: The `fee` already includes the `tip`. - fn withdraw_fee( - who: &T::AccountId, - call: &T::Call, - dispatch_info: &DispatchInfoOf, - fee: Self::Balance, - tip: Self::Balance, - ) -> Result; - - /// After the transaction was executed the actual fee can be calculated. - /// This function should refund any overpaid fees and optionally deposit - /// the corrected amount. - /// - /// Note: The `fee` already includes the `tip`. - fn correct_and_deposit_fee( - who: &T::AccountId, - dispatch_info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, - corrected_fee: Self::Balance, - tip: Self::Balance, - already_withdrawn: Self::LiquidityInfo, - ) -> Result<(), TransactionValidityError>; -} - -/// Implements the transaction payment for a pallet implementing the `Currency` -/// trait (eg. the pallet_balances) using an unbalance handler (implementing -/// `OnUnbalanced`). -/// -/// The unbalance handler is given 2 unbalanceds in [`OnUnbalanced::on_unbalanceds`]: fee and -/// then tip. -pub struct CurrencyAdapter(PhantomData<(C, OU)>); - -/// Default implementation for a Currency and an OnUnbalanced handler. -/// -/// The unbalance handler is given 2 unbalanceds in [`OnUnbalanced::on_unbalanceds`]: fee and -/// then tip. -impl OnChargeTransaction for CurrencyAdapter -where - T: Config, - C: Currency<::AccountId>, - C::PositiveImbalance: Imbalance< - ::AccountId>>::Balance, - Opposite = C::NegativeImbalance, - >, - C::NegativeImbalance: Imbalance< - ::AccountId>>::Balance, - Opposite = C::PositiveImbalance, - >, - OU: OnUnbalanced>, -{ - type LiquidityInfo = Option>; - type Balance = ::AccountId>>::Balance; - - /// Withdraw the predicted fee from the transaction origin. - /// - /// Note: The `fee` already includes the `tip`. - fn withdraw_fee( - who: &T::AccountId, - _call: &T::Call, - _info: &DispatchInfoOf, - fee: Self::Balance, - tip: Self::Balance, - ) -> Result { - if fee.is_zero() { - return Ok(None) - } - - let withdraw_reason = if tip.is_zero() { - WithdrawReasons::TRANSACTION_PAYMENT - } else { - WithdrawReasons::TRANSACTION_PAYMENT | WithdrawReasons::TIP - }; - - match C::withdraw(who, fee, withdraw_reason, ExistenceRequirement::KeepAlive) { - Ok(imbalance) => Ok(Some(imbalance)), - Err(_) => Err(InvalidTransaction::Payment.into()), - } - } - - /// Hand the fee and the tip over to the `[OnUnbalanced]` implementation. - /// Since the predicted fee might have been too high, parts of the fee may - /// be refunded. - /// - /// Note: The `corrected_fee` already includes the `tip`. - fn correct_and_deposit_fee( - who: &T::AccountId, - _dispatch_info: &DispatchInfoOf, - _post_info: &PostDispatchInfoOf, - corrected_fee: Self::Balance, - tip: Self::Balance, - already_withdrawn: Self::LiquidityInfo, - ) -> Result<(), TransactionValidityError> { - if let Some(paid) = already_withdrawn { - // Calculate how much refund we should return - let refund_amount = paid.peek().saturating_sub(corrected_fee); - // refund to the the account that paid the fees. If this fails, the - // account might have dropped below the existential balance. In - // that case we don't refund anything. - let refund_imbalance = C::deposit_into_existing(who, refund_amount) - .unwrap_or_else(|_| C::PositiveImbalance::zero()); - // merge the imbalance caused by paying the fees and refunding parts of it again. - let adjusted_paid = paid - .offset(refund_imbalance) - .same() - .map_err(|_| TransactionValidityError::Invalid(InvalidTransaction::Payment))?; - // Call someone else to handle the imbalance (fee and tip separately) - let (tip, fee) = adjusted_paid.split(tip); - OU::on_unbalanceds(Some(fee).into_iter().chain(Some(tip))); - } - Ok(()) - } -} diff --git a/frame/transaction-payment-mangata/src/types.rs b/frame/transaction-payment-mangata/src/types.rs deleted file mode 100644 index f866c2069e019..0000000000000 --- a/frame/transaction-payment-mangata/src/types.rs +++ /dev/null @@ -1,168 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Types for transaction-payment-mangata RPC. - -use codec::{Decode, Encode}; -#[cfg(feature = "std")] -use serde::{Deserialize, Serialize}; - -use sp_runtime::traits::{AtLeast32BitUnsigned, Zero}; -use sp_std::prelude::*; - -use frame_support::weights::{DispatchClass, Weight}; - -/// The base fee and adjusted weight and length fees constitute the _inclusion fee_. -#[derive(Encode, Decode, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] -#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] -pub struct InclusionFee { - /// This is the minimum amount a user pays for a transaction. It is declared - /// as a base _weight_ in the runtime and converted to a fee using `WeightToFee`. - pub base_fee: Balance, - /// The length fee, the amount paid for the encoded length (in bytes) of the transaction. - pub len_fee: Balance, - /// - /// - `targeted_fee_adjustment`: This is a multiplier that can tune the final fee based on the - /// congestion of the network. - /// - `weight_fee`: This amount is computed based on the weight of the transaction. Weight - /// accounts for the execution time of a transaction. - /// - /// adjusted_weight_fee = targeted_fee_adjustment * weight_fee - pub adjusted_weight_fee: Balance, -} - -impl InclusionFee { - /// Returns the total of inclusion fee. - /// - /// ```ignore - /// inclusion_fee = base_fee + len_fee + adjusted_weight_fee - /// ``` - pub fn inclusion_fee(&self) -> Balance { - self.base_fee - .saturating_add(self.len_fee) - .saturating_add(self.adjusted_weight_fee) - } -} - -/// The `FeeDetails` is composed of: -/// - (Optional) `inclusion_fee`: Only the `Pays::Yes` transaction can have the inclusion fee. -/// - `tip`: If included in the transaction, the tip will be added on top. Only signed -/// transactions can have a tip. -#[derive(Encode, Decode, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] -#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] -pub struct FeeDetails { - /// The minimum fee for a transaction to be included in a block. - pub inclusion_fee: Option>, - // Do not serialize and deserialize `tip` as we actually can not pass any tip to the RPC. - #[cfg_attr(feature = "std", serde(skip))] - pub tip: Balance, -} - -impl FeeDetails { - /// Returns the final fee. - /// - /// ```ignore - /// final_fee = inclusion_fee + tip; - /// ``` - pub fn final_fee(&self) -> Balance { - self.inclusion_fee - .as_ref() - .map(|i| i.inclusion_fee()) - .unwrap_or_else(|| Zero::zero()) - .saturating_add(self.tip) - } -} - -/// Information related to a dispatchable's class, weight, and fee that can be queried from the -/// runtime. -#[derive(Eq, PartialEq, Encode, Decode, Default)] -#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] -#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))] -#[cfg_attr(feature = "std", serde(bound(serialize = "Balance: std::fmt::Display")))] -#[cfg_attr(feature = "std", serde(bound(deserialize = "Balance: std::str::FromStr")))] -pub struct RuntimeDispatchInfo { - /// Weight of this dispatch. - pub weight: Weight, - /// Class of this dispatch. - pub class: DispatchClass, - /// The inclusion fee of this dispatch. - /// - /// This does not include a tip or anything else that - /// depends on the signature (i.e. depends on a `SignedExtension`). - #[cfg_attr(feature = "std", serde(with = "serde_balance"))] - pub partial_fee: Balance, -} - -#[cfg(feature = "std")] -mod serde_balance { - use serde::{Deserialize, Deserializer, Serializer}; - - pub fn serialize( - t: &T, - serializer: S, - ) -> Result { - serializer.serialize_str(&t.to_string()) - } - - pub fn deserialize<'de, D: Deserializer<'de>, T: std::str::FromStr>( - deserializer: D, - ) -> Result { - let s = String::deserialize(deserializer)?; - s.parse::().map_err(|_| serde::de::Error::custom("Parse from string failed")) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn should_serialize_and_deserialize_properly_with_string() { - let info = RuntimeDispatchInfo { - weight: 5, - class: DispatchClass::Normal, - partial_fee: 1_000_000_u64, - }; - - let json_str = r#"{"weight":5,"class":"normal","partialFee":"1000000"}"#; - - assert_eq!(serde_json::to_string(&info).unwrap(), json_str); - assert_eq!(serde_json::from_str::>(json_str).unwrap(), info); - - // should not panic - serde_json::to_value(&info).unwrap(); - } - - #[test] - fn should_serialize_and_deserialize_properly_large_value() { - let info = RuntimeDispatchInfo { - weight: 5, - class: DispatchClass::Normal, - partial_fee: u128::max_value(), - }; - - let json_str = r#"{"weight":5,"class":"normal","partialFee":"340282366920938463463374607431768211455"}"#; - - assert_eq!(serde_json::to_string(&info).unwrap(), json_str); - assert_eq!(serde_json::from_str::>(json_str).unwrap(), info); - - // should not panic - serde_json::to_value(&info).unwrap(); - } -} diff --git a/frame/transaction-payment/asset-tx-payment/Cargo.toml b/frame/transaction-payment/asset-tx-payment/Cargo.toml index de9772d885529..2c1247cfc557a 100644 --- a/frame/transaction-payment/asset-tx-payment/Cargo.toml +++ b/frame/transaction-payment/asset-tx-payment/Cargo.toml @@ -41,6 +41,7 @@ pallet-balances = { version = "4.0.0-dev", path = "../../balances" } [features] default = ["std"] std = [ + "scale-info/std", "serde", "codec/std", "sp-std/std", diff --git a/frame/transaction-payment/asset-tx-payment/src/lib.rs b/frame/transaction-payment/asset-tx-payment/src/lib.rs index 08561375247ae..e136da8b0bb75 100644 --- a/frame/transaction-payment/asset-tx-payment/src/lib.rs +++ b/frame/transaction-payment/asset-tx-payment/src/lib.rs @@ -39,7 +39,7 @@ use sp_std::prelude::*; use codec::{Decode, Encode}; use frame_support::{ - dispatch::DispatchResult, + dispatch::{DispatchInfo, DispatchResult, PostDispatchInfo}, traits::{ tokens::{ fungibles::{Balanced, CreditOf, Inspect}, @@ -47,7 +47,6 @@ use frame_support::{ }, IsType, }, - weights::{DispatchInfo, PostDispatchInfo}, DefaultNoBound, }; use pallet_transaction_payment::OnChargeTransaction; @@ -114,7 +113,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config + pallet_transaction_payment::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The fungibles instance used to pay for transactions in assets. type Fungibles: Balanced; /// The actual transaction charging logic that charges the fees. @@ -154,7 +153,7 @@ pub struct ChargeAssetTxPayment { impl ChargeAssetTxPayment where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, AssetBalanceOf: Send + Sync + FixedPointOperand, BalanceOf: Send + Sync + FixedPointOperand + IsType>, ChargeAssetIdOf: Send + Sync, @@ -170,8 +169,8 @@ where fn withdraw_fee( &self, who: &T::AccountId, - call: &T::Call, - info: &DispatchInfoOf, + call: &T::RuntimeCall, + info: &DispatchInfoOf, len: usize, ) -> Result<(BalanceOf, InitialPayment), TransactionValidityError> { let fee = pallet_transaction_payment::Pallet::::compute_fee(len as u32, info, self.tip); @@ -211,7 +210,7 @@ impl sp_std::fmt::Debug for ChargeAssetTxPayment { impl SignedExtension for ChargeAssetTxPayment where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, AssetBalanceOf: Send + Sync + FixedPointOperand, BalanceOf: Send + Sync + From + FixedPointOperand + IsType>, ChargeAssetIdOf: Send + Sync, @@ -219,7 +218,7 @@ where { const IDENTIFIER: &'static str = "ChargeAssetTxPayment"; type AccountId = T::AccountId; - type Call = T::Call; + type Call = T::RuntimeCall; type AdditionalSigned = (); type Pre = ( // tip diff --git a/frame/transaction-payment/asset-tx-payment/src/payment.rs b/frame/transaction-payment/asset-tx-payment/src/payment.rs index 394696cc18929..80ff4e40dcffa 100644 --- a/frame/transaction-payment/asset-tx-payment/src/payment.rs +++ b/frame/transaction-payment/asset-tx-payment/src/payment.rs @@ -54,8 +54,8 @@ pub trait OnChargeAssetTransaction { /// Note: The `fee` already includes the `tip`. fn withdraw_fee( who: &T::AccountId, - call: &T::Call, - dispatch_info: &DispatchInfoOf, + call: &T::RuntimeCall, + dispatch_info: &DispatchInfoOf, asset_id: Self::AssetId, fee: Self::Balance, tip: Self::Balance, @@ -68,8 +68,8 @@ pub trait OnChargeAssetTransaction { /// Note: The `fee` already includes the `tip`. fn correct_and_deposit_fee( who: &T::AccountId, - dispatch_info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + dispatch_info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, corrected_fee: Self::Balance, tip: Self::Balance, already_withdrawn: Self::LiquidityInfo, @@ -114,8 +114,8 @@ where /// Note: The `fee` already includes the `tip`. fn withdraw_fee( who: &T::AccountId, - _call: &T::Call, - _info: &DispatchInfoOf, + _call: &T::RuntimeCall, + _info: &DispatchInfoOf, asset_id: Self::AssetId, fee: Self::Balance, _tip: Self::Balance, @@ -142,8 +142,8 @@ where /// Note: The `corrected_fee` already includes the `tip`. fn correct_and_deposit_fee( who: &T::AccountId, - _dispatch_info: &DispatchInfoOf, - _post_info: &PostDispatchInfoOf, + _dispatch_info: &DispatchInfoOf, + _post_info: &PostDispatchInfoOf, corrected_fee: Self::Balance, _tip: Self::Balance, paid: Self::LiquidityInfo, diff --git a/frame/transaction-payment/asset-tx-payment/src/tests.rs b/frame/transaction-payment/asset-tx-payment/src/tests.rs index a17d564d7a334..e775f3aa92990 100644 --- a/frame/transaction-payment/asset-tx-payment/src/tests.rs +++ b/frame/transaction-payment/asset-tx-payment/src/tests.rs @@ -18,10 +18,11 @@ use crate as pallet_asset_tx_payment; use frame_support::{ assert_ok, + dispatch::{DispatchClass, DispatchInfo, PostDispatchInfo}, pallet_prelude::*, parameter_types, traits::{fungibles::Mutate, ConstU32, ConstU64, ConstU8, FindAuthor}, - weights::{DispatchClass, DispatchInfo, PostDispatchInfo, Weight, WeightToFee as WeightToFeeT}, + weights::{Weight, WeightToFee as WeightToFeeT}, ConsensusEngineId, }; use frame_system as system; @@ -33,7 +34,6 @@ use sp_runtime::{ testing::Header, traits::{BlakeTwo256, ConvertInto, IdentityLookup, SaturatedConversion, StaticLookup}, }; -use std::cell::RefCell; type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; type Block = frame_system::mocking::MockBlock; @@ -55,11 +55,11 @@ frame_support::construct_runtime!( } ); -const CALL: &::Call = - &Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); +const CALL: &::RuntimeCall = + &RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 69 }); -thread_local! { - static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(Weight::zero()); +parameter_types! { + static ExtrinsicBaseWeight: Weight = Weight::zero(); } pub struct BlockWeights; @@ -68,10 +68,10 @@ impl Get for BlockWeights { frame_system::limits::BlockWeights::builder() .base_block(Weight::zero()) .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow()).into(); + weights.base_extrinsic = ExtrinsicBaseWeight::get().into(); }) .for_class(DispatchClass::non_mandatory(), |weights| { - weights.max_total = Weight::from_ref_time(1024).into(); + weights.max_total = Weight::from_ref_time(1024).set_proof_size(u64::MAX).into(); }) .build_or_panic() } @@ -87,16 +87,16 @@ impl frame_system::Config for Runtime { type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = AccountId; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -115,7 +115,7 @@ parameter_types! { impl pallet_balances::Config for Runtime { type Balance = Balance; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<10>; type AccountStore = System; @@ -144,7 +144,7 @@ impl WeightToFeeT for TransactionByteFee { } impl pallet_transaction_payment::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter; type WeightToFee = WeightToFee; type LengthToFee = TransactionByteFee; @@ -153,7 +153,7 @@ impl pallet_transaction_payment::Config for Runtime { } impl pallet_assets::Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Balance = Balance; type AssetId = u32; type Currency = Balances; @@ -199,7 +199,7 @@ impl HandleCredit for CreditToBlockAuthor { } impl Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Fungibles = Assets; type OnChargeAssetTransaction = FungiblesAdapter< pallet_assets::BalanceToAssetBalance, @@ -235,7 +235,7 @@ impl ExtBuilder { self } fn set_constants(&self) { - EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow_mut() = self.base_weight); + ExtrinsicBaseWeight::mutate(|v| *v = self.base_weight); TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.byte_fee); WEIGHT_TO_FEE.with(|v| *v.borrow_mut() = self.weight_to_fee); } @@ -338,7 +338,7 @@ fn transaction_payment_in_asset_possible() { let asset_id = 1; let min_balance = 2; assert_ok!(Assets::force_create( - Origin::root(), + RuntimeOrigin::root(), asset_id, 42, /* owner */ true, /* is_sufficient */ @@ -391,7 +391,7 @@ fn transaction_payment_without_fee() { let asset_id = 1; let min_balance = 2; assert_ok!(Assets::force_create( - Origin::root(), + RuntimeOrigin::root(), asset_id, 42, /* owner */ true, /* is_sufficient */ @@ -444,7 +444,7 @@ fn asset_transaction_payment_with_tip_and_refund() { let asset_id = 1; let min_balance = 2; assert_ok!(Assets::force_create( - Origin::root(), + RuntimeOrigin::root(), asset_id, 42, /* owner */ true, /* is_sufficient */ @@ -496,7 +496,7 @@ fn payment_from_account_with_only_assets() { let asset_id = 1; let min_balance = 2; assert_ok!(Assets::force_create( - Origin::root(), + RuntimeOrigin::root(), asset_id, 42, /* owner */ true, /* is_sufficient */ @@ -555,7 +555,7 @@ fn payment_only_with_existing_sufficient_asset() { // create the non-sufficient asset let min_balance = 2; assert_ok!(Assets::force_create( - Origin::root(), + RuntimeOrigin::root(), asset_id, 42, /* owner */ false, /* is_sufficient */ @@ -580,7 +580,7 @@ fn converted_fee_is_never_zero_if_input_fee_is_not() { let asset_id = 1; let min_balance = 1; assert_ok!(Assets::force_create( - Origin::root(), + RuntimeOrigin::root(), asset_id, 42, /* owner */ true, /* is_sufficient */ @@ -645,7 +645,7 @@ fn post_dispatch_fee_is_zero_if_pre_dispatch_fee_is_zero() { let asset_id = 1; let min_balance = 100; assert_ok!(Assets::force_create( - Origin::root(), + RuntimeOrigin::root(), asset_id, 42, /* owner */ true, /* is_sufficient */ @@ -702,7 +702,7 @@ fn post_dispatch_fee_is_zero_if_unsigned_pre_dispatch_fee_is_zero() { let asset_id = 1; let min_balance = 100; assert_ok!(Assets::force_create( - Origin::root(), + RuntimeOrigin::root(), asset_id, 42, /* owner */ true, /* is_sufficient */ diff --git a/frame/transaction-payment/rpc/src/lib.rs b/frame/transaction-payment/rpc/src/lib.rs index 75ec42321ef5e..0c7e26cec0f58 100644 --- a/frame/transaction-payment/rpc/src/lib.rs +++ b/frame/transaction-payment/rpc/src/lib.rs @@ -21,7 +21,7 @@ use std::{convert::TryInto, sync::Arc}; use codec::{Codec, Decode}; use jsonrpsee::{ - core::{async_trait, Error as JsonRpseeError, RpcResult}, + core::{Error as JsonRpseeError, RpcResult}, proc_macros::rpc, types::error::{CallError, ErrorCode, ErrorObject}, }; @@ -81,7 +81,6 @@ impl From for i32 { } } -#[async_trait] impl TransactionPaymentApiServer<::Hash, RuntimeDispatchInfo> for TransactionPayment diff --git a/frame/transaction-payment/src/lib.rs b/frame/transaction-payment/src/lib.rs index 6ffce1776871c..3df3ba34fe9e2 100644 --- a/frame/transaction-payment/src/lib.rs +++ b/frame/transaction-payment/src/lib.rs @@ -63,11 +63,11 @@ use sp_runtime::{ use sp_std::prelude::*; use frame_support::{ - dispatch::DispatchResult, - traits::{EstimateCallFee, Get}, - weights::{ - DispatchClass, DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo, Weight, WeightToFee, + dispatch::{ + DispatchClass, DispatchInfo, DispatchResult, GetDispatchInfo, Pays, PostDispatchInfo, }, + traits::{EstimateCallFee, Get}, + weights::{Weight, WeightToFee}, }; mod payment; @@ -127,12 +127,14 @@ type BalanceOf = <::OnChargeTransaction as OnChargeTransaction -pub struct TargetedFeeAdjustment(sp_std::marker::PhantomData<(T, S, V, M)>); +pub struct TargetedFeeAdjustment(sp_std::marker::PhantomData<(T, S, V, M, X)>); /// Something that can convert the current multiplier to the next one. pub trait MultiplierUpdate: Convert { - /// Minimum multiplier + /// Minimum multiplier. Any outcome of the `convert` function should be at least this. fn min() -> Multiplier; + /// Maximum multiplier. Any outcome of the `convert` function should be less or equal this. + fn max() -> Multiplier; /// Target block saturation level fn target() -> Perquintill; /// Variability factor @@ -143,6 +145,9 @@ impl MultiplierUpdate for () { fn min() -> Multiplier { Default::default() } + fn max() -> Multiplier { + ::max_value() + } fn target() -> Perquintill { Default::default() } @@ -151,16 +156,20 @@ impl MultiplierUpdate for () { } } -impl MultiplierUpdate for TargetedFeeAdjustment +impl MultiplierUpdate for TargetedFeeAdjustment where T: frame_system::Config, S: Get, V: Get, M: Get, + X: Get, { fn min() -> Multiplier { M::get() } + fn max() -> Multiplier { + X::get() + } fn target() -> Perquintill { S::get() } @@ -169,18 +178,20 @@ where } } -impl Convert for TargetedFeeAdjustment +impl Convert for TargetedFeeAdjustment where T: frame_system::Config, S: Get, V: Get, M: Get, + X: Get, { fn convert(previous: Multiplier) -> Multiplier { // Defensive only. The multiplier in storage should always be at most positive. Nonetheless // we recover here in case of errors, because any value below this would be stale and can // never change. let min_multiplier = M::get(); + let max_multiplier = X::get(); let previous = previous.max(min_multiplier); let weights = T::BlockWeights::get(); @@ -217,15 +228,42 @@ where if positive { let excess = first_term.saturating_add(second_term).saturating_mul(previous); - previous.saturating_add(excess).max(min_multiplier) + previous.saturating_add(excess).clamp(min_multiplier, max_multiplier) } else { // Defensive-only: first_term > second_term. Safe subtraction. let negative = first_term.saturating_sub(second_term).saturating_mul(previous); - previous.saturating_sub(negative).max(min_multiplier) + previous.saturating_sub(negative).clamp(min_multiplier, max_multiplier) } } } +/// A struct to make the fee multiplier a constant +pub struct ConstFeeMultiplier>(sp_std::marker::PhantomData); + +impl> MultiplierUpdate for ConstFeeMultiplier { + fn min() -> Multiplier { + M::get() + } + fn max() -> Multiplier { + M::get() + } + fn target() -> Perquintill { + Default::default() + } + fn variability() -> Multiplier { + Default::default() + } +} + +impl Convert for ConstFeeMultiplier +where + M: Get, +{ + fn convert(_previous: Multiplier) -> Multiplier { + Self::min() + } +} + /// Storage releases of the pallet. #[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] enum Releases { @@ -258,7 +296,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// Handler for withdrawing, refunding and depositing the transaction fee. /// Transaction fees are withdrawn before the transaction is executed. @@ -371,7 +409,8 @@ pub mod pallet { // add 1 percent; let addition = target / 100; if addition == Weight::zero() { - // this is most likely because in a test setup we set everything to (). + // this is most likely because in a test setup we set everything to () + // or to `ConstFeeMultiplier`. return } @@ -417,7 +456,7 @@ where len: u32, ) -> RuntimeDispatchInfo> where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { // NOTE: we can actually make it understand `ChargeTransactionPayment`, but would be some // hassle for sure. We have to make it aware of the index of `ChargeTransactionPayment` in @@ -444,7 +483,7 @@ where len: u32, ) -> FeeDetails> where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { let dispatch_info = ::get_dispatch_info(&unchecked_extrinsic); @@ -459,11 +498,11 @@ where } /// Query information of a dispatch class, weight, and fee of a given encoded `Call`. - pub fn query_call_info(call: T::Call, len: u32) -> RuntimeDispatchInfo> + pub fn query_call_info(call: T::RuntimeCall, len: u32) -> RuntimeDispatchInfo> where - T::Call: Dispatchable + GetDispatchInfo, + T::RuntimeCall: Dispatchable + GetDispatchInfo, { - let dispatch_info = ::get_dispatch_info(&call); + let dispatch_info = ::get_dispatch_info(&call); let DispatchInfo { weight, class, .. } = dispatch_info; RuntimeDispatchInfo { @@ -474,20 +513,24 @@ where } /// Query fee details of a given encoded `Call`. - pub fn query_call_fee_details(call: T::Call, len: u32) -> FeeDetails> + pub fn query_call_fee_details(call: T::RuntimeCall, len: u32) -> FeeDetails> where - T::Call: Dispatchable + GetDispatchInfo, + T::RuntimeCall: Dispatchable + GetDispatchInfo, { - let dispatch_info = ::get_dispatch_info(&call); + let dispatch_info = ::get_dispatch_info(&call); let tip = 0u32.into(); Self::compute_fee_details(len, &dispatch_info, tip) } /// Compute the final fee value for a particular transaction. - pub fn compute_fee(len: u32, info: &DispatchInfoOf, tip: BalanceOf) -> BalanceOf + pub fn compute_fee( + len: u32, + info: &DispatchInfoOf, + tip: BalanceOf, + ) -> BalanceOf where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { Self::compute_fee_details(len, info, tip).final_fee() } @@ -495,11 +538,11 @@ where /// Compute the fee details for a particular transaction. pub fn compute_fee_details( len: u32, - info: &DispatchInfoOf, + info: &DispatchInfoOf, tip: BalanceOf, ) -> FeeDetails> where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { Self::compute_fee_raw(len, info.weight, tip, info.pays_fee, info.class) } @@ -510,12 +553,12 @@ where /// weight is used for the weight fee calculation. pub fn compute_actual_fee( len: u32, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, tip: BalanceOf, ) -> BalanceOf where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { Self::compute_actual_fee_details(len, info, post_info, tip).final_fee() } @@ -523,12 +566,12 @@ where /// Compute the actual post dispatch fee details for a particular transaction. pub fn compute_actual_fee_details( len: u32, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, tip: BalanceOf, ) -> FeeDetails> where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { Self::compute_fee_raw( len, @@ -609,7 +652,7 @@ pub struct ChargeTransactionPayment(#[codec(compact)] BalanceOf); impl ChargeTransactionPayment where - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, BalanceOf: Send + Sync + FixedPointOperand, { /// utility constructor. Used only in client/factory code. @@ -617,7 +660,7 @@ where Self(fee) } - /// Returns the tip as being choosen by the transaction sender. + /// Returns the tip as being chosen by the transaction sender. pub fn tip(&self) -> BalanceOf { self.0 } @@ -625,8 +668,8 @@ where fn withdraw_fee( &self, who: &T::AccountId, - call: &T::Call, - info: &DispatchInfoOf, + call: &T::RuntimeCall, + info: &DispatchInfoOf, len: usize, ) -> Result< ( @@ -658,7 +701,7 @@ where /// state of-the-art blockchains, number of per-block transactions is expected to be in a /// range reasonable enough to not saturate the `Balance` type while multiplying by the tip. pub fn get_priority( - info: &DispatchInfoOf, + info: &DispatchInfoOf, len: usize, tip: BalanceOf, final_fee: BalanceOf, @@ -672,8 +715,8 @@ where let max_block_weight = max_block_weight.ref_time(); let info_weight = info.weight.ref_time(); - let bounded_weight = info_weight.max(1).min(max_block_weight); - let bounded_length = (len as u64).max(1).min(max_block_length); + let bounded_weight = info_weight.clamp(1, max_block_weight); + let bounded_length = (len as u64).clamp(1, max_block_length); let max_tx_per_block_weight = max_block_weight / bounded_weight; let max_tx_per_block_length = max_block_length / bounded_length; @@ -732,11 +775,11 @@ impl sp_std::fmt::Debug for ChargeTransactionPayment { impl SignedExtension for ChargeTransactionPayment where BalanceOf: Send + Sync + From + FixedPointOperand, - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { const IDENTIFIER: &'static str = "ChargeTransactionPayment"; type AccountId = T::AccountId; - type Call = T::Call; + type Call = T::RuntimeCall; type AdditionalSigned = (); type Pre = ( // tip @@ -798,7 +841,7 @@ impl EstimateCallFee where BalanceOf: FixedPointOperand, - T::Call: Dispatchable, + T::RuntimeCall: Dispatchable, { fn estimate_call_fee(call: &AnyCall, post_info: PostDispatchInfo) -> BalanceOf { let len = call.encoded_size() as u32; @@ -812,8 +855,6 @@ mod tests { use super::*; use crate as pallet_transaction_payment; - use std::cell::RefCell; - use codec::Encode; use sp_core::H256; @@ -824,12 +865,11 @@ mod tests { }; use frame_support::{ - assert_noop, assert_ok, parameter_types, + assert_noop, assert_ok, + dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo}, + parameter_types, traits::{ConstU32, ConstU64, Currency, GenesisBuild, Imbalance, OnUnbalanced}, - weights::{ - DispatchClass, DispatchInfo, GetDispatchInfo, PostDispatchInfo, Weight, - WeightToFee as WeightToFeeT, - }, + weights::{Weight, WeightToFee as WeightToFeeT}, }; use frame_system as system; use pallet_balances::Call as BalancesCall; @@ -849,11 +889,11 @@ mod tests { } ); - const CALL: &::Call = - &Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); + const CALL: &::RuntimeCall = + &RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 69 }); - thread_local! { - static EXTRINSIC_BASE_WEIGHT: RefCell = RefCell::new(Weight::zero()); + parameter_types! { + static ExtrinsicBaseWeight: Weight = Weight::zero(); } pub struct BlockWeights; @@ -862,10 +902,10 @@ mod tests { frame_system::limits::BlockWeights::builder() .base_block(Weight::zero()) .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow()).into(); + weights.base_extrinsic = ExtrinsicBaseWeight::get().into(); }) .for_class(DispatchClass::non_mandatory(), |weights| { - weights.max_total = Weight::from_ref_time(1024).into(); + weights.max_total = Weight::from_ref_time(1024).set_proof_size(u64::MAX).into(); }) .build_or_panic() } @@ -882,16 +922,16 @@ mod tests { type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -906,7 +946,7 @@ mod tests { impl pallet_balances::Config for Runtime { type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -934,9 +974,9 @@ mod tests { } } - thread_local! { - static TIP_UNBALANCED_AMOUNT: RefCell = RefCell::new(0); - static FEE_UNBALANCED_AMOUNT: RefCell = RefCell::new(0); + parameter_types! { + static TipUnbalancedAmount: u64 = 0; + static FeeUnbalancedAmount: u64 = 0; } pub struct DealWithFees; @@ -945,16 +985,16 @@ mod tests { mut fees_then_tips: impl Iterator>, ) { if let Some(fees) = fees_then_tips.next() { - FEE_UNBALANCED_AMOUNT.with(|a| *a.borrow_mut() += fees.peek()); + FeeUnbalancedAmount::mutate(|a| *a += fees.peek()); if let Some(tips) = fees_then_tips.next() { - TIP_UNBALANCED_AMOUNT.with(|a| *a.borrow_mut() += tips.peek()); + TipUnbalancedAmount::mutate(|a| *a += tips.peek()); } } } } impl Config for Runtime { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter; type OperationalFeeMultiplier = OperationalFeeMultiplier; type WeightToFee = WeightToFee; @@ -1004,7 +1044,7 @@ mod tests { self } fn set_constants(&self) { - EXTRINSIC_BASE_WEIGHT.with(|v| *v.borrow_mut() = self.base_weight); + ExtrinsicBaseWeight::mutate(|v| *v = self.base_weight); TRANSACTION_BYTE_FEE.with(|v| *v.borrow_mut() = self.byte_fee); WEIGHT_TO_FEE.with(|v| *v.borrow_mut() = self.weight_to_fee); } @@ -1076,10 +1116,10 @@ mod tests { &Ok(()) )); assert_eq!(Balances::free_balance(1), 100 - 5 - 5 - 10); - assert_eq!(FEE_UNBALANCED_AMOUNT.with(|a| *a.borrow()), 5 + 5 + 10); - assert_eq!(TIP_UNBALANCED_AMOUNT.with(|a| *a.borrow()), 0); + assert_eq!(FeeUnbalancedAmount::get(), 5 + 5 + 10); + assert_eq!(TipUnbalancedAmount::get(), 0); - FEE_UNBALANCED_AMOUNT.with(|a| *a.borrow_mut() = 0); + FeeUnbalancedAmount::mutate(|a| *a = 0); let pre = ChargeTransactionPayment::::from(5 /* tipped */) .pre_dispatch(&2, CALL, &info_from_weight(Weight::from_ref_time(100)), len) @@ -1094,8 +1134,8 @@ mod tests { &Ok(()) )); assert_eq!(Balances::free_balance(2), 200 - 5 - 10 - 50 - 5); - assert_eq!(FEE_UNBALANCED_AMOUNT.with(|a| *a.borrow()), 5 + 10 + 50); - assert_eq!(TIP_UNBALANCED_AMOUNT.with(|a| *a.borrow()), 5); + assert_eq!(FeeUnbalancedAmount::get(), 5 + 10 + 50); + assert_eq!(TipUnbalancedAmount::get(), 5); }); } @@ -1217,7 +1257,7 @@ mod tests { #[test] fn query_info_and_fee_details_works() { - let call = Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); + let call = RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 69 }); let origin = 111111; let extra = (); let xt = TestXt::new(call.clone(), Some((origin, extra))); @@ -1280,7 +1320,7 @@ mod tests { #[test] fn query_call_info_and_fee_details_works() { - let call = Call::Balances(BalancesCall::transfer { dest: 2, value: 69 }); + let call = RuntimeCall::Balances(BalancesCall::transfer { dest: 2, value: 69 }); let info = call.get_dispatch_info(); let encoded_call = call.encode(); let len = encoded_call.len() as u32; @@ -1474,13 +1514,11 @@ mod tests { )); assert_eq!(Balances::free_balance(2), 0); // Transfer Event - System::assert_has_event(Event::Balances(pallet_balances::Event::Transfer { - from: 2, - to: 3, - amount: 80, - })); + System::assert_has_event(RuntimeEvent::Balances( + pallet_balances::Event::Transfer { from: 2, to: 3, amount: 80 }, + )); // Killed Event - System::assert_has_event(Event::System(system::Event::KilledAccount { + System::assert_has_event(RuntimeEvent::System(system::Event::KilledAccount { account: 2, })); }); @@ -1539,7 +1577,7 @@ mod tests { )); assert_eq!(Balances::total_balance(&user), 0); // TransactionFeePaid Event - System::assert_has_event(Event::TransactionPayment( + System::assert_has_event(RuntimeEvent::TransactionPayment( pallet_transaction_payment::Event::TransactionFeePaid { who: user, actual_fee: 0, diff --git a/frame/transaction-payment/src/payment.rs b/frame/transaction-payment/src/payment.rs index 3a5fad0d66a52..ebc9c5c5afd62 100644 --- a/frame/transaction-payment/src/payment.rs +++ b/frame/transaction-payment/src/payment.rs @@ -37,8 +37,8 @@ pub trait OnChargeTransaction { /// Note: The `fee` already includes the `tip`. fn withdraw_fee( who: &T::AccountId, - call: &T::Call, - dispatch_info: &DispatchInfoOf, + call: &T::RuntimeCall, + dispatch_info: &DispatchInfoOf, fee: Self::Balance, tip: Self::Balance, ) -> Result; @@ -50,8 +50,8 @@ pub trait OnChargeTransaction { /// Note: The `fee` already includes the `tip`. fn correct_and_deposit_fee( who: &T::AccountId, - dispatch_info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + dispatch_info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, corrected_fee: Self::Balance, tip: Self::Balance, already_withdrawn: Self::LiquidityInfo, @@ -92,8 +92,8 @@ where /// Note: The `fee` already includes the `tip`. fn withdraw_fee( who: &T::AccountId, - _call: &T::Call, - _info: &DispatchInfoOf, + _call: &T::RuntimeCall, + _info: &DispatchInfoOf, fee: Self::Balance, tip: Self::Balance, ) -> Result { @@ -120,8 +120,8 @@ where /// Note: The `corrected_fee` already includes the `tip`. fn correct_and_deposit_fee( who: &T::AccountId, - _dispatch_info: &DispatchInfoOf, - _post_info: &PostDispatchInfoOf, + _dispatch_info: &DispatchInfoOf, + _post_info: &PostDispatchInfoOf, corrected_fee: Self::Balance, tip: Self::Balance, already_withdrawn: Self::LiquidityInfo, diff --git a/frame/transaction-payment/src/types.rs b/frame/transaction-payment/src/types.rs index 5e915d62a26d4..fff41ef6937f5 100644 --- a/frame/transaction-payment/src/types.rs +++ b/frame/transaction-payment/src/types.rs @@ -24,7 +24,7 @@ use serde::{Deserialize, Serialize}; use sp_runtime::traits::{AtLeast32BitUnsigned, Zero}; use sp_std::prelude::*; -use frame_support::weights::{DispatchClass, Weight}; +use frame_support::{dispatch::DispatchClass, weights::Weight}; /// The base fee and adjusted weight and length fees constitute the _inclusion fee_. #[derive(Encode, Decode, Clone, Eq, PartialEq)] @@ -140,7 +140,8 @@ mod tests { partial_fee: 1_000_000_u64, }; - let json_str = r#"{"weight":{"ref_time":5},"class":"normal","partialFee":"1000000"}"#; + let json_str = + r#"{"weight":{"ref_time":5,"proof_size":0},"class":"normal","partialFee":"1000000"}"#; assert_eq!(serde_json::to_string(&info).unwrap(), json_str); assert_eq!(serde_json::from_str::>(json_str).unwrap(), info); @@ -157,7 +158,7 @@ mod tests { partial_fee: u128::max_value(), }; - let json_str = r#"{"weight":{"ref_time":5},"class":"normal","partialFee":"340282366920938463463374607431768211455"}"#; + let json_str = r#"{"weight":{"ref_time":5,"proof_size":0},"class":"normal","partialFee":"340282366920938463463374607431768211455"}"#; assert_eq!(serde_json::to_string(&info).unwrap(), json_str); assert_eq!(serde_json::from_str::>(json_str).unwrap(), info); diff --git a/frame/transaction-storage/Cargo.toml b/frame/transaction-storage/Cargo.toml index 8ed34cb50a652..a6e177af1853d 100644 --- a/frame/transaction-storage/Cargo.toml +++ b/frame/transaction-storage/Cargo.toml @@ -13,8 +13,8 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +array-bytes = { version = "4.1", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } -hex-literal = { version = "0.3.4", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", optional = true } frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" } @@ -34,8 +34,10 @@ sp-transaction-storage-proof = { version = "4.0.0-dev", default-features = true, [features] default = ["std"] -runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks", "hex-literal"] +runtime-benchmarks = ["array-bytes", "frame-benchmarking/runtime-benchmarks"] std = [ + "log/std", + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/transaction-storage/src/benchmarking.rs b/frame/transaction-storage/src/benchmarking.rs index def0cd3d44f48..c7fbd00fb565d 100644 --- a/frame/transaction-storage/src/benchmarking.rs +++ b/frame/transaction-storage/src/benchmarking.rs @@ -40,62 +40,75 @@ use crate::Pallet as TransactionStorage; // build_proof(hash.as_slice(), transactions).unwrap().encode() // ``` // while hardforcing target chunk key in `build_proof` to [22, 21, 1, 0]. -const PROOF: &[u8] = &hex_literal::hex!( - " - 0104000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - 000000000000000000000000000000014cd0780ffff80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe8 - 7d12a3662c4c0080e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb - 13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2 - f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f - 1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f - 3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a47 - 8e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cf - f93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e31 - 6a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f - 53cff93f3ca2f3dfe87d12a3662c4c80e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4c8 - 0e316a478e2f1fcb13cf22fd0b2dbb54a6f53cff93f3ca2f3dfe87d12a3662c4cbd05807777809a5d7a720ce5f9d9a012 - fbf25e92c30e732dadba8f312b05e02976313ea64d9f807d43bcbf8a3dc2f6b9e957d129e610c06d411e11743062dc1cf - 3ac289390ae4c8008592aa2d915f52941036afbe72bac4ebe7ce186c4ddc53f118e0ddd4decd8cc809a5d7a720ce5f9d9 - a012fbf25e92c30e732dadba8f312b05e02976313ea64d9f807d43bcbf8a3dc2f6b9e957d129e610c06d411e11743062d - c1cf3ac289390ae4c00809a5d7a720ce5f9d9a012fbf25e92c30e732dadba8f312b05e02976313ea64d9f807d43bcbf8a - 3dc2f6b9e957d129e610c06d411e11743062dc1cf3ac289390ae4c8008592aa2d915f52941036afbe72bac4ebe7ce186c - 4ddc53f118e0ddd4decd8cc809a5d7a720ce5f9d9a012fbf25e92c30e732dadba8f312b05e02976313ea64d9f807d43bc - bf8a3dc2f6b9e957d129e610c06d411e11743062dc1cf3ac289390ae4c8008592aa2d915f52941036afbe72bac4ebe7ce - 186c4ddc53f118e0ddd4decd8cccd0780ffff8081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb0 - 3bdb31008081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253 - 515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa139 - 8e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5 - f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3a - a1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2b - a8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f32 - 2d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa - 9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f0 - 2f322d3aa1398e0cb03bdb318081b825bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb318081b82 - 5bfa9b2ba8f5f253515e7db09eb1ad3d4f02f322d3aa1398e0cb03bdb31cd0780ffff80b4f23ac50c8e67d9b280f2b31a - 5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd1885 - 44c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2 - b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd - 188544c5f9b0080b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9 - b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84 - d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e - 67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977aca - ac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac5 - 0c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b89297 - 7acaac84d530bd188544c5f9b80b4f23ac50c8e67d9b280f2b31a5707d52b892977acaac84d530bd188544c5f9b104401 - 0000 -" -); +const PROOF: &str = "\ + 0104000000000000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000000000000000\ + 00000000000000000000000000000000000000000000000000000000000014cd0780ffff8030\ + 2eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba0080302eb0a6d2\ + f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15\ + f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1\ + 004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e304\ + 8cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697\ + eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a\ + 30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302e\ + b0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b\ + 834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e7\ + 29d1c1004657e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c10046\ + 57e3048cf206d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf2\ + 06d697eeb153f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb1\ + 53f61a30ba80302eb0a6d2f63b834d15f1e729d1c1004657e3048cf206d697eeb153f61a30ba\ + bd058077778010fd81bc1359802f0b871aeb95e4410a8ec92b93af10ea767a2027cf4734e8de\ + 808da338e6b722f7bf2051901bd5bccee5e71d5cf6b1faff338ad7120b0256c28380221ce17f\ + 19117affa96e077905fe48a99723a065969c638593b7d9ab57b538438010fd81bc1359802f0b\ + 871aeb95e4410a8ec92b93af10ea767a2027cf4734e8de808da338e6b722f7bf2051901bd5bc\ + cee5e71d5cf6b1faff338ad7120b0256c283008010fd81bc1359802f0b871aeb95e4410a8ec9\ + 2b93af10ea767a2027cf4734e8de808da338e6b722f7bf2051901bd5bccee5e71d5cf6b1faff\ + 338ad7120b0256c28380221ce17f19117affa96e077905fe48a99723a065969c638593b7d9ab\ + 57b538438010fd81bc1359802f0b871aeb95e4410a8ec92b93af10ea767a2027cf4734e8de80\ + 8da338e6b722f7bf2051901bd5bccee5e71d5cf6b1faff338ad7120b0256c28380221ce17f19\ + 117affa96e077905fe48a99723a065969c638593b7d9ab57b53843cd0780ffff804509f59593\ + fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c00804509f59593fd47b1a9\ + 7189127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba6\ + 5a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0\ + 346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f983\ + 6e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf89\ + 1a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c8045\ + 09f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd\ + 47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189\ + 127ba65a5649cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a56\ + 49cfb0346637f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb03466\ + 37f9836e155eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e15\ + 5eaf891a939c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a93\ + 9c804509f59593fd47b1a97189127ba65a5649cfb0346637f9836e155eaf891a939ccd0780ff\ + ff8078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e\ + 776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea\ + 05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f\ + 015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d\ + 06feafa3610fc44a5b2ef543cb81008078916e776c64ccea05e958559f015c082d9d06feafa3\ + 610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b\ + 2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb81\ + 8078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e77\ + 6c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05\ + e958559f015c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f01\ + 5c082d9d06feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06\ + feafa3610fc44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610f\ + c44a5b2ef543cb818078916e776c64ccea05e958559f015c082d9d06feafa3610fc44a5b2ef5\ + 43cb811044010000\ +"; +fn proof() -> Vec { + array_bytes::hex2bytes_unchecked(PROOF) +} type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; -fn assert_last_event(generic_event: ::Event) { +fn assert_last_event(generic_event: ::RuntimeEvent) { let events = System::::events(); - let system_event: ::Event = generic_event.into(); + let system_event: ::RuntimeEvent = generic_event.into(); let EventRecord { event, .. } = &events[events.len() - 1]; assert_eq!(event, &system_event); } @@ -147,8 +160,8 @@ benchmarks! { )?; } run_to_block::(StoragePeriod::::get() + T::BlockNumber::one()); - let mut encoded_proof = PROOF; - let proof = TransactionStorageProof::decode(&mut encoded_proof).unwrap(); + let encoded_proof = proof(); + let proof = TransactionStorageProof::decode(&mut &*encoded_proof).unwrap(); }: check_proof(RawOrigin::None, proof) verify { assert_last_event::(Event::ProofChecked.into()); diff --git a/frame/transaction-storage/src/lib.rs b/frame/transaction-storage/src/lib.rs index 681cd29af8222..07144c5617113 100644 --- a/frame/transaction-storage/src/lib.rs +++ b/frame/transaction-storage/src/lib.rs @@ -92,10 +92,10 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// A dispatchable call. - type Call: Parameter - + Dispatchable + type RuntimeCall: Parameter + + Dispatchable + GetDispatchInfo + From>; /// The currency trait. diff --git a/frame/transaction-storage/src/mock.rs b/frame/transaction-storage/src/mock.rs index 771387ef705be..8764b16c31d8d 100644 --- a/frame/transaction-storage/src/mock.rs +++ b/frame/transaction-storage/src/mock.rs @@ -51,8 +51,8 @@ impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -60,7 +60,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); @@ -77,7 +77,7 @@ impl frame_system::Config for Test { impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); @@ -87,8 +87,8 @@ impl pallet_balances::Config for Test { } impl pallet_transaction_storage::Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type Currency = Balances; type FeeDestination = (); type WeightInfo = (); @@ -116,7 +116,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { pub fn run_to_block(n: u64, f: impl Fn() -> Option) { while System::block_number() < n { if let Some(proof) = f() { - TransactionStorage::check_proof(Origin::none(), proof).unwrap(); + TransactionStorage::check_proof(RuntimeOrigin::none(), proof).unwrap(); } TransactionStorage::on_finalize(System::block_number()); System::on_finalize(System::block_number()); diff --git a/frame/transaction-storage/src/tests.rs b/frame/transaction-storage/src/tests.rs index 4f5ce1c4b654d..01b71a7851ac3 100644 --- a/frame/transaction-storage/src/tests.rs +++ b/frame/transaction-storage/src/tests.rs @@ -95,7 +95,7 @@ fn checks_proof() { let proof = build_proof(parent_hash.as_ref(), vec![vec![0u8; MAX_DATA_SIZE as usize]]).unwrap(); assert_noop!( - TransactionStorage::::check_proof(Origin::none(), proof,), + TransactionStorage::::check_proof(RuntimeOrigin::none(), proof,), Error::::UnexpectedProof, ); run_to_block(11, || None); @@ -103,13 +103,13 @@ fn checks_proof() { let invalid_proof = build_proof(parent_hash.as_ref(), vec![vec![0u8; 1000]]).unwrap(); assert_noop!( - TransactionStorage::::check_proof(Origin::none(), invalid_proof,), + TransactionStorage::::check_proof(RuntimeOrigin::none(), invalid_proof,), Error::::InvalidProof, ); let proof = build_proof(parent_hash.as_ref(), vec![vec![0u8; MAX_DATA_SIZE as usize]]).unwrap(); - assert_ok!(TransactionStorage::::check_proof(Origin::none(), proof)); + assert_ok!(TransactionStorage::::check_proof(RuntimeOrigin::none(), proof)); }); } diff --git a/frame/treasury/Cargo.toml b/frame/treasury/Cargo.toml index 5c84eda3604c9..6419c258571c2 100644 --- a/frame/treasury/Cargo.toml +++ b/frame/treasury/Cargo.toml @@ -34,6 +34,7 @@ sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/treasury/src/benchmarking.rs b/frame/treasury/src/benchmarking.rs index b2b670d86f07c..d718a5fb89521 100644 --- a/frame/treasury/src/benchmarking.rs +++ b/frame/treasury/src/benchmarking.rs @@ -61,7 +61,7 @@ fn setup_pot_account, I: 'static>() { let _ = T::Currency::make_free_balance_be(&pot_account, value); } -fn assert_last_event, I: 'static>(generic_event: >::Event) { +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } @@ -100,7 +100,7 @@ benchmarks_instance_pallet! { )?; let proposal_id = Treasury::::proposal_count() - 1; let reject_origin = T::RejectOrigin::successful_origin(); - }: _(reject_origin, proposal_id) + }: _(reject_origin, proposal_id) approve_proposal { let p in 0 .. T::MaxApprovals::get() - 1; @@ -113,7 +113,7 @@ benchmarks_instance_pallet! { )?; let proposal_id = Treasury::::proposal_count() - 1; let approve_origin = T::ApproveOrigin::successful_origin(); - }: _(approve_origin, proposal_id) + }: _(approve_origin, proposal_id) remove_approval { let (caller, value, beneficiary_lookup) = setup_proposal::(SEED); @@ -125,7 +125,7 @@ benchmarks_instance_pallet! { let proposal_id = Treasury::::proposal_count() - 1; Treasury::::approve_proposal(RawOrigin::Root.into(), proposal_id)?; let reject_origin = T::RejectOrigin::successful_origin(); - }: _(reject_origin, proposal_id) + }: _(reject_origin, proposal_id) on_initialize_proposals { let p in 0 .. T::MaxApprovals::get(); diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index cd4d9cf036abe..21b4d2b769c8b 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -149,13 +149,14 @@ pub mod pallet { type Currency: Currency + ReservableCurrency; /// Origin from which approvals must come. - type ApproveOrigin: EnsureOrigin; + type ApproveOrigin: EnsureOrigin; /// Origin from which rejections must come. - type RejectOrigin: EnsureOrigin; + type RejectOrigin: EnsureOrigin; /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Handler for the unbalanced decrease when slashing for a rejected proposal or bounty. type OnSlash: OnUnbalanced>; @@ -203,7 +204,7 @@ pub mod pallet { /// The origin required for approving spends from the treasury outside of the proposal /// process. The `Success` value is the maximum amount that this origin is allowed to /// spend at a time. - type SpendOrigin: EnsureOrigin>; + type SpendOrigin: EnsureOrigin>; } /// Number of proposals that have been made. diff --git a/frame/treasury/src/tests.rs b/frame/treasury/src/tests.rs index bec96daf576e3..9cfe147ec4ce4 100644 --- a/frame/treasury/src/tests.rs +++ b/frame/treasury/src/tests.rs @@ -19,8 +19,6 @@ #![cfg(test)] -use std::cell::RefCell; - use sp_core::H256; use sp_runtime::{ testing::Header, @@ -62,16 +60,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u128; // u64 is not enough to hold bytes used to generate bounty account type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -88,36 +86,33 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); } -thread_local! { - static TEN_TO_FOURTEEN: RefCell> = RefCell::new(vec![10,11,12,13,14]); -} parameter_types! { pub const ProposalBond: Permill = Permill::from_percent(5); pub const Burn: Permill = Permill::from_percent(50); pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry"); } pub struct TestSpendOrigin; -impl frame_support::traits::EnsureOrigin for TestSpendOrigin { +impl frame_support::traits::EnsureOrigin for TestSpendOrigin { type Success = u64; - fn try_origin(o: Origin) -> Result { - Result::, Origin>::from(o).and_then(|o| match o { + fn try_origin(o: RuntimeOrigin) -> Result { + Result::, RuntimeOrigin>::from(o).and_then(|o| match o { frame_system::RawOrigin::Root => Ok(u64::max_value()), frame_system::RawOrigin::Signed(10) => Ok(5), frame_system::RawOrigin::Signed(11) => Ok(10), frame_system::RawOrigin::Signed(12) => Ok(20), frame_system::RawOrigin::Signed(13) => Ok(50), - r => Err(Origin::from(r)), + r => Err(RuntimeOrigin::from(r)), }) } #[cfg(feature = "runtime-benchmarks")] - fn try_successful_origin() -> Result { - Ok(Origin::root()) + fn try_successful_origin() -> Result { + Ok(RuntimeOrigin::root()) } } @@ -126,7 +121,7 @@ impl Config for Test { type Currency = pallet_balances::Pallet; type ApproveOrigin = frame_system::EnsureRoot; type RejectOrigin = frame_system::EnsureRoot; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type OnSlash = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ConstU64<1>; @@ -163,21 +158,21 @@ fn genesis_config_works() { #[test] fn spend_origin_permissioning_works() { new_test_ext().execute_with(|| { - assert_noop!(Treasury::spend(Origin::signed(1), 1, 1), BadOrigin); + assert_noop!(Treasury::spend(RuntimeOrigin::signed(1), 1, 1), BadOrigin); assert_noop!( - Treasury::spend(Origin::signed(10), 6, 1), + Treasury::spend(RuntimeOrigin::signed(10), 6, 1), Error::::InsufficientPermission ); assert_noop!( - Treasury::spend(Origin::signed(11), 11, 1), + Treasury::spend(RuntimeOrigin::signed(11), 11, 1), Error::::InsufficientPermission ); assert_noop!( - Treasury::spend(Origin::signed(12), 21, 1), + Treasury::spend(RuntimeOrigin::signed(12), 21, 1), Error::::InsufficientPermission ); assert_noop!( - Treasury::spend(Origin::signed(13), 51, 1), + Treasury::spend(RuntimeOrigin::signed(13), 51, 1), Error::::InsufficientPermission ); }); @@ -188,13 +183,13 @@ fn spend_origin_works() { new_test_ext().execute_with(|| { // Check that accumulate works when we have Some value in Dummy already. Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::spend(Origin::signed(10), 5, 6)); - assert_ok!(Treasury::spend(Origin::signed(10), 5, 6)); - assert_ok!(Treasury::spend(Origin::signed(10), 5, 6)); - assert_ok!(Treasury::spend(Origin::signed(10), 5, 6)); - assert_ok!(Treasury::spend(Origin::signed(11), 10, 6)); - assert_ok!(Treasury::spend(Origin::signed(12), 20, 6)); - assert_ok!(Treasury::spend(Origin::signed(13), 50, 6)); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), 5, 6)); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), 5, 6)); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), 5, 6)); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(10), 5, 6)); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(11), 10, 6)); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(12), 20, 6)); + assert_ok!(Treasury::spend(RuntimeOrigin::signed(13), 50, 6)); >::on_initialize(1); assert_eq!(Balances::free_balance(6), 0); @@ -217,7 +212,7 @@ fn minting_works() { #[test] fn spend_proposal_takes_min_deposit() { new_test_ext().execute_with(|| { - assert_ok!(Treasury::propose_spend(Origin::signed(0), 1, 3)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 1, 3)); assert_eq!(Balances::free_balance(0), 99); assert_eq!(Balances::reserved_balance(0), 1); }); @@ -226,7 +221,7 @@ fn spend_proposal_takes_min_deposit() { #[test] fn spend_proposal_takes_proportional_deposit() { new_test_ext().execute_with(|| { - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); assert_eq!(Balances::free_balance(0), 95); assert_eq!(Balances::reserved_balance(0), 5); }); @@ -236,7 +231,7 @@ fn spend_proposal_takes_proportional_deposit() { fn spend_proposal_fails_when_proposer_poor() { new_test_ext().execute_with(|| { assert_noop!( - Treasury::propose_spend(Origin::signed(2), 100, 3), + Treasury::propose_spend(RuntimeOrigin::signed(2), 100, 3), Error::::InsufficientProposersBalance, ); }); @@ -247,8 +242,8 @@ fn accepted_spend_proposal_ignored_outside_spend_period() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(1); assert_eq!(Balances::free_balance(3), 0); @@ -274,8 +269,8 @@ fn rejected_spend_proposal_ignored_on_spend_period() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::reject_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::reject_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(2); assert_eq!(Balances::free_balance(3), 0); @@ -288,23 +283,32 @@ fn reject_already_rejected_spend_proposal_fails() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::reject_proposal(Origin::root(), 0)); - assert_noop!(Treasury::reject_proposal(Origin::root(), 0), Error::::InvalidIndex); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::reject_proposal(RuntimeOrigin::root(), 0)); + assert_noop!( + Treasury::reject_proposal(RuntimeOrigin::root(), 0), + Error::::InvalidIndex + ); }); } #[test] fn reject_non_existent_spend_proposal_fails() { new_test_ext().execute_with(|| { - assert_noop!(Treasury::reject_proposal(Origin::root(), 0), Error::::InvalidIndex); + assert_noop!( + Treasury::reject_proposal(RuntimeOrigin::root(), 0), + Error::::InvalidIndex + ); }); } #[test] fn accept_non_existent_spend_proposal_fails() { new_test_ext().execute_with(|| { - assert_noop!(Treasury::approve_proposal(Origin::root(), 0), Error::::InvalidIndex); + assert_noop!( + Treasury::approve_proposal(RuntimeOrigin::root(), 0), + Error::::InvalidIndex + ); }); } @@ -313,9 +317,12 @@ fn accept_already_rejected_spend_proposal_fails() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::reject_proposal(Origin::root(), 0)); - assert_noop!(Treasury::approve_proposal(Origin::root(), 0), Error::::InvalidIndex); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::reject_proposal(RuntimeOrigin::root(), 0)); + assert_noop!( + Treasury::approve_proposal(RuntimeOrigin::root(), 0), + Error::::InvalidIndex + ); }); } @@ -325,8 +332,8 @@ fn accepted_spend_proposal_enacted_on_spend_period() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(2); assert_eq!(Balances::free_balance(3), 100); @@ -340,8 +347,8 @@ fn pot_underflow_should_not_diminish() { Balances::make_free_balance_be(&Treasury::account_id(), 101); assert_eq!(Treasury::pot(), 100); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 150, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 150, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(2); assert_eq!(Treasury::pot(), 100); // Pot hasn't changed @@ -362,14 +369,14 @@ fn treasury_account_doesnt_get_deleted() { assert_eq!(Treasury::pot(), 100); let treasury_balance = Balances::free_balance(&Treasury::account_id()); - assert_ok!(Treasury::propose_spend(Origin::signed(0), treasury_balance, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), treasury_balance, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); >::on_initialize(2); assert_eq!(Treasury::pot(), 100); // Pot hasn't changed - assert_ok!(Treasury::propose_spend(Origin::signed(0), Treasury::pot(), 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 1)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), Treasury::pot(), 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 1)); >::on_initialize(4); assert_eq!(Treasury::pot(), 0); // Pot is emptied @@ -392,10 +399,10 @@ fn inexistent_account_works() { assert_eq!(Balances::free_balance(Treasury::account_id()), 0); // Account does not exist assert_eq!(Treasury::pot(), 0); // Pot is empty - assert_ok!(Treasury::propose_spend(Origin::signed(0), 99, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 1, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 1)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 99, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 1, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 1)); >::on_initialize(2); assert_eq!(Treasury::pot(), 0); // Pot hasn't changed assert_eq!(Balances::free_balance(3), 0); // Balance of `3` hasn't changed @@ -437,14 +444,14 @@ fn max_approvals_limited() { Balances::make_free_balance_be(&0, u64::MAX); for _ in 0..::MaxApprovals::get() { - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); } // One too many will fail - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); assert_noop!( - Treasury::approve_proposal(Origin::root(), 0), + Treasury::approve_proposal(RuntimeOrigin::root(), 0), Error::::TooManyApprovals ); }); @@ -455,14 +462,14 @@ fn remove_already_removed_approval_fails() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&Treasury::account_id(), 101); - assert_ok!(Treasury::propose_spend(Origin::signed(0), 100, 3)); - assert_ok!(Treasury::approve_proposal(Origin::root(), 0)); + assert_ok!(Treasury::propose_spend(RuntimeOrigin::signed(0), 100, 3)); + assert_ok!(Treasury::approve_proposal(RuntimeOrigin::root(), 0)); assert_eq!(Treasury::approvals(), vec![0]); - assert_ok!(Treasury::remove_approval(Origin::root(), 0)); + assert_ok!(Treasury::remove_approval(RuntimeOrigin::root(), 0)); assert_eq!(Treasury::approvals(), vec![]); assert_noop!( - Treasury::remove_approval(Origin::root(), 0), + Treasury::remove_approval(RuntimeOrigin::root(), 0), Error::::ProposalNotApproved ); }); diff --git a/frame/uniques/Cargo.toml b/frame/uniques/Cargo.toml index 19b0790947f84..31aa608ff84b6 100644 --- a/frame/uniques/Cargo.toml +++ b/frame/uniques/Cargo.toml @@ -32,7 +32,7 @@ sp-std = { version = "4.0.0", path = "../../primitives/std" } default = ["std"] std = [ "codec/std", - "frame-benchmarking/std", + "frame-benchmarking?/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/frame/uniques/src/benchmarking.rs b/frame/uniques/src/benchmarking.rs index 3e3148b5b5fc2..ab34558f95eb3 100644 --- a/frame/uniques/src/benchmarking.rs +++ b/frame/uniques/src/benchmarking.rs @@ -126,9 +126,9 @@ fn add_item_attribute, I: 'static>( (key, caller, caller_lookup) } -fn assert_last_event, I: 'static>(generic_event: >::Event) { +fn assert_last_event, I: 'static>(generic_event: >::RuntimeEvent) { let events = frame_system::Pallet::::events(); - let system_event: ::Event = generic_event.into(); + let system_event: ::RuntimeEvent = generic_event.into(); // compare to the last event record let frame_system::EventRecord { event, .. } = &events[events.len() - 1]; assert_eq!(event, &system_event); diff --git a/frame/uniques/src/lib.rs b/frame/uniques/src/lib.rs index 5f322e6268bfb..d519eedd2787f 100644 --- a/frame/uniques/src/lib.rs +++ b/frame/uniques/src/lib.rs @@ -91,7 +91,8 @@ pub mod pallet { /// The module configuration trait. pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Identifier for the collection of item. type CollectionId: Member + Parameter + MaxEncodedLen + Copy; @@ -104,12 +105,12 @@ pub mod pallet { /// The origin which may forcibly create or destroy an item or otherwise alter privileged /// attributes. - type ForceOrigin: EnsureOrigin; + type ForceOrigin: EnsureOrigin; /// Standard collection creation is only allowed if the origin attempting it and the /// collection are in this set. type CreateOrigin: EnsureOriginWithArg< - Self::Origin, + Self::RuntimeOrigin, Self::CollectionId, Success = Self::AccountId, >; diff --git a/frame/uniques/src/mock.rs b/frame/uniques/src/mock.rs index ff7b791de4950..d6ed5cc5cc23e 100644 --- a/frame/uniques/src/mock.rs +++ b/frame/uniques/src/mock.rs @@ -49,8 +49,8 @@ impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); type BlockLength = (); - type Origin = Origin; - type Call = Call; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -58,7 +58,7 @@ impl frame_system::Config for Test { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type DbWeight = (); type Version = (); @@ -75,7 +75,7 @@ impl frame_system::Config for Test { impl pallet_balances::Config for Test { type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); @@ -85,7 +85,7 @@ impl pallet_balances::Config for Test { } impl Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type CollectionId = u32; type ItemId = u32; type Currency = Balances; diff --git a/frame/uniques/src/tests.rs b/frame/uniques/src/tests.rs index 85d1bec574cf0..7af54ddbb188c 100644 --- a/frame/uniques/src/tests.rs +++ b/frame/uniques/src/tests.rs @@ -74,7 +74,7 @@ fn events() -> Vec> { let result = System::events() .into_iter() .map(|r| r.event) - .filter_map(|e| if let mock::Event::Uniques(inner) = e { Some(inner) } else { None }) + .filter_map(|e| if let mock::RuntimeEvent::Uniques(inner) = e { Some(inner) } else { None }) .collect::>(); System::reset_events(); @@ -92,14 +92,14 @@ fn basic_setup_works() { #[test] fn basic_minting_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); assert_eq!(collections(), vec![(1, 0)]); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 1)); assert_eq!(items(), vec![(1, 0, 42)]); - assert_ok!(Uniques::force_create(Origin::root(), 1, 2, true)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 1, 2, true)); assert_eq!(collections(), vec![(1, 0), (2, 1)]); - assert_ok!(Uniques::mint(Origin::signed(2), 1, 69, 1)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(2), 1, 69, 1)); assert_eq!(items(), vec![(1, 0, 42), (1, 1, 69)]); }); } @@ -108,32 +108,37 @@ fn basic_minting_should_work() { fn lifecycle_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); + assert_ok!(Uniques::create(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(Balances::reserved_balance(&1), 2); assert_eq!(collections(), vec![(1, 0)]); - assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0, 0], false)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::signed(1), + 0, + bvec![0, 0], + false + )); assert_eq!(Balances::reserved_balance(&1), 5); assert!(CollectionMetadataOf::::contains_key(0)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 10)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 10)); assert_eq!(Balances::reserved_balance(&1), 6); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 69, 20)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 69, 20)); assert_eq!(Balances::reserved_balance(&1), 7); assert_eq!(items(), vec![(10, 0, 42), (20, 0, 69)]); assert_eq!(Collection::::get(0).unwrap().items, 2); assert_eq!(Collection::::get(0).unwrap().item_metadatas, 0); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![42, 42], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![42, 42], false)); assert_eq!(Balances::reserved_balance(&1), 10); assert!(ItemMetadataOf::::contains_key(0, 42)); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 69, bvec![69, 69], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 69, bvec![69, 69], false)); assert_eq!(Balances::reserved_balance(&1), 13); assert!(ItemMetadataOf::::contains_key(0, 69)); let w = Collection::::get(0).unwrap().destroy_witness(); assert_eq!(w.items, 2); assert_eq!(w.item_metadatas, 2); - assert_ok!(Uniques::destroy(Origin::signed(1), 0, w)); + assert_ok!(Uniques::destroy(RuntimeOrigin::signed(1), 0, w)); assert_eq!(Balances::reserved_balance(&1), 0); assert!(!Collection::::contains_key(0)); @@ -151,19 +156,19 @@ fn lifecycle_should_work() { fn destroy_with_bad_witness_should_not_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); + assert_ok!(Uniques::create(RuntimeOrigin::signed(1), 0, 1)); let w = Collection::::get(0).unwrap().destroy_witness(); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); - assert_noop!(Uniques::destroy(Origin::signed(1), 0, w), Error::::BadWitness); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 1)); + assert_noop!(Uniques::destroy(RuntimeOrigin::signed(1), 0, w), Error::::BadWitness); }); } #[test] fn mint_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 1)); assert_eq!(Uniques::owner(0, 42).unwrap(), 1); assert_eq!(collections(), vec![(1, 0)]); assert_eq!(items(), vec![(1, 0, 42)]); @@ -173,54 +178,66 @@ fn mint_should_work() { #[test] fn transfer_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 2)); - assert_ok!(Uniques::transfer(Origin::signed(2), 0, 42, 3)); + assert_ok!(Uniques::transfer(RuntimeOrigin::signed(2), 0, 42, 3)); assert_eq!(items(), vec![(3, 0, 42)]); - assert_noop!(Uniques::transfer(Origin::signed(2), 0, 42, 4), Error::::NoPermission); + assert_noop!( + Uniques::transfer(RuntimeOrigin::signed(2), 0, 42, 4), + Error::::NoPermission + ); - assert_ok!(Uniques::approve_transfer(Origin::signed(3), 0, 42, 2)); - assert_ok!(Uniques::transfer(Origin::signed(2), 0, 42, 4)); + assert_ok!(Uniques::approve_transfer(RuntimeOrigin::signed(3), 0, 42, 2)); + assert_ok!(Uniques::transfer(RuntimeOrigin::signed(2), 0, 42, 4)); }); } #[test] fn freezing_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); - assert_ok!(Uniques::freeze(Origin::signed(1), 0, 42)); - assert_noop!(Uniques::transfer(Origin::signed(1), 0, 42, 2), Error::::Frozen); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 1)); + assert_ok!(Uniques::freeze(RuntimeOrigin::signed(1), 0, 42)); + assert_noop!(Uniques::transfer(RuntimeOrigin::signed(1), 0, 42, 2), Error::::Frozen); - assert_ok!(Uniques::thaw(Origin::signed(1), 0, 42)); - assert_ok!(Uniques::freeze_collection(Origin::signed(1), 0)); - assert_noop!(Uniques::transfer(Origin::signed(1), 0, 42, 2), Error::::Frozen); + assert_ok!(Uniques::thaw(RuntimeOrigin::signed(1), 0, 42)); + assert_ok!(Uniques::freeze_collection(RuntimeOrigin::signed(1), 0)); + assert_noop!(Uniques::transfer(RuntimeOrigin::signed(1), 0, 42, 2), Error::::Frozen); - assert_ok!(Uniques::thaw_collection(Origin::signed(1), 0)); - assert_ok!(Uniques::transfer(Origin::signed(1), 0, 42, 2)); + assert_ok!(Uniques::thaw_collection(RuntimeOrigin::signed(1), 0)); + assert_ok!(Uniques::transfer(RuntimeOrigin::signed(1), 0, 42, 2)); }); } #[test] fn origin_guards_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 1)); Balances::make_free_balance_be(&2, 100); - assert_ok!(Uniques::set_accept_ownership(Origin::signed(2), Some(0))); + assert_ok!(Uniques::set_accept_ownership(RuntimeOrigin::signed(2), Some(0))); + assert_noop!( + Uniques::transfer_ownership(RuntimeOrigin::signed(2), 0, 2), + Error::::NoPermission + ); + assert_noop!( + Uniques::set_team(RuntimeOrigin::signed(2), 0, 2, 2, 2), + Error::::NoPermission + ); + assert_noop!(Uniques::freeze(RuntimeOrigin::signed(2), 0, 42), Error::::NoPermission); + assert_noop!(Uniques::thaw(RuntimeOrigin::signed(2), 0, 42), Error::::NoPermission); + assert_noop!( + Uniques::mint(RuntimeOrigin::signed(2), 0, 69, 2), + Error::::NoPermission + ); assert_noop!( - Uniques::transfer_ownership(Origin::signed(2), 0, 2), + Uniques::burn(RuntimeOrigin::signed(2), 0, 42, None), Error::::NoPermission ); - assert_noop!(Uniques::set_team(Origin::signed(2), 0, 2, 2, 2), Error::::NoPermission); - assert_noop!(Uniques::freeze(Origin::signed(2), 0, 42), Error::::NoPermission); - assert_noop!(Uniques::thaw(Origin::signed(2), 0, 42), Error::::NoPermission); - assert_noop!(Uniques::mint(Origin::signed(2), 0, 69, 2), Error::::NoPermission); - assert_noop!(Uniques::burn(Origin::signed(2), 0, 42, None), Error::::NoPermission); let w = Collection::::get(0).unwrap().destroy_witness(); - assert_noop!(Uniques::destroy(Origin::signed(2), 0, w), Error::::NoPermission); + assert_noop!(Uniques::destroy(RuntimeOrigin::signed(2), 0, w), Error::::NoPermission); }); } @@ -230,14 +247,14 @@ fn transfer_owner_should_work() { Balances::make_free_balance_be(&1, 100); Balances::make_free_balance_be(&2, 100); Balances::make_free_balance_be(&3, 100); - assert_ok!(Uniques::create(Origin::signed(1), 0, 1)); + assert_ok!(Uniques::create(RuntimeOrigin::signed(1), 0, 1)); assert_eq!(collections(), vec![(1, 0)]); assert_noop!( - Uniques::transfer_ownership(Origin::signed(1), 0, 2), + Uniques::transfer_ownership(RuntimeOrigin::signed(1), 0, 2), Error::::Unaccepted ); - assert_ok!(Uniques::set_accept_ownership(Origin::signed(2), Some(0))); - assert_ok!(Uniques::transfer_ownership(Origin::signed(1), 0, 2)); + assert_ok!(Uniques::set_accept_ownership(RuntimeOrigin::signed(2), Some(0))); + assert_ok!(Uniques::transfer_ownership(RuntimeOrigin::signed(1), 0, 2)); assert_eq!(collections(), vec![(2, 0)]); assert_eq!(Balances::total_balance(&1), 98); @@ -245,18 +262,23 @@ fn transfer_owner_should_work() { assert_eq!(Balances::reserved_balance(&1), 0); assert_eq!(Balances::reserved_balance(&2), 2); - assert_ok!(Uniques::set_accept_ownership(Origin::signed(1), Some(0))); + assert_ok!(Uniques::set_accept_ownership(RuntimeOrigin::signed(1), Some(0))); assert_noop!( - Uniques::transfer_ownership(Origin::signed(1), 0, 1), + Uniques::transfer_ownership(RuntimeOrigin::signed(1), 0, 1), Error::::NoPermission ); // Mint and set metadata now and make sure that deposit gets transferred back. - assert_ok!(Uniques::set_collection_metadata(Origin::signed(2), 0, bvec![0u8; 20], false)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); - assert_ok!(Uniques::set_metadata(Origin::signed(2), 0, 42, bvec![0u8; 20], false)); - assert_ok!(Uniques::set_accept_ownership(Origin::signed(3), Some(0))); - assert_ok!(Uniques::transfer_ownership(Origin::signed(2), 0, 3)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::signed(2), + 0, + bvec![0u8; 20], + false + )); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 1)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(2), 0, 42, bvec![0u8; 20], false)); + assert_ok!(Uniques::set_accept_ownership(RuntimeOrigin::signed(3), Some(0))); + assert_ok!(Uniques::transfer_ownership(RuntimeOrigin::signed(2), 0, 3)); assert_eq!(collections(), vec![(3, 0)]); assert_eq!(Balances::total_balance(&2), 57); assert_eq!(Balances::total_balance(&3), 145); @@ -266,7 +288,7 @@ fn transfer_owner_should_work() { // 2's acceptence from before is reset when it became owner, so it cannot be transfered // without a fresh acceptance. assert_noop!( - Uniques::transfer_ownership(Origin::signed(3), 0, 2), + Uniques::transfer_ownership(RuntimeOrigin::signed(3), 0, 2), Error::::Unaccepted ); }); @@ -275,14 +297,14 @@ fn transfer_owner_should_work() { #[test] fn set_team_should_work() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::set_team(Origin::signed(1), 0, 2, 3, 4)); - - assert_ok!(Uniques::mint(Origin::signed(2), 0, 42, 2)); - assert_ok!(Uniques::freeze(Origin::signed(4), 0, 42)); - assert_ok!(Uniques::thaw(Origin::signed(3), 0, 42)); - assert_ok!(Uniques::transfer(Origin::signed(3), 0, 42, 3)); - assert_ok!(Uniques::burn(Origin::signed(3), 0, 42, None)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::set_team(RuntimeOrigin::signed(1), 0, 2, 3, 4)); + + assert_ok!(Uniques::mint(RuntimeOrigin::signed(2), 0, 42, 2)); + assert_ok!(Uniques::freeze(RuntimeOrigin::signed(4), 0, 42)); + assert_ok!(Uniques::thaw(RuntimeOrigin::signed(3), 0, 42)); + assert_ok!(Uniques::transfer(RuntimeOrigin::signed(3), 0, 42, 3)); + assert_ok!(Uniques::burn(RuntimeOrigin::signed(3), 0, 42, None)); }); } @@ -291,59 +313,89 @@ fn set_collection_metadata_should_work() { new_test_ext().execute_with(|| { // Cannot add metadata to unknown item assert_noop!( - Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 20], false), + Uniques::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 20], false), Error::::UnknownCollection, ); - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, false)); // Cannot add metadata to unowned item assert_noop!( - Uniques::set_collection_metadata(Origin::signed(2), 0, bvec![0u8; 20], false), + Uniques::set_collection_metadata(RuntimeOrigin::signed(2), 0, bvec![0u8; 20], false), Error::::NoPermission, ); // Successfully add metadata and take deposit Balances::make_free_balance_be(&1, 30); - assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 20], false)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::signed(1), + 0, + bvec![0u8; 20], + false + )); assert_eq!(Balances::free_balance(&1), 9); assert!(CollectionMetadataOf::::contains_key(0)); // Force origin works, too. - assert_ok!(Uniques::set_collection_metadata(Origin::root(), 0, bvec![0u8; 18], false)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::root(), + 0, + bvec![0u8; 18], + false + )); // Update deposit - assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 15], false)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::signed(1), + 0, + bvec![0u8; 15], + false + )); assert_eq!(Balances::free_balance(&1), 14); - assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 25], false)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::signed(1), + 0, + bvec![0u8; 25], + false + )); assert_eq!(Balances::free_balance(&1), 4); // Cannot over-reserve assert_noop!( - Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 40], false), + Uniques::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 40], false), BalancesError::::InsufficientBalance, ); // Can't set or clear metadata once frozen - assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 15], true)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::signed(1), + 0, + bvec![0u8; 15], + true + )); assert_noop!( - Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0u8; 15], false), + Uniques::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![0u8; 15], false), Error::::Frozen, ); assert_noop!( - Uniques::clear_collection_metadata(Origin::signed(1), 0), + Uniques::clear_collection_metadata(RuntimeOrigin::signed(1), 0), Error::::Frozen ); // Clear Metadata - assert_ok!(Uniques::set_collection_metadata(Origin::root(), 0, bvec![0u8; 15], false)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::root(), + 0, + bvec![0u8; 15], + false + )); assert_noop!( - Uniques::clear_collection_metadata(Origin::signed(2), 0), + Uniques::clear_collection_metadata(RuntimeOrigin::signed(2), 0), Error::::NoPermission ); assert_noop!( - Uniques::clear_collection_metadata(Origin::signed(1), 1), + Uniques::clear_collection_metadata(RuntimeOrigin::signed(1), 1), Error::::UnknownCollection ); - assert_ok!(Uniques::clear_collection_metadata(Origin::signed(1), 0)); + assert_ok!(Uniques::clear_collection_metadata(RuntimeOrigin::signed(1), 0)); assert!(!CollectionMetadataOf::::contains_key(0)); }); } @@ -354,53 +406,56 @@ fn set_item_metadata_should_work() { Balances::make_free_balance_be(&1, 30); // Cannot add metadata to unknown item - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, false)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 1)); // Cannot add metadata to unowned item assert_noop!( - Uniques::set_metadata(Origin::signed(2), 0, 42, bvec![0u8; 20], false), + Uniques::set_metadata(RuntimeOrigin::signed(2), 0, 42, bvec![0u8; 20], false), Error::::NoPermission, ); // Successfully add metadata and take deposit - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 20], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 20], false)); assert_eq!(Balances::free_balance(&1), 8); assert!(ItemMetadataOf::::contains_key(0, 42)); // Force origin works, too. - assert_ok!(Uniques::set_metadata(Origin::root(), 0, 42, bvec![0u8; 18], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::root(), 0, 42, bvec![0u8; 18], false)); // Update deposit - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 15], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 15], false)); assert_eq!(Balances::free_balance(&1), 13); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 25], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 25], false)); assert_eq!(Balances::free_balance(&1), 3); // Cannot over-reserve assert_noop!( - Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 40], false), + Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 40], false), BalancesError::::InsufficientBalance, ); // Can't set or clear metadata once frozen - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 15], true)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 15], true)); assert_noop!( - Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0u8; 15], false), + Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0u8; 15], false), Error::::Frozen, ); - assert_noop!(Uniques::clear_metadata(Origin::signed(1), 0, 42), Error::::Frozen); + assert_noop!( + Uniques::clear_metadata(RuntimeOrigin::signed(1), 0, 42), + Error::::Frozen + ); // Clear Metadata - assert_ok!(Uniques::set_metadata(Origin::root(), 0, 42, bvec![0u8; 15], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::root(), 0, 42, bvec![0u8; 15], false)); assert_noop!( - Uniques::clear_metadata(Origin::signed(2), 0, 42), + Uniques::clear_metadata(RuntimeOrigin::signed(2), 0, 42), Error::::NoPermission ); assert_noop!( - Uniques::clear_metadata(Origin::signed(1), 1, 42), + Uniques::clear_metadata(RuntimeOrigin::signed(1), 1, 42), Error::::UnknownCollection ); - assert_ok!(Uniques::clear_metadata(Origin::signed(1), 0, 42)); + assert_ok!(Uniques::clear_metadata(RuntimeOrigin::signed(1), 0, 42)); assert!(!ItemMetadataOf::::contains_key(0, 42)); }); } @@ -410,11 +465,23 @@ fn set_attribute_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, false)); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, None, bvec![0], bvec![0])); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![0], bvec![0])); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![1], bvec![0])); + assert_ok!(Uniques::set_attribute(RuntimeOrigin::signed(1), 0, None, bvec![0], bvec![0])); + assert_ok!(Uniques::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(0), + bvec![0], + bvec![0] + )); + assert_ok!(Uniques::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(0), + bvec![1], + bvec![0] + )); assert_eq!( attributes(0), vec![ @@ -425,7 +492,13 @@ fn set_attribute_should_work() { ); assert_eq!(Balances::reserved_balance(1), 9); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, None, bvec![0], bvec![0; 10])); + assert_ok!(Uniques::set_attribute( + RuntimeOrigin::signed(1), + 0, + None, + bvec![0], + bvec![0; 10] + )); assert_eq!( attributes(0), vec![ @@ -436,7 +509,7 @@ fn set_attribute_should_work() { ); assert_eq!(Balances::reserved_balance(1), 18); - assert_ok!(Uniques::clear_attribute(Origin::signed(1), 0, Some(0), bvec![1])); + assert_ok!(Uniques::clear_attribute(RuntimeOrigin::signed(1), 0, Some(0), bvec![1])); assert_eq!( attributes(0), vec![(None, bvec![0], bvec![0; 10]), (Some(0), bvec![0], bvec![0]),] @@ -444,7 +517,7 @@ fn set_attribute_should_work() { assert_eq!(Balances::reserved_balance(1), 15); let w = Collection::::get(0).unwrap().destroy_witness(); - assert_ok!(Uniques::destroy(Origin::signed(1), 0, w)); + assert_ok!(Uniques::destroy(RuntimeOrigin::signed(1), 0, w)); assert_eq!(attributes(0), vec![]); assert_eq!(Balances::reserved_balance(1), 0); }); @@ -455,11 +528,23 @@ fn set_attribute_should_respect_freeze() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, false)); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, None, bvec![0], bvec![0])); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![0], bvec![0])); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(1), bvec![0], bvec![0])); + assert_ok!(Uniques::set_attribute(RuntimeOrigin::signed(1), 0, None, bvec![0], bvec![0])); + assert_ok!(Uniques::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(0), + bvec![0], + bvec![0] + )); + assert_ok!(Uniques::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(1), + bvec![0], + bvec![0] + )); assert_eq!( attributes(0), vec![ @@ -470,15 +555,33 @@ fn set_attribute_should_respect_freeze() { ); assert_eq!(Balances::reserved_balance(1), 9); - assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![], true)); + assert_ok!(Uniques::set_collection_metadata(RuntimeOrigin::signed(1), 0, bvec![], true)); let e = Error::::Frozen; - assert_noop!(Uniques::set_attribute(Origin::signed(1), 0, None, bvec![0], bvec![0]), e); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![0], bvec![1])); + assert_noop!( + Uniques::set_attribute(RuntimeOrigin::signed(1), 0, None, bvec![0], bvec![0]), + e + ); + assert_ok!(Uniques::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(0), + bvec![0], + bvec![1] + )); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 0, bvec![], true)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 0, bvec![], true)); let e = Error::::Frozen; - assert_noop!(Uniques::set_attribute(Origin::signed(1), 0, Some(0), bvec![0], bvec![1]), e); - assert_ok!(Uniques::set_attribute(Origin::signed(1), 0, Some(1), bvec![0], bvec![1])); + assert_noop!( + Uniques::set_attribute(RuntimeOrigin::signed(1), 0, Some(0), bvec![0], bvec![1]), + e + ); + assert_ok!(Uniques::set_attribute( + RuntimeOrigin::signed(1), + 0, + Some(1), + bvec![0], + bvec![1] + )); }); } @@ -487,32 +590,42 @@ fn force_item_status_should_work() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 1)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 69, 2)); - assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0; 20], false)); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0; 20], false)); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 69, bvec![0; 20], false)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, false)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 1)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 69, 2)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::signed(1), + 0, + bvec![0; 20], + false + )); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0; 20], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 69, bvec![0; 20], false)); assert_eq!(Balances::reserved_balance(1), 65); // force item status to be free holding - assert_ok!(Uniques::force_item_status(Origin::root(), 0, 1, 1, 1, 1, true, false)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 142, 1)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 169, 2)); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 142, bvec![0; 20], false)); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 169, bvec![0; 20], false)); + assert_ok!(Uniques::force_item_status(RuntimeOrigin::root(), 0, 1, 1, 1, 1, true, false)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 142, 1)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 169, 2)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 142, bvec![0; 20], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 169, bvec![0; 20], false)); assert_eq!(Balances::reserved_balance(1), 65); - assert_ok!(Uniques::redeposit(Origin::signed(1), 0, bvec![0, 42, 50, 69, 100])); + assert_ok!(Uniques::redeposit(RuntimeOrigin::signed(1), 0, bvec![0, 42, 50, 69, 100])); assert_eq!(Balances::reserved_balance(1), 63); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 42, bvec![0; 20], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 42, bvec![0; 20], false)); assert_eq!(Balances::reserved_balance(1), 42); - assert_ok!(Uniques::set_metadata(Origin::signed(1), 0, 69, bvec![0; 20], false)); + assert_ok!(Uniques::set_metadata(RuntimeOrigin::signed(1), 0, 69, bvec![0; 20], false)); assert_eq!(Balances::reserved_balance(1), 21); - assert_ok!(Uniques::set_collection_metadata(Origin::signed(1), 0, bvec![0; 20], false)); + assert_ok!(Uniques::set_collection_metadata( + RuntimeOrigin::signed(1), + 0, + bvec![0; 20], + false + )); assert_eq!(Balances::reserved_balance(1), 0); }); } @@ -521,23 +634,29 @@ fn force_item_status_should_work() { fn burn_works() { new_test_ext().execute_with(|| { Balances::make_free_balance_be(&1, 100); - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, false)); - assert_ok!(Uniques::set_team(Origin::signed(1), 0, 2, 3, 4)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, false)); + assert_ok!(Uniques::set_team(RuntimeOrigin::signed(1), 0, 2, 3, 4)); assert_noop!( - Uniques::burn(Origin::signed(5), 0, 42, Some(5)), + Uniques::burn(RuntimeOrigin::signed(5), 0, 42, Some(5)), Error::::UnknownCollection ); - assert_ok!(Uniques::mint(Origin::signed(2), 0, 42, 5)); - assert_ok!(Uniques::mint(Origin::signed(2), 0, 69, 5)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(2), 0, 42, 5)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(2), 0, 69, 5)); assert_eq!(Balances::reserved_balance(1), 2); - assert_noop!(Uniques::burn(Origin::signed(0), 0, 42, None), Error::::NoPermission); - assert_noop!(Uniques::burn(Origin::signed(5), 0, 42, Some(6)), Error::::WrongOwner); + assert_noop!( + Uniques::burn(RuntimeOrigin::signed(0), 0, 42, None), + Error::::NoPermission + ); + assert_noop!( + Uniques::burn(RuntimeOrigin::signed(5), 0, 42, Some(6)), + Error::::WrongOwner + ); - assert_ok!(Uniques::burn(Origin::signed(5), 0, 42, Some(5))); - assert_ok!(Uniques::burn(Origin::signed(3), 0, 69, Some(5))); + assert_ok!(Uniques::burn(RuntimeOrigin::signed(5), 0, 42, Some(5))); + assert_ok!(Uniques::burn(RuntimeOrigin::signed(3), 0, 69, Some(5))); assert_eq!(Balances::reserved_balance(1), 0); }); } @@ -545,31 +664,37 @@ fn burn_works() { #[test] fn approval_lifecycle_works() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); - assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); - assert_ok!(Uniques::transfer(Origin::signed(3), 0, 42, 4)); - assert_noop!(Uniques::transfer(Origin::signed(3), 0, 42, 3), Error::::NoPermission); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 2)); + assert_ok!(Uniques::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3)); + assert_ok!(Uniques::transfer(RuntimeOrigin::signed(3), 0, 42, 4)); + assert_noop!( + Uniques::transfer(RuntimeOrigin::signed(3), 0, 42, 3), + Error::::NoPermission + ); assert!(Item::::get(0, 42).unwrap().approved.is_none()); - assert_ok!(Uniques::approve_transfer(Origin::signed(4), 0, 42, 2)); - assert_ok!(Uniques::transfer(Origin::signed(2), 0, 42, 2)); + assert_ok!(Uniques::approve_transfer(RuntimeOrigin::signed(4), 0, 42, 2)); + assert_ok!(Uniques::transfer(RuntimeOrigin::signed(2), 0, 42, 2)); }); } #[test] fn approved_account_gets_reset_after_transfer() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 2)); - assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); - assert_ok!(Uniques::transfer(Origin::signed(2), 0, 42, 5)); + assert_ok!(Uniques::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3)); + assert_ok!(Uniques::transfer(RuntimeOrigin::signed(2), 0, 42, 5)); // this shouldn't work because we have just transfered the item to another account. - assert_noop!(Uniques::transfer(Origin::signed(3), 0, 42, 4), Error::::NoPermission); + assert_noop!( + Uniques::transfer(RuntimeOrigin::signed(3), 0, 42, 4), + Error::::NoPermission + ); // The new owner can transfer fine: - assert_ok!(Uniques::transfer(Origin::signed(5), 0, 42, 6)); + assert_ok!(Uniques::transfer(RuntimeOrigin::signed(5), 0, 42, 6)); }); } @@ -581,47 +706,50 @@ fn approved_account_gets_reset_after_buy_item() { Balances::make_free_balance_be(&2, 100); - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, item, 1)); - assert_ok!(Uniques::approve_transfer(Origin::signed(1), 0, item, 5)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, item, 1)); + assert_ok!(Uniques::approve_transfer(RuntimeOrigin::signed(1), 0, item, 5)); - assert_ok!(Uniques::set_price(Origin::signed(1), 0, item, Some(price), None)); + assert_ok!(Uniques::set_price(RuntimeOrigin::signed(1), 0, item, Some(price), None)); - assert_ok!(Uniques::buy_item(Origin::signed(2), 0, item, price)); + assert_ok!(Uniques::buy_item(RuntimeOrigin::signed(2), 0, item, price)); // this shouldn't work because the item has been bough and the approved account should be // reset. - assert_noop!(Uniques::transfer(Origin::signed(5), 0, item, 4), Error::::NoPermission); + assert_noop!( + Uniques::transfer(RuntimeOrigin::signed(5), 0, item, 4), + Error::::NoPermission + ); }); } #[test] fn cancel_approval_works() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 2)); - assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); + assert_ok!(Uniques::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3)); assert_noop!( - Uniques::cancel_approval(Origin::signed(2), 1, 42, None), + Uniques::cancel_approval(RuntimeOrigin::signed(2), 1, 42, None), Error::::UnknownCollection ); assert_noop!( - Uniques::cancel_approval(Origin::signed(2), 0, 43, None), + Uniques::cancel_approval(RuntimeOrigin::signed(2), 0, 43, None), Error::::UnknownCollection ); assert_noop!( - Uniques::cancel_approval(Origin::signed(3), 0, 42, None), + Uniques::cancel_approval(RuntimeOrigin::signed(3), 0, 42, None), Error::::NoPermission ); assert_noop!( - Uniques::cancel_approval(Origin::signed(2), 0, 42, Some(4)), + Uniques::cancel_approval(RuntimeOrigin::signed(2), 0, 42, Some(4)), Error::::WrongDelegate ); - assert_ok!(Uniques::cancel_approval(Origin::signed(2), 0, 42, Some(3))); + assert_ok!(Uniques::cancel_approval(RuntimeOrigin::signed(2), 0, 42, Some(3))); assert_noop!( - Uniques::cancel_approval(Origin::signed(2), 0, 42, None), + Uniques::cancel_approval(RuntimeOrigin::signed(2), 0, 42, None), Error::::NoDelegate ); }); @@ -630,26 +758,26 @@ fn cancel_approval_works() { #[test] fn cancel_approval_works_with_admin() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 2)); - assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); + assert_ok!(Uniques::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3)); assert_noop!( - Uniques::cancel_approval(Origin::signed(1), 1, 42, None), + Uniques::cancel_approval(RuntimeOrigin::signed(1), 1, 42, None), Error::::UnknownCollection ); assert_noop!( - Uniques::cancel_approval(Origin::signed(1), 0, 43, None), + Uniques::cancel_approval(RuntimeOrigin::signed(1), 0, 43, None), Error::::UnknownCollection ); assert_noop!( - Uniques::cancel_approval(Origin::signed(1), 0, 42, Some(4)), + Uniques::cancel_approval(RuntimeOrigin::signed(1), 0, 42, Some(4)), Error::::WrongDelegate ); - assert_ok!(Uniques::cancel_approval(Origin::signed(1), 0, 42, Some(3))); + assert_ok!(Uniques::cancel_approval(RuntimeOrigin::signed(1), 0, 42, Some(3))); assert_noop!( - Uniques::cancel_approval(Origin::signed(1), 0, 42, None), + Uniques::cancel_approval(RuntimeOrigin::signed(1), 0, 42, None), Error::::NoDelegate ); }); @@ -658,26 +786,26 @@ fn cancel_approval_works_with_admin() { #[test] fn cancel_approval_works_with_force() { new_test_ext().execute_with(|| { - assert_ok!(Uniques::force_create(Origin::root(), 0, 1, true)); - assert_ok!(Uniques::mint(Origin::signed(1), 0, 42, 2)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), 0, 1, true)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(1), 0, 42, 2)); - assert_ok!(Uniques::approve_transfer(Origin::signed(2), 0, 42, 3)); + assert_ok!(Uniques::approve_transfer(RuntimeOrigin::signed(2), 0, 42, 3)); assert_noop!( - Uniques::cancel_approval(Origin::root(), 1, 42, None), + Uniques::cancel_approval(RuntimeOrigin::root(), 1, 42, None), Error::::UnknownCollection ); assert_noop!( - Uniques::cancel_approval(Origin::root(), 0, 43, None), + Uniques::cancel_approval(RuntimeOrigin::root(), 0, 43, None), Error::::UnknownCollection ); assert_noop!( - Uniques::cancel_approval(Origin::root(), 0, 42, Some(4)), + Uniques::cancel_approval(RuntimeOrigin::root(), 0, 42, Some(4)), Error::::WrongDelegate ); - assert_ok!(Uniques::cancel_approval(Origin::root(), 0, 42, Some(3))); + assert_ok!(Uniques::cancel_approval(RuntimeOrigin::root(), 0, 42, Some(3))); assert_noop!( - Uniques::cancel_approval(Origin::root(), 0, 42, None), + Uniques::cancel_approval(RuntimeOrigin::root(), 0, 42, None), Error::::NoDelegate ); }); @@ -691,11 +819,11 @@ fn max_supply_should_work() { let max_supply = 2; // validate set_collection_max_supply - assert_ok!(Uniques::force_create(Origin::root(), collection_id, user_id, true)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), collection_id, user_id, true)); assert!(!CollectionMaxSupply::::contains_key(collection_id)); assert_ok!(Uniques::set_collection_max_supply( - Origin::signed(user_id), + RuntimeOrigin::signed(user_id), collection_id, max_supply )); @@ -708,7 +836,7 @@ fn max_supply_should_work() { assert_noop!( Uniques::set_collection_max_supply( - Origin::signed(user_id), + RuntimeOrigin::signed(user_id), collection_id, max_supply + 1 ), @@ -716,16 +844,16 @@ fn max_supply_should_work() { ); // validate we can't mint more to max supply - assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, 0, user_id)); - assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, 1, user_id)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(user_id), collection_id, 0, user_id)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(user_id), collection_id, 1, user_id)); assert_noop!( - Uniques::mint(Origin::signed(user_id), collection_id, 2, user_id), + Uniques::mint(RuntimeOrigin::signed(user_id), collection_id, 2, user_id), Error::::MaxSupplyReached ); // validate we remove the CollectionMaxSupply record when we destroy the collection assert_ok!(Uniques::destroy( - Origin::signed(user_id), + RuntimeOrigin::signed(user_id), collection_id, Collection::::get(collection_id).unwrap().destroy_witness() )); @@ -741,13 +869,13 @@ fn set_price_should_work() { let item_1 = 1; let item_2 = 2; - assert_ok!(Uniques::force_create(Origin::root(), collection_id, user_id, true)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), collection_id, user_id, true)); - assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, item_1, user_id)); - assert_ok!(Uniques::mint(Origin::signed(user_id), collection_id, item_2, user_id)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(user_id), collection_id, item_1, user_id)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(user_id), collection_id, item_2, user_id)); assert_ok!(Uniques::set_price( - Origin::signed(user_id), + RuntimeOrigin::signed(user_id), collection_id, item_1, Some(1), @@ -755,7 +883,7 @@ fn set_price_should_work() { )); assert_ok!(Uniques::set_price( - Origin::signed(user_id), + RuntimeOrigin::signed(user_id), collection_id, item_2, Some(2), @@ -778,7 +906,13 @@ fn set_price_should_work() { })); // validate we can unset the price - assert_ok!(Uniques::set_price(Origin::signed(user_id), collection_id, item_2, None, None)); + assert_ok!(Uniques::set_price( + RuntimeOrigin::signed(user_id), + collection_id, + item_2, + None, + None + )); assert!(events().contains(&Event::::ItemPriceRemoved { collection: collection_id, item: item_2 @@ -805,14 +939,14 @@ fn buy_item_should_work() { Balances::make_free_balance_be(&user_2, initial_balance); Balances::make_free_balance_be(&user_3, initial_balance); - assert_ok!(Uniques::force_create(Origin::root(), collection_id, user_1, true)); + assert_ok!(Uniques::force_create(RuntimeOrigin::root(), collection_id, user_1, true)); - assert_ok!(Uniques::mint(Origin::signed(user_1), collection_id, item_1, user_1)); - assert_ok!(Uniques::mint(Origin::signed(user_1), collection_id, item_2, user_1)); - assert_ok!(Uniques::mint(Origin::signed(user_1), collection_id, item_3, user_1)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(user_1), collection_id, item_1, user_1)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(user_1), collection_id, item_2, user_1)); + assert_ok!(Uniques::mint(RuntimeOrigin::signed(user_1), collection_id, item_3, user_1)); assert_ok!(Uniques::set_price( - Origin::signed(user_1), + RuntimeOrigin::signed(user_1), collection_id, item_1, Some(price_1), @@ -820,7 +954,7 @@ fn buy_item_should_work() { )); assert_ok!(Uniques::set_price( - Origin::signed(user_1), + RuntimeOrigin::signed(user_1), collection_id, item_2, Some(price_2), @@ -829,12 +963,17 @@ fn buy_item_should_work() { // can't buy for less assert_noop!( - Uniques::buy_item(Origin::signed(user_2), collection_id, item_1, 1), + Uniques::buy_item(RuntimeOrigin::signed(user_2), collection_id, item_1, 1), Error::::BidTooLow ); // pass the higher price to validate it will still deduct correctly - assert_ok!(Uniques::buy_item(Origin::signed(user_2), collection_id, item_1, price_1 + 1,)); + assert_ok!(Uniques::buy_item( + RuntimeOrigin::signed(user_2), + collection_id, + item_1, + price_1 + 1, + )); // validate the new owner & balances let item = Item::::get(collection_id, item_1).unwrap(); @@ -844,18 +983,23 @@ fn buy_item_should_work() { // can't buy from yourself assert_noop!( - Uniques::buy_item(Origin::signed(user_1), collection_id, item_2, price_2), + Uniques::buy_item(RuntimeOrigin::signed(user_1), collection_id, item_2, price_2), Error::::NoPermission ); // can't buy when the item is listed for a specific buyer assert_noop!( - Uniques::buy_item(Origin::signed(user_2), collection_id, item_2, price_2), + Uniques::buy_item(RuntimeOrigin::signed(user_2), collection_id, item_2, price_2), Error::::NoPermission ); // can buy when I'm a whitelisted buyer - assert_ok!(Uniques::buy_item(Origin::signed(user_3), collection_id, item_2, price_2,)); + assert_ok!(Uniques::buy_item( + RuntimeOrigin::signed(user_3), + collection_id, + item_2, + price_2, + )); assert!(events().contains(&Event::::ItemBought { collection: collection_id, @@ -870,14 +1014,14 @@ fn buy_item_should_work() { // can't buy when item is not for sale assert_noop!( - Uniques::buy_item(Origin::signed(user_2), collection_id, item_3, price_2), + Uniques::buy_item(RuntimeOrigin::signed(user_2), collection_id, item_3, price_2), Error::::NotForSale ); // ensure we can't buy an item when the collection or an item is frozen { assert_ok!(Uniques::set_price( - Origin::signed(user_1), + RuntimeOrigin::signed(user_1), collection_id, item_3, Some(price_1), @@ -885,26 +1029,32 @@ fn buy_item_should_work() { )); // freeze collection - assert_ok!(Uniques::freeze_collection(Origin::signed(user_1), collection_id)); + assert_ok!(Uniques::freeze_collection(RuntimeOrigin::signed(user_1), collection_id)); - let buy_item_call = mock::Call::Uniques(crate::Call::::buy_item { + let buy_item_call = mock::RuntimeCall::Uniques(crate::Call::::buy_item { collection: collection_id, item: item_3, bid_price: price_1, }); - assert_noop!(buy_item_call.dispatch(Origin::signed(user_2)), Error::::Frozen); + assert_noop!( + buy_item_call.dispatch(RuntimeOrigin::signed(user_2)), + Error::::Frozen + ); - assert_ok!(Uniques::thaw_collection(Origin::signed(user_1), collection_id)); + assert_ok!(Uniques::thaw_collection(RuntimeOrigin::signed(user_1), collection_id)); // freeze item - assert_ok!(Uniques::freeze(Origin::signed(user_1), collection_id, item_3)); + assert_ok!(Uniques::freeze(RuntimeOrigin::signed(user_1), collection_id, item_3)); - let buy_item_call = mock::Call::Uniques(crate::Call::::buy_item { + let buy_item_call = mock::RuntimeCall::Uniques(crate::Call::::buy_item { collection: collection_id, item: item_3, bid_price: price_1, }); - assert_noop!(buy_item_call.dispatch(Origin::signed(user_2)), Error::::Frozen); + assert_noop!( + buy_item_call.dispatch(RuntimeOrigin::signed(user_2)), + Error::::Frozen + ); } }); } diff --git a/frame/uniques/src/weights.rs b/frame/uniques/src/weights.rs index c7a8a2f6baa0f..a134b68d093b6 100644 --- a/frame/uniques/src/weights.rs +++ b/frame/uniques/src/weights.rs @@ -18,12 +18,12 @@ //! Autogenerated weights for pallet_uniques //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-07-13, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `test-bench-bot`, CPU: `Intel(R) Xeon(R) CPU @ 3.10GHz` +//! DATE: 2022-10-20, STEPS: `50`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! HOSTNAME: `bm3`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// target/production/substrate +// /home/benchbot/cargo_target_dir/production/substrate // benchmark // pallet // --steps=50 @@ -32,6 +32,7 @@ // --execution=wasm // --wasm-execution=compiled // --heap-pages=4096 +// --json-file=/var/lib/gitlab-runner/builds/zyw4fam_/0/parity/mirrors/substrate/.git/.artifacts/bench.json // --pallet=pallet_uniques // --chain=dev // --output=./frame/uniques/src/weights.rs @@ -80,14 +81,16 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - Weight::from_ref_time(33_075_000 as u64) + // Minimum execution time: 32_901 nanoseconds. + Weight::from_ref_time(33_628_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - Weight::from_ref_time(19_528_000 as u64) + // Minimum execution time: 21_633 nanoseconds. + Weight::from_ref_time(22_380_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -103,13 +106,14 @@ impl WeightInfo for SubstrateWeight { /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(13_639_000 as u64).saturating_mul(n as u64)) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(2_393_000 as u64).saturating_mul(m as u64)) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(2_217_000 as u64).saturating_mul(a as u64)) + // Minimum execution time: 2_429_508 nanoseconds. + Weight::from_ref_time(2_446_263_000 as u64) + // Standard Error: 28_236 + .saturating_add(Weight::from_ref_time(8_477_090 as u64).saturating_mul(n as u64)) + // Standard Error: 28_236 + .saturating_add(Weight::from_ref_time(314_268 as u64).saturating_mul(m as u64)) + // Standard Error: 28_236 + .saturating_add(Weight::from_ref_time(249_624 as u64).saturating_mul(a as u64)) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) .saturating_add(T::DbWeight::get().writes(4 as u64)) @@ -122,7 +126,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - Weight::from_ref_time(42_146_000 as u64) + // Minimum execution time: 41_938 nanoseconds. + Weight::from_ref_time(42_814_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(3 as u64)) } @@ -131,7 +136,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Account (r:0 w:1) // Storage: Uniques ItemPriceOf (r:0 w:1) fn burn() -> Weight { - Weight::from_ref_time(42_960_000 as u64) + // Minimum execution time: 43_593 nanoseconds. + Weight::from_ref_time(44_420_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -140,17 +146,19 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Account (r:0 w:2) // Storage: Uniques ItemPriceOf (r:0 w:1) fn transfer() -> Weight { - Weight::from_ref_time(33_025_000 as u64) + // Minimum execution time: 34_037 nanoseconds. + Weight::from_ref_time(34_848_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques Asset (r:100 w:100) + // Storage: Uniques Asset (r:102 w:102) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 24_000 - .saturating_add(Weight::from_ref_time(15_540_000 as u64).saturating_mul(i as u64)) + // Minimum execution time: 23_295 nanoseconds. + Weight::from_ref_time(23_482_000 as u64) + // Standard Error: 9_490 + .saturating_add(Weight::from_ref_time(10_899_320 as u64).saturating_mul(i as u64)) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(i as u64))) .saturating_add(T::DbWeight::get().writes(1 as u64)) @@ -159,26 +167,30 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - Weight::from_ref_time(25_194_000 as u64) + // Minimum execution time: 27_005 nanoseconds. + Weight::from_ref_time(27_344_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - Weight::from_ref_time(25_397_000 as u64) + // Minimum execution time: 26_815 nanoseconds. + Weight::from_ref_time(27_400_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - Weight::from_ref_time(19_278_000 as u64) + // Minimum execution time: 21_988 nanoseconds. + Weight::from_ref_time(22_596_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - Weight::from_ref_time(19_304_000 as u64) + // Minimum execution time: 21_886 nanoseconds. + Weight::from_ref_time(22_617_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -186,20 +198,23 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - Weight::from_ref_time(28_615_000 as u64) + // Minimum execution time: 30_241 nanoseconds. + Weight::from_ref_time(30_677_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - Weight::from_ref_time(19_943_000 as u64) + // Minimum execution time: 23_011 nanoseconds. + Weight::from_ref_time(23_796_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - Weight::from_ref_time(22_583_000 as u64) + // Minimum execution time: 25_739 nanoseconds. + Weight::from_ref_time(26_572_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -207,7 +222,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - Weight::from_ref_time(47_520_000 as u64) + // Minimum execution time: 48_486 nanoseconds. + Weight::from_ref_time(49_029_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } @@ -215,69 +231,79 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - Weight::from_ref_time(45_316_000 as u64) + // Minimum execution time: 47_408 nanoseconds. + Weight::from_ref_time(48_753_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - Weight::from_ref_time(38_391_000 as u64) + // Minimum execution time: 40_085 nanoseconds. + Weight::from_ref_time(40_625_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - Weight::from_ref_time(38_023_000 as u64) + // Minimum execution time: 40_546 nanoseconds. + Weight::from_ref_time(41_113_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - Weight::from_ref_time(37_398_000 as u64) + // Minimum execution time: 39_902 nanoseconds. + Weight::from_ref_time(40_599_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - Weight::from_ref_time(35_621_000 as u64) + // Minimum execution time: 37_597 nanoseconds. + Weight::from_ref_time(37_964_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - Weight::from_ref_time(25_856_000 as u64) + // Minimum execution time: 28_719 nanoseconds. + Weight::from_ref_time(29_213_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - Weight::from_ref_time(26_098_000 as u64) + // Minimum execution time: 27_608 nanoseconds. + Weight::from_ref_time(28_096_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - Weight::from_ref_time(24_076_000 as u64) + // Minimum execution time: 25_568 nanoseconds. + Weight::from_ref_time(26_098_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - Weight::from_ref_time(22_035_000 as u64) + // Minimum execution time: 24_521 nanoseconds. + Weight::from_ref_time(25_062_000 as u64) .saturating_add(T::DbWeight::get().reads(2 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:0) // Storage: Uniques ItemPriceOf (r:0 w:1) fn set_price() -> Weight { - Weight::from_ref_time(22_534_000 as u64) + // Minimum execution time: 25_337 nanoseconds. + Weight::from_ref_time(25_902_000 as u64) .saturating_add(T::DbWeight::get().reads(1 as u64)) .saturating_add(T::DbWeight::get().writes(1 as u64)) } @@ -286,7 +312,8 @@ impl WeightInfo for SubstrateWeight { // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Account (r:0 w:2) fn buy_item() -> Weight { - Weight::from_ref_time(45_272_000 as u64) + // Minimum execution time: 46_736 nanoseconds. + Weight::from_ref_time(47_264_000 as u64) .saturating_add(T::DbWeight::get().reads(3 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } @@ -297,14 +324,16 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn create() -> Weight { - Weight::from_ref_time(33_075_000 as u64) + // Minimum execution time: 32_901 nanoseconds. + Weight::from_ref_time(33_628_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_create() -> Weight { - Weight::from_ref_time(19_528_000 as u64) + // Minimum execution time: 21_633 nanoseconds. + Weight::from_ref_time(22_380_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -320,13 +349,14 @@ impl WeightInfo for () { /// The range of component `m` is `[0, 1000]`. /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(13_639_000 as u64).saturating_mul(n as u64)) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(2_393_000 as u64).saturating_mul(m as u64)) - // Standard Error: 25_000 - .saturating_add(Weight::from_ref_time(2_217_000 as u64).saturating_mul(a as u64)) + // Minimum execution time: 2_429_508 nanoseconds. + Weight::from_ref_time(2_446_263_000 as u64) + // Standard Error: 28_236 + .saturating_add(Weight::from_ref_time(8_477_090 as u64).saturating_mul(n as u64)) + // Standard Error: 28_236 + .saturating_add(Weight::from_ref_time(314_268 as u64).saturating_mul(m as u64)) + // Standard Error: 28_236 + .saturating_add(Weight::from_ref_time(249_624 as u64).saturating_mul(a as u64)) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(n as u64))) .saturating_add(RocksDbWeight::get().writes(4 as u64)) @@ -339,7 +369,8 @@ impl WeightInfo for () { // Storage: Uniques CollectionMaxSupply (r:1 w:0) // Storage: Uniques Account (r:0 w:1) fn mint() -> Weight { - Weight::from_ref_time(42_146_000 as u64) + // Minimum execution time: 41_938 nanoseconds. + Weight::from_ref_time(42_814_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(3 as u64)) } @@ -348,7 +379,8 @@ impl WeightInfo for () { // Storage: Uniques Account (r:0 w:1) // Storage: Uniques ItemPriceOf (r:0 w:1) fn burn() -> Weight { - Weight::from_ref_time(42_960_000 as u64) + // Minimum execution time: 43_593 nanoseconds. + Weight::from_ref_time(44_420_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } @@ -357,17 +389,19 @@ impl WeightInfo for () { // Storage: Uniques Account (r:0 w:2) // Storage: Uniques ItemPriceOf (r:0 w:1) fn transfer() -> Weight { - Weight::from_ref_time(33_025_000 as u64) + // Minimum execution time: 34_037 nanoseconds. + Weight::from_ref_time(34_848_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Uniques Class (r:1 w:1) - // Storage: Uniques Asset (r:100 w:100) + // Storage: Uniques Asset (r:102 w:102) /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { - Weight::from_ref_time(0 as u64) - // Standard Error: 24_000 - .saturating_add(Weight::from_ref_time(15_540_000 as u64).saturating_mul(i as u64)) + // Minimum execution time: 23_295 nanoseconds. + Weight::from_ref_time(23_482_000 as u64) + // Standard Error: 9_490 + .saturating_add(Weight::from_ref_time(10_899_320 as u64).saturating_mul(i as u64)) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(i as u64))) .saturating_add(RocksDbWeight::get().writes(1 as u64)) @@ -376,26 +410,30 @@ impl WeightInfo for () { // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn freeze() -> Weight { - Weight::from_ref_time(25_194_000 as u64) + // Minimum execution time: 27_005 nanoseconds. + Weight::from_ref_time(27_344_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn thaw() -> Weight { - Weight::from_ref_time(25_397_000 as u64) + // Minimum execution time: 26_815 nanoseconds. + Weight::from_ref_time(27_400_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) fn freeze_collection() -> Weight { - Weight::from_ref_time(19_278_000 as u64) + // Minimum execution time: 21_988 nanoseconds. + Weight::from_ref_time(22_596_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) fn thaw_collection() -> Weight { - Weight::from_ref_time(19_304_000 as u64) + // Minimum execution time: 21_886 nanoseconds. + Weight::from_ref_time(22_617_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -403,20 +441,23 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:2) fn transfer_ownership() -> Weight { - Weight::from_ref_time(28_615_000 as u64) + // Minimum execution time: 30_241 nanoseconds. + Weight::from_ref_time(30_677_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } // Storage: Uniques Class (r:1 w:1) fn set_team() -> Weight { - Weight::from_ref_time(19_943_000 as u64) + // Minimum execution time: 23_011 nanoseconds. + Weight::from_ref_time(23_796_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassAccount (r:0 w:1) fn force_item_status() -> Weight { - Weight::from_ref_time(22_583_000 as u64) + // Minimum execution time: 25_739 nanoseconds. + Weight::from_ref_time(26_572_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -424,7 +465,8 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn set_attribute() -> Weight { - Weight::from_ref_time(47_520_000 as u64) + // Minimum execution time: 48_486 nanoseconds. + Weight::from_ref_time(49_029_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } @@ -432,69 +474,79 @@ impl WeightInfo for () { // Storage: Uniques InstanceMetadataOf (r:1 w:0) // Storage: Uniques Attribute (r:1 w:1) fn clear_attribute() -> Weight { - Weight::from_ref_time(45_316_000 as u64) + // Minimum execution time: 47_408 nanoseconds. + Weight::from_ref_time(48_753_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn set_metadata() -> Weight { - Weight::from_ref_time(38_391_000 as u64) + // Minimum execution time: 40_085 nanoseconds. + Weight::from_ref_time(40_625_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques InstanceMetadataOf (r:1 w:1) fn clear_metadata() -> Weight { - Weight::from_ref_time(38_023_000 as u64) + // Minimum execution time: 40_546 nanoseconds. + Weight::from_ref_time(41_113_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:1) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn set_collection_metadata() -> Weight { - Weight::from_ref_time(37_398_000 as u64) + // Minimum execution time: 39_902 nanoseconds. + Weight::from_ref_time(40_599_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(2 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques ClassMetadataOf (r:1 w:1) fn clear_collection_metadata() -> Weight { - Weight::from_ref_time(35_621_000 as u64) + // Minimum execution time: 37_597 nanoseconds. + Weight::from_ref_time(37_964_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn approve_transfer() -> Weight { - Weight::from_ref_time(25_856_000 as u64) + // Minimum execution time: 28_719 nanoseconds. + Weight::from_ref_time(29_213_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Asset (r:1 w:1) fn cancel_approval() -> Weight { - Weight::from_ref_time(26_098_000 as u64) + // Minimum execution time: 27_608 nanoseconds. + Weight::from_ref_time(28_096_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques OwnershipAcceptance (r:1 w:1) fn set_accept_ownership() -> Weight { - Weight::from_ref_time(24_076_000 as u64) + // Minimum execution time: 25_568 nanoseconds. + Weight::from_ref_time(26_098_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques CollectionMaxSupply (r:1 w:1) // Storage: Uniques Class (r:1 w:0) fn set_collection_max_supply() -> Weight { - Weight::from_ref_time(22_035_000 as u64) + // Minimum execution time: 24_521 nanoseconds. + Weight::from_ref_time(25_062_000 as u64) .saturating_add(RocksDbWeight::get().reads(2 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } // Storage: Uniques Asset (r:1 w:0) // Storage: Uniques ItemPriceOf (r:0 w:1) fn set_price() -> Weight { - Weight::from_ref_time(22_534_000 as u64) + // Minimum execution time: 25_337 nanoseconds. + Weight::from_ref_time(25_902_000 as u64) .saturating_add(RocksDbWeight::get().reads(1 as u64)) .saturating_add(RocksDbWeight::get().writes(1 as u64)) } @@ -503,7 +555,8 @@ impl WeightInfo for () { // Storage: Uniques Class (r:1 w:0) // Storage: Uniques Account (r:0 w:2) fn buy_item() -> Weight { - Weight::from_ref_time(45_272_000 as u64) + // Minimum execution time: 46_736 nanoseconds. + Weight::from_ref_time(47_264_000 as u64) .saturating_add(RocksDbWeight::get().reads(3 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } diff --git a/frame/utility/Cargo.toml b/frame/utility/Cargo.toml index 68750f77b7365..6dfe6659d402b 100644 --- a/frame/utility/Cargo.toml +++ b/frame/utility/Cargo.toml @@ -30,6 +30,7 @@ sp-core = { version = "6.0.0", path = "../../primitives/core" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/utility/src/benchmarking.rs b/frame/utility/src/benchmarking.rs index 018280f69baeb..07bc14951cb3b 100644 --- a/frame/utility/src/benchmarking.rs +++ b/frame/utility/src/benchmarking.rs @@ -25,15 +25,15 @@ use frame_system::RawOrigin; const SEED: u32 = 0; -fn assert_last_event(generic_event: ::Event) { +fn assert_last_event(generic_event: ::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } benchmarks! { - where_clause { where ::PalletsOrigin: Clone } + where_clause { where ::PalletsOrigin: Clone } batch { let c in 0 .. 1000; - let mut calls: Vec<::Call> = Vec::new(); + let mut calls: Vec<::RuntimeCall> = Vec::new(); for i in 0 .. c { let call = frame_system::Call::remark { remark: vec![] }.into(); calls.push(call); @@ -54,7 +54,7 @@ benchmarks! { batch_all { let c in 0 .. 1000; - let mut calls: Vec<::Call> = Vec::new(); + let mut calls: Vec<::RuntimeCall> = Vec::new(); for i in 0 .. c { let call = frame_system::Call::remark { remark: vec![] }.into(); calls.push(call); @@ -68,14 +68,14 @@ benchmarks! { dispatch_as { let caller = account("caller", SEED, SEED); let call = Box::new(frame_system::Call::remark { remark: vec![] }.into()); - let origin: T::Origin = RawOrigin::Signed(caller).into(); - let pallets_origin: ::PalletsOrigin = origin.caller().clone(); + let origin: T::RuntimeOrigin = RawOrigin::Signed(caller).into(); + let pallets_origin: ::PalletsOrigin = origin.caller().clone(); let pallets_origin = Into::::into(pallets_origin); }: _(RawOrigin::Root, Box::new(pallets_origin), call) force_batch { let c in 0 .. 1000; - let mut calls: Vec<::Call> = Vec::new(); + let mut calls: Vec<::RuntimeCall> = Vec::new(); for i in 0 .. c { let call = frame_system::Call::remark { remark: vec![] }.into(); calls.push(call); diff --git a/frame/utility/src/lib.rs b/frame/utility/src/lib.rs index 1424c88b8a1e1..544add1da68d3 100644 --- a/frame/utility/src/lib.rs +++ b/frame/utility/src/lib.rs @@ -58,9 +58,8 @@ pub mod weights; use codec::{Decode, Encode}; use frame_support::{ - dispatch::PostDispatchInfo, + dispatch::{extract_actual_weight, GetDispatchInfo, PostDispatchInfo}, traits::{IsSubType, OriginTrait, UnfilteredDispatchable}, - weights::{extract_actual_weight, GetDispatchInfo}, }; use sp_core::TypeId; use sp_io::hashing::blake2_256; @@ -84,21 +83,21 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From + IsType<::Event>; + type RuntimeEvent: From + IsType<::RuntimeEvent>; /// The overarching call type. - type Call: Parameter - + Dispatchable + type RuntimeCall: Parameter + + Dispatchable + GetDispatchInfo + From> - + UnfilteredDispatchable + + UnfilteredDispatchable + IsSubType> - + IsType<::Call>; + + IsType<::RuntimeCall>; /// The caller origin, overarching type of all pallets origins. type PalletsOrigin: Parameter + - Into<::Origin> + - IsType<<::Origin as frame_support::traits::OriginTrait>::PalletsOrigin>; + Into<::RuntimeOrigin> + + IsType<<::RuntimeOrigin as frame_support::traits::OriginTrait>::PalletsOrigin>; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; @@ -125,7 +124,7 @@ pub mod pallet { // Align the call size to 1KB. As we are currently compiling the runtime for native/wasm // the `size_of` of the `Call` can be different. To ensure that this don't leads to // mismatches between native/wasm or to different metadata for the same runtime, we - // algin the call size. The value is choosen big enough to hopefully never reach it. + // algin the call size. The value is chosen big enough to hopefully never reach it. const CALL_ALIGN: u32 = 1024; #[pallet::extra_constants] @@ -133,8 +132,9 @@ pub mod pallet { /// The limit on the number of batched calls. fn batched_calls_limit() -> u32 { let allocator_limit = sp_core::MAX_POSSIBLE_ALLOCATION; - let call_size = ((sp_std::mem::size_of::<::Call>() as u32 + CALL_ALIGN - - 1) / CALL_ALIGN) * CALL_ALIGN; + let call_size = ((sp_std::mem::size_of::<::RuntimeCall>() as u32 + + CALL_ALIGN - 1) / CALL_ALIGN) * + CALL_ALIGN; // The margin to take into account vec doubling capacity. let margin_factor = 3; @@ -147,7 +147,7 @@ pub mod pallet { fn integrity_test() { // If you hit this error, you need to try to `Box` big dispatchable parameters. assert!( - sp_std::mem::size_of::<::Call>() as u32 <= CALL_ALIGN, + sp_std::mem::size_of::<::RuntimeCall>() as u32 <= CALL_ALIGN, "Call enum size should be smaller than {} bytes.", CALL_ALIGN, ); @@ -201,7 +201,7 @@ pub mod pallet { })] pub fn batch( origin: OriginFor, - calls: Vec<::Call>, + calls: Vec<::RuntimeCall>, ) -> DispatchResultWithPostInfo { // Do not allow the `None` origin. if ensure_none(origin.clone()).is_ok() { @@ -267,7 +267,7 @@ pub mod pallet { pub fn as_derivative( origin: OriginFor, index: u16, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResultWithPostInfo { let mut origin = origin; let who = ensure_signed(origin.clone())?; @@ -322,7 +322,7 @@ pub mod pallet { })] pub fn batch_all( origin: OriginFor, - calls: Vec<::Call>, + calls: Vec<::RuntimeCall>, ) -> DispatchResultWithPostInfo { // Do not allow the `None` origin. if ensure_none(origin.clone()).is_ok() { @@ -343,10 +343,12 @@ pub mod pallet { } else { let mut filtered_origin = origin.clone(); // Don't allow users to nest `batch_all` calls. - filtered_origin.add_filter(move |c: &::Call| { - let c = ::Call::from_ref(c); - !matches!(c.is_sub_type(), Some(Call::batch_all { .. })) - }); + filtered_origin.add_filter( + move |c: &::RuntimeCall| { + let c = ::RuntimeCall::from_ref(c); + !matches!(c.is_sub_type(), Some(Call::batch_all { .. })) + }, + ); call.dispatch(filtered_origin) }; // Add the weight of this call. @@ -386,7 +388,7 @@ pub mod pallet { pub fn dispatch_as( origin: OriginFor, as_origin: Box, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResult { ensure_root(origin)?; @@ -432,7 +434,7 @@ pub mod pallet { })] pub fn force_batch( origin: OriginFor, - calls: Vec<::Call>, + calls: Vec<::RuntimeCall>, ) -> DispatchResultWithPostInfo { // Do not allow the `None` origin. if ensure_none(origin.clone()).is_ok() { diff --git a/frame/utility/src/tests.rs b/frame/utility/src/tests.rs index d996bb2837e4a..ebd8dda81adbc 100644 --- a/frame/utility/src/tests.rs +++ b/frame/utility/src/tests.rs @@ -24,11 +24,11 @@ use super::*; use crate as utility; use frame_support::{ assert_err_ignore_postinfo, assert_noop, assert_ok, - dispatch::{DispatchError, DispatchErrorWithPostInfo, Dispatchable}, + dispatch::{DispatchError, DispatchErrorWithPostInfo, Dispatchable, Pays}, error::BadOrigin, parameter_types, storage, traits::{ConstU32, ConstU64, Contains}, - weights::{Pays, Weight}, + weights::Weight, }; use sp_core::H256; use sp_runtime::{ @@ -107,16 +107,16 @@ impl frame_system::Config for Test { type BlockWeights = BlockWeights; type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -135,7 +135,7 @@ impl pallet_balances::Config for Test { type ReserveIdentifier = [u8; 8]; type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ConstU64<1>; type AccountStore = System; type WeightInfo = (); @@ -149,23 +149,23 @@ parameter_types! { impl example::Config for Test {} pub struct TestBaseCallFilter; -impl Contains for TestBaseCallFilter { - fn contains(c: &Call) -> bool { +impl Contains for TestBaseCallFilter { + fn contains(c: &RuntimeCall) -> bool { match *c { // Transfer works. Use `transfer_keep_alive` for a call that doesn't pass the filter. - Call::Balances(pallet_balances::Call::transfer { .. }) => true, - Call::Utility(_) => true, + RuntimeCall::Balances(pallet_balances::Call::transfer { .. }) => true, + RuntimeCall::Utility(_) => true, // For benchmarking, this acts as a noop call - Call::System(frame_system::Call::remark { .. }) => true, + RuntimeCall::System(frame_system::Call::remark { .. }) => true, // For tests - Call::Example(_) => true, + RuntimeCall::Example(_) => true, _ => false, } } } impl Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; type WeightInfo = (); } @@ -188,24 +188,28 @@ pub fn new_test_ext() -> sp_io::TestExternalities { ext } -fn call_transfer(dest: u64, value: u64) -> Call { - Call::Balances(BalancesCall::transfer { dest, value }) +fn call_transfer(dest: u64, value: u64) -> RuntimeCall { + RuntimeCall::Balances(BalancesCall::transfer { dest, value }) } -fn call_foobar(err: bool, start_weight: Weight, end_weight: Option) -> Call { - Call::Example(ExampleCall::foobar { err, start_weight, end_weight }) +fn call_foobar(err: bool, start_weight: Weight, end_weight: Option) -> RuntimeCall { + RuntimeCall::Example(ExampleCall::foobar { err, start_weight, end_weight }) } #[test] fn as_derivative_works() { new_test_ext().execute_with(|| { let sub_1_0 = Utility::derivative_account_id(1, 0); - assert_ok!(Balances::transfer(Origin::signed(1), sub_1_0, 5)); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(1), sub_1_0, 5)); assert_err_ignore_postinfo!( - Utility::as_derivative(Origin::signed(1), 1, Box::new(call_transfer(6, 3)),), + Utility::as_derivative(RuntimeOrigin::signed(1), 1, Box::new(call_transfer(6, 3)),), BalancesError::::InsufficientBalance ); - assert_ok!(Utility::as_derivative(Origin::signed(1), 0, Box::new(call_transfer(2, 3)),)); + assert_ok!(Utility::as_derivative( + RuntimeOrigin::signed(1), + 0, + Box::new(call_transfer(2, 3)), + )); assert_eq!(Balances::free_balance(sub_1_0), 2); assert_eq!(Balances::free_balance(2), 13); }); @@ -220,29 +224,35 @@ fn as_derivative_handles_weight_refund() { // Full weight when ok let inner_call = call_foobar(false, start_weight, None); - let call = - Call::Utility(UtilityCall::as_derivative { index: 0, call: Box::new(inner_call) }); + let call = RuntimeCall::Utility(UtilityCall::as_derivative { + index: 0, + call: Box::new(inner_call), + }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), info.weight); // Refund weight when ok let inner_call = call_foobar(false, start_weight, Some(end_weight)); - let call = - Call::Utility(UtilityCall::as_derivative { index: 0, call: Box::new(inner_call) }); + let call = RuntimeCall::Utility(UtilityCall::as_derivative { + index: 0, + call: Box::new(inner_call), + }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); // Diff is refunded assert_eq!(extract_actual_weight(&result, &info), info.weight - diff); // Full weight when err let inner_call = call_foobar(true, start_weight, None); - let call = - Call::Utility(UtilityCall::as_derivative { index: 0, call: Box::new(inner_call) }); + let call = RuntimeCall::Utility(UtilityCall::as_derivative { + index: 0, + call: Box::new(inner_call), + }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_noop!( result, DispatchErrorWithPostInfo { @@ -257,10 +267,12 @@ fn as_derivative_handles_weight_refund() { // Refund weight when err let inner_call = call_foobar(true, start_weight, Some(end_weight)); - let call = - Call::Utility(UtilityCall::as_derivative { index: 0, call: Box::new(inner_call) }); + let call = RuntimeCall::Utility(UtilityCall::as_derivative { + index: 0, + call: Box::new(inner_call), + }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_noop!( result, DispatchErrorWithPostInfo { @@ -280,9 +292,9 @@ fn as_derivative_filters() { new_test_ext().execute_with(|| { assert_err_ignore_postinfo!( Utility::as_derivative( - Origin::signed(1), + RuntimeOrigin::signed(1), 1, - Box::new(Call::Balances(pallet_balances::Call::transfer_keep_alive { + Box::new(RuntimeCall::Balances(pallet_balances::Call::transfer_keep_alive { dest: 2, value: 1 })), @@ -296,16 +308,25 @@ fn as_derivative_filters() { fn batch_with_root_works() { new_test_ext().execute_with(|| { let k = b"a".to_vec(); - let call = - Call::System(frame_system::Call::set_storage { items: vec![(k.clone(), k.clone())] }); + let call = RuntimeCall::System(frame_system::Call::set_storage { + items: vec![(k.clone(), k.clone())], + }); assert!(!TestBaseCallFilter::contains(&call)); assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 10); assert_ok!(Utility::batch( - Origin::root(), + RuntimeOrigin::root(), vec![ - Call::Balances(BalancesCall::force_transfer { source: 1, dest: 2, value: 5 }), - Call::Balances(BalancesCall::force_transfer { source: 1, dest: 2, value: 5 }), + RuntimeCall::Balances(BalancesCall::force_transfer { + source: 1, + dest: 2, + value: 5 + }), + RuntimeCall::Balances(BalancesCall::force_transfer { + source: 1, + dest: 2, + value: 5 + }), call, // Check filters are correctly bypassed ] )); @@ -321,7 +342,7 @@ fn batch_with_signed_works() { assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 10); assert_ok!(Utility::batch( - Origin::signed(1), + RuntimeOrigin::signed(1), vec![call_transfer(2, 5), call_transfer(2, 5)] ),); assert_eq!(Balances::free_balance(1), 0); @@ -333,8 +354,11 @@ fn batch_with_signed_works() { fn batch_with_signed_filters() { new_test_ext().execute_with(|| { assert_ok!(Utility::batch( - Origin::signed(1), - vec![Call::Balances(pallet_balances::Call::transfer_keep_alive { dest: 2, value: 1 })] + RuntimeOrigin::signed(1), + vec![RuntimeCall::Balances(pallet_balances::Call::transfer_keep_alive { + dest: 2, + value: 1 + })] ),); System::assert_last_event( utility::Event::BatchInterrupted { @@ -352,7 +376,7 @@ fn batch_early_exit_works() { assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 10); assert_ok!(Utility::batch( - Origin::signed(1), + RuntimeOrigin::signed(1), vec![call_transfer(2, 5), call_transfer(2, 10), call_transfer(2, 5),] ),); assert_eq!(Balances::free_balance(1), 5); @@ -364,11 +388,12 @@ fn batch_early_exit_works() { fn batch_weight_calculation_doesnt_overflow() { use sp_runtime::Perbill; new_test_ext().execute_with(|| { - let big_call = Call::System(SystemCall::fill_block { ratio: Perbill::from_percent(50) }); + let big_call = + RuntimeCall::System(SystemCall::fill_block { ratio: Perbill::from_percent(50) }); assert_eq!(big_call.get_dispatch_info().weight, Weight::MAX / 2); // 3 * 50% saturates to 100% - let batch_call = Call::Utility(crate::Call::batch { + let batch_call = RuntimeCall::Utility(crate::Call::batch { calls: vec![big_call.clone(), big_call.clone(), big_call.clone()], }); @@ -387,18 +412,18 @@ fn batch_handles_weight_refund() { // Full weight when ok let inner_call = call_foobar(false, start_weight, None); let batch_calls = vec![inner_call; batch_len as usize]; - let call = Call::Utility(UtilityCall::batch { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), info.weight); // Refund weight when ok let inner_call = call_foobar(false, start_weight, Some(end_weight)); let batch_calls = vec![inner_call; batch_len as usize]; - let call = Call::Utility(UtilityCall::batch { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); // Diff is refunded assert_eq!(extract_actual_weight(&result, &info), info.weight - diff * batch_len); @@ -407,9 +432,9 @@ fn batch_handles_weight_refund() { let good_call = call_foobar(false, start_weight, None); let bad_call = call_foobar(true, start_weight, None); let batch_calls = vec![good_call, bad_call]; - let call = Call::Utility(UtilityCall::batch { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); System::assert_last_event( utility::Event::BatchInterrupted { index: 1, error: DispatchError::Other("") }.into(), @@ -422,9 +447,9 @@ fn batch_handles_weight_refund() { let bad_call = call_foobar(true, start_weight, Some(end_weight)); let batch_calls = vec![good_call, bad_call]; let batch_len = batch_calls.len() as u64; - let call = Call::Utility(UtilityCall::batch { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); System::assert_last_event( utility::Event::BatchInterrupted { index: 1, error: DispatchError::Other("") }.into(), @@ -435,9 +460,9 @@ fn batch_handles_weight_refund() { let good_call = call_foobar(false, start_weight, Some(end_weight)); let bad_call = call_foobar(true, start_weight, Some(end_weight)); let batch_calls = vec![good_call, bad_call.clone(), bad_call]; - let call = Call::Utility(UtilityCall::batch { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); System::assert_last_event( utility::Event::BatchInterrupted { index: 1, error: DispatchError::Other("") }.into(), @@ -456,7 +481,7 @@ fn batch_all_works() { assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 10); assert_ok!(Utility::batch_all( - Origin::signed(1), + RuntimeOrigin::signed(1), vec![call_transfer(2, 5), call_transfer(2, 5)] ),); assert_eq!(Balances::free_balance(1), 0); @@ -472,11 +497,11 @@ fn batch_all_revert() { assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 10); - let batch_all_calls = Call::Utility(crate::Call::::batch_all { + let batch_all_calls = RuntimeCall::Utility(crate::Call::::batch_all { calls: vec![call_transfer(2, 5), call_transfer(2, 10), call_transfer(2, 5)], }); assert_noop!( - batch_all_calls.dispatch(Origin::signed(1)), + batch_all_calls.dispatch(RuntimeOrigin::signed(1)), DispatchErrorWithPostInfo { post_info: PostDispatchInfo { actual_weight: Some( @@ -503,18 +528,18 @@ fn batch_all_handles_weight_refund() { // Full weight when ok let inner_call = call_foobar(false, start_weight, None); let batch_calls = vec![inner_call; batch_len as usize]; - let call = Call::Utility(UtilityCall::batch_all { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch_all { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); assert_eq!(extract_actual_weight(&result, &info), info.weight); // Refund weight when ok let inner_call = call_foobar(false, start_weight, Some(end_weight)); let batch_calls = vec![inner_call; batch_len as usize]; - let call = Call::Utility(UtilityCall::batch_all { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch_all { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_ok!(result); // Diff is refunded assert_eq!(extract_actual_weight(&result, &info), info.weight - diff * batch_len); @@ -523,9 +548,9 @@ fn batch_all_handles_weight_refund() { let good_call = call_foobar(false, start_weight, None); let bad_call = call_foobar(true, start_weight, None); let batch_calls = vec![good_call, bad_call]; - let call = Call::Utility(UtilityCall::batch_all { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch_all { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_err_ignore_postinfo!(result, "The cake is a lie."); // No weight is refunded assert_eq!(extract_actual_weight(&result, &info), info.weight); @@ -535,9 +560,9 @@ fn batch_all_handles_weight_refund() { let bad_call = call_foobar(true, start_weight, Some(end_weight)); let batch_calls = vec![good_call, bad_call]; let batch_len = batch_calls.len() as u64; - let call = Call::Utility(UtilityCall::batch_all { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch_all { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_err_ignore_postinfo!(result, "The cake is a lie."); assert_eq!(extract_actual_weight(&result, &info), info.weight - diff * batch_len); @@ -545,9 +570,9 @@ fn batch_all_handles_weight_refund() { let good_call = call_foobar(false, start_weight, Some(end_weight)); let bad_call = call_foobar(true, start_weight, Some(end_weight)); let batch_calls = vec![good_call, bad_call.clone(), bad_call]; - let call = Call::Utility(UtilityCall::batch_all { calls: batch_calls }); + let call = RuntimeCall::Utility(UtilityCall::batch_all { calls: batch_calls }); let info = call.get_dispatch_info(); - let result = call.dispatch(Origin::signed(1)); + let result = call.dispatch(RuntimeOrigin::signed(1)); assert_err_ignore_postinfo!(result, "The cake is a lie."); assert_eq!( extract_actual_weight(&result, &info), @@ -560,7 +585,7 @@ fn batch_all_handles_weight_refund() { #[test] fn batch_all_does_not_nest() { new_test_ext().execute_with(|| { - let batch_all = Call::Utility(UtilityCall::batch_all { + let batch_all = RuntimeCall::Utility(UtilityCall::batch_all { calls: vec![call_transfer(2, 1), call_transfer(2, 1), call_transfer(2, 1)], }); @@ -570,7 +595,7 @@ fn batch_all_does_not_nest() { assert_eq!(Balances::free_balance(2), 10); // A nested batch_all call will not pass the filter, and fail with `BadOrigin`. assert_noop!( - Utility::batch_all(Origin::signed(1), vec![batch_all.clone()]), + Utility::batch_all(RuntimeOrigin::signed(1), vec![batch_all.clone()]), DispatchErrorWithPostInfo { post_info: PostDispatchInfo { actual_weight: Some(::WeightInfo::batch_all(1) + info.weight), @@ -583,10 +608,10 @@ fn batch_all_does_not_nest() { // And for those who want to get a little fancy, we check that the filter persists across // other kinds of dispatch wrapping functions... in this case // `batch_all(batch(batch_all(..)))` - let batch_nested = Call::Utility(UtilityCall::batch { calls: vec![batch_all] }); + let batch_nested = RuntimeCall::Utility(UtilityCall::batch { calls: vec![batch_all] }); // Batch will end with `Ok`, but does not actually execute as we can see from the event // and balances. - assert_ok!(Utility::batch_all(Origin::signed(1), vec![batch_nested])); + assert_ok!(Utility::batch_all(RuntimeOrigin::signed(1), vec![batch_nested])); System::assert_has_event( utility::Event::BatchInterrupted { index: 0, @@ -602,9 +627,15 @@ fn batch_all_does_not_nest() { #[test] fn batch_limit() { new_test_ext().execute_with(|| { - let calls = vec![Call::System(SystemCall::remark { remark: vec![] }); 40_000]; - assert_noop!(Utility::batch(Origin::signed(1), calls.clone()), Error::::TooManyCalls); - assert_noop!(Utility::batch_all(Origin::signed(1), calls), Error::::TooManyCalls); + let calls = vec![RuntimeCall::System(SystemCall::remark { remark: vec![] }); 40_000]; + assert_noop!( + Utility::batch(RuntimeOrigin::signed(1), calls.clone()), + Error::::TooManyCalls + ); + assert_noop!( + Utility::batch_all(RuntimeOrigin::signed(1), calls), + Error::::TooManyCalls + ); }); } @@ -614,7 +645,7 @@ fn force_batch_works() { assert_eq!(Balances::free_balance(1), 10); assert_eq!(Balances::free_balance(2), 10); assert_ok!(Utility::force_batch( - Origin::signed(1), + RuntimeOrigin::signed(1), vec![ call_transfer(2, 5), call_foobar(true, Weight::from_ref_time(75), None), @@ -630,12 +661,12 @@ fn force_batch_works() { assert_eq!(Balances::free_balance(2), 20); assert_ok!(Utility::force_batch( - Origin::signed(2), + RuntimeOrigin::signed(2), vec![call_transfer(1, 5), call_transfer(1, 5),] )); System::assert_last_event(utility::Event::BatchCompleted.into()); - assert_ok!(Utility::force_batch(Origin::signed(1), vec![call_transfer(2, 50),]),); + assert_ok!(Utility::force_batch(RuntimeOrigin::signed(1), vec![call_transfer(2, 50),]),); System::assert_last_event(utility::Event::BatchCompletedWithErrors.into()); }); } @@ -643,8 +674,8 @@ fn force_batch_works() { #[test] fn none_origin_does_not_work() { new_test_ext().execute_with(|| { - assert_noop!(Utility::force_batch(Origin::none(), vec![]), BadOrigin); - assert_noop!(Utility::batch(Origin::none(), vec![]), BadOrigin); - assert_noop!(Utility::batch_all(Origin::none(), vec![]), BadOrigin); + assert_noop!(Utility::force_batch(RuntimeOrigin::none(), vec![]), BadOrigin); + assert_noop!(Utility::batch(RuntimeOrigin::none(), vec![]), BadOrigin); + assert_noop!(Utility::batch_all(RuntimeOrigin::none(), vec![]), BadOrigin); }) } diff --git a/frame/vesting-mangata/src/lib.rs b/frame/vesting-mangata/src/lib.rs index 5b47aa43270ef..5f13f1596d889 100644 --- a/frame/vesting-mangata/src/lib.rs +++ b/frame/vesting-mangata/src/lib.rs @@ -152,7 +152,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The tokens trait. type Tokens: MultiTokenLockableCurrency; diff --git a/frame/vesting/Cargo.toml b/frame/vesting/Cargo.toml index eb902c0633331..6a64b474d1485 100644 --- a/frame/vesting/Cargo.toml +++ b/frame/vesting/Cargo.toml @@ -32,6 +32,7 @@ sp-io = { version = "6.0.0", default-features = false, path = "../../primitives/ [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/vesting/README.md b/frame/vesting/README.md index c3800eb994d4d..b19a60c5b6824 100644 --- a/frame/vesting/README.md +++ b/frame/vesting/README.md @@ -7,7 +7,8 @@ A simple module providing a means of placing a linear curve on an account's locked balance. This module ensures that there is a lock in place preventing the balance to drop below the *unvested* -amount for any reason other than transaction fee payment. +amount for reason other than the ones specified in `UnvestedFundsAllowedWithdrawReasons` +configuration value. As the amount vested increases over time, the amount unvested reduces. However, locks remain in place and explicit action is needed on behalf of the user to ensure that the amount locked is diff --git a/frame/vesting/src/lib.rs b/frame/vesting/src/lib.rs index 8ac625e775e4f..a92f94baf6cf9 100644 --- a/frame/vesting/src/lib.rs +++ b/frame/vesting/src/lib.rs @@ -24,7 +24,8 @@ //! //! A simple pallet providing a means of placing a linear curve on an account's locked balance. This //! pallet ensures that there is a lock in place preventing the balance to drop below the *unvested* -//! amount for any reason other than transaction fee payment. +//! amount for any reason other than the ones specified in `UnvestedFundsAllowedWithdrawReasons` +//! configuration value. //! //! As the amount vested increases over time, the amount unvested reduces. However, locks remain in //! place and explicit action is needed on behalf of the user to ensure that the amount locked is @@ -155,7 +156,7 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The currency trait. type Currency: LockableCurrency; @@ -170,6 +171,10 @@ pub mod pallet { /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; + /// Reasons that determine under which conditions the balance may drop below + /// the unvested amount. + type UnvestedFundsAllowedWithdrawReasons: Get; + /// Maximum number of vesting schedules an account may have at a given moment. const MAX_VESTING_SCHEDULES: u32; } @@ -249,7 +254,9 @@ pub mod pallet { Vesting::::try_append(who, vesting_info) .expect("Too many vesting schedules at genesis."); - let reasons = WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE; + let reasons = + WithdrawReasons::except(T::UnvestedFundsAllowedWithdrawReasons::get()); + T::Currency::set_lock(VESTING_ID, who, locked, reasons); } } @@ -569,7 +576,7 @@ impl Pallet { T::Currency::remove_lock(VESTING_ID, who); Self::deposit_event(Event::::VestingCompleted { account: who.clone() }); } else { - let reasons = WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE; + let reasons = WithdrawReasons::except(T::UnvestedFundsAllowedWithdrawReasons::get()); T::Currency::set_lock(VESTING_ID, who, total_locked_now, reasons); Self::deposit_event(Event::::VestingUpdated { account: who.clone(), diff --git a/frame/vesting/src/mock.rs b/frame/vesting/src/mock.rs index 8875404f03fa2..0bd371a0353f1 100644 --- a/frame/vesting/src/mock.rs +++ b/frame/vesting/src/mock.rs @@ -17,7 +17,7 @@ use frame_support::{ parameter_types, - traits::{ConstU32, ConstU64, GenesisBuild}, + traits::{ConstU32, ConstU64, GenesisBuild, WithdrawReasons}, }; use sp_core::H256; use sp_runtime::{ @@ -55,9 +55,9 @@ impl frame_system::Config for Test { type BlockLength = (); type BlockNumber = u64; type BlockWeights = (); - type Call = Call; + type RuntimeCall = RuntimeCall; type DbWeight = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Hash = H256; type Hashing = BlakeTwo256; type Header = Header; @@ -67,7 +67,7 @@ impl frame_system::Config for Test { type OnNewAccount = (); type OnSetCode = (); type MaxConsumers = frame_support::traits::ConstU32<16>; - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type PalletInfo = PalletInfo; type SS58Prefix = (); type SystemWeightInfo = (); @@ -78,7 +78,7 @@ impl pallet_balances::Config for Test { type AccountStore = System; type Balance = u64; type DustRemoval = (); - type Event = Event; + type RuntimeEvent = RuntimeEvent; type ExistentialDeposit = ExistentialDeposit; type MaxLocks = ConstU32<10>; type MaxReserves = (); @@ -87,15 +87,18 @@ impl pallet_balances::Config for Test { } parameter_types! { pub const MinVestedTransfer: u64 = 256 * 2; + pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons = + WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); pub static ExistentialDeposit: u64 = 0; } impl Config for Test { type BlockNumberToBalance = Identity; type Currency = Balances; - type Event = Event; + type RuntimeEvent = RuntimeEvent; const MAX_VESTING_SCHEDULES: u32 = 3; type MinVestedTransfer = MinVestedTransfer; type WeightInfo = (); + type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; } pub struct ExtBuilder { diff --git a/frame/whitelist/Cargo.toml b/frame/whitelist/Cargo.toml index daee560904a08..895a6e753816d 100644 --- a/frame/whitelist/Cargo.toml +++ b/frame/whitelist/Cargo.toml @@ -31,6 +31,7 @@ sp-io = { version = "6.0.0", path = "../../primitives/io" } [features] default = ["std"] std = [ + "frame-benchmarking?/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/frame/whitelist/src/benchmarking.rs b/frame/whitelist/src/benchmarking.rs index cafd1668819dd..e0a758b2ddfdf 100644 --- a/frame/whitelist/src/benchmarking.rs +++ b/frame/whitelist/src/benchmarking.rs @@ -33,7 +33,7 @@ benchmarks! { whitelist_call { let origin = T::WhitelistOrigin::successful_origin(); let call_hash = Default::default(); - }: _(origin, call_hash) + }: _(origin, call_hash) verify { ensure!( WhitelistedCall::::contains_key(call_hash), @@ -50,7 +50,7 @@ benchmarks! { let call_hash = Default::default(); Pallet::::whitelist_call(origin.clone(), call_hash) .expect("whitelisting call must be successful"); - }: _(origin, call_hash) + }: _(origin, call_hash) verify { ensure!( !WhitelistedCall::::contains_key(call_hash), @@ -71,7 +71,7 @@ benchmarks! { let remark_len = >::MaxSize::get() - 10; let remark = sp_std::vec![1u8; remark_len as usize]; - let call: ::Call = frame_system::Call::remark { remark }.into(); + let call: ::RuntimeCall = frame_system::Call::remark { remark }.into(); let call_weight = call.get_dispatch_info().weight; let encoded_call = call.encode(); let call_hash = T::Hashing::hash(&encoded_call[..]); @@ -82,7 +82,7 @@ benchmarks! { let encoded_call = encoded_call.try_into().expect("encoded_call must be small enough"); T::PreimageProvider::note_preimage(encoded_call); - }: _(origin, call_hash, call_weight) + }: _(origin, call_hash, call_weight) verify { ensure!( !WhitelistedCall::::contains_key(call_hash), @@ -100,12 +100,12 @@ benchmarks! { let origin = T::DispatchWhitelistedOrigin::successful_origin(); let remark = sp_std::vec![1u8; n as usize]; - let call: ::Call = frame_system::Call::remark { remark }.into(); + let call: ::RuntimeCall = frame_system::Call::remark { remark }.into(); let call_hash = T::Hashing::hash_of(&call); Pallet::::whitelist_call(origin.clone(), call_hash) .expect("whitelisting call must be successful"); - }: _(origin, Box::new(call)) + }: _(origin, Box::new(call)) verify { ensure!( !WhitelistedCall::::contains_key(call_hash), diff --git a/frame/whitelist/src/lib.rs b/frame/whitelist/src/lib.rs index 5fb4e3aeb9ba6..55d5c42b8f4bc 100644 --- a/frame/whitelist/src/lib.rs +++ b/frame/whitelist/src/lib.rs @@ -42,9 +42,10 @@ pub use weights::WeightInfo; use codec::{DecodeLimit, Encode, FullCodec}; use frame_support::{ + dispatch::{GetDispatchInfo, PostDispatchInfo}, ensure, traits::{PreimageProvider, PreimageRecipient}, - weights::{GetDispatchInfo, PostDispatchInfo, Weight}, + weights::Weight, }; use scale_info::TypeInfo; use sp_runtime::traits::{Dispatchable, Hash}; @@ -61,11 +62,11 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { /// The overarching event type. - type Event: From> + IsType<::Event>; + type RuntimeEvent: From> + IsType<::RuntimeEvent>; /// The overarching call type. - type Call: IsType<::Call> - + Dispatchable + type RuntimeCall: IsType<::RuntimeCall> + + Dispatchable + GetDispatchInfo + FullCodec + TypeInfo @@ -73,10 +74,10 @@ pub mod pallet { + Parameter; /// Required origin for whitelisting a call. - type WhitelistOrigin: EnsureOrigin; + type WhitelistOrigin: EnsureOrigin; /// Required origin for dispatching whitelisted call with root origin. - type DispatchWhitelistedOrigin: EnsureOrigin; + type DispatchWhitelistedOrigin: EnsureOrigin; /// The handler of pre-images. // NOTE: recipient is only needed for benchmarks. @@ -165,14 +166,14 @@ pub mod pallet { let call = T::PreimageProvider::get_preimage(&call_hash) .ok_or(Error::::UnavailablePreImage)?; - let call = ::Call::decode_all_with_depth_limit( + let call = ::RuntimeCall::decode_all_with_depth_limit( sp_api::MAX_EXTRINSIC_DEPTH, &mut &call[..], ) .map_err(|_| Error::::UndecodableCall)?; ensure!( - call.get_dispatch_info().weight <= call_weight_witness, + call.get_dispatch_info().weight.all_lte(call_weight_witness), Error::::InvalidCallWeightWitness ); @@ -191,7 +192,7 @@ pub mod pallet { })] pub fn dispatch_whitelisted_call_with_preimage( origin: OriginFor, - call: Box<::Call>, + call: Box<::RuntimeCall>, ) -> DispatchResultWithPostInfo { T::DispatchWhitelistedOrigin::ensure_origin(origin)?; @@ -216,7 +217,7 @@ impl Pallet { /// Clean whitelisting/preimage and dispatch call. /// /// Return the call actual weight of the dispatched call if there is some. - fn clean_and_dispatch(call_hash: T::Hash, call: ::Call) -> Option { + fn clean_and_dispatch(call_hash: T::Hash, call: ::RuntimeCall) -> Option { WhitelistedCall::::remove(call_hash); T::PreimageProvider::unrequest_preimage(&call_hash); diff --git a/frame/whitelist/src/mock.rs b/frame/whitelist/src/mock.rs index b18236099d445..d4446cb8031ab 100644 --- a/frame/whitelist/src/mock.rs +++ b/frame/whitelist/src/mock.rs @@ -58,16 +58,16 @@ impl frame_system::Config for Test { type BlockWeights = (); type BlockLength = (); type DbWeight = (); - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Index = u64; type BlockNumber = u64; type Hash = H256; - type Call = Call; + type RuntimeCall = RuntimeCall; type Hashing = BlakeTwo256; type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); type PalletInfo = PalletInfo; @@ -85,7 +85,7 @@ impl pallet_balances::Config for Test { type MaxReserves = (); type ReserveIdentifier = [u8; 8]; type Balance = u64; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<1>; type AccountStore = System; @@ -93,18 +93,17 @@ impl pallet_balances::Config for Test { } impl pallet_preimage::Config for Test { - type Event = Event; + type RuntimeEvent = RuntimeEvent; type Currency = Balances; type ManagerOrigin = EnsureRoot; - type MaxSize = ConstU32<{ 4096 * 1024 }>; // PreimageMaxSize Taken from Polkadot as reference. type BaseDeposit = ConstU64<1>; type ByteDeposit = ConstU64<1>; type WeightInfo = (); } impl pallet_whitelist::Config for Test { - type Event = Event; - type Call = Call; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; type WhitelistOrigin = EnsureRoot; type DispatchWhitelistedOrigin = EnsureRoot; type PreimageProvider = Preimage; diff --git a/frame/whitelist/src/tests.rs b/frame/whitelist/src/tests.rs index 24974bd726d43..fd6558e83f30e 100644 --- a/frame/whitelist/src/tests.rs +++ b/frame/whitelist/src/tests.rs @@ -27,40 +27,40 @@ use sp_runtime::{traits::Hash, DispatchError}; #[test] fn test_whitelist_call_and_remove() { new_test_ext().execute_with(|| { - let call = Call::System(frame_system::Call::remark { remark: vec![] }); + let call = RuntimeCall::System(frame_system::Call::remark { remark: vec![] }); let encoded_call = call.encode(); let call_hash = ::Hashing::hash(&encoded_call[..]); assert_noop!( - Whitelist::remove_whitelisted_call(Origin::root(), call_hash), + Whitelist::remove_whitelisted_call(RuntimeOrigin::root(), call_hash), crate::Error::::CallIsNotWhitelisted, ); assert_noop!( - Whitelist::whitelist_call(Origin::signed(1), call_hash), + Whitelist::whitelist_call(RuntimeOrigin::signed(1), call_hash), DispatchError::BadOrigin, ); - assert_ok!(Whitelist::whitelist_call(Origin::root(), call_hash)); + assert_ok!(Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash)); assert!(Preimage::preimage_requested(&call_hash)); assert_noop!( - Whitelist::whitelist_call(Origin::root(), call_hash), + Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash), crate::Error::::CallAlreadyWhitelisted, ); assert_noop!( - Whitelist::remove_whitelisted_call(Origin::signed(1), call_hash), + Whitelist::remove_whitelisted_call(RuntimeOrigin::signed(1), call_hash), DispatchError::BadOrigin, ); - assert_ok!(Whitelist::remove_whitelisted_call(Origin::root(), call_hash)); + assert_ok!(Whitelist::remove_whitelisted_call(RuntimeOrigin::root(), call_hash)); assert!(!Preimage::preimage_requested(&call_hash)); assert_noop!( - Whitelist::remove_whitelisted_call(Origin::root(), call_hash), + Whitelist::remove_whitelisted_call(RuntimeOrigin::root(), call_hash), crate::Error::::CallIsNotWhitelisted, ); }); @@ -69,47 +69,51 @@ fn test_whitelist_call_and_remove() { #[test] fn test_whitelist_call_and_execute() { new_test_ext().execute_with(|| { - let call = Call::System(frame_system::Call::remark_with_event { remark: vec![1] }); + let call = RuntimeCall::System(frame_system::Call::remark_with_event { remark: vec![1] }); let call_weight = call.get_dispatch_info().weight; let encoded_call = call.encode(); let call_hash = ::Hashing::hash(&encoded_call[..]); assert_noop!( - Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight), + Whitelist::dispatch_whitelisted_call(RuntimeOrigin::root(), call_hash, call_weight), crate::Error::::CallIsNotWhitelisted, ); - assert_ok!(Whitelist::whitelist_call(Origin::root(), call_hash)); + assert_ok!(Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash)); assert_noop!( - Whitelist::dispatch_whitelisted_call(Origin::signed(1), call_hash, call_weight), + Whitelist::dispatch_whitelisted_call(RuntimeOrigin::signed(1), call_hash, call_weight), DispatchError::BadOrigin, ); assert_noop!( - Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight), + Whitelist::dispatch_whitelisted_call(RuntimeOrigin::root(), call_hash, call_weight), crate::Error::::UnavailablePreImage, ); - assert_ok!(Preimage::note_preimage(Origin::root(), encoded_call)); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::root(), encoded_call)); assert!(Preimage::preimage_requested(&call_hash)); assert_noop!( Whitelist::dispatch_whitelisted_call( - Origin::root(), + RuntimeOrigin::root(), call_hash, call_weight - Weight::from_ref_time(1) ), crate::Error::::InvalidCallWeightWitness, ); - assert_ok!(Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight)); + assert_ok!(Whitelist::dispatch_whitelisted_call( + RuntimeOrigin::root(), + call_hash, + call_weight + )); assert!(!Preimage::preimage_requested(&call_hash)); assert_noop!( - Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight), + Whitelist::dispatch_whitelisted_call(RuntimeOrigin::root(), call_hash, call_weight), crate::Error::::CallIsNotWhitelisted, ); }); @@ -118,7 +122,7 @@ fn test_whitelist_call_and_execute() { #[test] fn test_whitelist_call_and_execute_failing_call() { new_test_ext().execute_with(|| { - let call = Call::Whitelist(crate::Call::dispatch_whitelisted_call { + let call = RuntimeCall::Whitelist(crate::Call::dispatch_whitelisted_call { call_hash: Default::default(), call_weight_witness: Weight::zero(), }); @@ -126,10 +130,14 @@ fn test_whitelist_call_and_execute_failing_call() { let encoded_call = call.encode(); let call_hash = ::Hashing::hash(&encoded_call[..]); - assert_ok!(Whitelist::whitelist_call(Origin::root(), call_hash)); - assert_ok!(Preimage::note_preimage(Origin::root(), encoded_call)); + assert_ok!(Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash)); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::root(), encoded_call)); assert!(Preimage::preimage_requested(&call_hash)); - assert_ok!(Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight)); + assert_ok!(Whitelist::dispatch_whitelisted_call( + RuntimeOrigin::root(), + call_hash, + call_weight + )); assert!(!Preimage::preimage_requested(&call_hash)); }); } @@ -137,22 +145,23 @@ fn test_whitelist_call_and_execute_failing_call() { #[test] fn test_whitelist_call_and_execute_without_note_preimage() { new_test_ext().execute_with(|| { - let call = - Box::new(Call::System(frame_system::Call::remark_with_event { remark: vec![1] })); + let call = Box::new(RuntimeCall::System(frame_system::Call::remark_with_event { + remark: vec![1], + })); let call_hash = ::Hashing::hash_of(&call); - assert_ok!(Whitelist::whitelist_call(Origin::root(), call_hash)); + assert_ok!(Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash)); assert!(Preimage::preimage_requested(&call_hash)); assert_ok!(Whitelist::dispatch_whitelisted_call_with_preimage( - Origin::root(), + RuntimeOrigin::root(), call.clone() )); assert!(!Preimage::preimage_requested(&call_hash)); assert_noop!( - Whitelist::dispatch_whitelisted_call_with_preimage(Origin::root(), call), + Whitelist::dispatch_whitelisted_call_with_preimage(RuntimeOrigin::root(), call), crate::Error::::CallIsNotWhitelisted, ); }); @@ -161,7 +170,7 @@ fn test_whitelist_call_and_execute_without_note_preimage() { #[test] fn test_whitelist_call_and_execute_decode_consumes_all() { new_test_ext().execute_with(|| { - let call = Call::System(frame_system::Call::remark_with_event { remark: vec![1] }); + let call = RuntimeCall::System(frame_system::Call::remark_with_event { remark: vec![1] }); let call_weight = call.get_dispatch_info().weight; let mut call = call.encode(); // Appending something does not make the encoded call invalid. @@ -170,11 +179,11 @@ fn test_whitelist_call_and_execute_decode_consumes_all() { let call_hash = ::Hashing::hash(&call[..]); - assert_ok!(Preimage::note_preimage(Origin::root(), call)); - assert_ok!(Whitelist::whitelist_call(Origin::root(), call_hash)); + assert_ok!(Preimage::note_preimage(RuntimeOrigin::root(), call)); + assert_ok!(Whitelist::whitelist_call(RuntimeOrigin::root(), call_hash)); assert_noop!( - Whitelist::dispatch_whitelisted_call(Origin::root(), call_hash, call_weight), + Whitelist::dispatch_whitelisted_call(RuntimeOrigin::root(), call_hash, call_weight), crate::Error::::UndecodableCall, ); }); diff --git a/primitives/api/Cargo.toml b/primitives/api/Cargo.toml index 75c935bf844bd..a322799048a31 100644 --- a/primitives/api/Cargo.toml +++ b/primitives/api/Cargo.toml @@ -19,8 +19,8 @@ sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-version = { version = "5.0.0", default-features = false, path = "../version" } -sp-state-machine = { version = "0.12.0", optional = true, path = "../state-machine" } -sp-trie = { version = "6.0.0", optional = true, path = "../trie" } +sp-state-machine = { version = "0.12.0", default-features = false, optional = true, path = "../state-machine" } +sp-trie = { version = "6.0.0", default-features = false, optional = true, path = "../trie" } hash-db = { version = "0.15.2", optional = true } thiserror = { version = "1.0.30", optional = true } @@ -36,8 +36,8 @@ std = [ "sp-core/std", "sp-std/std", "sp-runtime/std", - "sp-state-machine", - "sp-trie", + "sp-state-machine/std", + "sp-trie/std", "sp-version/std", "hash-db", "thiserror", diff --git a/primitives/api/proc-macro/Cargo.toml b/primitives/api/proc-macro/Cargo.toml index 0a57be8d7a300..8acc15d6a0591 100644 --- a/primitives/api/proc-macro/Cargo.toml +++ b/primitives/api/proc-macro/Cargo.toml @@ -19,7 +19,7 @@ proc-macro = true quote = "1.0.10" syn = { version = "1.0.98", features = ["full", "fold", "extra-traits", "visit"] } proc-macro2 = "1.0.37" -blake2 = { version = "0.10.2", default-features = false } +blake2 = { version = "0.10.4", default-features = false } proc-macro-crate = "1.1.3" # Required for the doc tests diff --git a/primitives/api/proc-macro/src/decl_runtime_apis.rs b/primitives/api/proc-macro/src/decl_runtime_apis.rs index aac4491720c34..8d46047dbda5a 100644 --- a/primitives/api/proc-macro/src/decl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/decl_runtime_apis.rs @@ -535,7 +535,7 @@ impl<'a> Fold for ToClientSideDecl<'a> { if is_core_trait { // Add all the supertraits we want to have for `Core`. - input.supertraits = parse_quote!('static + Send + Sync); + input.supertraits = parse_quote!('static + Send); } else { // Add the `Core` runtime api as super trait. let crate_ = &self.crate_; diff --git a/primitives/api/proc-macro/src/impl_runtime_apis.rs b/primitives/api/proc-macro/src/impl_runtime_apis.rs index 5ab8fa0521699..c3f4e36655d22 100644 --- a/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -211,19 +211,6 @@ fn generate_runtime_api_base_structures() -> Result { recorder: std::option::Option<#crate_::ProofRecorder>, } - // `RuntimeApi` itself is not threadsafe. However, an instance is only available in a - // `ApiRef` object and `ApiRef` also has an associated lifetime. This lifetimes makes it - // impossible to move `RuntimeApi` into another thread. - #[cfg(any(feature = "std", test))] - unsafe impl> Send - for RuntimeApiImpl - {} - - #[cfg(any(feature = "std", test))] - unsafe impl> Sync - for RuntimeApiImpl - {} - #[cfg(any(feature = "std", test))] impl> #crate_::ApiExt for RuntimeApiImpl @@ -449,28 +436,30 @@ impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> { } let res = (|| { - let version = #crate_::CallApiAt::<__SR_API_BLOCK__>::runtime_version_at(self.call, at)?; - - let params = #crate_::CallApiAtParams::<_, fn() -> _, _> { - at, - function: (*fn_name)(version), - native_call: None, - arguments: params, - overlayed_changes: &self.changes, - storage_transaction_cache: &self.storage_transaction_cache, - context, - recorder: &self.recorder, - }; - - #crate_::CallApiAt::<__SR_API_BLOCK__>::call_api_at::<#crate_::NeverNativeValue, _>( - self.call, - params, - ) - })(); + let version = #crate_::CallApiAt::<__SR_API_BLOCK__>::runtime_version_at( + self.call, + at, + )?; + + let params = #crate_::CallApiAtParams { + at, + function: (*fn_name)(version), + arguments: params, + overlayed_changes: &self.changes, + storage_transaction_cache: &self.storage_transaction_cache, + context, + recorder: &self.recorder, + }; + + #crate_::CallApiAt::<__SR_API_BLOCK__>::call_api_at( + self.call, + params, + ) + })(); self.commit_or_rollback(std::result::Result::is_ok(&res)); - res.map(#crate_::NativeOrEncoded::into_encoded) + res } }); @@ -513,6 +502,8 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> { #crate_::StateBackend<#crate_::HashFor<__SR_API_BLOCK__>> }); + where_clause.predicates.push(parse_quote! { &'static RuntimeApiImplCall: Send }); + // Require that all types used in the function signatures are unwind safe. extract_all_signature_types(&input.items).iter().for_each(|i| { where_clause.predicates.push(parse_quote! { diff --git a/primitives/api/src/lib.rs b/primitives/api/src/lib.rs index 353ebd91cf5df..91d4b07a1cefc 100644 --- a/primitives/api/src/lib.rs +++ b/primitives/api/src/lib.rs @@ -83,8 +83,6 @@ use sp_core::OpaqueMetadata; pub use sp_core::{offchain, ExecutionContext}; #[doc(hidden)] #[cfg(feature = "std")] -pub use sp_core::{NativeOrEncoded, NeverNativeValue}; -#[cfg(feature = "std")] pub use sp_runtime::StateVersion; #[doc(hidden)] pub use sp_runtime::{ @@ -102,14 +100,12 @@ pub use sp_state_machine::{ backend::AsTrieBackend, Backend as StateBackend, InMemoryBackend, OverlayedChanges, StorageProof, TrieBackend, TrieBackendBuilder, }; -#[cfg(feature = "std")] -use sp_std::result; #[doc(hidden)] pub use sp_std::{mem, slice}; #[doc(hidden)] pub use sp_version::{create_apis_vec, ApiId, ApisVec, RuntimeVersion}; #[cfg(feature = "std")] -use std::{cell::RefCell, panic::UnwindSafe}; +use std::cell::RefCell; /// Maximum nesting level for extrinsics. pub const MAX_EXTRINSIC_DEPTH: u32 = 256; @@ -590,16 +586,11 @@ pub trait ApiExt { /// Parameters for [`CallApiAt::call_api_at`]. #[cfg(feature = "std")] -pub struct CallApiAtParams<'a, Block: BlockT, NC, Backend: StateBackend>> { +pub struct CallApiAtParams<'a, Block: BlockT, Backend: StateBackend>> { /// The block id that determines the state that should be setup when calling the function. pub at: &'a BlockId, /// The name of the function that should be called. pub function: &'static str, - /// An optional native call that calls the `function`. This is an optimization to call into a - /// native runtime without requiring to encode/decode the parameters. The native runtime can - /// still be called when this value is `None`, we then just fallback to encoding/decoding the - /// parameters. - pub native_call: Option, /// The encoded arguments of the function. pub arguments: Vec, /// The overlayed changes that are on top of the state. @@ -620,13 +611,10 @@ pub trait CallApiAt { /// Calls the given api function with the given encoded arguments at the given block and returns /// the encoded result. - fn call_api_at< - R: Encode + Decode + PartialEq, - NC: FnOnce() -> result::Result + UnwindSafe, - >( + fn call_api_at( &self, - params: CallApiAtParams, - ) -> Result, ApiError>; + params: CallApiAtParams, + ) -> Result, ApiError>; /// Returns the runtime version at the given block. fn runtime_version_at(&self, at: &BlockId) -> Result; diff --git a/primitives/api/test/benches/bench.rs b/primitives/api/test/benches/bench.rs index 2682c91f94106..2445a5c07f09e 100644 --- a/primitives/api/test/benches/bench.rs +++ b/primitives/api/test/benches/bench.rs @@ -27,14 +27,14 @@ fn sp_api_benchmark(c: &mut Criterion) { c.bench_function("add one with same runtime api", |b| { let client = substrate_test_runtime_client::new(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); b.iter(|| runtime_api.benchmark_add_one(&block_id, &1)) }); c.bench_function("add one with recreating runtime api", |b| { let client = substrate_test_runtime_client::new(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); b.iter(|| client.runtime_api().benchmark_add_one(&block_id, &1)) }); @@ -42,7 +42,7 @@ fn sp_api_benchmark(c: &mut Criterion) { c.bench_function("vector add one with same runtime api", |b| { let client = substrate_test_runtime_client::new(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); let data = vec![0; 1000]; b.iter_with_large_drop(|| runtime_api.benchmark_vector_add_one(&block_id, &data)) @@ -50,7 +50,7 @@ fn sp_api_benchmark(c: &mut Criterion) { c.bench_function("vector add one with recreating runtime api", |b| { let client = substrate_test_runtime_client::new(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); let data = vec![0; 1000]; b.iter_with_large_drop(|| client.runtime_api().benchmark_vector_add_one(&block_id, &data)) @@ -60,7 +60,7 @@ fn sp_api_benchmark(c: &mut Criterion) { let client = TestClientBuilder::new() .set_execution_strategy(ExecutionStrategy::AlwaysWasm) .build(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); b.iter(|| client.runtime_api().benchmark_indirect_call(&block_id).unwrap()) }); @@ -68,7 +68,7 @@ fn sp_api_benchmark(c: &mut Criterion) { let client = TestClientBuilder::new() .set_execution_strategy(ExecutionStrategy::AlwaysWasm) .build(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); b.iter(|| client.runtime_api().benchmark_direct_call(&block_id).unwrap()) }); } diff --git a/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr b/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr index 2c47c2f480add..f5b6ac1da4576 100644 --- a/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr +++ b/primitives/api/test/tests/ui/impl_incorrect_method_signature.stderr @@ -18,5 +18,18 @@ note: type in trait error[E0308]: mismatched types --> tests/ui/impl_incorrect_method_signature.rs:19:11 | -19 | fn test(data: String) {} - | ^^^^ expected `u64`, found struct `std::string::String` +17 | / sp_api::impl_runtime_apis! { +18 | | impl self::Api for Runtime { +19 | | fn test(data: String) {} + | | ^^^^ expected `u64`, found struct `std::string::String` +20 | | } +... | +32 | | } +33 | | } + | |_- arguments to this function are incorrect + | +note: associated function defined here + --> tests/ui/impl_incorrect_method_signature.rs:13:6 + | +13 | fn test(data: u64); + | ^^^^ diff --git a/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr b/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr index 479e1cf05a9d1..6a99dcd3a1aed 100644 --- a/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr +++ b/primitives/api/test/tests/ui/type_reference_in_impl_runtime_apis_call.stderr @@ -18,9 +18,21 @@ note: type in trait error[E0308]: mismatched types --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:19:11 | -19 | fn test(data: &u64) { - | ^^^^^^^ expected `u64`, found `&u64` +17 | / sp_api::impl_runtime_apis! { +18 | | impl self::Api for Runtime { +19 | | fn test(data: &u64) { + | | ^^^^^^^ expected `u64`, found `&u64` +20 | | unimplemented!() +... | +34 | | } +35 | | } + | |_- arguments to this function are incorrect + | +note: associated function defined here + --> tests/ui/type_reference_in_impl_runtime_apis_call.rs:13:6 | +13 | fn test(data: u64); + | ^^^^ help: consider removing the borrow | 19 - fn test(data: &u64) { diff --git a/primitives/arithmetic/Cargo.toml b/primitives/arithmetic/Cargo.toml index d7046b3254699..60eac2247e830 100644 --- a/primitives/arithmetic/Cargo.toml +++ b/primitives/arithmetic/Cargo.toml @@ -28,7 +28,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] criterion = "0.3" -primitive-types = "0.11.1" +primitive-types = "0.12.0" sp-core = { version = "6.0.0", features = ["full_crypto"], path = "../core" } rand = "0.7.2" diff --git a/primitives/arithmetic/fuzzer/Cargo.toml b/primitives/arithmetic/fuzzer/Cargo.toml index 990106f990323..b1ffa746b6b63 100644 --- a/primitives/arithmetic/fuzzer/Cargo.toml +++ b/primitives/arithmetic/fuzzer/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] honggfuzz = "0.5.49" num-bigint = "0.2" -primitive-types = "0.11.1" +primitive-types = "0.12.0" sp-arithmetic = { version = "5.0.0", path = ".." } [[bin]] diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs index 2932a742063db..baf4d95973fa0 100644 --- a/primitives/arithmetic/src/per_things.rs +++ b/primitives/arithmetic/src/per_things.rs @@ -547,16 +547,18 @@ where rem_mul_div_inner += 1.into(); } }, - Rounding::NearestPrefDown => + Rounding::NearestPrefDown => { if rem_mul_upper % denom_upper > denom_upper / 2.into() { // `rem * numer / denom` is less than `numer`, so this will not overflow. rem_mul_div_inner += 1.into(); - }, - Rounding::NearestPrefUp => + } + }, + Rounding::NearestPrefUp => { if rem_mul_upper % denom_upper >= denom_upper / 2.into() + denom_upper % 2.into() { // `rem * numer / denom` is less than `numer`, so this will not overflow. rem_mul_div_inner += 1.into(); - }, + } + }, } rem_mul_div_inner.into() } diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index 320a30770ab42..22e41b5130abb 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -14,16 +14,18 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } sp-core = { version = "6.0.0", default-features = false, path = "../core" } +sp-io = { version = "6.0.0", default-features = false, path = "../io" } +sp-mmr-primitives = { version = "4.0.0-dev", default-features = false, path = "../merkle-mountain-range" } sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] -hex = "0.4.3" -hex-literal = "0.3" +array-bytes = "4.1" sp-keystore = { version = "0.12.0", path = "../keystore" } [features] @@ -31,9 +33,12 @@ default = ["std"] std = [ "codec/std", "scale-info/std", + "serde", "sp-api/std", "sp-application-crypto/std", "sp-core/std", + "sp-io/std", + "sp-mmr-primitives/std", "sp-runtime/std", "sp-std/std", ] diff --git a/primitives/beefy/src/commitment.rs b/primitives/beefy/src/commitment.rs index ddf58474e77a0..5765ff3609dbb 100644 --- a/primitives/beefy/src/commitment.rs +++ b/primitives/beefy/src/commitment.rs @@ -16,63 +16,10 @@ // limitations under the License. use codec::{Decode, Encode, Error, Input}; +use scale_info::TypeInfo; use sp_std::{cmp, prelude::*}; -use crate::ValidatorSetId; - -/// Id of different payloads in the [`Commitment`] data -pub type BeefyPayloadId = [u8; 2]; - -/// Registry of all known [`BeefyPayloadId`]. -pub mod known_payload_ids { - use crate::BeefyPayloadId; - - /// A [`Payload`](super::Payload) identifier for Merkle Mountain Range root hash. - /// - /// Encoded value should contain a [`crate::MmrRootHash`] type (i.e. 32-bytes hash). - pub const MMR_ROOT_ID: BeefyPayloadId = *b"mh"; -} - -/// A BEEFY payload type allowing for future extensibility of adding additional kinds of payloads. -/// -/// The idea is to store a vector of SCALE-encoded values with an extra identifier. -/// Identifiers MUST be sorted by the [`BeefyPayloadId`] to allow efficient lookup of expected -/// value. Duplicated identifiers are disallowed. It's okay for different implementations to only -/// support a subset of possible values. -#[derive(Decode, Encode, Debug, PartialEq, Eq, Clone, Ord, PartialOrd, Hash)] -pub struct Payload(Vec<(BeefyPayloadId, Vec)>); - -impl Payload { - /// Construct a new payload given an initial vallue - pub fn new(id: BeefyPayloadId, value: Vec) -> Self { - Self(vec![(id, value)]) - } - - /// Returns a raw payload under given `id`. - /// - /// If the [`BeefyPayloadId`] is not found in the payload `None` is returned. - pub fn get_raw(&self, id: &BeefyPayloadId) -> Option<&Vec> { - let index = self.0.binary_search_by(|probe| probe.0.cmp(id)).ok()?; - Some(&self.0[index].1) - } - - /// Returns a decoded payload value under given `id`. - /// - /// In case the value is not there or it cannot be decoded does not match `None` is returned. - pub fn get_decoded(&self, id: &BeefyPayloadId) -> Option { - self.get_raw(id).and_then(|raw| T::decode(&mut &raw[..]).ok()) - } - - /// Push a `Vec` with a given id into the payload vec. - /// This method will internally sort the payload vec after every push. - /// - /// Returns self to allow for daisy chaining. - pub fn push_raw(mut self, id: BeefyPayloadId, value: Vec) -> Self { - self.0.push((id, value)); - self.0.sort_by_key(|(id, _)| *id); - self - } -} +use crate::{Payload, ValidatorSetId}; /// A commitment signed by GRANDPA validators as part of BEEFY protocol. /// @@ -80,7 +27,7 @@ impl Payload { /// height [block_number](Commitment::block_number). /// GRANDPA validators collect signatures on commitments and a stream of such signed commitments /// (see [SignedCommitment]) forms the BEEFY protocol. -#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode)] +#[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, TypeInfo)] pub struct Commitment { /// A collection of payloads to be signed, see [`Payload`] for details. /// @@ -138,7 +85,7 @@ where /// Note that SCALE-encoding of the structure is optimized for size efficiency over the wire, /// please take a look at custom [`Encode`] and [`Decode`] implementations and /// `CompactSignedCommitment` struct. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, TypeInfo)] pub struct SignedCommitment { /// The commitment signatures are collected for. pub commitment: Commitment, @@ -301,19 +248,18 @@ impl From> for VersionedFinalityProof { #[cfg(test)] mod tests { - - use sp_core::{keccak_256, Pair}; - use sp_keystore::{testing::KeyStore, SyncCryptoStore, SyncCryptoStorePtr}; - use super::*; + use crate::{crypto, known_payloads, KEY_TYPE}; use codec::Decode; - - use crate::{crypto, KEY_TYPE}; + use sp_core::{keccak_256, Pair}; + use sp_keystore::{testing::KeyStore, SyncCryptoStore, SyncCryptoStorePtr}; type TestCommitment = Commitment; type TestSignedCommitment = SignedCommitment; type TestVersionedFinalityProof = VersionedFinalityProof; + const LARGE_RAW_COMMITMENT: &[u8] = include_bytes!("../test-res/large-raw-commitment"); + // The mock signatures are equivalent to the ones produced by the BEEFY keystore fn mock_signatures() -> (crypto::Signature, crypto::Signature) { let store: SyncCryptoStorePtr = KeyStore::new().into(); @@ -339,7 +285,8 @@ mod tests { #[test] fn commitment_encode_decode() { // given - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); + let payload = + Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; @@ -351,7 +298,7 @@ mod tests { assert_eq!(decoded, Ok(commitment)); assert_eq!( encoded, - hex_literal::hex!( + array_bytes::hex2bytes_unchecked( "046d68343048656c6c6f20576f726c6421050000000000000000000000000000000000000000000000" ) ); @@ -360,7 +307,8 @@ mod tests { #[test] fn signed_commitment_encode_decode() { // given - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); + let payload = + Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; @@ -379,12 +327,14 @@ mod tests { assert_eq!(decoded, Ok(signed)); assert_eq!( encoded, - hex_literal::hex!( - "046d68343048656c6c6f20576f726c6421050000000000000000000000000000000000000000000000 - 04300400000008558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746 - cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba012d6e1f8105c337a86cdd9a - aacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b - 6a0046395a71681be3d0c2a00" + array_bytes::hex2bytes_unchecked( + "\ + 046d68343048656c6c6f20576f726c64210500000000000000000000000000000000000000000000000\ + 4300400000008558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746c\ + c321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba012d6e1f8105c337a86cdd9aa\ + acdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b6\ + a0046395a71681be3d0c2a00\ + " ) ); } @@ -392,7 +342,8 @@ mod tests { #[test] fn signed_commitment_count_signatures() { // given - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); + let payload = + Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; @@ -417,7 +368,8 @@ mod tests { block_number: u128, validator_set_id: crate::ValidatorSetId, ) -> TestCommitment { - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); + let payload = + Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); Commitment { payload, block_number, validator_set_id } } @@ -437,7 +389,8 @@ mod tests { #[test] fn versioned_commitment_encode_decode() { - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); + let payload = + Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; @@ -463,7 +416,8 @@ mod tests { #[test] fn large_signed_commitment_encode_decode() { // given - let payload = Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".encode()); + let payload = + Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; @@ -481,56 +435,6 @@ mod tests { // then assert_eq!(decoded, Ok(signed)); - assert_eq!( - encoded, - hex_literal::hex!( - "046d68343048656c6c6f20576f726c6421050000000000000000000000000000000000000000000000 - 05020000000000000000000000000000000000000000000000000000000000000000000000000000000 - 000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - fffffffffff0000040000b10a558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed - 4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad812 - 79df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d1 - 0dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2 - ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01 - 558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e9 - 9a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72 - d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bc - b7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc3 - 21f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc9855 - 80e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0 - c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da - 8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279d - f0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd - 3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac8 - 0a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558 - 455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a8 - 30e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d94 - 8d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb78 - 16f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f - 2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e - 4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33 - c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da848 - 0c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df07 - 95cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd - 68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a0 - 9abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455 - ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e - 314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1 - 107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f - 9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f231 - 9a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb - 75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86 - e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c7 - 46cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795c - c985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68c - e3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09ab - ed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad8 - 1279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314 - d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107 - b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba - 01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01" - ) - ); + assert_eq!(encoded, LARGE_RAW_COMMITMENT); } } diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs index 87f1b8756af65..453eb67315d4e 100644 --- a/primitives/beefy/src/lib.rs +++ b/primitives/beefy/src/lib.rs @@ -33,21 +33,38 @@ mod commitment; pub mod mmr; +mod payload; pub mod witness; -pub use commitment::{ - known_payload_ids, BeefyPayloadId, Commitment, Payload, SignedCommitment, - VersionedFinalityProof, -}; +pub use commitment::{Commitment, SignedCommitment, VersionedFinalityProof}; +pub use payload::{known_payloads, BeefyPayloadId, Payload, PayloadProvider}; use codec::{Codec, Decode, Encode}; use scale_info::TypeInfo; +use sp_application_crypto::RuntimeAppPublic; use sp_core::H256; +use sp_runtime::traits::Hash; use sp_std::prelude::*; /// Key type for BEEFY module. pub const KEY_TYPE: sp_application_crypto::KeyTypeId = sp_application_crypto::KeyTypeId(*b"beef"); +/// Trait representing BEEFY authority id. +pub trait BeefyAuthorityId: RuntimeAppPublic {} + +/// Means of verification for a BEEFY authority signature. +/// +/// Accepts custom hashing fn for the message and custom convertor fn for the signer. +pub trait BeefyVerify { + /// Type of the signer. + type Signer: BeefyAuthorityId; + + /// Verify a signature. + /// + /// Return `true` if signature is valid for the value. + fn verify(&self, msg: &[u8], signer: &Self::Signer) -> bool; +} + /// BEEFY cryptographic types /// /// This module basically introduces three crypto types: @@ -61,7 +78,9 @@ pub const KEY_TYPE: sp_application_crypto::KeyTypeId = sp_application_crypto::Ke /// The current underlying crypto scheme used is ECDSA. This can be changed, /// without affecting code restricted against the above listed crypto types. pub mod crypto { + use super::{BeefyAuthorityId, BeefyVerify, Hash}; use sp_application_crypto::{app_crypto, ecdsa}; + use sp_core::crypto::Wraps; app_crypto!(ecdsa, crate::KEY_TYPE); /// Identity of a BEEFY authority using ECDSA as its crypto. @@ -69,6 +88,26 @@ pub mod crypto { /// Signature for a BEEFY authority using ECDSA as its crypto. pub type AuthoritySignature = Signature; + + impl BeefyAuthorityId for AuthorityId {} + + impl BeefyVerify for AuthoritySignature + where + ::Output: Into<[u8; 32]>, + { + type Signer = AuthorityId; + + fn verify(&self, msg: &[u8], signer: &Self::Signer) -> bool { + let msg_hash = ::hash(msg).into(); + match sp_io::crypto::secp256k1_ecdsa_recover_compressed( + self.as_inner_ref().as_ref(), + &msg_hash, + ) { + Ok(raw_pubkey) => raw_pubkey.as_ref() == AsRef::<[u8]>::as_ref(signer), + _ => false, + } + } + } } /// The `ConsensusEngineId` of BEEFY. @@ -181,7 +220,8 @@ sp_api::decl_runtime_apis! { mod tests { use super::*; use sp_application_crypto::ecdsa::{self, Public}; - use sp_core::Pair; + use sp_core::{blake2_256, crypto::Wraps, keccak_256, Pair}; + use sp_runtime::traits::{BlakeTwo256, Keccak256}; #[test] fn validator_set() { @@ -195,4 +235,36 @@ mod tests { assert_eq!(validators.id(), set_id); assert_eq!(validators.validators(), &vec![alice.public()]); } + + #[test] + fn beefy_verify_works() { + let msg = &b"test-message"[..]; + let (pair, _) = crypto::Pair::generate(); + + let keccak_256_signature: crypto::Signature = + pair.as_inner_ref().sign_prehashed(&keccak_256(msg)).into(); + + let blake2_256_signature: crypto::Signature = + pair.as_inner_ref().sign_prehashed(&blake2_256(msg)).into(); + + // Verification works if same hashing function is used when signing and verifying. + assert!(BeefyVerify::::verify(&keccak_256_signature, msg, &pair.public())); + assert!(BeefyVerify::::verify(&blake2_256_signature, msg, &pair.public())); + // Verification fails if distinct hashing functions are used when signing and verifying. + assert!(!BeefyVerify::::verify(&blake2_256_signature, msg, &pair.public())); + assert!(!BeefyVerify::::verify(&keccak_256_signature, msg, &pair.public())); + + // Other public key doesn't work + let (other_pair, _) = crypto::Pair::generate(); + assert!(!BeefyVerify::::verify( + &keccak_256_signature, + msg, + &other_pair.public() + )); + assert!(!BeefyVerify::::verify( + &blake2_256_signature, + msg, + &other_pair.public() + )); + } } diff --git a/primitives/beefy/src/mmr.rs b/primitives/beefy/src/mmr.rs index 761eee9f8ef85..78ceef0b6b396 100644 --- a/primitives/beefy/src/mmr.rs +++ b/primitives/beefy/src/mmr.rs @@ -17,8 +17,8 @@ //! BEEFY + MMR utilties. //! -//! While BEEFY can be used completely indepentently as an additional consensus gadget, -//! it is designed around a main use case of making bridging standalone networks together. +//! While BEEFY can be used completely independently as an additional consensus gadget, +//! it is designed around a main use case of bridging standalone networks together. //! For that use case it's common to use some aggregated data structure (like MMR) to be //! used in conjunction with BEEFY, to be able to efficiently prove any past blockchain data. //! @@ -26,9 +26,13 @@ //! but we imagine they will be useful for other chains that either want to bridge with Polkadot //! or are completely standalone, but heavily inspired by Polkadot. -use crate::Vec; +use crate::{crypto::AuthorityId, ConsensusLog, MmrRootHash, Vec, BEEFY_ENGINE_ID}; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; +use sp_runtime::{ + generic::OpaqueDigestItemId, + traits::{Block, Header}, +}; /// A provider for extra data that gets added to the Mmr leaf pub trait BeefyDataProvider { @@ -44,7 +48,7 @@ impl BeefyDataProvider> for () { } /// A standard leaf that gets added every block to the MMR constructed by Substrate's `pallet_mmr`. -#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] +#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] pub struct MmrLeaf { /// Version of the leaf format. /// @@ -73,7 +77,7 @@ pub struct MmrLeaf { /// Given that adding new struct elements in SCALE is backward compatible (i.e. old format can be /// still decoded, the new fields will simply be ignored). We expect the major version to be bumped /// very rarely (hopefuly never). -#[derive(Debug, Default, PartialEq, Eq, Clone, Encode, Decode)] +#[derive(Debug, Default, PartialEq, Eq, Clone, Encode, Decode, TypeInfo)] pub struct MmrLeafVersion(u8); impl MmrLeafVersion { /// Create new version object from `major` and `minor` components. @@ -97,6 +101,7 @@ impl MmrLeafVersion { /// Details of a BEEFY authority set. #[derive(Debug, Default, PartialEq, Eq, Clone, Encode, Decode, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub struct BeefyAuthoritySet { /// Id of the set. /// @@ -121,9 +126,78 @@ pub struct BeefyAuthoritySet { /// Details of the next BEEFY authority set. pub type BeefyNextAuthoritySet = BeefyAuthoritySet; +/// Extract the MMR root hash from a digest in the given header, if it exists. +pub fn find_mmr_root_digest(header: &B::Header) -> Option { + let id = OpaqueDigestItemId::Consensus(&BEEFY_ENGINE_ID); + + let filter = |log: ConsensusLog| match log { + ConsensusLog::MmrRoot(root) => Some(root), + _ => None, + }; + header.digest().convert_first(|l| l.try_to(id).and_then(filter)) +} + +#[cfg(feature = "std")] +pub use mmr_root_provider::MmrRootProvider; +#[cfg(feature = "std")] +mod mmr_root_provider { + use super::*; + use crate::{known_payloads, payload::PayloadProvider, Payload}; + use sp_api::{NumberFor, ProvideRuntimeApi}; + use sp_mmr_primitives::MmrApi; + use sp_runtime::generic::BlockId; + use sp_std::{marker::PhantomData, sync::Arc}; + + /// A [`crate::Payload`] provider where payload is Merkle Mountain Range root hash. + /// + /// Encoded payload contains a [`crate::MmrRootHash`] type (i.e. 32-bytes hash). + pub struct MmrRootProvider { + runtime: Arc, + _phantom: PhantomData, + } + + impl MmrRootProvider + where + B: Block, + R: ProvideRuntimeApi, + R::Api: MmrApi>, + { + /// Create new BEEFY Payload provider with MMR Root as payload. + pub fn new(runtime: Arc) -> Self { + Self { runtime, _phantom: PhantomData } + } + + /// Simple wrapper that gets MMR root from header digests or from client state. + fn mmr_root_from_digest_or_runtime(&self, header: &B::Header) -> Option { + find_mmr_root_digest::(header).or_else(|| { + self.runtime + .runtime_api() + .mmr_root(&BlockId::hash(header.hash())) + .ok() + .and_then(|r| r.ok()) + }) + } + } + + impl PayloadProvider for MmrRootProvider + where + B: Block, + R: ProvideRuntimeApi, + R::Api: MmrApi>, + { + fn payload(&self, header: &B::Header) -> Option { + self.mmr_root_from_digest_or_runtime(header).map(|mmr_root| { + Payload::from_single_entry(known_payloads::MMR_ROOT_ID, mmr_root.encode()) + }) + } + } +} + #[cfg(test)] mod tests { use super::*; + use crate::H256; + use sp_runtime::{traits::BlakeTwo256, Digest, DigestItem, OpaqueExtrinsic}; #[test] fn should_construct_version_correctly() { @@ -147,4 +221,30 @@ mod tests { fn should_panic_if_minor_too_large() { MmrLeafVersion::new(0, 32); } + + #[test] + fn extract_mmr_root_digest() { + type Header = sp_runtime::generic::Header; + type Block = sp_runtime::generic::Block; + let mut header = Header::new( + 1u64, + Default::default(), + Default::default(), + Default::default(), + Digest::default(), + ); + + // verify empty digest shows nothing + assert!(find_mmr_root_digest::(&header).is_none()); + + let mmr_root_hash = H256::random(); + header.digest_mut().push(DigestItem::Consensus( + BEEFY_ENGINE_ID, + ConsensusLog::::MmrRoot(mmr_root_hash).encode(), + )); + + // verify validator set is correctly extracted from digest + let extracted = find_mmr_root_digest::(&header); + assert_eq!(extracted, Some(mmr_root_hash)); + } } diff --git a/primitives/beefy/src/payload.rs b/primitives/beefy/src/payload.rs new file mode 100644 index 0000000000000..0f23c3f381f19 --- /dev/null +++ b/primitives/beefy/src/payload.rs @@ -0,0 +1,105 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_runtime::traits::Block; +use sp_std::prelude::*; + +/// Id of different payloads in the [`crate::Commitment`] data. +pub type BeefyPayloadId = [u8; 2]; + +/// Registry of all known [`BeefyPayloadId`]. +pub mod known_payloads { + use crate::BeefyPayloadId; + + /// A [`Payload`](super::Payload) identifier for Merkle Mountain Range root hash. + /// + /// Encoded value should contain a [`crate::MmrRootHash`] type (i.e. 32-bytes hash). + pub const MMR_ROOT_ID: BeefyPayloadId = *b"mh"; +} + +/// A BEEFY payload type allowing for future extensibility of adding additional kinds of payloads. +/// +/// The idea is to store a vector of SCALE-encoded values with an extra identifier. +/// Identifiers MUST be sorted by the [`BeefyPayloadId`] to allow efficient lookup of expected +/// value. Duplicated identifiers are disallowed. It's okay for different implementations to only +/// support a subset of possible values. +#[derive(Decode, Encode, Debug, PartialEq, Eq, Clone, Ord, PartialOrd, Hash, TypeInfo)] +pub struct Payload(Vec<(BeefyPayloadId, Vec)>); + +impl Payload { + /// Construct a new payload given an initial vallue + pub fn from_single_entry(id: BeefyPayloadId, value: Vec) -> Self { + Self(vec![(id, value)]) + } + + /// Returns a raw payload under given `id`. + /// + /// If the [`BeefyPayloadId`] is not found in the payload `None` is returned. + pub fn get_raw(&self, id: &BeefyPayloadId) -> Option<&Vec> { + let index = self.0.binary_search_by(|probe| probe.0.cmp(id)).ok()?; + Some(&self.0[index].1) + } + + /// Returns a decoded payload value under given `id`. + /// + /// In case the value is not there or it cannot be decoded does not match `None` is returned. + pub fn get_decoded(&self, id: &BeefyPayloadId) -> Option { + self.get_raw(id).and_then(|raw| T::decode(&mut &raw[..]).ok()) + } + + /// Push a `Vec` with a given id into the payload vec. + /// This method will internally sort the payload vec after every push. + /// + /// Returns self to allow for daisy chaining. + pub fn push_raw(mut self, id: BeefyPayloadId, value: Vec) -> Self { + self.0.push((id, value)); + self.0.sort_by_key(|(id, _)| *id); + self + } +} + +/// Trait for custom BEEFY payload providers. +pub trait PayloadProvider { + /// Provide BEEFY payload if available for `header`. + fn payload(&self, header: &B::Header) -> Option; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn payload_methods_work_as_expected() { + let id1: BeefyPayloadId = *b"hw"; + let msg1: String = "1. Hello World!".to_string(); + let id2: BeefyPayloadId = *b"yb"; + let msg2: String = "2. Yellow Board!".to_string(); + let id3: BeefyPayloadId = *b"cs"; + let msg3: String = "3. Cello Cord!".to_string(); + + let payload = Payload::from_single_entry(id1, msg1.encode()) + .push_raw(id2, msg2.encode()) + .push_raw(id3, msg3.encode()); + + assert_eq!(payload.get_decoded(&id1), Some(msg1)); + assert_eq!(payload.get_decoded(&id2), Some(msg2)); + assert_eq!(payload.get_raw(&id3), Some(&msg3.encode())); + assert_eq!(payload.get_raw(&known_payloads::MMR_ROOT_ID), None); + } +} diff --git a/primitives/beefy/src/witness.rs b/primitives/beefy/src/witness.rs index aae0608150534..2c45e0ade90c4 100644 --- a/primitives/beefy/src/witness.rs +++ b/primitives/beefy/src/witness.rs @@ -81,7 +81,7 @@ mod tests { use super::*; use codec::Decode; - use crate::{crypto, known_payload_ids, Payload, KEY_TYPE}; + use crate::{crypto, known_payloads, Payload, KEY_TYPE}; type TestCommitment = Commitment; type TestSignedCommitment = SignedCommitment; @@ -111,8 +111,10 @@ mod tests { } fn signed_commitment() -> TestSignedCommitment { - let payload = - Payload::new(known_payload_ids::MMR_ROOT_ID, "Hello World!".as_bytes().to_vec()); + let payload = Payload::from_single_entry( + known_payloads::MMR_ROOT_ID, + "Hello World!".as_bytes().to_vec(), + ); let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; @@ -148,12 +150,14 @@ mod tests { assert_eq!(decoded, Ok(witness)); assert_eq!( encoded, - hex_literal::hex!( - "046d683048656c6c6f20576f726c642105000000000000000000000000000000000000000000000010 - 0000010110000001558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c - 746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01012d6e1f8105c337a86 - cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bc - a2324b6a0046395a71681be3d0c2a00" + array_bytes::hex2bytes_unchecked( + "\ + 046d683048656c6c6f20576f726c642105000000000000000000000000000000000000000000000010\ + 0000010110000001558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c\ + 746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01012d6e1f8105c337a8\ + 6cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487b\ + ca2324b6a0046395a71681be3d0c2a00\ + " ) ); } diff --git a/primitives/beefy/test-res/large-raw-commitment b/primitives/beefy/test-res/large-raw-commitment new file mode 100644 index 0000000000000..d5dbbe402a88e Binary files /dev/null and b/primitives/beefy/test-res/large-raw-commitment differ diff --git a/primitives/blockchain/src/backend.rs b/primitives/blockchain/src/backend.rs index f80c6d0269116..79c05aec8adca 100644 --- a/primitives/blockchain/src/backend.rs +++ b/primitives/blockchain/src/backend.rs @@ -78,8 +78,8 @@ pub trait HeaderBackend: Send + Sync { /// Convert an arbitrary block ID into a block hash. Returns `UnknownBlock` error if block is /// not found. fn expect_block_hash_from_id(&self, id: &BlockId) -> Result { - self.block_hash_from_id(id).and_then(|n| { - n.ok_or_else(|| Error::UnknownBlock(format!("Expect block hash from id: {}", id))) + self.block_hash_from_id(id).and_then(|h| { + h.ok_or_else(|| Error::UnknownBlock(format!("Expect block hash from id: {}", id))) }) } } diff --git a/primitives/blockchain/src/header_metadata.rs b/primitives/blockchain/src/header_metadata.rs index 46477a75b8a1f..0ced264d5c786 100644 --- a/primitives/blockchain/src/header_metadata.rs +++ b/primitives/blockchain/src/header_metadata.rs @@ -176,6 +176,13 @@ pub struct TreeRoute { } impl TreeRoute { + /// Creates a new `TreeRoute`. + /// + /// It is required that `pivot >= route.len()`, otherwise it may panics. + pub fn new(route: Vec>, pivot: usize) -> Self { + TreeRoute { route, pivot } + } + /// Get a slice of all retracted blocks in reverse order (towards common ancestor). pub fn retracted(&self) -> &[HashAndNumber] { &self.route[..self.pivot] diff --git a/primitives/consensus/common/src/lib.rs b/primitives/consensus/common/src/lib.rs index 043533cbf2258..458a5eee259a9 100644 --- a/primitives/consensus/common/src/lib.rs +++ b/primitives/consensus/common/src/lib.rs @@ -25,7 +25,6 @@ use std::{sync::Arc, time::Duration}; use futures::prelude::*; use sp_runtime::{ - generic::BlockId, traits::{Block as BlockT, HashFor}, Digest, }; @@ -268,61 +267,3 @@ where T::is_offline(self) } } - -/// Checks if the current active native block authoring implementation can author with the runtime -/// at the given block. -pub trait CanAuthorWith { - /// See trait docs for more information. - /// - /// # Return - /// - /// - Returns `Ok(())` when authoring is supported. - /// - Returns `Err(_)` when authoring is not supported. - fn can_author_with(&self, at: &BlockId) -> Result<(), String>; -} - -/// Checks if the node can author blocks by using -/// [`NativeVersion::can_author_with`](sp_version::NativeVersion::can_author_with). -#[derive(Clone)] -pub struct CanAuthorWithNativeVersion(T); - -impl CanAuthorWithNativeVersion { - /// Creates a new instance of `Self`. - pub fn new(inner: T) -> Self { - Self(inner) - } -} - -impl + sp_version::GetNativeVersion, Block: BlockT> - CanAuthorWith for CanAuthorWithNativeVersion -{ - fn can_author_with(&self, at: &BlockId) -> Result<(), String> { - match self.0.runtime_version(at) { - Ok(version) => self.0.native_version().can_author_with(&version), - Err(e) => Err(format!( - "Failed to get runtime version at `{}` and will disable authoring. Error: {}", - at, e, - )), - } - } -} - -/// Returns always `true` for `can_author_with`. This is useful for tests. -#[derive(Clone)] -pub struct AlwaysCanAuthor; - -impl CanAuthorWith for AlwaysCanAuthor { - fn can_author_with(&self, _: &BlockId) -> Result<(), String> { - Ok(()) - } -} - -/// Never can author. -#[derive(Clone)] -pub struct NeverCanAuthor; - -impl CanAuthorWith for NeverCanAuthor { - fn can_author_with(&self, _: &BlockId) -> Result<(), String> { - Err("Authoring is always disabled.".to_string()) - } -} diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index d591657ee4bd9..b7bc6dfdce496 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -21,9 +21,9 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive" log = { version = "0.4.17", default-features = false } serde = { version = "1.0.136", optional = true, features = ["derive"] } byteorder = { version = "1.3.2", default-features = false } -primitive-types = { version = "0.11.1", default-features = false, features = ["codec", "scale-info"] } -impl-serde = { version = "0.3.0", optional = true } -wasmi = { version = "0.9.1", optional = true } +primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "scale-info"] } +impl-serde = { version = "0.4.0", optional = true } +wasmi = { version = "0.13", optional = true } hash-db = { version = "0.15.2", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } base58 = { version = "0.2.0", optional = true } @@ -40,30 +40,29 @@ sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } sp-storage = { version = "6.0.0", default-features = false, path = "../storage" } sp-externalities = { version = "0.12.0", optional = true, path = "../externalities" } -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } futures = { version = "0.3.21", optional = true } dyn-clonable = { version = "0.9.0", optional = true } thiserror = { version = "1.0.30", optional = true } bitflags = "1.3" # full crypto +array-bytes = { version = "4.1", optional = true } ed25519-zebra = { version = "3.0.0", default-features = false, optional = true} -blake2-rfc = { version = "0.2.18", default-features = false, optional = true } +blake2 = { version = "0.10.4", default-features = false, optional = true } schnorrkel = { version = "0.9.1", features = [ "preaudit_deprecated", "u64_backend", ], default-features = false, optional = true } -hex = { version = "0.4", default-features = false, optional = true } libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"], optional = true } merlin = { version = "2.0", default-features = false, optional = true } secp256k1 = { version = "0.24.0", default-features = false, features = ["recovery", "alloc"], optional = true } -ss58-registry = { version = "1.18.0", default-features = false } +ss58-registry = { version = "1.29.0", default-features = false } sp-core-hashing = { version = "4.0.0", path = "./hashing", default-features = false, optional = true } sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../runtime-interface" } [dev-dependencies] sp-serializer = { version = "4.0.0-dev", path = "../serializer" } -hex-literal = "0.3.4" rand = "0.7.2" criterion = "0.3.3" serde_json = "1.0" @@ -79,6 +78,8 @@ bench = false [features] default = ["std"] std = [ + "parity-util-mem/std", + "merlin?/std", "full_crypto", "log/std", "thiserror", @@ -96,9 +97,9 @@ std = [ "hash-db/std", "sp-std/std", "serde", - "blake2-rfc/std", + "blake2/std", + "array-bytes", "ed25519-zebra", - "hex/std", "base58", "substrate-bip39", "tiny-bip39", @@ -127,10 +128,10 @@ std = [ # or Intel SGX. # For the regular wasm runtime builds this should not be used. full_crypto = [ + "array-bytes", "ed25519-zebra", - "blake2-rfc", + "blake2", "schnorrkel", - "hex", "libsecp256k1", "secp256k1", "sp-core-hashing", diff --git a/primitives/core/hashing/Cargo.toml b/primitives/core/hashing/Cargo.toml index d85e28d1b2e56..efe38af1602dd 100644 --- a/primitives/core/hashing/Cargo.toml +++ b/primitives/core/hashing/Cargo.toml @@ -13,7 +13,7 @@ documentation = "https://docs.rs/sp-core-hashing" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -blake2 = { version = "0.10.2", default-features = false } +blake2 = { version = "0.10.4", default-features = false } byteorder = { version = "1.3.2", default-features = false } digest = { version = "0.10.3", default-features = false } sha2 = { version = "0.10.2", default-features = false } @@ -24,6 +24,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../../std" } [features] default = ["std"] std = [ + "digest/std", "blake2/std", "byteorder/std", "sha2/std", diff --git a/primitives/runtime/src/bounded.rs b/primitives/core/src/bounded.rs similarity index 100% rename from primitives/runtime/src/bounded.rs rename to primitives/core/src/bounded.rs diff --git a/primitives/runtime/src/bounded/bounded_btree_map.rs b/primitives/core/src/bounded/bounded_btree_map.rs similarity index 99% rename from primitives/runtime/src/bounded/bounded_btree_map.rs rename to primitives/core/src/bounded/bounded_btree_map.rs index 725864b462694..32f8d85ca795b 100644 --- a/primitives/runtime/src/bounded/bounded_btree_map.rs +++ b/primitives/core/src/bounded/bounded_btree_map.rs @@ -17,7 +17,7 @@ //! Traits, types and structs to support a bounded BTreeMap. -use crate::traits::{Get, TryCollect}; +use crate::{Get, TryCollect}; use codec::{Decode, Encode, MaxEncodedLen}; use sp_std::{borrow::Borrow, collections::btree_map::BTreeMap, marker::PhantomData, ops::Deref}; @@ -363,7 +363,7 @@ where #[cfg(test)] pub mod test { use super::*; - use crate::traits::ConstU32; + use crate::ConstU32; fn map_from_keys(keys: &[K]) -> BTreeMap where diff --git a/primitives/runtime/src/bounded/bounded_btree_set.rs b/primitives/core/src/bounded/bounded_btree_set.rs similarity index 99% rename from primitives/runtime/src/bounded/bounded_btree_set.rs rename to primitives/core/src/bounded/bounded_btree_set.rs index c19d176f11bef..5feac6b7150f0 100644 --- a/primitives/runtime/src/bounded/bounded_btree_set.rs +++ b/primitives/core/src/bounded/bounded_btree_set.rs @@ -17,7 +17,7 @@ //! Traits, types and structs to support a bounded `BTreeSet`. -use crate::traits::{Get, TryCollect}; +use crate::{Get, TryCollect}; use codec::{Decode, Encode, MaxEncodedLen}; use sp_std::{borrow::Borrow, collections::btree_set::BTreeSet, marker::PhantomData, ops::Deref}; @@ -321,7 +321,7 @@ where #[cfg(test)] pub mod test { use super::*; - use crate::traits::ConstU32; + use crate::ConstU32; fn set_from_keys(keys: &[T]) -> BTreeSet where diff --git a/primitives/runtime/src/bounded/bounded_vec.rs b/primitives/core/src/bounded/bounded_vec.rs similarity index 97% rename from primitives/runtime/src/bounded/bounded_vec.rs rename to primitives/core/src/bounded/bounded_vec.rs index aed1a156ad699..1832e43e8646c 100644 --- a/primitives/runtime/src/bounded/bounded_vec.rs +++ b/primitives/core/src/bounded/bounded_vec.rs @@ -19,7 +19,7 @@ //! or a double map. use super::WeakBoundedVec; -use crate::traits::{Get, TryCollect}; +use crate::{Get, TryCollect}; use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; use core::{ ops::{Deref, Index, IndexMut, RangeBounds}, @@ -276,6 +276,14 @@ impl<'a, T, S> sp_std::iter::IntoIterator for BoundedSlice<'a, T, S> { } } +impl<'a, T, S: Get> BoundedSlice<'a, T, S> { + /// Create an instance from the first elements of the given slice (or all of it if it is smaller + /// than the length bound). + pub fn truncate_from(s: &'a [T]) -> Self { + Self(&s[0..(s.len().min(S::get() as usize))], PhantomData) + } +} + impl> Decode for BoundedVec { fn decode(input: &mut I) -> Result { let inner = Vec::::decode(input)?; @@ -620,12 +628,12 @@ impl> BoundedVec { /// # Panics /// /// Panics if `index > len`. - pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), ()> { + pub fn try_insert(&mut self, index: usize, element: T) -> Result<(), T> { if self.len() < Self::bound() { self.0.insert(index, element); Ok(()) } else { - Err(()) + Err(element) } } @@ -635,12 +643,12 @@ impl> BoundedVec { /// # Panics /// /// Panics if the new capacity exceeds isize::MAX bytes. - pub fn try_push(&mut self, element: T) -> Result<(), ()> { + pub fn try_push(&mut self, element: T) -> Result<(), T> { if self.len() < Self::bound() { self.0.push(element); Ok(()) } else { - Err(()) + Err(element) } } } @@ -673,13 +681,13 @@ where } impl> TryFrom> for BoundedVec { - type Error = (); + type Error = Vec; fn try_from(t: Vec) -> Result { if t.len() <= Self::bound() { // explicit check just above Ok(Self::unchecked_from(t)) } else { - Err(()) + Err(t) } } } @@ -884,7 +892,17 @@ where #[cfg(test)] pub mod test { use super::*; - use crate::{bounded_vec, traits::ConstU32}; + use crate::{bounded_vec, ConstU32}; + + #[test] + fn slice_truncate_from_works() { + let bounded = BoundedSlice::>::truncate_from(&[1, 2, 3, 4, 5]); + assert_eq!(bounded.deref(), &[1, 2, 3, 4]); + let bounded = BoundedSlice::>::truncate_from(&[1, 2, 3, 4]); + assert_eq!(bounded.deref(), &[1, 2, 3, 4]); + let bounded = BoundedSlice::>::truncate_from(&[1, 2, 3]); + assert_eq!(bounded.deref(), &[1, 2, 3]); + } #[test] fn slide_works() { diff --git a/primitives/runtime/src/bounded/weak_bounded_vec.rs b/primitives/core/src/bounded/weak_bounded_vec.rs similarity index 99% rename from primitives/runtime/src/bounded/weak_bounded_vec.rs rename to primitives/core/src/bounded/weak_bounded_vec.rs index a447e7285f906..5aff35f010c8b 100644 --- a/primitives/runtime/src/bounded/weak_bounded_vec.rs +++ b/primitives/core/src/bounded/weak_bounded_vec.rs @@ -19,7 +19,7 @@ //! or a double map. use super::{BoundedSlice, BoundedVec}; -use crate::traits::Get; +use crate::Get; use codec::{Decode, Encode, MaxEncodedLen}; use core::{ ops::{Deref, Index, IndexMut}, @@ -453,7 +453,7 @@ where #[cfg(test)] pub mod test { use super::*; - use crate::traits::ConstU32; + use crate::ConstU32; #[test] fn bound_returns_correct_value() { diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 80b44449dbac1..06703acea7202 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -132,9 +132,7 @@ impl DeriveJunction { let mut cc: [u8; JUNCTION_ID_LEN] = Default::default(); index.using_encoded(|data| { if data.len() > JUNCTION_ID_LEN { - let hash_result = blake2_rfc::blake2b::blake2b(JUNCTION_ID_LEN, &[], data); - let hash = hash_result.as_bytes(); - cc.copy_from_slice(hash); + cc.copy_from_slice(&sp_core_hashing::blake2_256(data)); } else { cc[0..data.len()].copy_from_slice(data); } @@ -292,7 +290,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + ByteArray { } let hash = ss58hash(&data[0..body_len + prefix_len]); - let checksum = &hash.as_bytes()[0..CHECKSUM_LEN]; + let checksum = &hash[0..CHECKSUM_LEN]; if data[body_len + prefix_len..body_len + prefix_len + CHECKSUM_LEN] != *checksum { // Invalid checksum. return Err(PublicError::InvalidChecksum) @@ -333,7 +331,7 @@ pub trait Ss58Codec: Sized + AsMut<[u8]> + AsRef<[u8]> + ByteArray { }; v.extend(self.as_ref()); let r = ss58hash(&v); - v.extend(&r.as_bytes()[0..2]); + v.extend(&r[0..2]); v.to_base58() } @@ -366,11 +364,13 @@ pub trait Derive: Sized { const PREFIX: &[u8] = b"SS58PRE"; #[cfg(feature = "std")] -fn ss58hash(data: &[u8]) -> blake2_rfc::blake2b::Blake2bResult { - let mut context = blake2_rfc::blake2b::Blake2b::new(64); - context.update(PREFIX); - context.update(data); - context.finalize() +fn ss58hash(data: &[u8]) -> Vec { + use blake2::{Blake2b512, Digest}; + + let mut ctx = Blake2b512::new(); + ctx.update(PREFIX); + ctx.update(data); + ctx.finalize().to_vec() } /// Default prefix number @@ -421,7 +421,7 @@ impl + AsRef<[u8]> + Public + Derive> Ss58Codec for T { let cap = SS58_REGEX.captures(s).ok_or(PublicError::InvalidFormat)?; let s = cap.name("ss58").map(|r| r.as_str()).unwrap_or(DEV_ADDRESS); let addr = if let Some(stripped) = s.strip_prefix("0x") { - let d = hex::decode(stripped).map_err(|_| PublicError::InvalidFormat)?; + let d = array_bytes::hex2bytes(stripped).map_err(|_| PublicError::InvalidFormat)?; Self::from_slice(&d).map_err(|()| PublicError::BadLength)? } else { Self::from_ss58check(s)? @@ -614,10 +614,7 @@ impl sp_std::str::FromStr for AccountId32 { fn from_str(s: &str) -> Result { let hex_or_ss58_without_prefix = s.trim_start_matches("0x"); if hex_or_ss58_without_prefix.len() == 64 { - let mut bytes = [0u8; 32]; - hex::decode_to_slice(hex_or_ss58_without_prefix, &mut bytes) - .map_err(|_| "invalid hex address.") - .map(|_| Self::from(bytes)) + array_bytes::hex_n_into(hex_or_ss58_without_prefix).map_err(|_| "invalid hex address.") } else { Self::from_ss58check(s).map_err(|_| "invalid ss58 address.") } @@ -943,7 +940,7 @@ pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { password_override.or_else(|| password.as_ref().map(|p| p.expose_secret().as_str())); let (root, seed) = if let Some(stripped) = phrase.expose_secret().strip_prefix("0x") { - hex::decode(stripped) + array_bytes::hex2bytes(stripped) .ok() .and_then(|seed_vec| { let mut seed = Self::Seed::default(); @@ -987,6 +984,11 @@ pub trait IsWrappedBy: From + Into { pub trait Wraps: Sized { /// The inner type it is wrapping. type Inner: IsWrappedBy; + + /// Get a reference to the inner type that is wrapped. + fn as_inner_ref(&self) -> &Self::Inner { + Self::Inner::from_ref(self) + } } impl IsWrappedBy for T @@ -1127,7 +1129,6 @@ pub mod key_types { mod tests { use super::*; use crate::DeriveJunction; - use hex_literal::hex; #[derive(Clone, Eq, PartialEq, Debug)] enum TestPair { @@ -1269,7 +1270,7 @@ mod tests { fn interpret_std_seed_should_work() { assert_eq!( TestPair::from_string("0x0123456789abcdef", None), - Ok(TestPair::Seed(hex!["0123456789abcdef"][..].to_owned())) + Ok(TestPair::Seed(array_bytes::hex2bytes_unchecked("0123456789abcdef"))) ); } @@ -1311,6 +1312,14 @@ mod tests { path: vec![DeriveJunction::soft("DOT")] }) ); + assert_eq!( + TestPair::from_string("hello world/0123456789012345678901234567890123456789", None), + Ok(TestPair::Standard { + phrase: "hello world".to_owned(), + password: None, + path: vec![DeriveJunction::soft("0123456789012345678901234567890123456789")] + }) + ); assert_eq!( TestPair::from_string("hello world//1", None), Ok(TestPair::Standard { @@ -1327,6 +1336,14 @@ mod tests { path: vec![DeriveJunction::hard("DOT")] }) ); + assert_eq!( + TestPair::from_string("hello world//0123456789012345678901234567890123456789", None), + Ok(TestPair::Standard { + phrase: "hello world".to_owned(), + password: None, + path: vec![DeriveJunction::hard("0123456789012345678901234567890123456789")] + }) + ); assert_eq!( TestPair::from_string("hello world//1/DOT", None), Ok(TestPair::Standard { diff --git a/primitives/core/src/ecdsa.rs b/primitives/core/src/ecdsa.rs index d56f65fd289e7..ca6b800625bc2 100644 --- a/primitives/core/src/ecdsa.rs +++ b/primitives/core/src/ecdsa.rs @@ -229,7 +229,7 @@ impl Serialize for Signature { where S: Serializer, { - serializer.serialize_str(&hex::encode(self)) + serializer.serialize_str(&array_bytes::bytes2hex("", self.as_ref())) } } @@ -239,7 +239,7 @@ impl<'de> Deserialize<'de> for Signature { where D: Deserializer<'de>, { - let signature_hex = hex::decode(&String::deserialize(deserializer)?) + let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) .map_err(|e| de::Error::custom(format!("{:?}", e)))?; Signature::try_from(signature_hex.as_ref()) .map_err(|e| de::Error::custom(format!("{:?}", e))) @@ -597,7 +597,6 @@ mod test { set_default_ss58_version, PublicError, Ss58AddressFormat, Ss58AddressFormatRegistry, DEV_PHRASE, }; - use hex_literal::hex; use serde_json; #[test] @@ -612,31 +611,35 @@ mod test { #[test] fn seed_and_derive_should_work() { - let seed = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let seed = array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + ); let pair = Pair::from_seed(&seed); assert_eq!(pair.seed(), seed); let path = vec![DeriveJunction::Hard([0u8; 32])]; let derived = pair.derive(path.into_iter(), None).ok().unwrap(); assert_eq!( derived.0.seed(), - hex!("b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61") + array_bytes::hex2array_unchecked::<32>( + "b8eefc4937200a8382d00050e050ced2d4ab72cc2ef1b061477afb51564fdd61" + ) ); } #[test] fn test_vector_should_work() { - let pair = Pair::from_seed(&hex!( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", )); let public = pair.public(); assert_eq!( public, Public::from_full( - &hex!("8db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd913ebbe148dd17c56551a52952371071a6c604b3f3abe8f2c8fa742158ea6dd7d4")[..], + &array_bytes::hex2bytes_unchecked("8db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd913ebbe148dd17c56551a52952371071a6c604b3f3abe8f2c8fa742158ea6dd7d4"), ).unwrap(), ); let message = b""; - let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00"); + let signature = array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00"); let signature = Signature::from_raw(signature); assert!(pair.sign(&message[..]) == signature); assert!(Pair::verify(&signature, &message[..], &public)); @@ -653,11 +656,11 @@ mod test { assert_eq!( public, Public::from_full( - &hex!("8db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd913ebbe148dd17c56551a52952371071a6c604b3f3abe8f2c8fa742158ea6dd7d4")[..], + &array_bytes::hex2bytes_unchecked("8db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd913ebbe148dd17c56551a52952371071a6c604b3f3abe8f2c8fa742158ea6dd7d4"), ).unwrap(), ); let message = b""; - let signature = hex!("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00"); + let signature = array_bytes::hex2array_unchecked("3dde91174bd9359027be59a428b8146513df80a2a3c7eda2194f64de04a69ab97b753169e94db6ffd50921a2668a48b94ca11e3d32c1ff19cfe88890aa7e8f3c00"); let signature = Signature::from_raw(signature); assert!(pair.sign(&message[..]) == signature); assert!(Pair::verify(&signature, &message[..], &public)); @@ -680,10 +683,10 @@ mod test { assert_eq!( public, Public::from_full( - &hex!("5676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba995840f3de562156558efbfdac3f16af0065e5f66795f4dd8262a228ef8c6d813")[..], + &array_bytes::hex2bytes_unchecked("5676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba995840f3de562156558efbfdac3f16af0065e5f66795f4dd8262a228ef8c6d813"), ).unwrap(), ); - let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); + let message = array_bytes::hex2bytes_unchecked("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); let signature = pair.sign(&message[..]); println!("Correct signature: {:?}", signature); assert!(Pair::verify(&signature, &message[..], &public)); diff --git a/primitives/core/src/ed25519.rs b/primitives/core/src/ed25519.rs index 0553cf4843df5..e85eb87c9fd83 100644 --- a/primitives/core/src/ed25519.rs +++ b/primitives/core/src/ed25519.rs @@ -228,7 +228,7 @@ impl Serialize for Signature { where S: Serializer, { - serializer.serialize_str(&hex::encode(self)) + serializer.serialize_str(&array_bytes::bytes2hex("", self.as_ref())) } } @@ -238,7 +238,7 @@ impl<'de> Deserialize<'de> for Signature { where D: Deserializer<'de>, { - let signature_hex = hex::decode(&String::deserialize(deserializer)?) + let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) .map_err(|e| de::Error::custom(format!("{:?}", e)))?; Signature::try_from(signature_hex.as_ref()) .map_err(|e| de::Error::custom(format!("{:?}", e))) @@ -551,7 +551,6 @@ impl CryptoType for Pair { mod test { use super::*; use crate::crypto::DEV_PHRASE; - use hex_literal::hex; use serde_json; #[test] @@ -566,31 +565,35 @@ mod test { #[test] fn seed_and_derive_should_work() { - let seed = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let seed = array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + ); let pair = Pair::from_seed(&seed); assert_eq!(pair.seed(), seed); let path = vec![DeriveJunction::Hard([0u8; 32])]; let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; assert_eq!( derived.seed(), - hex!("ede3354e133f9c8e337ddd6ee5415ed4b4ffe5fc7d21e933f4930a3730e5b21c") + array_bytes::hex2array_unchecked::<32>( + "ede3354e133f9c8e337ddd6ee5415ed4b4ffe5fc7d21e933f4930a3730e5b21c" + ) ); } #[test] fn test_vector_should_work() { - let pair = Pair::from_seed(&hex!( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", )); let public = pair.public(); assert_eq!( public, - Public::from_raw(hex!( + Public::from_raw(array_bytes::hex2array_unchecked( "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a" )) ); let message = b""; - let signature = hex!("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b"); + let signature = array_bytes::hex2array_unchecked("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b"); let signature = Signature::from_raw(signature); assert!(pair.sign(&message[..]) == signature); assert!(Pair::verify(&signature, &message[..], &public)); @@ -606,12 +609,12 @@ mod test { let public = pair.public(); assert_eq!( public, - Public::from_raw(hex!( + Public::from_raw(array_bytes::hex2array_unchecked( "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a" )) ); let message = b""; - let signature = hex!("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b"); + let signature = array_bytes::hex2array_unchecked("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b"); let signature = Signature::from_raw(signature); assert!(pair.sign(&message[..]) == signature); assert!(Pair::verify(&signature, &message[..], &public)); @@ -633,11 +636,11 @@ mod test { let public = pair.public(); assert_eq!( public, - Public::from_raw(hex!( + Public::from_raw(array_bytes::hex2array_unchecked( "2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee" )) ); - let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); + let message = array_bytes::hex2bytes_unchecked("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); let signature = pair.sign(&message[..]); println!("Correct signature: {:?}", signature); assert!(Pair::verify(&signature, &message[..], &public)); diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 5517dbb8bd4eb..160c2fa2c17c5 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -40,8 +40,6 @@ pub use serde; use serde::{Deserialize, Serialize}; use sp_runtime_interface::pass_by::{PassByEnum, PassByInner}; use sp_std::{ops::Deref, prelude::*}; -#[cfg(feature = "std")] -use std::borrow::Cow; pub use sp_debug_derive::RuntimeDebug; @@ -53,6 +51,7 @@ pub mod hashing; #[cfg(feature = "full_crypto")] pub use hashing::{blake2_128, blake2_256, keccak_256, twox_128, twox_256, twox_64}; +pub mod bounded; pub mod crypto; pub mod hexdisplay; @@ -210,85 +209,6 @@ impl OpaquePeerId { } } -/// Something that is either a native or an encoded value. -#[cfg(feature = "std")] -pub enum NativeOrEncoded { - /// The native representation. - Native(R), - /// The encoded representation. - Encoded(Vec), -} - -#[cfg(feature = "std")] -impl From for NativeOrEncoded { - fn from(val: R) -> Self { - Self::Native(val) - } -} - -#[cfg(feature = "std")] -impl sp_std::fmt::Debug for NativeOrEncoded { - fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { - hexdisplay::HexDisplay::from(&self.as_encoded().as_ref()).fmt(f) - } -} - -#[cfg(feature = "std")] -impl NativeOrEncoded { - /// Return the value as the encoded format. - pub fn as_encoded(&self) -> Cow<'_, [u8]> { - match self { - NativeOrEncoded::Encoded(e) => Cow::Borrowed(e.as_slice()), - NativeOrEncoded::Native(n) => Cow::Owned(n.encode()), - } - } - - /// Return the value as the encoded format. - pub fn into_encoded(self) -> Vec { - match self { - NativeOrEncoded::Encoded(e) => e, - NativeOrEncoded::Native(n) => n.encode(), - } - } -} - -#[cfg(feature = "std")] -impl PartialEq for NativeOrEncoded { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (NativeOrEncoded::Native(l), NativeOrEncoded::Native(r)) => l == r, - (NativeOrEncoded::Native(n), NativeOrEncoded::Encoded(e)) | - (NativeOrEncoded::Encoded(e), NativeOrEncoded::Native(n)) => - Some(n) == codec::Decode::decode(&mut &e[..]).ok().as_ref(), - (NativeOrEncoded::Encoded(l), NativeOrEncoded::Encoded(r)) => l == r, - } - } -} - -/// A value that is never in a native representation. -/// This is type is useful in conjunction with `NativeOrEncoded`. -#[cfg(feature = "std")] -#[derive(PartialEq)] -pub enum NeverNativeValue {} - -#[cfg(feature = "std")] -impl codec::Encode for NeverNativeValue { - fn encode(&self) -> Vec { - // The enum is not constructable, so this function should never be callable! - unreachable!() - } -} - -#[cfg(feature = "std")] -impl codec::EncodeLike for NeverNativeValue {} - -#[cfg(feature = "std")] -impl codec::Decode for NeverNativeValue { - fn decode(_: &mut I) -> Result { - Err("`NeverNativeValue` should never be decoded".into()) - } -} - /// Provide a simple 4 byte identifier for a type. pub trait TypeId { /// Simple 4 byte identifier. @@ -468,3 +388,239 @@ macro_rules! impl_maybe_marker { // The maximum possible allocation size was chosen rather arbitrary, 32 MiB should be enough for // everybody. pub const MAX_POSSIBLE_ALLOCATION: u32 = 33554432; // 2^25 bytes, 32 MiB + +/// A trait for querying a single value from a type defined in the trait. +/// +/// It is not required that the value is constant. +pub trait TypedGet { + /// The type which is returned. + type Type; + /// Return the current value. + fn get() -> Self::Type; +} + +/// A trait for querying a single value from a type. +/// +/// It is not required that the value is constant. +pub trait Get { + /// Return the current value. + fn get() -> T; +} + +impl Get for () { + fn get() -> T { + T::default() + } +} + +/// Implement Get by returning Default for any type that implements Default. +pub struct GetDefault; +impl Get for GetDefault { + fn get() -> T { + T::default() + } +} + +macro_rules! impl_const_get { + ($name:ident, $t:ty) => { + #[doc = "Const getter for a basic type."] + #[derive($crate::RuntimeDebug)] + pub struct $name; + impl Get<$t> for $name { + fn get() -> $t { + T + } + } + impl Get> for $name { + fn get() -> Option<$t> { + Some(T) + } + } + impl TypedGet for $name { + type Type = $t; + fn get() -> $t { + T + } + } + }; +} + +impl_const_get!(ConstBool, bool); +impl_const_get!(ConstU8, u8); +impl_const_get!(ConstU16, u16); +impl_const_get!(ConstU32, u32); +impl_const_get!(ConstU64, u64); +impl_const_get!(ConstU128, u128); +impl_const_get!(ConstI8, i8); +impl_const_get!(ConstI16, i16); +impl_const_get!(ConstI32, i32); +impl_const_get!(ConstI64, i64); +impl_const_get!(ConstI128, i128); + +/// Try and collect into a collection `C`. +pub trait TryCollect { + /// The error type that gets returned when a collection can't be made from `self`. + type Error; + /// Consume self and try to collect the results into `C`. + /// + /// This is useful in preventing the undesirable `.collect().try_into()` call chain on + /// collections that need to be converted into a bounded type (e.g. `BoundedVec`). + fn try_collect(self) -> Result; +} + +/// Create new implementations of the [`Get`](crate::Get) trait. +/// +/// The so-called parameter type can be created in four different ways: +/// +/// - Using `const` to create a parameter type that provides a `const` getter. It is required that +/// the `value` is const. +/// +/// - Declare the parameter type without `const` to have more freedom when creating the value. +/// +/// NOTE: A more substantial version of this macro is available in `frame_support` crate which +/// allows mutable and persistant variants. +/// +/// # Examples +/// +/// ``` +/// # use sp_core::Get; +/// # use sp_core::parameter_types; +/// // This function cannot be used in a const context. +/// fn non_const_expression() -> u64 { 99 } +/// +/// const FIXED_VALUE: u64 = 10; +/// parameter_types! { +/// pub const Argument: u64 = 42 + FIXED_VALUE; +/// /// Visibility of the type is optional +/// OtherArgument: u64 = non_const_expression(); +/// } +/// +/// trait Config { +/// type Parameter: Get; +/// type OtherParameter: Get; +/// } +/// +/// struct Runtime; +/// impl Config for Runtime { +/// type Parameter = Argument; +/// type OtherParameter = OtherArgument; +/// } +/// ``` +/// +/// # Invalid example: +/// +/// ```compile_fail +/// # use sp_core::Get; +/// # use sp_core::parameter_types; +/// // This function cannot be used in a const context. +/// fn non_const_expression() -> u64 { 99 } +/// +/// parameter_types! { +/// pub const Argument: u64 = non_const_expression(); +/// } +/// ``` +#[macro_export] +macro_rules! parameter_types { + ( + $( #[ $attr:meta ] )* + $vis:vis const $name:ident: $type:ty = $value:expr; + $( $rest:tt )* + ) => ( + $( #[ $attr ] )* + $vis struct $name; + $crate::parameter_types!(@IMPL_CONST $name , $type , $value); + $crate::parameter_types!( $( $rest )* ); + ); + ( + $( #[ $attr:meta ] )* + $vis:vis $name:ident: $type:ty = $value:expr; + $( $rest:tt )* + ) => ( + $( #[ $attr ] )* + $vis struct $name; + $crate::parameter_types!(@IMPL $name, $type, $value); + $crate::parameter_types!( $( $rest )* ); + ); + () => (); + (@IMPL_CONST $name:ident, $type:ty, $value:expr) => { + impl $name { + /// Returns the value of this parameter type. + pub const fn get() -> $type { + $value + } + } + + impl> $crate::Get for $name { + fn get() -> I { + I::from(Self::get()) + } + } + + impl $crate::TypedGet for $name { + type Type = $type; + fn get() -> $type { + Self::get() + } + } + }; + (@IMPL $name:ident, $type:ty, $value:expr) => { + impl $name { + /// Returns the value of this parameter type. + pub fn get() -> $type { + $value + } + } + + impl> $crate::Get for $name { + fn get() -> I { + I::from(Self::get()) + } + } + + impl $crate::TypedGet for $name { + type Type = $type; + fn get() -> $type { + Self::get() + } + } + }; +} + +/// Build a bounded vec from the given literals. +/// +/// The type of the outcome must be known. +/// +/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding +/// bounded vec type. Thus, this is only suitable for testing and non-consensus code. +#[macro_export] +#[cfg(feature = "std")] +macro_rules! bounded_vec { + ($ ($values:expr),* $(,)?) => { + { + $crate::sp_std::vec![$($values),*].try_into().unwrap() + } + }; + ( $value:expr ; $repetition:expr ) => { + { + $crate::sp_std::vec![$value ; $repetition].try_into().unwrap() + } + } +} + +/// Build a bounded btree-map from the given literals. +/// +/// The type of the outcome must be known. +/// +/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding +/// bounded vec type. Thus, this is only suitable for testing and non-consensus code. +#[macro_export] +#[cfg(feature = "std")] +macro_rules! bounded_btree_map { + ($ ( $key:expr => $value:expr ),* $(,)?) => { + { + $crate::TryCollect::<$crate::bounded::BoundedBTreeMap<_, _, _>>::try_collect( + $crate::sp_std::vec![$(($key, $value)),*].into_iter() + ).unwrap() + } + }; +} diff --git a/primitives/core/src/sr25519.rs b/primitives/core/src/sr25519.rs index ef033c2099b5f..9064fb7427393 100644 --- a/primitives/core/src/sr25519.rs +++ b/primitives/core/src/sr25519.rs @@ -233,7 +233,7 @@ impl Serialize for Signature { where S: Serializer, { - serializer.serialize_str(&hex::encode(self)) + serializer.serialize_str(&array_bytes::bytes2hex("", self.as_ref())) } } @@ -243,7 +243,7 @@ impl<'de> Deserialize<'de> for Signature { where D: Deserializer<'de>, { - let signature_hex = hex::decode(&String::deserialize(deserializer)?) + let signature_hex = array_bytes::hex2bytes(&String::deserialize(deserializer)?) .map_err(|e| de::Error::custom(format!("{:?}", e)))?; Signature::try_from(signature_hex.as_ref()) .map_err(|e| de::Error::custom(format!("{:?}", e))) @@ -664,7 +664,6 @@ pub fn verify_batch( mod compatibility_test { use super::*; use crate::crypto::DEV_PHRASE; - use hex_literal::hex; // NOTE: tests to ensure addresses that are created with the `0.1.x` version (pre-audit) are // still functional. @@ -673,7 +672,9 @@ mod compatibility_test { fn derive_soft_known_pair_should_work() { let pair = Pair::from_string(&format!("{}/Alice", DEV_PHRASE), None).unwrap(); // known address of DEV_PHRASE with 1.1 - let known = hex!("d6c71059dbbe9ad2b0ed3f289738b800836eb425544ce694825285b958ca755e"); + let known = array_bytes::hex2bytes_unchecked( + "d6c71059dbbe9ad2b0ed3f289738b800836eb425544ce694825285b958ca755e", + ); assert_eq!(pair.public().to_raw_vec(), known); } @@ -681,17 +682,19 @@ mod compatibility_test { fn derive_hard_known_pair_should_work() { let pair = Pair::from_string(&format!("{}//Alice", DEV_PHRASE), None).unwrap(); // known address of DEV_PHRASE with 1.1 - let known = hex!("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"); + let known = array_bytes::hex2bytes_unchecked( + "d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", + ); assert_eq!(pair.public().to_raw_vec(), known); } #[test] fn verify_known_old_message_should_work() { - let public = Public::from_raw(hex!( - "b4bfa1f7a5166695eb75299fd1c4c03ea212871c342f2c5dfea0902b2c246918" + let public = Public::from_raw(array_bytes::hex2array_unchecked( + "b4bfa1f7a5166695eb75299fd1c4c03ea212871c342f2c5dfea0902b2c246918", )); // signature generated by the 1.1 version with the same ^^ public key. - let signature = Signature::from_raw(hex!( + let signature = Signature::from_raw(array_bytes::hex2array_unchecked( "5a9755f069939f45d96aaf125cf5ce7ba1db998686f87f2fb3cbdea922078741a73891ba265f70c31436e18a9acd14d189d73c12317ab6c313285cd938453202" )); let message = b"Verifying that I am the owner of 5G9hQLdsKQswNPgB499DeA5PkFBbgkLPJWkkS6FAM6xGQ8xD. Hash: 221455a3\n"; @@ -704,7 +707,6 @@ mod compatibility_test { mod test { use super::*; use crate::crypto::{Ss58Codec, DEV_ADDRESS, DEV_PHRASE}; - use hex_literal::hex; use serde_json; #[test] @@ -745,8 +747,8 @@ mod test { #[test] fn derive_soft_should_work() { - let pair = Pair::from_seed(&hex!( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", )); let derive_1 = pair.derive(Some(DeriveJunction::soft(1)).into_iter(), None).unwrap().0; let derive_1b = pair.derive(Some(DeriveJunction::soft(1)).into_iter(), None).unwrap().0; @@ -757,8 +759,8 @@ mod test { #[test] fn derive_hard_should_work() { - let pair = Pair::from_seed(&hex!( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", )); let derive_1 = pair.derive(Some(DeriveJunction::hard(1)).into_iter(), None).unwrap().0; let derive_1b = pair.derive(Some(DeriveJunction::hard(1)).into_iter(), None).unwrap().0; @@ -769,8 +771,8 @@ mod test { #[test] fn derive_soft_public_should_work() { - let pair = Pair::from_seed(&hex!( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", )); let path = Some(DeriveJunction::soft(1)); let pair_1 = pair.derive(path.into_iter(), None).unwrap().0; @@ -780,8 +782,8 @@ mod test { #[test] fn derive_hard_public_should_fail() { - let pair = Pair::from_seed(&hex!( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", )); let path = Some(DeriveJunction::hard(1)); assert!(pair.public().derive(path.into_iter()).is_none()); @@ -789,13 +791,13 @@ mod test { #[test] fn sr_test_vector_should_work() { - let pair = Pair::from_seed(&hex!( - "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + let pair = Pair::from_seed(&array_bytes::hex2array_unchecked( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", )); let public = pair.public(); assert_eq!( public, - Public::from_raw(hex!( + Public::from_raw(array_bytes::hex2array_unchecked( "44a996beb1eef7bdcab976ab6d2ca26104834164ecf28fb375600576fcc6eb0f" )) ); @@ -840,11 +842,11 @@ mod test { let public = pair.public(); assert_eq!( public, - Public::from_raw(hex!( + Public::from_raw(array_bytes::hex2array_unchecked( "741c08a06f41c596608f6774259bd9043304adfa5d3eea62760bd9be97634d63" )) ); - let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); + let message = array_bytes::hex2bytes_unchecked("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); let signature = pair.sign(&message[..]); assert!(Pair::verify(&signature, &message[..], &public)); } @@ -865,11 +867,11 @@ mod test { // schnorrkel-js. // // This is to make sure that the wasm library is compatible. - let pk = Pair::from_seed(&hex!( - "0000000000000000000000000000000000000000000000000000000000000000" + let pk = Pair::from_seed(&array_bytes::hex2array_unchecked( + "0000000000000000000000000000000000000000000000000000000000000000", )); let public = pk.public(); - let js_signature = Signature::from_raw(hex!( + let js_signature = Signature::from_raw(array_bytes::hex2array_unchecked( "28a854d54903e056f89581c691c1f7d2ff39f8f896c9e9c22475e60902cc2b3547199e0e91fa32902028f2ca2355e8cdd16cfe19ba5e8b658c94aa80f3b81a00" )); assert!(Pair::verify_deprecated(&js_signature, b"SUBSTRATE", &public)); diff --git a/primitives/core/src/traits.rs b/primitives/core/src/traits.rs index 80e8963a2909d..c5149cc48c074 100644 --- a/primitives/core/src/traits.rs +++ b/primitives/core/src/traits.rs @@ -20,7 +20,6 @@ use std::{ borrow::Cow, fmt::{Debug, Display}, - panic::UnwindSafe, }; pub use sp_externalities::{Externalities, ExternalitiesExt}; @@ -32,18 +31,14 @@ pub trait CodeExecutor: Sized + Send + Sync + ReadRuntimeVersion + Clone + 'stat /// Call a given method in the runtime. Returns a tuple of the result (either the output data /// or an execution error) together with a `bool`, which is true if native execution was used. - fn call< - R: codec::Codec + PartialEq, - NC: FnOnce() -> Result> + UnwindSafe, - >( + fn call( &self, ext: &mut dyn Externalities, runtime_code: &RuntimeCode, method: &str, data: &[u8], use_native: bool, - native_call: Option, - ) -> (Result, Self::Error>, bool); + ) -> (Result, Self::Error>, bool); } /// Something that can fetch the runtime `:code`. diff --git a/primitives/core/src/uint.rs b/primitives/core/src/uint.rs index 17604512f251c..61ebb5e54cdf1 100644 --- a/primitives/core/src/uint.rs +++ b/primitives/core/src/uint.rs @@ -35,7 +35,6 @@ mod tests { ($name::from(2), "0x2"), ($name::from(10), "0xa"), ($name::from(15), "0xf"), - ($name::from(15), "0xf"), ($name::from(16), "0x10"), ($name::from(1_000), "0x3e8"), ($name::from(100_000), "0x186a0"), @@ -52,8 +51,6 @@ mod tests { assert!(ser::from_str::<$name>("\"0x\"").unwrap_err().is_data()); assert!(ser::from_str::<$name>("\"0xg\"").unwrap_err().is_data()); assert!(ser::from_str::<$name>("\"\"").unwrap_err().is_data()); - assert!(ser::from_str::<$name>("\"10\"").unwrap_err().is_data()); - assert!(ser::from_str::<$name>("\"0\"").unwrap_err().is_data()); } }; } diff --git a/primitives/database/Cargo.toml b/primitives/database/Cargo.toml index a3f09536f4f5c..f19a647fed032 100644 --- a/primitives/database/Cargo.toml +++ b/primitives/database/Cargo.toml @@ -11,5 +11,5 @@ documentation = "https://docs.rs/sp-database" readme = "README.md" [dependencies] -kvdb = "0.11.0" +kvdb = "0.12.0" parking_lot = "0.12.1" diff --git a/primitives/finality-grandpa/src/lib.rs b/primitives/finality-grandpa/src/lib.rs index 4be42c3d19b6c..2adfce1bea241 100644 --- a/primitives/finality-grandpa/src/lib.rs +++ b/primitives/finality-grandpa/src/lib.rs @@ -29,7 +29,10 @@ use codec::{Codec, Decode, Encode, Input}; use scale_info::TypeInfo; #[cfg(feature = "std")] use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; -use sp_runtime::{traits::NumberFor, ConsensusEngineId, RuntimeDebug}; +use sp_runtime::{ + traits::{Header as HeaderT, NumberFor}, + ConsensusEngineId, RuntimeDebug, +}; use sp_std::{borrow::Cow, vec::Vec}; #[cfg(feature = "std")] @@ -76,6 +79,63 @@ pub type RoundNumber = u64; /// A list of Grandpa authorities with associated weights. pub type AuthorityList = Vec<(AuthorityId, AuthorityWeight)>; +/// A GRANDPA message for a substrate chain. +pub type Message

= grandpa::Message<
::Hash,
::Number>; + +/// A signed message. +pub type SignedMessage
= grandpa::SignedMessage< +
::Hash, +
::Number, + AuthoritySignature, + AuthorityId, +>; + +/// A primary propose message for this chain's block type. +pub type PrimaryPropose
= + grandpa::PrimaryPropose<
::Hash,
::Number>; +/// A prevote message for this chain's block type. +pub type Prevote
= grandpa::Prevote<
::Hash,
::Number>; +/// A precommit message for this chain's block type. +pub type Precommit
= + grandpa::Precommit<
::Hash,
::Number>; +/// A catch up message for this chain's block type. +pub type CatchUp
= grandpa::CatchUp< +
::Hash, +
::Number, + AuthoritySignature, + AuthorityId, +>; +/// A commit message for this chain's block type. +pub type Commit
= grandpa::Commit< +
::Hash, +
::Number, + AuthoritySignature, + AuthorityId, +>; + +/// A compact commit message for this chain's block type. +pub type CompactCommit
= grandpa::CompactCommit< +
::Hash, +
::Number, + AuthoritySignature, + AuthorityId, +>; + +/// A GRANDPA justification for block finality, it includes a commit message and +/// an ancestry proof including all headers routing all precommit target blocks +/// to the commit target block. Due to the current voting strategy the precommit +/// targets should be the same as the commit target, since honest voters don't +/// vote past authority set change blocks. +/// +/// This is meant to be stored in the db and passed around the network to other +/// nodes, and are used by syncing nodes to prove authority set handoffs. +#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug)] +pub struct GrandpaJustification { + pub round: u64, + pub commit: Commit
, + pub votes_ancestries: Vec
, +} + /// A scheduled change of authority set. #[cfg_attr(feature = "std", derive(Serialize))] #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)] diff --git a/primitives/inherents/Cargo.toml b/primitives/inherents/Cargo.toml index 628f938880e9f..b176147c053a6 100644 --- a/primitives/inherents/Cargo.toml +++ b/primitives/inherents/Cargo.toml @@ -19,7 +19,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = impl-trait-for-tuples = "0.2.2" thiserror = { version = "1.0.30", optional = true } sp-core = { version = "6.0.0", default-features = false, path = "../core" } -sp-runtime = { version = "6.0.0", optional = true, path = "../runtime" } +sp-runtime = { version = "6.0.0", optional = true, default-features = false, path = "../runtime" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] @@ -31,7 +31,7 @@ std = [ "async-trait", "codec/std", "sp-core/std", - "sp-runtime", + "sp-runtime/std", "sp-std/std", "thiserror", ] diff --git a/primitives/io/Cargo.toml b/primitives/io/Cargo.toml index 2e271d3949dee..26dec17e032dd 100644 --- a/primitives/io/Cargo.toml +++ b/primitives/io/Cargo.toml @@ -22,10 +22,10 @@ sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-keystore = { version = "0.12.0", default-features = false, optional = true, path = "../keystore" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } libsecp256k1 = { version = "0.7", optional = true } -sp-state-machine = { version = "0.12.0", optional = true, path = "../state-machine" } +sp-state-machine = { version = "0.12.0", default-features = false, optional = true, path = "../state-machine" } sp-wasm-interface = { version = "6.0.0", path = "../wasm-interface", default-features = false } sp-runtime-interface = { version = "6.0.0", default-features = false, path = "../runtime-interface" } -sp-trie = { version = "6.0.0", optional = true, path = "../trie" } +sp-trie = { version = "6.0.0", default-features = false, optional = true, path = "../trie" } sp-externalities = { version = "0.12.0", default-features = false, path = "../externalities" } sp-tracing = { version = "5.0.0", default-features = false, path = "../tracing" } log = { version = "0.4.17", optional = true } @@ -38,14 +38,15 @@ tracing-core = { version = "0.1.28", default-features = false} [features] default = ["std"] std = [ + "bytes/std", "sp-externalities/std", "sp-core/std", "sp-keystore", "codec/std", "sp-std/std", "hash-db/std", - "sp-trie", - "sp-state-machine", + "sp-trie/std", + "sp-state-machine/std", "libsecp256k1", "secp256k1", "sp-runtime-interface/std", diff --git a/primitives/keystore/src/testing.rs b/primitives/keystore/src/testing.rs index 65f86265c6b9f..c13aeb9e3f825 100644 --- a/primitives/keystore/src/testing.rs +++ b/primitives/keystore/src/testing.rs @@ -368,8 +368,11 @@ impl SyncCryptoStore for KeyStore { transcript_data: VRFTranscriptData, ) -> Result, Error> { let transcript = make_transcript(transcript_data); - let pair = - if let Some(k) = self.sr25519_key_pair(key_type, public) { k } else { return Ok(None) }; + let pair = if let Some(k) = self.sr25519_key_pair(key_type, public) { + k + } else { + return Ok(None) + }; let (inout, proof, _) = pair.as_ref().vrf_sign(transcript); Ok(Some(VRFSignature { output: inout.to_output(), proof })) diff --git a/primitives/merkle-mountain-range/Cargo.toml b/primitives/merkle-mountain-range/Cargo.toml index 2be3f592b2b20..0be53132f3eec 100644 --- a/primitives/merkle-mountain-range/Cargo.toml +++ b/primitives/merkle-mountain-range/Cargo.toml @@ -13,6 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-api = { version = "4.0.0-dev", default-features = false, path = "../api" } @@ -22,7 +23,7 @@ sp-runtime = { version = "6.0.0", default-features = false, path = "../runtime" sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] -hex-literal = "0.3" +array-bytes = "4.1" [features] default = ["std"] diff --git a/primitives/merkle-mountain-range/src/lib.rs b/primitives/merkle-mountain-range/src/lib.rs index 8a2e901aefddf..06bc1f4bffe84 100644 --- a/primitives/merkle-mountain-range/src/lib.rs +++ b/primitives/merkle-mountain-range/src/lib.rs @@ -20,6 +20,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #![warn(missing_docs)] +use scale_info::TypeInfo; use sp_debug_derive::RuntimeDebug; use sp_runtime::traits; #[cfg(not(feature = "std"))] @@ -69,7 +70,7 @@ impl OnNewRoot for () { } /// A MMR proof data for one of the leaves. -#[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq)] +#[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)] pub struct Proof { /// The index of the leaf the proof is for. pub leaf_index: LeafIndex, @@ -352,7 +353,7 @@ impl_leaf_data_for_tuple!(A:0, B:1, C:2, D:3); impl_leaf_data_for_tuple!(A:0, B:1, C:2, D:3, E:4); /// A MMR proof data for a group of leaves. -#[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq)] +#[derive(codec::Encode, codec::Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)] pub struct BatchProof { /// The indices of the leaves the proof is for. pub leaf_indices: Vec, @@ -386,6 +387,8 @@ impl Proof { /// Merkle Mountain Range operation error. #[derive(RuntimeDebug, codec::Encode, codec::Decode, PartialEq, Eq)] pub enum Error { + /// Error during translation of a block number into a leaf index. + BlockNumToLeafIndex, /// Error while pushing new node. Push, /// Error getting the new root. @@ -402,6 +405,8 @@ pub enum Error { PalletNotIncluded, /// Cannot find the requested leaf index InvalidLeafIndex, + /// The provided best know block number is invalid. + InvalidBestKnownBlock, } impl Error { @@ -431,9 +436,9 @@ impl Error { sp_api::decl_runtime_apis! { /// API to interact with MMR pallet. - pub trait MmrApi { - /// Generate MMR proof for a leaf under given index. - fn generate_proof(leaf_index: LeafIndex) -> Result<(EncodableOpaqueLeaf, Proof), Error>; + pub trait MmrApi { + /// Generate MMR proof for a block with a specified `block_number`. + fn generate_proof(block_number: BlockNumber) -> Result<(EncodableOpaqueLeaf, Proof), Error>; /// Verify MMR proof against on-chain MMR. /// @@ -454,8 +459,14 @@ sp_api::decl_runtime_apis! { /// Return the on-chain MMR root hash. fn mmr_root() -> Result; - /// Generate MMR proof for a series of leaves under given indices. - fn generate_batch_proof(leaf_indices: Vec) -> Result<(Vec, BatchProof), Error>; + /// Generate MMR proof for a series of blocks with the specified block numbers. + fn generate_batch_proof(block_numbers: Vec) -> Result<(Vec, BatchProof), Error>; + + /// Generate MMR proof for a series of `block_numbers`, given the `best_known_block_number`. + fn generate_historical_batch_proof( + block_numbers: Vec, + best_known_block_number: BlockNumber + ) -> Result<(Vec, BatchProof), Error>; /// Verify MMR proof against on-chain MMR for a batch of leaves. /// @@ -535,11 +546,16 @@ mod tests { cases.into_iter().map(Result::<_, codec::Error>::Ok).collect::>() ); // check encoding correctness - assert_eq!(&encoded[0], &hex_literal::hex!("00343048656c6c6f20576f726c6421")); + assert_eq!( + &encoded[0], + &array_bytes::hex2bytes_unchecked("00343048656c6c6f20576f726c6421") + ); assert_eq!( encoded[1].as_slice(), - hex_literal::hex!("01c3e7ba6b511162fead58f2c8b5764ce869ed1118011ac37392522ed16720bbcd") - .as_ref() + array_bytes::hex2bytes_unchecked( + "01c3e7ba6b511162fead58f2c8b5764ce869ed1118011ac37392522ed16720bbcd" + ) + .as_slice() ); } diff --git a/primitives/npos-elections/fuzzer/Cargo.toml b/primitives/npos-elections/fuzzer/Cargo.toml index a200d5c41ee35..293a17624820b 100644 --- a/primitives/npos-elections/fuzzer/Cargo.toml +++ b/primitives/npos-elections/fuzzer/Cargo.toml @@ -14,7 +14,7 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } honggfuzz = "0.5" rand = { version = "0.8", features = ["std", "small_rng"] } @@ -36,4 +36,4 @@ path = "src/phragmms_balancing.rs" [[bin]] name = "phragmen_pjr" -path = "src/phragmen_pjr.rs" \ No newline at end of file +path = "src/phragmen_pjr.rs" diff --git a/primitives/npos-elections/fuzzer/src/common.rs b/primitives/npos-elections/fuzzer/src/common.rs index e5853f28c4929..ad9bd43f9bce0 100644 --- a/primitives/npos-elections/fuzzer/src/common.rs +++ b/primitives/npos-elections/fuzzer/src/common.rs @@ -80,7 +80,7 @@ pub fn generate_random_npos_inputs( } candidates.push(id); } - candidates.sort_unstable(); + candidates.sort(); candidates.dedup(); assert_eq!(candidates.len(), candidate_count); @@ -99,11 +99,11 @@ pub fn generate_random_npos_inputs( let mut chosen_candidates = Vec::with_capacity(n_candidates_chosen); chosen_candidates.extend(candidates.choose_multiple(&mut rng, n_candidates_chosen)); - chosen_candidates.sort_unstable(); + chosen_candidates.sort(); voters.push((id, vote_weight, chosen_candidates)); } - voters.sort_unstable(); + voters.sort(); voters.dedup_by_key(|(id, _weight, _chosen_candidates)| *id); assert_eq!(voters.len(), voter_count); diff --git a/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs b/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs index 2396fdfa3b40e..0401249a3df1d 100644 --- a/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs +++ b/primitives/npos-elections/fuzzer/src/phragmen_pjr.rs @@ -68,18 +68,18 @@ fn main() { #[cfg(not(fuzzing))] #[derive(Debug, Parser)] -#[clap(author, version, about)] +#[command(author, version, about)] struct Opt { /// How many candidates participate in this election - #[clap(short, long)] + #[arg(short, long)] candidates: Option, /// How many voters participate in this election - #[clap(short, long)] + #[arg(short, long)] voters: Option, /// Random seed to use in this election - #[clap(long)] + #[arg(long)] seed: Option, } diff --git a/primitives/npos-elections/src/lib.rs b/primitives/npos-elections/src/lib.rs index dd2a9bf198f8d..514ded67ad38b 100644 --- a/primitives/npos-elections/src/lib.rs +++ b/primitives/npos-elections/src/lib.rs @@ -74,17 +74,16 @@ #![cfg_attr(not(feature = "std"), no_std)] +use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; use sp_arithmetic::{traits::Zero, Normalizable, PerThing, Rational128, ThresholdOrd}; -use sp_core::RuntimeDebug; +use sp_core::{bounded::BoundedVec, RuntimeDebug}; use sp_std::{ cell::RefCell, cmp::Ordering, collections::btree_map::BTreeMap, prelude::*, rc::Rc, vec, }; -use codec::{Decode, Encode, MaxEncodedLen}; -#[cfg(feature = "std")] -use serde::{Deserialize, Serialize}; - #[cfg(test)] mod mock; #[cfg(test)] @@ -451,6 +450,11 @@ impl Default for Support { /// The main advantage of this is that it is encodable. pub type Supports = Vec<(A, Support)>; +/// Same as `Supports` bounded by `MaxWinners`. +/// +/// To note, the inner `Support` is still unbounded. +pub type BoundedSupports = BoundedVec<(A, Support), MaxWinners>; + /// Linkage from a winner to their [`Support`]. /// /// This is more helpful than a normal [`Supports`] as it allows faster error checking. diff --git a/primitives/runtime-interface/Cargo.toml b/primitives/runtime-interface/Cargo.toml index a657c98381c9a..e7f0cee3f140f 100644 --- a/primitives/runtime-interface/Cargo.toml +++ b/primitives/runtime-interface/Cargo.toml @@ -22,7 +22,7 @@ sp-runtime-interface-proc-macro = { version = "5.0.0", path = "proc-macro" } sp-externalities = { version = "0.12.0", default-features = false, path = "../externalities" } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["bytes"] } static_assertions = "1.0.0" -primitive-types = { version = "0.11.1", default-features = false } +primitive-types = { version = "0.12.0", default-features = false } sp-storage = { version = "6.0.0", default-features = false, path = "../storage" } impl-trait-for-tuples = "0.2.2" @@ -37,6 +37,8 @@ trybuild = "1.0.60" [features] default = [ "std" ] std = [ + "sp-storage/std", + "bytes/std", "sp-wasm-interface/std", "sp-std/std", "sp-tracing/std", diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 9e4b36c584e91..01594ed69e312 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -19,7 +19,7 @@ either = { version = "1.5", default-features = false } hash256-std-hasher = { version = "0.15.2", default-features = false } impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", default-features = false } -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } paste = "1.0" rand = { version = "0.7.2", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } @@ -29,6 +29,7 @@ sp-arithmetic = { version = "5.0.0", default-features = false, path = "../arithm sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-io = { version = "6.0.0", default-features = false, path = "../io" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } +sp-weights = { version = "4.0.0", default-features = false, path = "../weights" } [dev-dependencies] rand = "0.7.2" @@ -40,7 +41,6 @@ sp-tracing = { version = "5.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } [features] -bench = [] runtime-benchmarks = [] default = ["std"] std = [ @@ -57,4 +57,5 @@ std = [ "sp-core/std", "sp-io/std", "sp-std/std", + "sp-weights/std", ] diff --git a/primitives/runtime/src/generic/checked_extrinsic.rs b/primitives/runtime/src/generic/checked_extrinsic.rs index 5d6c657a68977..fd7745c6031ff 100644 --- a/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/primitives/runtime/src/generic/checked_extrinsic.rs @@ -39,12 +39,13 @@ pub struct CheckedExtrinsic { pub function: Call, } -impl traits::Applyable for CheckedExtrinsic +impl traits::Applyable + for CheckedExtrinsic where AccountId: Member + MaybeDisplay, - Call: Member + Dispatchable, + Call: Member + Dispatchable, Extra: SignedExtension, - Origin: From>, + RuntimeOrigin: From>, { type Call = Call; @@ -78,7 +79,7 @@ where U::pre_dispatch(&self.function)?; (None, None) }; - let res = self.function.dispatch(Origin::from(maybe_who)); + let res = self.function.dispatch(RuntimeOrigin::from(maybe_who)); let post_info = match res { Ok(info) => info, Err(err) => err.post_info, diff --git a/primitives/runtime/src/generic/era.rs b/primitives/runtime/src/generic/era.rs index 2ca50b12b2e1f..b26545fb8404e 100644 --- a/primitives/runtime/src/generic/era.rs +++ b/primitives/runtime/src/generic/era.rs @@ -63,7 +63,7 @@ impl Era { /// does not exceed `BlockHashCount` parameter passed to `system` module, since that /// prunes old blocks and renders transactions immediately invalid. pub fn mortal(period: u64, current: u64) -> Self { - let period = period.checked_next_power_of_two().unwrap_or(1 << 16).max(4).min(1 << 16); + let period = period.checked_next_power_of_two().unwrap_or(1 << 16).clamp(4, 1 << 16); let phase = current % period; let quantize_factor = (period >> 12).max(1); let quantized_phase = phase / quantize_factor * quantize_factor; @@ -105,7 +105,7 @@ impl Encode for Era { Self::Immortal => output.push_byte(0), Self::Mortal(period, phase) => { let quantize_factor = (*period as u64 >> 12).max(1); - let encoded = (period.trailing_zeros() - 1).max(1).min(15) as u16 | + let encoded = (period.trailing_zeros() - 1).clamp(1, 15) as u16 | ((phase / quantize_factor) << 4) as u16; encoded.encode_to(output); }, diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 811ca33dbfa25..96706dd919650 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -19,10 +19,6 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -// to allow benchmarking -#![cfg_attr(feature = "bench", feature(test))] -#[cfg(feature = "bench")] -extern crate test; #[doc(hidden)] pub use codec; @@ -36,6 +32,8 @@ pub use sp_std; #[doc(hidden)] pub use paste; +#[doc(hidden)] +pub use sp_arithmetic::traits::Saturating; #[doc(hidden)] pub use sp_application_crypto as app_crypto; @@ -55,7 +53,6 @@ use sp_std::prelude::*; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -pub mod bounded; pub mod curve; pub mod generic; pub mod legacy; @@ -70,9 +67,6 @@ pub mod transaction_validity; pub use crate::runtime_string::*; -// Re-export bounded types -pub use bounded::{BoundedBTreeMap, BoundedBTreeSet, BoundedSlice, BoundedVec, WeakBoundedVec}; - // Re-export Multiaddress pub use multiaddress::MultiAddress; @@ -82,9 +76,13 @@ pub use generic::{Digest, DigestItem}; pub use sp_application_crypto::{BoundToRuntimeAppPublic, RuntimeAppPublic}; /// Re-export this since it's part of the API of this crate. pub use sp_core::{ + bounded::{BoundedBTreeMap, BoundedBTreeSet, BoundedSlice, BoundedVec, WeakBoundedVec}, crypto::{key_types, AccountId32, CryptoType, CryptoTypeId, KeyTypeId}, TypeId, }; +/// Re-export bounded_vec and bounded_btree_map macros only when std is enabled. +#[cfg(feature = "std")] +pub use sp_core::{bounded_btree_map, bounded_vec}; /// Re-export `RuntimeDebug`, to avoid dependency clutter. pub use sp_core::RuntimeDebug; @@ -549,6 +547,12 @@ pub enum DispatchError { /// The number of transactional layers has been reached, or we are not in a transactional /// layer. Transactional(TransactionalError), + /// Resources exhausted, e.g. attempt to read/write data which is too large to manipulate. + Exhausted, + /// The state is corrupt; this is generally not going to fix itself. + Corruption, + /// Some resource (e.g. a preimage) is unavailable right now. This might fix itself later. + Unavailable, } /// Result of a `Dispatchable` which contains the `DispatchResult` and additional information about @@ -673,18 +677,21 @@ impl From<&'static str> for DispatchError { impl From for &'static str { fn from(err: DispatchError) -> &'static str { + use DispatchError::*; match err { - DispatchError::Other(msg) => msg, - DispatchError::CannotLookup => "Cannot lookup", - DispatchError::BadOrigin => "Bad origin", - DispatchError::Module(ModuleError { message, .. }) => - message.unwrap_or("Unknown module error"), - DispatchError::ConsumerRemaining => "Consumer remaining", - DispatchError::NoProviders => "No providers", - DispatchError::TooManyConsumers => "Too many consumers", - DispatchError::Token(e) => e.into(), - DispatchError::Arithmetic(e) => e.into(), - DispatchError::Transactional(e) => e.into(), + Other(msg) => msg, + CannotLookup => "Cannot lookup", + BadOrigin => "Bad origin", + Module(ModuleError { message, .. }) => message.unwrap_or("Unknown module error"), + ConsumerRemaining => "Consumer remaining", + NoProviders => "No providers", + TooManyConsumers => "Too many consumers", + Token(e) => e.into(), + Arithmetic(e) => e.into(), + Transactional(e) => e.into(), + Exhausted => "Resources exhausted", + Corruption => "State corrupt", + Unavailable => "Resource unavailable", } } } @@ -700,33 +707,37 @@ where impl traits::Printable for DispatchError { fn print(&self) { + use DispatchError::*; "DispatchError".print(); match self { - Self::Other(err) => err.print(), - Self::CannotLookup => "Cannot lookup".print(), - Self::BadOrigin => "Bad origin".print(), - Self::Module(ModuleError { index, error, message }) => { + Other(err) => err.print(), + CannotLookup => "Cannot lookup".print(), + BadOrigin => "Bad origin".print(), + Module(ModuleError { index, error, message }) => { index.print(); error.print(); if let Some(msg) = message { msg.print(); } }, - Self::ConsumerRemaining => "Consumer remaining".print(), - Self::NoProviders => "No providers".print(), - Self::TooManyConsumers => "Too many consumers".print(), - Self::Token(e) => { + ConsumerRemaining => "Consumer remaining".print(), + NoProviders => "No providers".print(), + TooManyConsumers => "Too many consumers".print(), + Token(e) => { "Token error: ".print(); <&'static str>::from(*e).print(); }, - Self::Arithmetic(e) => { + Arithmetic(e) => { "Arithmetic error: ".print(); <&'static str>::from(*e).print(); }, - Self::Transactional(e) => { + Transactional(e) => { "Transactional error: ".print(); <&'static str>::from(*e).print(); }, + Exhausted => "Resources exhausted".print(), + Corruption => "State corrupt".print(), + Unavailable => "Resource unavailable".print(), } } } @@ -825,7 +836,8 @@ pub fn verify_encoded_lazy( macro_rules! assert_eq_error_rate { ($x:expr, $y:expr, $error:expr $(,)?) => { assert!( - ($x) >= (($y) - ($error)) && ($x) <= (($y) + ($error)), + ($x >= $crate::Saturating::saturating_sub($y, $error)) && + ($x <= $crate::Saturating::saturating_add($y, $error)), "{:?} != {:?} (with error rate {:?})", $x, $y, @@ -834,42 +846,19 @@ macro_rules! assert_eq_error_rate { }; } -/// Build a bounded vec from the given literals. -/// -/// The type of the outcome must be known. -/// -/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding -/// bounded vec type. Thus, this is only suitable for testing and non-consensus code. +/// Same as [`assert_eq_error_rate`], but intended to be used with floating point number, or +/// generally those who do not have over/underflow potentials. #[macro_export] #[cfg(feature = "std")] -macro_rules! bounded_vec { - ($ ($values:expr),* $(,)?) => { - { - $crate::sp_std::vec![$($values),*].try_into().unwrap() - } - }; - ( $value:expr ; $repetition:expr ) => { - { - $crate::sp_std::vec![$value ; $repetition].try_into().unwrap() - } - } -} - -/// Build a bounded btree-map from the given literals. -/// -/// The type of the outcome must be known. -/// -/// Will not handle any errors and just panic if the given literals cannot fit in the corresponding -/// bounded vec type. Thus, this is only suitable for testing and non-consensus code. -#[macro_export] -#[cfg(feature = "std")] -macro_rules! bounded_btree_map { - ($ ( $key:expr => $value:expr ),* $(,)?) => { - { - $crate::traits::TryCollect::<$crate::BoundedBTreeMap<_, _, _>>::try_collect( - $crate::sp_std::vec![$(($key, $value)),*].into_iter() - ).unwrap() - } +macro_rules! assert_eq_error_rate_float { + ($x:expr, $y:expr, $error:expr $(,)?) => { + assert!( + ($x >= $y - $error) && ($x <= $y + $error), + "{:?} != {:?} (with error rate {:?})", + $x, + $y, + $error, + ); }; } diff --git a/primitives/runtime/src/offchain/storage_lock.rs b/primitives/runtime/src/offchain/storage_lock.rs index 4ea9030745296..47325743bd2f3 100644 --- a/primitives/runtime/src/offchain/storage_lock.rs +++ b/primitives/runtime/src/offchain/storage_lock.rs @@ -77,8 +77,8 @@ const STORAGE_LOCK_DEFAULT_EXPIRY_DURATION: Duration = Duration::from_millis(20_ const STORAGE_LOCK_DEFAULT_EXPIRY_BLOCKS: u32 = 4; /// Time between checks if the lock is still being held in milliseconds. -const STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MIN: Duration = Duration::from_millis(100); -const STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MAX: Duration = Duration::from_millis(10); +const STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MIN: Duration = Duration::from_millis(10); +const STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MAX: Duration = Duration::from_millis(100); /// Lockable item for use with a persisted storage lock. /// @@ -137,10 +137,9 @@ impl Lockable for Time { let remainder: Duration = now.diff(deadline); // do not snooze the full duration, but instead snooze max 100ms // it might get unlocked in another thread - use core::cmp::{max, min}; - let snooze = max( - min(remainder, STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MAX), + let snooze = remainder.clamp( STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MIN, + STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MAX, ); sp_io::offchain::sleep_until(now.add(snooze)); } @@ -239,10 +238,9 @@ impl Lockable for BlockAndTime { fn snooze(deadline: &Self::Deadline) { let now = offchain::timestamp(); let remainder: Duration = now.diff(&(deadline.timestamp)); - use core::cmp::{max, min}; - let snooze = max( - min(remainder, STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MAX), + let snooze = remainder.clamp( STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MIN, + STORAGE_LOCK_PER_CHECK_ITERATION_SNOOZE_MAX, ); sp_io::offchain::sleep_until(now.add(snooze)); } diff --git a/primitives/runtime/src/testing.rs b/primitives/runtime/src/testing.rs index 47547d517f02e..045ad89553157 100644 --- a/primitives/runtime/src/testing.rs +++ b/primitives/runtime/src/testing.rs @@ -393,8 +393,15 @@ where impl Applyable for TestXt where - Call: - 'static + Sized + Send + Sync + Clone + Eq + Codec + Debug + Dispatchable, + Call: 'static + + Sized + + Send + + Sync + + Clone + + Eq + + Codec + + Debug + + Dispatchable, Extra: SignedExtension, Origin: From>, { diff --git a/primitives/runtime/src/traits.rs b/primitives/runtime/src/traits.rs index 3501106bcb86c..49508051ddbdf 100644 --- a/primitives/runtime/src/traits.rs +++ b/primitives/runtime/src/traits.rs @@ -38,6 +38,11 @@ pub use sp_arithmetic::traits::{ }; use sp_core::{self, storage::StateVersion, Hasher, RuntimeDebug, ShufflingSeed, TypeId}; #[doc(hidden)] +pub use sp_core::{ + parameter_types, ConstBool, ConstI128, ConstI16, ConstI32, ConstI64, ConstI8, ConstU128, + ConstU16, ConstU32, ConstU64, ConstU8, Get, GetDefault, TryCollect, TypedGet, +}; +#[doc(hidden)] pub use sp_std::marker::PhantomData; use sp_std::{self, fmt::Debug, prelude::*}; #[cfg(feature = "std")] @@ -276,203 +281,6 @@ where } } -/// A trait for querying a single value from a type defined in the trait. -/// -/// It is not required that the value is constant. -pub trait TypedGet { - /// The type which is returned. - type Type; - /// Return the current value. - fn get() -> Self::Type; -} - -/// A trait for querying a single value from a type. -/// -/// It is not required that the value is constant. -pub trait Get { - /// Return the current value. - fn get() -> T; -} - -impl Get for () { - fn get() -> T { - T::default() - } -} - -/// Implement Get by returning Default for any type that implements Default. -pub struct GetDefault; -impl Get for GetDefault { - fn get() -> T { - T::default() - } -} - -/// Try and collect into a collection `C`. -pub trait TryCollect { - /// The error type that gets returned when a collection can't be made from `self`. - type Error; - /// Consume self and try to collect the results into `C`. - /// - /// This is useful in preventing the undesirable `.collect().try_into()` call chain on - /// collections that need to be converted into a bounded type (e.g. `BoundedVec`). - fn try_collect(self) -> Result; -} - -macro_rules! impl_const_get { - ($name:ident, $t:ty) => { - #[doc = "Const getter for a basic type."] - #[derive($crate::RuntimeDebug)] - pub struct $name; - impl Get<$t> for $name { - fn get() -> $t { - T - } - } - impl Get> for $name { - fn get() -> Option<$t> { - Some(T) - } - } - impl TypedGet for $name { - type Type = $t; - fn get() -> $t { - T - } - } - }; -} - -impl_const_get!(ConstBool, bool); -impl_const_get!(ConstU8, u8); -impl_const_get!(ConstU16, u16); -impl_const_get!(ConstU32, u32); -impl_const_get!(ConstU64, u64); -impl_const_get!(ConstU128, u128); -impl_const_get!(ConstI8, i8); -impl_const_get!(ConstI16, i16); -impl_const_get!(ConstI32, i32); -impl_const_get!(ConstI64, i64); -impl_const_get!(ConstI128, i128); - -/// Create new implementations of the [`Get`](crate::traits::Get) trait. -/// -/// The so-called parameter type can be created in four different ways: -/// -/// - Using `const` to create a parameter type that provides a `const` getter. It is required that -/// the `value` is const. -/// -/// - Declare the parameter type without `const` to have more freedom when creating the value. -/// -/// NOTE: A more substantial version of this macro is available in `frame_support` crate which -/// allows mutable and persistant variants. -/// -/// # Examples -/// -/// ``` -/// # use sp_runtime::traits::Get; -/// # use sp_runtime::parameter_types; -/// // This function cannot be used in a const context. -/// fn non_const_expression() -> u64 { 99 } -/// -/// const FIXED_VALUE: u64 = 10; -/// parameter_types! { -/// pub const Argument: u64 = 42 + FIXED_VALUE; -/// /// Visibility of the type is optional -/// OtherArgument: u64 = non_const_expression(); -/// } -/// -/// trait Config { -/// type Parameter: Get; -/// type OtherParameter: Get; -/// } -/// -/// struct Runtime; -/// impl Config for Runtime { -/// type Parameter = Argument; -/// type OtherParameter = OtherArgument; -/// } -/// ``` -/// -/// # Invalid example: -/// -/// ```compile_fail -/// # use sp_runtime::traits::Get; -/// # use sp_runtime::parameter_types; -/// // This function cannot be used in a const context. -/// fn non_const_expression() -> u64 { 99 } -/// -/// parameter_types! { -/// pub const Argument: u64 = non_const_expression(); -/// } -/// ``` -#[macro_export] -macro_rules! parameter_types { - ( - $( #[ $attr:meta ] )* - $vis:vis const $name:ident: $type:ty = $value:expr; - $( $rest:tt )* - ) => ( - $( #[ $attr ] )* - $vis struct $name; - $crate::parameter_types!(@IMPL_CONST $name , $type , $value); - $crate::parameter_types!( $( $rest )* ); - ); - ( - $( #[ $attr:meta ] )* - $vis:vis $name:ident: $type:ty = $value:expr; - $( $rest:tt )* - ) => ( - $( #[ $attr ] )* - $vis struct $name; - $crate::parameter_types!(@IMPL $name, $type, $value); - $crate::parameter_types!( $( $rest )* ); - ); - () => (); - (@IMPL_CONST $name:ident, $type:ty, $value:expr) => { - impl $name { - /// Returns the value of this parameter type. - pub const fn get() -> $type { - $value - } - } - - impl> $crate::traits::Get for $name { - fn get() -> I { - I::from(Self::get()) - } - } - - impl $crate::traits::TypedGet for $name { - type Type = $type; - fn get() -> $type { - Self::get() - } - } - }; - (@IMPL $name:ident, $type:ty, $value:expr) => { - impl $name { - /// Returns the value of this parameter type. - pub fn get() -> $type { - $value - } - } - - impl> $crate::traits::Get for $name { - fn get() -> I { - I::from(Self::get()) - } - } - - impl $crate::traits::TypedGet for $name { - type Type = $type; - fn get() -> $type { - Self::get() - } - } - }; -} - /// Extensible conversion trait. Generic over only source type, with destination type being /// associated. pub trait Morph { @@ -1239,7 +1047,7 @@ pub trait Dispatchable { /// Every function call from your runtime has an origin, which specifies where the extrinsic was /// generated from. In the case of a signed extrinsic (transaction), the origin contains an /// identifier for the caller. The origin can be empty in the case of an inherent extrinsic. - type Origin; + type RuntimeOrigin; /// ... type Config; /// An opaque set of information attached to the transaction. This could be constructed anywhere @@ -1250,7 +1058,8 @@ pub trait Dispatchable { /// with information about a `Dispatchable` that is ownly known post dispatch. type PostInfo: Eq + PartialEq + Clone + Copy + Encode + Decode + Printable; /// Actually dispatch this call and return the result of it. - fn dispatch(self, origin: Self::Origin) -> crate::DispatchResultWithInfo; + fn dispatch(self, origin: Self::RuntimeOrigin) + -> crate::DispatchResultWithInfo; } /// Shortcut to reference the `Info` type of a `Dispatchable`. @@ -1259,11 +1068,14 @@ pub type DispatchInfoOf = ::Info; pub type PostDispatchInfoOf = ::PostInfo; impl Dispatchable for () { - type Origin = (); + type RuntimeOrigin = (); type Config = (); type Info = (); type PostInfo = (); - fn dispatch(self, _origin: Self::Origin) -> crate::DispatchResultWithInfo { + fn dispatch( + self, + _origin: Self::RuntimeOrigin, + ) -> crate::DispatchResultWithInfo { panic!("This implementation should not be used for actual dispatch."); } } @@ -2041,6 +1853,12 @@ impl Printable for bool { } } +impl Printable for sp_weights::Weight { + fn print(&self) { + self.ref_time().print() + } +} + impl Printable for () { fn print(&self) { "()".print() diff --git a/primitives/sandbox/Cargo.toml b/primitives/sandbox/Cargo.toml index 6a83e20a94618..90b7df105ecde 100644 --- a/primitives/sandbox/Cargo.toml +++ b/primitives/sandbox/Cargo.toml @@ -12,16 +12,10 @@ readme = "README.md" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] -[target.'cfg(target_arch = "wasm32")'.dependencies] -wasmi = { version = "0.9.1", default-features = false, features = ["core"] } - -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] -wasmi = "0.9.0" - [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false } log = { version = "0.4", default-features = false } -wasmi = { version = "0.9.0", optional = true } +wasmi = { version = "0.13", default-features = false } sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-io = { version = "6.0.0", default-features = false, path = "../io" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } @@ -40,7 +34,7 @@ std = [ "sp-io/std", "sp-std/std", "sp-wasm-interface/std", - "wasmi", + "wasmi/std", ] strict = [] wasmer-sandbox = [] diff --git a/primitives/sandbox/src/embedded_executor.rs b/primitives/sandbox/src/embedded_executor.rs index 4410e26c8d122..115c3192f3d89 100644 --- a/primitives/sandbox/src/embedded_executor.rs +++ b/primitives/sandbox/src/embedded_executor.rs @@ -22,7 +22,7 @@ use alloc::string::String; use wasmi::{ memory_units::Pages, Externals, FuncInstance, FuncRef, GlobalDescriptor, GlobalRef, ImportResolver, MemoryDescriptor, MemoryInstance, MemoryRef, Module, ModuleInstance, ModuleRef, - RuntimeArgs, RuntimeValue, Signature, TableDescriptor, TableRef, Trap, TrapKind, + RuntimeArgs, RuntimeValue, Signature, TableDescriptor, TableRef, Trap, }; use sp_std::{ @@ -113,7 +113,7 @@ impl<'a, T> Externals for GuestExternals<'a, T> { ReturnValue::Value(v) => Some(to_wasmi(v)), ReturnValue::Unit => None, }), - Err(HostError) => Err(TrapKind::Host(Box::new(DummyHostError)).into()), + Err(HostError) => Err(Trap::host(DummyHostError)), } } } diff --git a/primitives/state-machine/Cargo.toml b/primitives/state-machine/Cargo.toml index 5de6eb7112eea..860bca2a9de18 100644 --- a/primitives/state-machine/Cargo.toml +++ b/primitives/state-machine/Cargo.toml @@ -31,7 +31,7 @@ sp-std = { version = "4.0.0", default-features = false, path = "../std" } sp-trie = { version = "6.0.0", default-features = false, path = "../trie" } [dev-dependencies] -hex-literal = "0.3.4" +array-bytes = "4.1" pretty_assertions = "1.2.1" rand = "0.7.2" sp-runtime = { version = "6.0.0", path = "../runtime" } diff --git a/primitives/state-machine/src/basic.rs b/primitives/state-machine/src/basic.rs index 236a515a2412d..fdc50e3f8f207 100644 --- a/primitives/state-machine/src/basic.rs +++ b/primitives/state-machine/src/basic.rs @@ -356,7 +356,6 @@ impl sp_externalities::ExtensionStore for BasicExternalities { #[cfg(test)] mod tests { use super::*; - use hex_literal::hex; use sp_core::{ map, storage::{well_known_keys::CODE, Storage, StorageChild}, @@ -368,10 +367,11 @@ mod tests { ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec()); ext.set_storage(b"dog".to_vec(), b"puppy".to_vec()); ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec()); - const ROOT: [u8; 32] = - hex!("39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa"); + let root = array_bytes::hex2bytes_unchecked( + "39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa", + ); - assert_eq!(&ext.storage_root(StateVersion::default())[..], &ROOT); + assert_eq!(&ext.storage_root(StateVersion::default())[..], &root); } #[test] diff --git a/primitives/state-machine/src/in_memory_backend.rs b/primitives/state-machine/src/in_memory_backend.rs index e205e83e85572..06714fb41405a 100644 --- a/primitives/state-machine/src/in_memory_backend.rs +++ b/primitives/state-machine/src/in_memory_backend.rs @@ -157,8 +157,8 @@ where fn from((inners, state_version): (Storage, StateVersion)) -> Self { let mut inner: HashMap, BTreeMap> = inners .children_default - .into_iter() - .map(|(_k, c)| (Some(c.child_info), c.data)) + .into_values() + .map(|c| (Some(c.child_info), c.data)) .collect(); inner.insert(None, inners.top); (inner, state_version).into() diff --git a/primitives/state-machine/src/lib.rs b/primitives/state-machine/src/lib.rs index 59488599883e9..4126aea478d5b 100644 --- a/primitives/state-machine/src/lib.rs +++ b/primitives/state-machine/src/lib.rs @@ -157,31 +157,28 @@ mod execution { use crate::backend::AsTrieBackend; use super::*; - use codec::{Codec, Decode, Encode}; + use codec::Codec; use hash_db::Hasher; use smallvec::SmallVec; use sp_core::{ hexdisplay::HexDisplay, storage::{ChildInfo, ChildType, PrefixedStorageKey}, traits::{CodeExecutor, ReadRuntimeVersionExt, RuntimeCode, SpawnNamed}, - NativeOrEncoded, NeverNativeValue, }; use sp_externalities::Extensions; use std::{ collections::{HashMap, HashSet}, fmt, - panic::UnwindSafe, - result, }; const PROOF_CLOSE_TRANSACTION: &str = "\ Closing a transaction that was started in this function. Client initiated transactions are protected from being closed by the runtime. qed"; - pub(crate) type CallResult = Result, E>; + pub(crate) type CallResult = Result, E>; /// Default handler of the execution manager. - pub type DefaultHandler = fn(CallResult, CallResult) -> CallResult; + pub type DefaultHandler = fn(CallResult, CallResult) -> CallResult; /// Trie backend with in-memory storage. pub type InMemoryBackend = TrieBackend, H>; @@ -243,9 +240,7 @@ mod execution { impl ExecutionStrategy { /// Gets the corresponding manager for the execution strategy. - pub fn get_manager( - self, - ) -> ExecutionManager> { + pub fn get_manager(self) -> ExecutionManager> { match self { ExecutionStrategy::AlwaysWasm => ExecutionManager::AlwaysWasm(BackendTrustLevel::Trusted), @@ -265,19 +260,19 @@ mod execution { } /// Evaluate to ExecutionManager::NativeElseWasm, without having to figure out the type. - pub fn native_else_wasm() -> ExecutionManager> { + pub fn native_else_wasm() -> ExecutionManager> { ExecutionManager::NativeElseWasm } /// Evaluate to ExecutionManager::AlwaysWasm with trusted backend, without having to figure out /// the type. - fn always_wasm() -> ExecutionManager> { + fn always_wasm() -> ExecutionManager> { ExecutionManager::AlwaysWasm(BackendTrustLevel::Trusted) } /// Evaluate ExecutionManager::AlwaysWasm with untrusted backend, without having to figure out /// the type. - fn always_untrusted_wasm() -> ExecutionManager> { + fn always_untrusted_wasm() -> ExecutionManager> { ExecutionManager::AlwaysWasm(BackendTrustLevel::Untrusted) } @@ -379,23 +374,10 @@ mod execution { pub fn execute(&mut self, strategy: ExecutionStrategy) -> Result, Box> { // We are not giving a native call and thus we are sure that the result can never be a // native value. - self.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( - strategy.get_manager(), - None, - ) - .map(NativeOrEncoded::into_encoded) + self.execute_using_consensus_failure_handler(strategy.get_manager()) } - fn execute_aux( - &mut self, - use_native: bool, - native_call: Option, - ) -> (CallResult, bool) - where - R: Decode + Encode + PartialEq, - NC: FnOnce() -> result::Result> - + UnwindSafe, - { + fn execute_aux(&mut self, use_native: bool) -> (CallResult, bool) { let mut cache = StorageTransactionCache::default(); let cache = match self.storage_transaction_cache.as_mut() { @@ -426,7 +408,6 @@ mod execution { self.method, self.call_data, use_native, - native_call, ); self.overlay @@ -444,26 +425,20 @@ mod execution { (result, was_native) } - fn execute_call_with_both_strategy( + fn execute_call_with_both_strategy( &mut self, - mut native_call: Option, on_consensus_failure: Handler, - ) -> CallResult + ) -> CallResult where - R: Decode + Encode + PartialEq, - NC: FnOnce() -> result::Result> - + UnwindSafe, - Handler: FnOnce( - CallResult, - CallResult, - ) -> CallResult, + Handler: + FnOnce(CallResult, CallResult) -> CallResult, { self.overlay.start_transaction(); - let (result, was_native) = self.execute_aux(true, native_call.take()); + let (result, was_native) = self.execute_aux(true); if was_native { self.overlay.rollback_transaction().expect(PROOF_CLOSE_TRANSACTION); - let (wasm_result, _) = self.execute_aux(false, native_call); + let (wasm_result, _) = self.execute_aux(false); if (result.is_ok() && wasm_result.is_ok() && result.as_ref().ok() == wasm_result.as_ref().ok()) || @@ -479,25 +454,16 @@ mod execution { } } - fn execute_call_with_native_else_wasm_strategy( - &mut self, - mut native_call: Option, - ) -> CallResult - where - R: Decode + Encode + PartialEq, - NC: FnOnce() -> result::Result> - + UnwindSafe, - { + fn execute_call_with_native_else_wasm_strategy(&mut self) -> CallResult { self.overlay.start_transaction(); - let (result, was_native) = self.execute_aux(true, native_call.take()); + let (result, was_native) = self.execute_aux(true); if !was_native || result.is_ok() { self.overlay.commit_transaction().expect(PROOF_CLOSE_TRANSACTION); result } else { self.overlay.rollback_transaction().expect(PROOF_CLOSE_TRANSACTION); - let (wasm_result, _) = self.execute_aux(false, native_call); - wasm_result + self.execute_aux(false).0 } } @@ -510,35 +476,29 @@ mod execution { /// /// Returns the result of the executed function either in native representation `R` or /// in SCALE encoded representation. - pub fn execute_using_consensus_failure_handler( + pub fn execute_using_consensus_failure_handler( &mut self, manager: ExecutionManager, - mut native_call: Option, - ) -> Result, Box> + ) -> Result, Box> where - R: Decode + Encode + PartialEq, - NC: FnOnce() -> result::Result> - + UnwindSafe, - Handler: FnOnce( - CallResult, - CallResult, - ) -> CallResult, + Handler: + FnOnce(CallResult, CallResult) -> CallResult, { let result = { match manager { - ExecutionManager::Both(on_consensus_failure) => self - .execute_call_with_both_strategy(native_call.take(), on_consensus_failure), + ExecutionManager::Both(on_consensus_failure) => + self.execute_call_with_both_strategy(on_consensus_failure), ExecutionManager::NativeElseWasm => - self.execute_call_with_native_else_wasm_strategy(native_call.take()), + self.execute_call_with_native_else_wasm_strategy(), ExecutionManager::AlwaysWasm(trust_level) => { let _abort_guard = match trust_level { BackendTrustLevel::Trusted => None, BackendTrustLevel::Untrusted => Some(sp_panic_handler::AbortGuard::never_abort()), }; - self.execute_aux(false, native_call).0 + self.execute_aux(false).0 }, - ExecutionManager::NativeWhenPossible => self.execute_aux(true, native_call).0, + ExecutionManager::NativeWhenPossible => self.execute_aux(true).0, } }; @@ -603,29 +563,23 @@ mod execution { let proving_backend = TrieBackendBuilder::wrap(trie_backend).with_recorder(Default::default()).build(); - let result = { - let mut sm = StateMachine::<_, H, Exec>::new( - &proving_backend, - overlay, - exec, - method, - call_data, - Extensions::default(), - runtime_code, - spawn_handle, - ); - - sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( - always_wasm(), - None, - )? - }; + let result = StateMachine::<_, H, Exec>::new( + &proving_backend, + overlay, + exec, + method, + call_data, + Extensions::default(), + runtime_code, + spawn_handle, + ) + .execute_using_consensus_failure_handler::<_>(always_wasm())?; let proof = proving_backend .extract_proof() .expect("A recorder was set and thus, a storage proof can be extracted; qed"); - Ok((result.into_encoded(), proof)) + Ok((result, proof)) } /// Check execution proof, generated by `prove_execution` call. @@ -673,7 +627,7 @@ mod execution { Exec: CodeExecutor + Clone + 'static, Spawn: SpawnNamed + Send + 'static, { - let mut sm = StateMachine::<_, H, Exec>::new( + StateMachine::<_, H, Exec>::new( trie_backend, overlay, exec, @@ -682,13 +636,8 @@ mod execution { Extensions::default(), runtime_code, spawn_handle, - ); - - sm.execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( - always_untrusted_wasm(), - None, ) - .map(NativeOrEncoded::into_encoded) + .execute_using_consensus_failure_handler(always_untrusted_wasm()) } /// Generate storage read proof. @@ -1362,21 +1311,16 @@ mod tests { use super::{backend::AsTrieBackend, ext::Ext, *}; use crate::{execution::CallResult, in_memory_backend::new_in_mem_hash_key}; use assert_matches::assert_matches; - use codec::{Decode, Encode}; + use codec::Encode; use sp_core::{ map, storage::{ChildInfo, StateVersion}, testing::TaskExecutor, traits::{CodeExecutor, Externalities, RuntimeCode}, - NativeOrEncoded, NeverNativeValue, }; use sp_runtime::traits::BlakeTwo256; use sp_trie::trie_types::{TrieDBMutBuilderV0, TrieDBMutBuilderV1}; - use std::{ - collections::{BTreeMap, HashMap}, - panic::UnwindSafe, - result, - }; + use std::collections::{BTreeMap, HashMap}; #[derive(Clone)] struct DummyCodeExecutor { @@ -1388,28 +1332,20 @@ mod tests { impl CodeExecutor for DummyCodeExecutor { type Error = u8; - fn call< - R: Encode + Decode + PartialEq, - NC: FnOnce() -> result::Result> + UnwindSafe, - >( + fn call( &self, ext: &mut dyn Externalities, _: &RuntimeCode, _method: &str, _data: &[u8], use_native: bool, - native_call: Option, - ) -> (CallResult, bool) { + ) -> (CallResult, bool) { let using_native = use_native && self.native_available; - match (using_native, self.native_succeeds, self.fallback_succeeds, native_call) { - (true, true, _, Some(call)) => { - let res = sp_externalities::set_and_run_with_externalities(ext, call); - (res.map(NativeOrEncoded::Native).map_err(|_| 0), true) - }, - (true, true, _, None) | (false, _, true, None) => ( - Ok(NativeOrEncoded::Encoded(vec![ + match (using_native, self.native_succeeds, self.fallback_succeeds) { + (true, true, _) | (false, _, true) => ( + Ok(vec![ ext.storage(b"value1").unwrap()[0] + ext.storage(b"value2").unwrap()[0], - ])), + ]), using_native, ), _ => (Err(0), using_native), @@ -1510,13 +1446,10 @@ mod tests { ); assert!(state_machine - .execute_using_consensus_failure_handler::<_, NeverNativeValue, fn() -> _>( - ExecutionManager::Both(|we, _ne| { - consensus_failed = true; - we - }), - None, - ) + .execute_using_consensus_failure_handler(ExecutionManager::Both(|we, _ne| { + consensus_failed = true; + we + }),) .is_err()); assert!(consensus_failed); } @@ -2260,51 +2193,4 @@ mod tests { overlay.commit_transaction().unwrap(); assert_eq!(overlay.storage(b"ccc"), Some(None)); } - - #[test] - fn runtime_registered_extensions_are_removed_after_execution() { - let state_version = StateVersion::default(); - use sp_externalities::ExternalitiesExt; - sp_externalities::decl_extension! { - struct DummyExt(u32); - } - - let backend = trie_backend::tests::test_trie(state_version, None, None); - let mut overlayed_changes = Default::default(); - let wasm_code = RuntimeCode::empty(); - - let mut state_machine = StateMachine::new( - &backend, - &mut overlayed_changes, - &DummyCodeExecutor { - native_available: true, - native_succeeds: true, - fallback_succeeds: false, - }, - "test", - &[], - Default::default(), - &wasm_code, - TaskExecutor::new(), - ); - - let run_state_machine = |state_machine: &mut StateMachine<_, _, _>| { - state_machine - .execute_using_consensus_failure_handler:: _, _, _>( - ExecutionManager::NativeWhenPossible, - Some(|| { - sp_externalities::with_externalities(|mut ext| { - ext.register_extension(DummyExt(2)).unwrap(); - }) - .unwrap(); - - Ok(()) - }), - ) - .unwrap(); - }; - - run_state_machine(&mut state_machine); - run_state_machine(&mut state_machine); - } } diff --git a/primitives/state-machine/src/overlayed_changes/mod.rs b/primitives/state-machine/src/overlayed_changes/mod.rs index 001b4b656c34e..9eb26d52f79f8 100644 --- a/primitives/state-machine/src/overlayed_changes/mod.rs +++ b/primitives/state-machine/src/overlayed_changes/mod.rs @@ -474,7 +474,7 @@ impl OverlayedChanges { pub fn children( &self, ) -> impl Iterator, &ChildInfo)> { - self.children.iter().map(|(_, v)| (v.0.changes(), &v.1)) + self.children.values().map(|v| (v.0.changes(), &v.1)) } /// Get an iterator over all top changes as been by the current transaction. @@ -743,7 +743,6 @@ impl<'a> OverlayedExtensions<'a> { mod tests { use super::*; use crate::{ext::Ext, InMemoryBackend}; - use hex_literal::hex; use sp_core::{traits::Externalities, Blake2Hasher}; use std::collections::BTreeMap; @@ -870,10 +869,11 @@ mod tests { let mut cache = StorageTransactionCache::default(); let mut ext = Ext::new(&mut overlay, &mut cache, &backend, None); - const ROOT: [u8; 32] = - hex!("39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa"); + let root = array_bytes::hex2bytes_unchecked( + "39245109cef3758c2eed2ccba8d9b370a917850af3824bc8348d505df2c298fa", + ); - assert_eq!(&ext.storage_root(state_version)[..], &ROOT); + assert_eq!(&ext.storage_root(state_version)[..], &root); } #[test] diff --git a/primitives/state-machine/src/testing.rs b/primitives/state-machine/src/testing.rs index 46b7573d9d1a6..e94d34b5560cd 100644 --- a/primitives/state-machine/src/testing.rs +++ b/primitives/state-machine/src/testing.rs @@ -334,7 +334,6 @@ where #[cfg(test)] mod tests { use super::*; - use hex_literal::hex; use sp_core::{storage::ChildInfo, traits::Externalities, H256}; use sp_runtime::traits::BlakeTwo256; @@ -346,8 +345,9 @@ mod tests { ext.set_storage(b"doe".to_vec(), b"reindeer".to_vec()); ext.set_storage(b"dog".to_vec(), b"puppy".to_vec()); ext.set_storage(b"dogglesworth".to_vec(), b"cat".to_vec()); - let root = - H256::from(hex!("ed4d8c799d996add422395a6abd7545491d40bd838d738afafa1b8a4de625489")); + let root = array_bytes::hex_n_into_unchecked::( + "ed4d8c799d996add422395a6abd7545491d40bd838d738afafa1b8a4de625489", + ); assert_eq!(H256::from_slice(ext.storage_root(Default::default()).as_slice()), root); } diff --git a/primitives/storage/Cargo.toml b/primitives/storage/Cargo.toml index b37a4eb4b331d..d04a88d129d34 100644 --- a/primitives/storage/Cargo.toml +++ b/primitives/storage/Cargo.toml @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -impl-serde = { version = "0.3.1", optional = true } +impl-serde = { version = "0.4.0", optional = true } ref-cast = "1.0.0" serde = { version = "1.0.136", features = ["derive"], optional = true } sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } diff --git a/primitives/storage/src/lib.rs b/primitives/storage/src/lib.rs index 0948cf431158d..79c1012196bde 100644 --- a/primitives/storage/src/lib.rs +++ b/primitives/storage/src/lib.rs @@ -19,6 +19,8 @@ #![cfg_attr(not(feature = "std"), no_std)] +use core::fmt::Display; + #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; use sp_debug_derive::RuntimeDebug; @@ -47,8 +49,9 @@ impl AsRef<[u8]> for StorageKey { } /// Storage key with read/write tracking information. -#[derive(PartialEq, Eq, RuntimeDebug, Clone, Encode, Decode)] -#[cfg_attr(feature = "std", derive(Hash, PartialOrd, Ord))] +#[derive( + PartialEq, Eq, Ord, PartialOrd, sp_std::hash::Hash, RuntimeDebug, Clone, Encode, Decode, +)] pub struct TrackedStorageKey { pub key: Vec, pub reads: u32, @@ -411,6 +414,15 @@ pub enum StateVersion { V1 = 1, } +impl Display for StateVersion { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + StateVersion::V0 => f.write_str("0"), + StateVersion::V1 => f.write_str("1"), + } + } +} + impl Default for StateVersion { fn default() -> Self { StateVersion::V1 diff --git a/primitives/test-primitives/Cargo.toml b/primitives/test-primitives/Cargo.toml index 2a20addf66b2b..28fa6e6213daf 100644 --- a/primitives/test-primitives/Cargo.toml +++ b/primitives/test-primitives/Cargo.toml @@ -13,7 +13,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } serde = { version = "1.0.136", features = ["derive"], optional = true } sp-application-crypto = { version = "6.0.0", default-features = false, path = "../application-crypto" } sp-core = { version = "6.0.0", default-features = false, path = "../core" } diff --git a/primitives/timestamp/src/lib.rs b/primitives/timestamp/src/lib.rs index b98a87c37f69d..d88b1839babe6 100644 --- a/primitives/timestamp/src/lib.rs +++ b/primitives/timestamp/src/lib.rs @@ -56,6 +56,17 @@ impl Timestamp { pub fn checked_sub(self, other: Self) -> Option { self.0.checked_sub(other.0).map(Self) } + + /// The current timestamp using the system time. + #[cfg(feature = "std")] + pub fn current() -> Self { + use std::time::SystemTime; + + let now = SystemTime::now(); + now.duration_since(SystemTime::UNIX_EPOCH) + .expect("Current time is always after unix epoch; qed") + .into() + } } impl sp_std::ops::Deref for Timestamp { @@ -165,18 +176,6 @@ impl TimestampInherentData for InherentData { } } -/// The current timestamp using the system time. -/// -/// This timestamp is the time since the UNIX epoch. -#[cfg(feature = "std")] -fn current_timestamp() -> std::time::Duration { - use std::time::SystemTime; - - let now = SystemTime::now(); - now.duration_since(SystemTime::UNIX_EPOCH) - .expect("Current time is always after unix epoch; qed") -} - /// Provide duration since unix epoch in millisecond for timestamp inherent. #[cfg(feature = "std")] pub struct InherentDataProvider { @@ -190,7 +189,7 @@ impl InherentDataProvider { pub fn from_system_time() -> Self { Self { max_drift: std::time::Duration::from_secs(60).into(), - timestamp: current_timestamp().into(), + timestamp: Timestamp::current(), } } diff --git a/primitives/trie/Cargo.toml b/primitives/trie/Cargo.toml index 291615c9354c1..2636648f40387 100644 --- a/primitives/trie/Cargo.toml +++ b/primitives/trie/Cargo.toml @@ -24,7 +24,7 @@ hashbrown = { version = "0.12.3", optional = true } hash-db = { version = "0.15.2", default-features = false } lazy_static = { version = "1.4.0", optional = true } lru = { version = "0.7.5", optional = true } -memory-db = { version = "0.29.0", default-features = false } +memory-db = { version = "0.30.0", default-features = false } nohash-hasher = { version = "0.2.0", optional = true } parking_lot = { version = "0.12.1", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } @@ -36,9 +36,9 @@ sp-core = { version = "6.0.0", default-features = false, path = "../core" } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [dev-dependencies] +array-bytes = "4.1" criterion = "0.3.3" -hex-literal = "0.3.4" -trie-bench = "0.31.0" +trie-bench = "0.32.0" trie-standardmap = "0.15.2" sp-runtime = { version = "6.0.0", path = "../runtime" } diff --git a/primitives/trie/src/lib.rs b/primitives/trie/src/lib.rs index fafa2a2891ce4..c2ab12dbee14c 100644 --- a/primitives/trie/src/lib.rs +++ b/primitives/trie/src/lib.rs @@ -542,7 +542,6 @@ mod tests { use super::*; use codec::{Compact, Decode, Encode}; use hash_db::{HashDB, Hasher}; - use hex_literal::hex; use sp_core::Blake2Hasher; use trie_db::{DBValue, NodeCodec as NodeCodecT, Trie, TrieMut}; use trie_standardmap::{Alphabet, StandardMap, ValueMode}; @@ -845,8 +844,14 @@ mod tests { } fn iterator_works_inner() { let pairs = vec![ - (hex!("0103000000000000000464").to_vec(), hex!("0400000000").to_vec()), - (hex!("0103000000000000000469").to_vec(), hex!("0401000000").to_vec()), + ( + array_bytes::hex2bytes_unchecked("0103000000000000000464"), + array_bytes::hex2bytes_unchecked("0400000000"), + ), + ( + array_bytes::hex2bytes_unchecked("0103000000000000000469"), + array_bytes::hex2bytes_unchecked("0401000000"), + ), ]; let mut mdb = MemoryDB::default(); @@ -859,7 +864,7 @@ mod tests { let mut iter_pairs = Vec::new(); for pair in iter { let (key, value) = pair.unwrap(); - iter_pairs.push((key, value.to_vec())); + iter_pairs.push((key, value)); } assert_eq!(pairs, iter_pairs); @@ -868,15 +873,15 @@ mod tests { #[test] fn proof_non_inclusion_works() { let pairs = vec![ - (hex!("0102").to_vec(), hex!("01").to_vec()), - (hex!("0203").to_vec(), hex!("0405").to_vec()), + (array_bytes::hex2bytes_unchecked("0102"), array_bytes::hex2bytes_unchecked("01")), + (array_bytes::hex2bytes_unchecked("0203"), array_bytes::hex2bytes_unchecked("0405")), ]; let mut memdb = MemoryDB::default(); let mut root = Default::default(); populate_trie::(&mut memdb, &mut root, &pairs); - let non_included_key: Vec = hex!("0909").to_vec(); + let non_included_key: Vec = array_bytes::hex2bytes_unchecked("0909"); let proof = generate_trie_proof::(&memdb, root, &[non_included_key.clone()]) .unwrap(); @@ -893,7 +898,7 @@ mod tests { assert!(verify_trie_proof::>( &root, &proof, - &[(non_included_key, Some(hex!("1010").to_vec()))], + &[(non_included_key, Some(array_bytes::hex2bytes_unchecked("1010")))], ) .is_err()); } @@ -901,8 +906,8 @@ mod tests { #[test] fn proof_inclusion_works() { let pairs = vec![ - (hex!("0102").to_vec(), hex!("01").to_vec()), - (hex!("0203").to_vec(), hex!("0405").to_vec()), + (array_bytes::hex2bytes_unchecked("0102"), array_bytes::hex2bytes_unchecked("01")), + (array_bytes::hex2bytes_unchecked("0203"), array_bytes::hex2bytes_unchecked("0405")), ]; let mut memdb = MemoryDB::default(); @@ -932,7 +937,7 @@ mod tests { assert!(verify_trie_proof::( &root, &proof, - &[(hex!("4242").to_vec(), Some(pairs[0].1.clone()))] + &[(array_bytes::hex2bytes_unchecked("4242"), Some(pairs[0].1.clone()))] ) .is_err()); diff --git a/primitives/trie/src/recorder.rs b/primitives/trie/src/recorder.rs index 5599ad1c36904..6fbf698592a31 100644 --- a/primitives/trie/src/recorder.rs +++ b/primitives/trie/src/recorder.rs @@ -109,7 +109,7 @@ impl Recorder { /// Returns the [`StorageProof`]. pub fn to_storage_proof(&self) -> StorageProof { let recorder = self.inner.lock(); - StorageProof::new(recorder.accessed_nodes.iter().map(|(_, v)| v.clone())) + StorageProof::new(recorder.accessed_nodes.values().cloned()) } /// Returns the estimated encoded size of the proof. diff --git a/primitives/version/Cargo.toml b/primitives/version/Cargo.toml index 0ca78940fbbbc..0dcbbd81fd93f 100644 --- a/primitives/version/Cargo.toml +++ b/primitives/version/Cargo.toml @@ -15,8 +15,8 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -impl-serde = { version = "0.3.1", optional = true } -parity-wasm = { version = "0.42.2", optional = true } +impl-serde = { version = "0.4.0", optional = true } +parity-wasm = { version = "0.45", optional = true } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } serde = { version = "1.0.136", features = ["derive"], optional = true } thiserror = { version = "1.0.30", optional = true } diff --git a/primitives/wasm-interface/Cargo.toml b/primitives/wasm-interface/Cargo.toml index ee6ce51efdc02..d61c74f20222c 100644 --- a/primitives/wasm-interface/Cargo.toml +++ b/primitives/wasm-interface/Cargo.toml @@ -17,8 +17,8 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } impl-trait-for-tuples = "0.2.2" log = { version = "0.4.17", optional = true } -wasmi = { version = "0.9.1", optional = true } -wasmtime = { version = "0.38.0", default-features = false, optional = true } +wasmi = { version = "0.13", optional = true } +wasmtime = { version = "1.0.0", default-features = false, optional = true } sp-std = { version = "4.0.0", default-features = false, path = "../std" } [features] diff --git a/primitives/weights/Cargo.toml b/primitives/weights/Cargo.toml new file mode 100644 index 0000000000000..8c0302ff5d1b2 --- /dev/null +++ b/primitives/weights/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "sp-weights" +version = "4.0.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "Types and traits for interfacing between the host and the wasm runtime." +documentation = "https://docs.rs/sp-wasm-interface" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } +impl-trait-for-tuples = "0.2.2" +scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +serde = { version = "1.0.136", optional = true, features = ["derive"] } +smallvec = "1.8.0" +sp-arithmetic = { version = "5.0.0", default-features = false, path = "../arithmetic" } +sp-core = { version = "6.0.0", default-features = false, path = "../core" } +sp-debug-derive = { version = "4.0.0", default-features = false, path = "../debug-derive" } +sp-std = { version = "4.0.0", default-features = false, path = "../std" } + +[features] +default = [ "std" ] +std = [ + "codec/std", + "scale-info/std", + "serde", + "sp-arithmetic/std", + "sp-core/std", + "sp-debug-derive/std", + "sp-std/std" +] +# By default some types have documentation, `full-metadata-docs` allows to add documentation to +# more types in the metadata. +full-metadata-docs = ["scale-info/docs"] diff --git a/primitives/weights/src/lib.rs b/primitives/weights/src/lib.rs new file mode 100644 index 0000000000000..e1ac7fcd4e892 --- /dev/null +++ b/primitives/weights/src/lib.rs @@ -0,0 +1,318 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Primitives for transaction weighting. +//! +//! Latest machine specification used to benchmark are: +//! - Digital Ocean: ubuntu-s-2vcpu-4gb-ams3-01 +//! - 2x Intel(R) Xeon(R) CPU E5-2650 v4 @ 2.20GHz +//! - 4GB RAM +//! - Ubuntu 19.10 (GNU/Linux 5.3.0-18-generic x86_64) +//! - rustc 1.42.0 (b8cedc004 2020-03-09) + +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate self as sp_weights; + +mod weight_v2; + +use codec::{CompactAs, Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; +use smallvec::SmallVec; +use sp_arithmetic::{ + traits::{BaseArithmetic, SaturatedConversion, Saturating, Unsigned}, + Perbill, +}; +use sp_core::Get; +use sp_debug_derive::RuntimeDebug; + +pub use weight_v2::*; + +pub mod constants { + use super::Weight; + + pub const WEIGHT_PER_SECOND: Weight = Weight::from_ref_time(1_000_000_000_000); + pub const WEIGHT_PER_MILLIS: Weight = Weight::from_ref_time(1_000_000_000); + pub const WEIGHT_PER_MICROS: Weight = Weight::from_ref_time(1_000_000); + pub const WEIGHT_PER_NANOS: Weight = Weight::from_ref_time(1_000); +} + +/// The old weight type. +/// +/// NOTE: This type exists purely for compatibility purposes! Use [`weight_v2::Weight`] in all other +/// cases. +#[derive( + Decode, + Encode, + CompactAs, + PartialEq, + Eq, + Clone, + Copy, + RuntimeDebug, + Default, + MaxEncodedLen, + TypeInfo, +)] +pub struct OldWeight(pub u64); + +/// The weight of database operations that the runtime can invoke. +/// +/// NOTE: This is currently only measured in computational time, and will probably +/// be updated all together once proof size is accounted for. +#[derive(Clone, Copy, Eq, PartialEq, Default, RuntimeDebug, Encode, Decode, TypeInfo)] +pub struct RuntimeDbWeight { + pub read: u64, + pub write: u64, +} + +impl RuntimeDbWeight { + pub fn reads(self, r: u64) -> Weight { + Weight::from_ref_time(self.read.saturating_mul(r)) + } + + pub fn writes(self, w: u64) -> Weight { + Weight::from_ref_time(self.write.saturating_mul(w)) + } + + pub fn reads_writes(self, r: u64, w: u64) -> Weight { + let read_weight = self.read.saturating_mul(r); + let write_weight = self.write.saturating_mul(w); + Weight::from_ref_time(read_weight.saturating_add(write_weight)) + } +} + +/// One coefficient and its position in the `WeightToFee`. +/// +/// One term of polynomial is calculated as: +/// +/// ```ignore +/// coeff_integer * x^(degree) + coeff_frac * x^(degree) +/// ``` +/// +/// The `negative` value encodes whether the term is added or substracted from the +/// overall polynomial result. +#[derive(Clone, Encode, Decode, TypeInfo)] +pub struct WeightToFeeCoefficient { + /// The integral part of the coefficient. + pub coeff_integer: Balance, + /// The fractional part of the coefficient. + pub coeff_frac: Perbill, + /// True iff the coefficient should be interpreted as negative. + pub negative: bool, + /// Degree/exponent of the term. + pub degree: u8, +} + +/// A list of coefficients that represent one polynomial. +pub type WeightToFeeCoefficients = SmallVec<[WeightToFeeCoefficient; 4]>; + +/// A trait that describes the weight to fee calculation. +pub trait WeightToFee { + /// The type that is returned as result from calculation. + type Balance: BaseArithmetic + From + Copy + Unsigned; + + /// Calculates the fee from the passed `weight`. + fn weight_to_fee(weight: &Weight) -> Self::Balance; +} + +/// A trait that describes the weight to fee calculation as polynomial. +/// +/// An implementor should only implement the `polynomial` function. +pub trait WeightToFeePolynomial { + /// The type that is returned as result from polynomial evaluation. + type Balance: BaseArithmetic + From + Copy + Unsigned; + + /// Returns a polynomial that describes the weight to fee conversion. + /// + /// This is the only function that should be manually implemented. Please note + /// that all calculation is done in the probably unsigned `Balance` type. This means + /// that the order of coefficients is important as putting the negative coefficients + /// first will most likely saturate the result to zero mid evaluation. + fn polynomial() -> WeightToFeeCoefficients; +} + +impl WeightToFee for T +where + T: WeightToFeePolynomial, +{ + type Balance = ::Balance; + + /// Calculates the fee from the passed `weight` according to the `polynomial`. + /// + /// This should not be overridden in most circumstances. Calculation is done in the + /// `Balance` type and never overflows. All evaluation is saturating. + fn weight_to_fee(weight: &Weight) -> Self::Balance { + Self::polynomial() + .iter() + .fold(Self::Balance::saturated_from(0u32), |mut acc, args| { + let w = Self::Balance::saturated_from(weight.ref_time()) + .saturating_pow(args.degree.into()); + + // The sum could get negative. Therefore we only sum with the accumulator. + // The Perbill Mul implementation is non overflowing. + let frac = args.coeff_frac * w; + let integer = args.coeff_integer.saturating_mul(w); + + if args.negative { + acc = acc.saturating_sub(frac); + acc = acc.saturating_sub(integer); + } else { + acc = acc.saturating_add(frac); + acc = acc.saturating_add(integer); + } + + acc + }) + } +} + +/// Implementor of `WeightToFee` that maps one unit of weight to one unit of fee. +pub struct IdentityFee(sp_std::marker::PhantomData); + +impl WeightToFee for IdentityFee +where + T: BaseArithmetic + From + Copy + Unsigned, +{ + type Balance = T; + + fn weight_to_fee(weight: &Weight) -> Self::Balance { + Self::Balance::saturated_from(weight.ref_time()) + } +} + +/// Implementor of [`WeightToFee`] that uses a constant multiplier. +/// # Example +/// +/// ``` +/// # use sp_core::ConstU128; +/// # use sp_weights::ConstantMultiplier; +/// // Results in a multiplier of 10 for each unit of weight (or length) +/// type LengthToFee = ConstantMultiplier::>; +/// ``` +pub struct ConstantMultiplier(sp_std::marker::PhantomData<(T, M)>); + +impl WeightToFee for ConstantMultiplier +where + T: BaseArithmetic + From + Copy + Unsigned, + M: Get, +{ + type Balance = T; + + fn weight_to_fee(weight: &Weight) -> Self::Balance { + Self::Balance::saturated_from(weight.ref_time()).saturating_mul(M::get()) + } +} + +#[cfg(test)] +#[allow(dead_code)] +mod tests { + use super::*; + use smallvec::smallvec; + + type Balance = u64; + + // 0.5x^3 + 2.333x^2 + 7x - 10_000 + struct Poly; + impl WeightToFeePolynomial for Poly { + type Balance = Balance; + + fn polynomial() -> WeightToFeeCoefficients { + smallvec![ + WeightToFeeCoefficient { + coeff_integer: 0, + coeff_frac: Perbill::from_float(0.5), + negative: false, + degree: 3 + }, + WeightToFeeCoefficient { + coeff_integer: 2, + coeff_frac: Perbill::from_rational(1u32, 3u32), + negative: false, + degree: 2 + }, + WeightToFeeCoefficient { + coeff_integer: 7, + coeff_frac: Perbill::zero(), + negative: false, + degree: 1 + }, + WeightToFeeCoefficient { + coeff_integer: 10_000, + coeff_frac: Perbill::zero(), + negative: true, + degree: 0 + }, + ] + } + } + + #[test] + fn polynomial_works() { + // 100^3/2=500000 100^2*(2+1/3)=23333 700 -10000 + assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(100)), 514033); + // 10123^3/2=518677865433 10123^2*(2+1/3)=239108634 70861 -10000 + assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(10_123)), 518917034928); + } + + #[test] + fn polynomial_does_not_underflow() { + assert_eq!(Poly::weight_to_fee(&Weight::zero()), 0); + assert_eq!(Poly::weight_to_fee(&Weight::from_ref_time(10)), 0); + } + + #[test] + fn polynomial_does_not_overflow() { + assert_eq!(Poly::weight_to_fee(&Weight::MAX), Balance::max_value() - 10_000); + } + + #[test] + fn identity_fee_works() { + assert_eq!(IdentityFee::::weight_to_fee(&Weight::zero()), 0); + assert_eq!(IdentityFee::::weight_to_fee(&Weight::from_ref_time(50)), 50); + assert_eq!(IdentityFee::::weight_to_fee(&Weight::MAX), Balance::max_value()); + } + + #[test] + fn constant_fee_works() { + use sp_core::ConstU128; + assert_eq!( + ConstantMultiplier::>::weight_to_fee(&Weight::zero()), + 0 + ); + assert_eq!( + ConstantMultiplier::>::weight_to_fee(&Weight::from_ref_time( + 50 + )), + 500 + ); + assert_eq!( + ConstantMultiplier::>::weight_to_fee(&Weight::from_ref_time( + 16 + )), + 16384 + ); + assert_eq!( + ConstantMultiplier::>::weight_to_fee( + &Weight::from_ref_time(2) + ), + u128::MAX + ); + } +} diff --git a/primitives/weights/src/weight_v2.rs b/primitives/weights/src/weight_v2.rs new file mode 100644 index 0000000000000..2933d80099dd7 --- /dev/null +++ b/primitives/weights/src/weight_v2.rs @@ -0,0 +1,462 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use codec::{Decode, Encode, MaxEncodedLen}; +use core::ops::{Add, AddAssign, Div, Mul, Sub, SubAssign}; +use sp_arithmetic::traits::{Bounded, CheckedAdd, CheckedSub, Zero}; +use sp_debug_derive::RuntimeDebug; + +use super::*; + +#[derive( + Encode, Decode, MaxEncodedLen, TypeInfo, Eq, PartialEq, Copy, Clone, RuntimeDebug, Default, +)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct Weight { + #[codec(compact)] + /// The weight of computational time used based on some reference hardware. + ref_time: u64, + #[codec(compact)] + /// The weight of storage space used by proof of validity. + proof_size: u64, +} + +impl From for Weight { + fn from(old: OldWeight) -> Self { + Weight::from_ref_time(old.0) + } +} + +impl Weight { + /// Set the reference time part of the weight. + pub const fn set_ref_time(mut self, c: u64) -> Self { + self.ref_time = c; + self + } + + /// Set the storage size part of the weight. + pub const fn set_proof_size(mut self, c: u64) -> Self { + self.proof_size = c; + self + } + + /// Return the reference time part of the weight. + pub const fn ref_time(&self) -> u64 { + self.ref_time + } + + /// Return the storage size part of the weight. + pub const fn proof_size(&self) -> u64 { + self.proof_size + } + + /// Return a mutable reference to the reference time part of the weight. + pub fn ref_time_mut(&mut self) -> &mut u64 { + &mut self.ref_time + } + + /// Return a mutable reference to the storage size part of the weight. + pub fn proof_size_mut(&mut self) -> &mut u64 { + &mut self.proof_size + } + + pub const MAX: Self = Self { ref_time: u64::MAX, proof_size: u64::MAX }; + + /// Get the conservative min of `self` and `other` weight. + pub fn min(&self, other: Self) -> Self { + Self { + ref_time: self.ref_time.min(other.ref_time), + proof_size: self.proof_size.min(other.proof_size), + } + } + + /// Get the aggressive max of `self` and `other` weight. + pub fn max(&self, other: Self) -> Self { + Self { + ref_time: self.ref_time.max(other.ref_time), + proof_size: self.proof_size.max(other.proof_size), + } + } + + /// Try to add some `other` weight while upholding the `limit`. + pub fn try_add(&self, other: &Self, limit: &Self) -> Option { + let total = self.checked_add(other)?; + if total.any_gt(*limit) { + None + } else { + Some(total) + } + } + + /// Construct [`Weight`] with reference time weight and 0 storage size weight. + pub const fn from_ref_time(ref_time: u64) -> Self { + Self { ref_time, proof_size: 0 } + } + + /// Construct [`Weight`] with storage size weight and 0 reference time weight. + pub const fn from_proof_size(proof_size: u64) -> Self { + Self { ref_time: 0, proof_size } + } + + /// Construct [`Weight`] from weight parts, namely reference time and proof size weights. + pub const fn from_parts(ref_time: u64, proof_size: u64) -> Self { + Self { ref_time, proof_size } + } + + /// Saturating [`Weight`] addition. Computes `self + rhs`, saturating at the numeric bounds of + /// all fields instead of overflowing. + pub const fn saturating_add(self, rhs: Self) -> Self { + Self { + ref_time: self.ref_time.saturating_add(rhs.ref_time), + proof_size: self.proof_size.saturating_add(rhs.proof_size), + } + } + + /// Saturating [`Weight`] subtraction. Computes `self - rhs`, saturating at the numeric bounds + /// of all fields instead of overflowing. + pub const fn saturating_sub(self, rhs: Self) -> Self { + Self { + ref_time: self.ref_time.saturating_sub(rhs.ref_time), + proof_size: self.proof_size.saturating_sub(rhs.proof_size), + } + } + + /// Saturating [`Weight`] scalar multiplication. Computes `self.field * scalar` for all fields, + /// saturating at the numeric bounds of all fields instead of overflowing. + pub const fn saturating_mul(self, scalar: u64) -> Self { + Self { + ref_time: self.ref_time.saturating_mul(scalar), + proof_size: self.proof_size.saturating_mul(scalar), + } + } + + /// Saturating [`Weight`] scalar division. Computes `self.field / scalar` for all fields, + /// saturating at the numeric bounds of all fields instead of overflowing. + pub const fn saturating_div(self, scalar: u64) -> Self { + Self { + ref_time: self.ref_time.saturating_div(scalar), + proof_size: self.proof_size.saturating_div(scalar), + } + } + + /// Saturating [`Weight`] scalar exponentiation. Computes `self.field.pow(exp)` for all fields, + /// saturating at the numeric bounds of all fields instead of overflowing. + pub const fn saturating_pow(self, exp: u32) -> Self { + Self { + ref_time: self.ref_time.saturating_pow(exp), + proof_size: self.proof_size.saturating_pow(exp), + } + } + + /// Increment [`Weight`] by `amount` via saturating addition. + pub fn saturating_accrue(&mut self, amount: Self) { + *self = self.saturating_add(amount); + } + + /// Checked [`Weight`] addition. Computes `self + rhs`, returning `None` if overflow occurred. + pub const fn checked_add(&self, rhs: &Self) -> Option { + let ref_time = match self.ref_time.checked_add(rhs.ref_time) { + Some(t) => t, + None => return None, + }; + let proof_size = match self.proof_size.checked_add(rhs.proof_size) { + Some(s) => s, + None => return None, + }; + Some(Self { ref_time, proof_size }) + } + + /// Checked [`Weight`] subtraction. Computes `self - rhs`, returning `None` if overflow + /// occurred. + pub const fn checked_sub(&self, rhs: &Self) -> Option { + let ref_time = match self.ref_time.checked_sub(rhs.ref_time) { + Some(t) => t, + None => return None, + }; + let proof_size = match self.proof_size.checked_sub(rhs.proof_size) { + Some(s) => s, + None => return None, + }; + Some(Self { ref_time, proof_size }) + } + + /// Checked [`Weight`] scalar multiplication. Computes `self.field * scalar` for each field, + /// returning `None` if overflow occurred. + pub const fn checked_mul(self, scalar: u64) -> Option { + let ref_time = match self.ref_time.checked_mul(scalar) { + Some(t) => t, + None => return None, + }; + let proof_size = match self.proof_size.checked_mul(scalar) { + Some(s) => s, + None => return None, + }; + Some(Self { ref_time, proof_size }) + } + + /// Checked [`Weight`] scalar division. Computes `self.field / scalar` for each field, returning + /// `None` if overflow occurred. + pub const fn checked_div(self, scalar: u64) -> Option { + let ref_time = match self.ref_time.checked_div(scalar) { + Some(t) => t, + None => return None, + }; + let proof_size = match self.proof_size.checked_div(scalar) { + Some(s) => s, + None => return None, + }; + Some(Self { ref_time, proof_size }) + } + + /// Return a [`Weight`] where all fields are zero. + pub const fn zero() -> Self { + Self { ref_time: 0, proof_size: 0 } + } + + /// Constant version of Add with u64. + /// + /// Is only overflow safe when evaluated at compile-time. + pub const fn add(self, scalar: u64) -> Self { + Self { ref_time: self.ref_time + scalar, proof_size: self.proof_size + scalar } + } + + /// Constant version of Sub with u64. + /// + /// Is only overflow safe when evaluated at compile-time. + pub const fn sub(self, scalar: u64) -> Self { + Self { ref_time: self.ref_time - scalar, proof_size: self.proof_size - scalar } + } + + /// Constant version of Div with u64. + /// + /// Is only overflow safe when evaluated at compile-time. + pub const fn div(self, scalar: u64) -> Self { + Self { ref_time: self.ref_time / scalar, proof_size: self.proof_size / scalar } + } + + /// Constant version of Mul with u64. + /// + /// Is only overflow safe when evaluated at compile-time. + pub const fn mul(self, scalar: u64) -> Self { + Self { ref_time: self.ref_time * scalar, proof_size: self.proof_size * scalar } + } + + /// Returns true if any of `self`'s constituent weights is strictly greater than that of the + /// `other`'s, otherwise returns false. + pub const fn any_gt(self, other: Self) -> bool { + self.ref_time > other.ref_time || self.proof_size > other.proof_size + } + + /// Returns true if all of `self`'s constituent weights is strictly greater than that of the + /// `other`'s, otherwise returns false. + pub const fn all_gt(self, other: Self) -> bool { + self.ref_time > other.ref_time && self.proof_size > other.proof_size + } + + /// Returns true if any of `self`'s constituent weights is strictly less than that of the + /// `other`'s, otherwise returns false. + pub const fn any_lt(self, other: Self) -> bool { + self.ref_time < other.ref_time || self.proof_size < other.proof_size + } + + /// Returns true if all of `self`'s constituent weights is strictly less than that of the + /// `other`'s, otherwise returns false. + pub const fn all_lt(self, other: Self) -> bool { + self.ref_time < other.ref_time && self.proof_size < other.proof_size + } + + /// Returns true if any of `self`'s constituent weights is greater than or equal to that of the + /// `other`'s, otherwise returns false. + pub const fn any_gte(self, other: Self) -> bool { + self.ref_time >= other.ref_time || self.proof_size >= other.proof_size + } + + /// Returns true if all of `self`'s constituent weights is greater than or equal to that of the + /// `other`'s, otherwise returns false. + pub const fn all_gte(self, other: Self) -> bool { + self.ref_time >= other.ref_time && self.proof_size >= other.proof_size + } + + /// Returns true if any of `self`'s constituent weights is less than or equal to that of the + /// `other`'s, otherwise returns false. + pub const fn any_lte(self, other: Self) -> bool { + self.ref_time <= other.ref_time || self.proof_size <= other.proof_size + } + + /// Returns true if all of `self`'s constituent weights is less than or equal to that of the + /// `other`'s, otherwise returns false. + pub const fn all_lte(self, other: Self) -> bool { + self.ref_time <= other.ref_time && self.proof_size <= other.proof_size + } + + /// Returns true if any of `self`'s constituent weights is equal to that of the `other`'s, + /// otherwise returns false. + pub const fn any_eq(self, other: Self) -> bool { + self.ref_time == other.ref_time || self.proof_size == other.proof_size + } + + // NOTE: `all_eq` does not exist, as it's simply the `eq` method from the `PartialEq` trait. +} + +impl Zero for Weight { + fn zero() -> Self { + Self::zero() + } + + fn is_zero(&self) -> bool { + self == &Self::zero() + } +} + +impl Add for Weight { + type Output = Self; + fn add(self, rhs: Self) -> Self { + Self { + ref_time: self.ref_time + rhs.ref_time, + proof_size: self.proof_size + rhs.proof_size, + } + } +} + +impl Sub for Weight { + type Output = Self; + fn sub(self, rhs: Self) -> Self { + Self { + ref_time: self.ref_time - rhs.ref_time, + proof_size: self.proof_size - rhs.proof_size, + } + } +} + +impl Mul for Weight +where + T: Mul + Copy, +{ + type Output = Self; + fn mul(self, b: T) -> Self { + Self { ref_time: b * self.ref_time, proof_size: b * self.proof_size } + } +} + +macro_rules! weight_mul_per_impl { + ($($t:ty),* $(,)?) => { + $( + impl Mul for $t { + type Output = Weight; + fn mul(self, b: Weight) -> Weight { + Weight { + ref_time: self * b.ref_time, + proof_size: self * b.proof_size, + } + } + } + )* + } +} +weight_mul_per_impl!( + sp_arithmetic::Percent, + sp_arithmetic::PerU16, + sp_arithmetic::Permill, + sp_arithmetic::Perbill, + sp_arithmetic::Perquintill, +); + +macro_rules! weight_mul_primitive_impl { + ($($t:ty),* $(,)?) => { + $( + impl Mul for $t { + type Output = Weight; + fn mul(self, b: Weight) -> Weight { + Weight { + ref_time: u64::from(self) * b.ref_time, + proof_size: u64::from(self) * b.proof_size, + } + } + } + )* + } +} +weight_mul_primitive_impl!(u8, u16, u32, u64); + +impl Div for Weight +where + u64: Div, + T: Copy, +{ + type Output = Self; + fn div(self, b: T) -> Self { + Self { ref_time: self.ref_time / b, proof_size: self.proof_size / b } + } +} + +impl CheckedAdd for Weight { + fn checked_add(&self, rhs: &Self) -> Option { + self.checked_add(rhs) + } +} + +impl CheckedSub for Weight { + fn checked_sub(&self, rhs: &Self) -> Option { + self.checked_sub(rhs) + } +} + +impl core::fmt::Display for Weight { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Weight(ref_time: {}, proof_size: {})", self.ref_time, self.proof_size) + } +} + +impl Bounded for Weight { + fn min_value() -> Self { + Zero::zero() + } + fn max_value() -> Self { + Self::MAX + } +} + +impl AddAssign for Weight { + fn add_assign(&mut self, other: Self) { + *self = Self { + ref_time: self.ref_time + other.ref_time, + proof_size: self.proof_size + other.proof_size, + }; + } +} + +impl SubAssign for Weight { + fn sub_assign(&mut self, other: Self) { + *self = Self { + ref_time: self.ref_time - other.ref_time, + proof_size: self.proof_size - other.proof_size, + }; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn is_zero_works() { + assert!(Weight::zero().is_zero()); + assert!(!Weight::from_parts(1, 0).is_zero()); + assert!(!Weight::from_parts(0, 1).is_zero()); + assert!(!Weight::MAX.is_zero()); + } +} diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index eedd2ee0bb409..482d54b50f73d 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -62,7 +62,7 @@ build-linux-substrate: - !reference [.rusty-cachier, before_script] script: - rusty-cachier snapshot create - - WASM_BUILD_NO_COLOR=1 time cargo build --release --verbose + - WASM_BUILD_NO_COLOR=1 time cargo build --locked --release --verbose - mv $CARGO_TARGET_DIR/release/substrate ./artifacts/substrate/. - echo -n "Substrate version = " - if [ "${CI_COMMIT_TAG}" ]; then @@ -95,7 +95,7 @@ build-linux-substrate: script: - rusty-cachier snapshot create - cd ./bin/utils/subkey - - SKIP_WASM_BUILD=1 time cargo build --release --verbose + - SKIP_WASM_BUILD=1 time cargo build --locked --release --verbose - cd - - mv $CARGO_TARGET_DIR/release/subkey ./artifacts/subkey/. - echo -n "Subkey version = " @@ -117,7 +117,7 @@ build-subkey-macos: - mkdir -p ./artifacts/subkey script: - cd ./bin/utils/subkey - - SKIP_WASM_BUILD=1 time cargo build --release --verbose + - SKIP_WASM_BUILD=1 time cargo build --locked --release --verbose - cd - - mv ./target/release/subkey ./artifacts/subkey/. - echo -n "Subkey version = " @@ -149,7 +149,7 @@ build-rustdoc: - ./crate-docs/ script: - rusty-cachier snapshot create - - time cargo +nightly doc --workspace --all-features --verbose --no-deps + - time cargo +nightly doc --locked --workspace --all-features --verbose --no-deps - rm -f $CARGO_TARGET_DIR/doc/.lock - mv $CARGO_TARGET_DIR/doc ./crate-docs # FIXME: remove me after CI image gets nonroot diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index acd2cb1fa7855..e85ab85afe6ed 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -59,7 +59,7 @@ cargo-check-benches: CI_JOB_NAME: "cargo-check-benches" extends: - .docker-env - - .test-refs + - .test-refs-check-benches - .collect-artifacts - .pipeline-stopper-artifacts before_script: @@ -83,14 +83,14 @@ cargo-check-benches: - echo "___Running benchmarks___"; - case ${CI_NODE_INDEX} in 1) - SKIP_WASM_BUILD=1 time cargo +nightly check --benches --all; - cargo run --release -p node-bench -- ::trie::read::small --json + SKIP_WASM_BUILD=1 time cargo +nightly check --locked --benches --all; + cargo run --locked --release -p node-bench -- ::trie::read::small --json | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::trie::read::small.json; echo "___Uploading cache for rusty-cachier___"; rusty-cachier cache upload ;; 2) - cargo run --release -p node-bench -- ::node::import::native::sr25519::transfer_keep_alive::paritydb::small --json + cargo run --locked --release -p node-bench -- ::node::import::native::sr25519::transfer_keep_alive::paritydb::small --json | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::node::import::native::sr25519::transfer_keep_alive::paritydb::small.json ;; esac @@ -110,6 +110,8 @@ node-bench-regression-guard: - job: cargo-check-benches artifacts: true # polls artifact from master to compare with current result + # need to specify both parallel jobs from master because of the bug + # https://gitlab.com/gitlab-org/gitlab/-/issues/39063 - project: $CI_PROJECT_PATH job: "cargo-check-benches 1/2" ref: master @@ -127,6 +129,7 @@ node-bench-regression-guard: - echo "In case of this job failure, check your pipeline's cargo-check-benches" - 'node-bench-regression-guard --reference artifacts/benches/master-* --compare-with artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA' + after_script: [""] cargo-check-subkey: stage: test @@ -137,7 +140,7 @@ cargo-check-subkey: script: - rusty-cachier snapshot create - cd ./bin/utils/subkey - - SKIP_WASM_BUILD=1 time cargo check --release + - SKIP_WASM_BUILD=1 time cargo check --locked --release - rusty-cachier cache upload cargo-check-try-runtime: @@ -151,7 +154,7 @@ cargo-check-try-runtime: - .test-refs script: - rusty-cachier snapshot create - - time cargo check --features try-runtime + - time cargo check --locked --features try-runtime - rusty-cachier cache upload cargo-check-wasmer-sandbox: @@ -165,7 +168,7 @@ cargo-check-wasmer-sandbox: - .test-refs script: - rusty-cachier snapshot create - - time cargo check --features wasmer-sandbox + - time cargo check --locked --features wasmer-sandbox - rusty-cachier cache upload test-deterministic-wasm: @@ -184,13 +187,13 @@ test-deterministic-wasm: script: - rusty-cachier snapshot create # build runtime - - cargo build --verbose --release -p kitchensink-runtime + - cargo build --locked --verbose --release -p kitchensink-runtime # make checksum - sha256sum $CARGO_TARGET_DIR/release/wbuild/kitchensink-runtime/target/wasm32-unknown-unknown/release/kitchensink_runtime.wasm > checksum.sha256 # clean up - rm -rf $CARGO_TARGET_DIR/release/wbuild # build again - - cargo build --verbose --release -p kitchensink-runtime + - cargo build --locked --verbose --release -p kitchensink-runtime # confirm checksum - sha256sum -c ./checksum.sha256 # clean up again, don't put release binaries into the cache @@ -248,7 +251,7 @@ test-frame-support: RUN_UI_TESTS: 1 script: - rusty-cachier snapshot create - - time cargo test -p frame-support-test --features=conditional-storage,no-metadata-docs --manifest-path ./frame/support/test/Cargo.toml --test pallet # does not reuse cache 1 min 44 sec + - time cargo test --locked -p frame-support-test --features=frame-feature-testing,no-metadata-docs --manifest-path ./frame/support/test/Cargo.toml --test pallet # does not reuse cache 1 min 44 sec - SUBSTRATE_TEST_TIMEOUT=1 time cargo test -p substrate-test-utils --release --verbose --locked -- --ignored timeout - rusty-cachier cache upload @@ -292,7 +295,7 @@ quick-benchmarks: WASM_BUILD_RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" script: - rusty-cachier snapshot create - - time cargo run --release --features runtime-benchmarks -- benchmark pallet --execution wasm --wasm-execution compiled --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 + - time cargo run --locked --release --features runtime-benchmarks -- benchmark pallet --execution wasm --wasm-execution compiled --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 - rusty-cachier cache upload test-frame-examples-compile-to-wasm: @@ -311,9 +314,9 @@ test-frame-examples-compile-to-wasm: script: - rusty-cachier snapshot create - cd ./frame/examples/offchain-worker/ - - cargo +nightly build --target=wasm32-unknown-unknown --no-default-features + - cargo +nightly build --locked --target=wasm32-unknown-unknown --no-default-features - cd ../basic - - cargo +nightly build --target=wasm32-unknown-unknown --no-default-features + - cargo +nightly build --locked --target=wasm32-unknown-unknown --no-default-features - rusty-cachier cache upload test-linux-stable-int: @@ -355,8 +358,8 @@ check-tracing: script: - rusty-cachier snapshot create # with-tracing must be explicitly activated, we run a test to ensure this works as expected in both cases - - time cargo +nightly test --manifest-path ./primitives/tracing/Cargo.toml --no-default-features - - time cargo +nightly test --manifest-path ./primitives/tracing/Cargo.toml --no-default-features --features=with-tracing + - time cargo +nightly test --locked --manifest-path ./primitives/tracing/Cargo.toml --no-default-features + - time cargo +nightly test --locked --manifest-path ./primitives/tracing/Cargo.toml --no-default-features --features=with-tracing - rusty-cachier cache upload # more information about this job can be found here: @@ -380,9 +383,9 @@ test-full-crypto-feature: script: - rusty-cachier snapshot create - cd primitives/core/ - - time cargo +nightly build --verbose --no-default-features --features full_crypto + - time cargo +nightly build --locked --verbose --no-default-features --features full_crypto - cd ../application-crypto - - time cargo +nightly build --verbose --no-default-features --features full_crypto + - time cargo +nightly build --locked --verbose --no-default-features --features full_crypto - rusty-cachier cache upload test-wasmer-sandbox: @@ -396,7 +399,7 @@ test-wasmer-sandbox: script: - rusty-cachier snapshot create - echo "Node index - ${CI_NODE_INDEX}. Total amount - ${CI_NODE_TOTAL}" - - time cargo nextest run --release --features runtime-benchmarks,wasmer-sandbox,disable-ui-tests --partition count:${CI_NODE_INDEX}/${CI_NODE_TOTAL} + - time cargo nextest run --locked --release --features runtime-benchmarks,wasmer-sandbox,disable-ui-tests --partition count:${CI_NODE_INDEX}/${CI_NODE_TOTAL} - if [ ${CI_NODE_INDEX} == 1 ]; then rusty-cachier cache upload; fi cargo-check-macos: @@ -405,7 +408,7 @@ cargo-check-macos: before_script: - !reference [.rust-info-script, script] script: - - SKIP_WASM_BUILD=1 time cargo check --release + - SKIP_WASM_BUILD=1 time cargo check --locked --release tags: - osx @@ -421,5 +424,5 @@ check-rustdoc: RUSTDOCFLAGS: "-Dwarnings" script: - rusty-cachier snapshot create - - time cargo +nightly doc --workspace --all-features --verbose --no-deps + - time cargo +nightly doc --locked --workspace --all-features --verbose --no-deps - rusty-cachier cache upload diff --git a/scripts/ci/node-template-release/Cargo.toml b/scripts/ci/node-template-release/Cargo.toml index 8871a04e19b16..0800b17536453 100644 --- a/scripts/ci/node-template-release/Cargo.toml +++ b/scripts/ci/node-template-release/Cargo.toml @@ -10,7 +10,7 @@ homepage = "https://substrate.io" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "3.0", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } flate2 = "1.0" fs_extra = "1" git2 = "0.8" diff --git a/scripts/ci/node-template-release/src/main.rs b/scripts/ci/node-template-release/src/main.rs index 62e9b66715768..91a7e865458cf 100644 --- a/scripts/ci/node-template-release/src/main.rs +++ b/scripts/ci/node-template-release/src/main.rs @@ -29,10 +29,10 @@ type CargoToml = HashMap; #[derive(Parser)] struct Options { /// The path to the `node-template` source. - #[clap(parse(from_os_str))] + #[arg()] node_template: PathBuf, /// The path where to output the generated `tar.gz` file. - #[clap(parse(from_os_str))] + #[arg()] output: PathBuf, } diff --git a/test-utils/client/Cargo.toml b/test-utils/client/Cargo.toml index f8a1f437d45e1..fcac37441ba98 100644 --- a/test-utils/client/Cargo.toml +++ b/test-utils/client/Cargo.toml @@ -12,10 +12,10 @@ publish = false targets = ["x86_64-unknown-linux-gnu"] [dependencies] +array-bytes = "4.1" async-trait = "0.1.57" codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.21" -hex = "0.4" serde = "1.0.136" serde_json = "1.0.85" sc-client-api = { version = "4.0.0-dev", path = "../../client/api" } diff --git a/test-utils/client/src/lib.rs b/test-utils/client/src/lib.rs index 3115be58425e6..d3e71f0ad28d6 100644 --- a/test-utils/client/src/lib.rs +++ b/test-utils/client/src/lib.rs @@ -26,7 +26,7 @@ pub use sc_client_api::{ execution_extensions::{ExecutionExtensions, ExecutionStrategies}, BadBlocks, ForkBlocks, }; -pub use sc_client_db::{self, Backend}; +pub use sc_client_db::{self, Backend, BlocksPruning}; pub use sc_executor::{self, NativeElseWasmExecutor, WasmExecutionMethod}; pub use sc_service::{client, RpcHandlers}; pub use sp_consensus; @@ -102,7 +102,8 @@ impl /// Create new `TestClientBuilder` with default backend and storage chain mode pub fn with_tx_storage(blocks_pruning: u32) -> Self { - let backend = Arc::new(Backend::new_test_with_tx_storage(blocks_pruning, 0)); + let backend = + Arc::new(Backend::new_test_with_tx_storage(BlocksPruning::Some(blocks_pruning), 0)); Self::with_backend(backend) } } @@ -346,7 +347,7 @@ impl RpcHandlersExt for RpcHandlers { "params": ["0x{}"], "id": 0 }}"#, - hex::encode(extrinsic.encode()) + array_bytes::bytes2hex("", &extrinsic.encode()) )) .await .expect("valid JSON-RPC request object; qed"); diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 52e9fd7233c06..61b7301ab0519 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -23,7 +23,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0", default-features = scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../primitives/inherents" } sp-keyring = { version = "6.0.0", optional = true, path = "../../primitives/keyring" } -memory-db = { version = "0.29.0", default-features = false } +memory-db = { version = "0.30.0", default-features = false } sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../primitives/offchain" } sp-core = { version = "6.0.0", default-features = false, path = "../../primitives/core" } sp-std = { version = "4.0.0", default-features = false, path = "../../primitives/std" } @@ -42,7 +42,7 @@ sp-finality-grandpa = { version = "4.0.0-dev", default-features = false, path = sp-trie = { version = "6.0.0", default-features = false, path = "../../primitives/trie" } sp-transaction-pool = { version = "4.0.0-dev", default-features = false, path = "../../primitives/transaction-pool" } trie-db = { version = "0.24.0", default-features = false } -parity-util-mem = { version = "0.11.0", default-features = false, features = ["primitive-types"] } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } sc-service = { version = "0.10.0-dev", default-features = false, optional = true, features = ["test-helpers"], path = "../../client/service" } sp-state-machine = { version = "0.12.0", default-features = false, path = "../../primitives/state-machine" } sp-externalities = { version = "0.12.0", default-features = false, path = "../../primitives/externalities" } @@ -69,6 +69,7 @@ default = [ "std", ] std = [ + "parity-util-mem/std", "beefy-primitives/std", "beefy-merkle-tree/std", "sp-application-crypto/std", diff --git a/test-utils/runtime/client/src/lib.rs b/test-utils/runtime/client/src/lib.rs index fe0fef3516671..99d4e1163e272 100644 --- a/test-utils/runtime/client/src/lib.rs +++ b/test-utils/runtime/client/src/lib.rs @@ -134,7 +134,7 @@ impl substrate_test_client::GenesisInit for GenesisParameters { .insert(sp_core::storage::well_known_keys::CODE.to_vec(), code.clone()); } - let child_roots = storage.children_default.iter().map(|(_sk, child_content)| { + let child_roots = storage.children_default.values().map(|child_content| { let state_root = <<::Header as HeaderT>::Hashing as HashT>::trie_root( child_content.data.clone().into_iter().collect(), diff --git a/test-utils/runtime/src/genesismap.rs b/test-utils/runtime/src/genesismap.rs index 3ece5165e1757..42706730eb9ac 100644 --- a/test-utils/runtime/src/genesismap.rs +++ b/test-utils/runtime/src/genesismap.rs @@ -17,8 +17,9 @@ //! Tool for creating the genesis block. -use super::{system, wasm_binary_unwrap, AccountId, AuthorityId}; +use super::{system, wasm_binary_unwrap, AccountId, AuthorityId, Runtime}; use codec::{Encode, Joiner, KeyedVec}; +use frame_support::traits::GenesisBuild; use sc_service::client::genesis; use sp_core::{ map, @@ -80,10 +81,11 @@ impl GenesisConfig { // Assimilate the system genesis config. let mut storage = Storage { top: map, children_default: self.extra_storage.children_default.clone() }; - let config = system::GenesisConfig { authorities: self.authorities.clone() }; - config - .assimilate_storage(&mut storage) - .expect("Adding `system::GensisConfig` to the genesis"); + >::assimilate_storage( + &system::GenesisConfig { authorities: self.authorities.clone() }, + &mut storage, + ) + .expect("Adding `system::GensisConfig` to the genesis"); storage } diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index b1febe85cb52b..30276826909dd 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -37,8 +37,9 @@ use trie_db::{Trie, TrieMut}; use cfg_if::cfg_if; use frame_support::{ + dispatch::RawOrigin, parameter_types, - traits::{ConstU32, ConstU64, CrateVersion, KeyOwnerProofSystem}, + traits::{CallerTrait, ConstU32, ConstU64, CrateVersion, KeyOwnerProofSystem}, weights::{RuntimeDbWeight, Weight}, }; use frame_system::limits::{BlockLength, BlockWeights}; @@ -119,7 +120,7 @@ pub fn native_version() -> NativeVersion { } /// Calls in transactions. -#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub struct Transfer { pub from: AccountId, pub to: AccountId, @@ -150,7 +151,7 @@ impl Transfer { } /// Extrinsic for test-runtime. -#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] pub enum Extrinsic { AuthoritiesChange(Vec), Transfer { @@ -235,11 +236,14 @@ impl ExtrinsicT for Extrinsic { } impl sp_runtime::traits::Dispatchable for Extrinsic { - type Origin = Origin; + type RuntimeOrigin = RuntimeOrigin; type Config = (); type Info = (); type PostInfo = (); - fn dispatch(self, _origin: Self::Origin) -> sp_runtime::DispatchResultWithInfo { + fn dispatch( + self, + _origin: Self::RuntimeOrigin, + ) -> sp_runtime::DispatchResultWithInfo { panic!("This implementation should not be used for actual dispatch."); } } @@ -443,22 +447,33 @@ impl GetRuntimeBlockType for Runtime { } #[derive(Clone, RuntimeDebug, Encode, Decode, PartialEq, Eq, TypeInfo, MaxEncodedLen)] -pub struct Origin; +pub struct RuntimeOrigin; + +impl From::AccountId>> for RuntimeOrigin { + fn from(_: RawOrigin<::AccountId>) -> Self { + unimplemented!("Not required in tests!") + } +} -impl From> for Origin { - fn from(_o: frame_system::Origin) -> Self { +impl CallerTrait<::AccountId> for RuntimeOrigin { + fn into_system(self) -> Option::AccountId>> { + unimplemented!("Not required in tests!") + } + + fn as_system_ref(&self) -> Option<&RawOrigin<::AccountId>> { unimplemented!("Not required in tests!") } } -impl From for Result, Origin> { - fn from(_origin: Origin) -> Result, Origin> { + +impl From for Result, RuntimeOrigin> { + fn from(_origin: RuntimeOrigin) -> Result, RuntimeOrigin> { unimplemented!("Not required in tests!") } } -impl frame_support::traits::OriginTrait for Origin { - type Call = ::Call; - type PalletsOrigin = Origin; +impl frame_support::traits::OriginTrait for RuntimeOrigin { + type Call = ::RuntimeCall; + type PalletsOrigin = RuntimeOrigin; type AccountId = ::AccountId; fn add_filter(&mut self, _filter: impl Fn(&Self::Call) -> bool + 'static) { @@ -481,6 +496,10 @@ impl frame_support::traits::OriginTrait for Origin { unimplemented!("Not required in tests!") } + fn into_caller(self) -> Self::PalletsOrigin { + unimplemented!("Not required in tests!") + } + fn try_with_caller( self, _f: impl FnOnce(Self::PalletsOrigin) -> Result, @@ -500,12 +519,15 @@ impl frame_support::traits::OriginTrait for Origin { fn as_signed(self) -> Option { unimplemented!("Not required in tests!") } + fn as_system_ref(&self) -> Option<&RawOrigin> { + unimplemented!("Not required in tests!") + } } #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] -pub struct Event; +pub struct RuntimeEvent; -impl From> for Event { +impl From> for RuntimeEvent { fn from(_evt: frame_system::Event) -> Self { unimplemented!("Not required in tests!") } @@ -582,12 +604,18 @@ parameter_types! { BlockWeights::with_sensible_defaults(Weight::from_ref_time(4 * 1024 * 1024), Perbill::from_percent(75)); } +impl From> for Extrinsic { + fn from(_: frame_system::Call) -> Self { + unimplemented!("Not required in tests!") + } +} + impl frame_system::Config for Runtime { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = RuntimeBlockWeights; type BlockLength = RuntimeBlockLength; - type Origin = Origin; - type Call = Extrinsic; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = Extrinsic; type Index = u64; type BlockNumber = u64; type Hash = H256; @@ -595,7 +623,7 @@ impl frame_system::Config for Runtime { type AccountId = u64; type Lookup = IdentityLookup; type Header = Header; - type Event = Event; + type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<2400>; type DbWeight = (); type Version = (); @@ -609,6 +637,8 @@ impl frame_system::Config for Runtime { type MaxConsumers = ConstU32<16>; } +impl system::Config for Runtime {} + impl pallet_timestamp::Config for Runtime { /// A timestamp: milliseconds since the unix epoch. type Moment = u64; @@ -1340,7 +1370,7 @@ mod tests { .set_execution_strategy(ExecutionStrategy::AlwaysWasm) .set_heap_pages(8) .build(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); // Try to allocate 1024k of memory on heap. This is going to fail since it is twice larger // than the heap. @@ -1377,7 +1407,7 @@ mod tests { let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); runtime_api.test_storage(&block_id).unwrap(); } @@ -1404,7 +1434,7 @@ mod tests { let client = TestClientBuilder::new().set_execution_strategy(ExecutionStrategy::Both).build(); let runtime_api = client.runtime_api(); - let block_id = BlockId::Number(client.chain_info().best_number); + let block_id = BlockId::Hash(client.chain_info().best_hash); runtime_api.test_witness(&block_id, proof, root).unwrap(); } diff --git a/test-utils/runtime/src/system.rs b/test-utils/runtime/src/system.rs index a82cc969758c8..afcf68ccce9cf 100644 --- a/test-utils/runtime/src/system.rs +++ b/test-utils/runtime/src/system.rs @@ -19,11 +19,11 @@ //! and depositing logs. use crate::{ - AccountId, AuthorityId, Block, BlockNumber, Digest, Extrinsic, Header, Transfer, H256 as Hash, + AccountId, AuthorityId, Block, BlockNumber, Digest, Extrinsic, Header, Runtime, Transfer, + H256 as Hash, }; use codec::{Decode, Encode, KeyedVec}; -use frame_support::{decl_module, decl_storage, storage}; -use frame_system::Config; +use frame_support::storage; use sp_core::storage::well_known_keys; use sp_io::{hashing::blake2_256, storage::root as storage_root, trie}; use sp_runtime::{ @@ -39,19 +39,51 @@ use sp_std::prelude::*; const NONCE_OF: &[u8] = b"nonce:"; const BALANCE_OF: &[u8] = b"balance:"; -decl_module! { - pub struct Module for enum Call where origin: T::Origin {} -} +pub use self::pallet::*; + +#[frame_support::pallet] +mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + #[pallet::without_storage_info] + pub struct Pallet(PhantomData); + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::storage] + pub type ExtrinsicData = StorageMap<_, Blake2_128Concat, u32, Vec, ValueQuery>; + + // The current block number being processed. Set by `execute_block`. + #[pallet::storage] + pub type Number = StorageValue<_, BlockNumber, OptionQuery>; -decl_storage! { - trait Store for Module as TestRuntime { - ExtrinsicData: map hasher(blake2_128_concat) u32 => Vec; - // The current block number being processed. Set by `execute_block`. - Number get(fn number): Option; - ParentHash get(fn parent_hash): Hash; - NewAuthorities get(fn new_authorities): Option>; - StorageDigest get(fn storage_digest): Option; - Authorities get(fn authorities) config(): Vec; + #[pallet::storage] + pub type ParentHash = StorageValue<_, Hash, ValueQuery>; + + #[pallet::storage] + pub type NewAuthorities = StorageValue<_, Vec, OptionQuery>; + + #[pallet::storage] + pub type StorageDigest = StorageValue<_, Digest, OptionQuery>; + + #[pallet::storage] + pub type Authorities = StorageValue<_, Vec, ValueQuery>; + + #[pallet::genesis_config] + #[cfg_attr(feature = "std", derive(Default))] + pub struct GenesisConfig { + pub authorities: Vec, + } + + #[pallet::genesis_build] + impl GenesisBuild for GenesisConfig { + fn build(&self) { + >::put(self.authorities.clone()); + } } } @@ -69,9 +101,9 @@ pub fn nonce_of(who: AccountId) -> u64 { pub fn initialize_block(header: &Header) { // populate environment. - ::put(&header.number); - ::put(&header.parent_hash); - ::put(header.digest()); + >::put(&header.number); + >::put(&header.parent_hash); + >::put(header.digest()); storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &0u32); // try to read something that depends on current header digest @@ -82,15 +114,15 @@ pub fn initialize_block(header: &Header) { } pub fn authorities() -> Vec { - Authorities::get() + >::get() } pub fn get_block_number() -> Option { - Number::get() + >::get() } pub fn take_block_number() -> Option { - Number::take() + >::take() } #[derive(Copy, Clone)] @@ -124,8 +156,8 @@ fn execute_block_with_state_root_handler(block: &mut Block, mode: Mode) -> Heade header.state_root = new_header.state_root; } else { info_expect_equal_hash(&new_header.state_root, &header.state_root); - assert!( - new_header.state_root == header.state_root, + assert_eq!( + new_header.state_root, header.state_root, "Storage root must match that calculated.", ); } @@ -134,8 +166,8 @@ fn execute_block_with_state_root_handler(block: &mut Block, mode: Mode) -> Heade header.extrinsics_root = new_header.extrinsics_root; } else { info_expect_equal_hash(&new_header.extrinsics_root, &header.extrinsics_root); - assert!( - new_header.extrinsics_root == header.extrinsics_root, + assert_eq!( + new_header.extrinsics_root, header.extrinsics_root, "Transaction trie root must be valid.", ); } @@ -187,7 +219,7 @@ pub fn execute_transaction(utx: Extrinsic) -> ApplyExtrinsicResult { let extrinsic_index: u32 = storage::unhashed::get(well_known_keys::EXTRINSIC_INDEX).unwrap_or_default(); let result = execute_transaction_backend(&utx, extrinsic_index); - ExtrinsicData::insert(extrinsic_index, utx.encode()); + >::insert(extrinsic_index, utx.encode()); storage::unhashed::put(well_known_keys::EXTRINSIC_INDEX, &(extrinsic_index + 1)); result } @@ -196,13 +228,14 @@ pub fn execute_transaction(utx: Extrinsic) -> ApplyExtrinsicResult { pub fn finalize_block() -> Header { use sp_core::storage::StateVersion; let extrinsic_index: u32 = storage::unhashed::take(well_known_keys::EXTRINSIC_INDEX).unwrap(); - let txs: Vec<_> = (0..extrinsic_index).map(ExtrinsicData::take).collect(); + let txs: Vec<_> = (0..extrinsic_index).map(>::take).collect(); let extrinsics_root = trie::blake2_256_ordered_root(txs, StateVersion::V0); - let number = ::take().expect("Number is set by `initialize_block`"); - let parent_hash = ::take(); - let mut digest = ::take().expect("StorageDigest is set by `initialize_block`"); + let number = >::take().expect("Number is set by `initialize_block`"); + let parent_hash = >::take(); + let mut digest = + >::take().expect("StorageDigest is set by `initialize_block`"); - let o_new_authorities = ::take(); + let o_new_authorities = >::take(); // This MUST come after all changes to storage are done. Otherwise we will fail the // “Storage root does not match that calculated” assertion. @@ -289,7 +322,7 @@ fn execute_store(data: Vec) -> ApplyExtrinsicResult { } fn execute_new_authorities_backend(new_authorities: &[AuthorityId]) -> ApplyExtrinsicResult { - NewAuthorities::put(new_authorities.to_vec()); + >::put(new_authorities.to_vec()); Ok(Ok(())) } @@ -331,7 +364,6 @@ mod tests { use sp_core::{ map, traits::{CodeExecutor, RuntimeCode}, - NeverNativeValue, }; use sp_io::{hashing::twox_128, TestExternalities}; use substrate_test_runtime_client::{AccountKeyring, Sr25519Keyring}; @@ -417,14 +449,7 @@ mod tests { }; executor() - .call:: _>( - &mut ext, - &runtime_code, - "Core_execute_block", - &b.encode(), - false, - None, - ) + .call(&mut ext, &runtime_code, "Core_execute_block", &b.encode(), false) .0 .unwrap(); }) @@ -530,14 +555,7 @@ mod tests { }; executor() - .call:: _>( - &mut ext, - &runtime_code, - "Core_execute_block", - &b.encode(), - false, - None, - ) + .call(&mut ext, &runtime_code, "Core_execute_block", &b.encode(), false) .0 .unwrap(); }) diff --git a/test-utils/runtime/transaction-pool/src/lib.rs b/test-utils/runtime/transaction-pool/src/lib.rs index 47c519212eb36..a6fc1c4eba287 100644 --- a/test-utils/runtime/transaction-pool/src/lib.rs +++ b/test-utils/runtime/transaction-pool/src/lib.rs @@ -22,7 +22,7 @@ use codec::Encode; use futures::future::ready; use parking_lot::RwLock; -use sp_blockchain::CachedHeaderMetadata; +use sp_blockchain::{CachedHeaderMetadata, TreeRoute}; use sp_runtime::{ generic::{self, BlockId}, traits::{ @@ -337,6 +337,14 @@ impl sc_transaction_pool::ChainApi for TestApi { self.chain.read().block_by_hash.get(hash).map(|b| b.header().clone()), }) } + + fn tree_route( + &self, + from: ::Hash, + to: ::Hash, + ) -> Result, Self::Error> { + sp_blockchain::tree_route::(self, from, to).map_err(Into::into) + } } impl sp_blockchain::HeaderMetadata for TestApi { diff --git a/utils/frame/benchmarking-cli/Cargo.toml b/utils/frame/benchmarking-cli/Cargo.toml index 5215f422ccb2d..756b5d9441f24 100644 --- a/utils/frame/benchmarking-cli/Cargo.toml +++ b/utils/frame/benchmarking-cli/Cargo.toml @@ -13,20 +13,20 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +array-bytes = "4.1" chrono = "0.4" -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } comfy-table = { version = "6.0.0", default-features = false } handlebars = "4.2.2" hash-db = "0.15.2" -hex = "0.4.3" Inflector = "0.11.4" itertools = "0.10.3" -kvdb = "0.11.0" +kvdb = "0.12.0" lazy_static = "1.4.0" linked-hash-map = "0.5.4" log = "0.4.17" -memory-db = "0.29.0" +memory-db = "0.30.0" rand = { version = "0.8.4", features = ["small_rng"] } rand_pcg = "0.3.1" serde = "1.0.136" @@ -66,6 +66,6 @@ gethostname = "0.2.3" futures = "0.3.21" [features] -default = ["rocksdb", "runtime-benchmarks"] +default = ["rocksdb"] runtime-benchmarks = ["sc-client-db/runtime-benchmarks"] rocksdb = ["sc-cli/rocksdb", "sc-client-db/rocksdb"] diff --git a/utils/frame/benchmarking-cli/src/block/bench.rs b/utils/frame/benchmarking-cli/src/block/bench.rs index 36215c8a0586d..47cd047e158d0 100644 --- a/utils/frame/benchmarking-cli/src/block/bench.rs +++ b/utils/frame/benchmarking-cli/src/block/bench.rs @@ -22,7 +22,9 @@ use frame_support::weights::constants::WEIGHT_PER_NANOS; use frame_system::ConsumedWeight; use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; use sc_cli::{Error, Result}; -use sc_client_api::{Backend as ClientBackend, BlockBackend, StorageProvider, UsageProvider}; +use sc_client_api::{ + Backend as ClientBackend, BlockBackend, HeaderBackend, StorageProvider, UsageProvider, +}; use sp_api::{ApiExt, Core, HeaderT, ProvideRuntimeApi}; use sp_blockchain::Error::RuntimeApiError; use sp_runtime::{generic::BlockId, traits::Block as BlockT, DigestItem, OpaqueExtrinsic}; @@ -43,15 +45,15 @@ const LOG_TARGET: &'static str = "benchmark::block::weight"; #[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] pub struct BenchmarkParams { /// Number of the first block to consider. - #[clap(long)] + #[arg(long)] pub from: u32, /// Last block number to consider. - #[clap(long)] + #[arg(long)] pub to: u32, /// Number of times that the benchmark should be repeated for each block. - #[clap(long, default_value = "10")] + #[arg(long, default_value_t = 10)] pub repeat: u32, } @@ -73,7 +75,8 @@ where + ProvideRuntimeApi + StorageProvider + UsageProvider - + BlockBackend, + + BlockBackend + + HeaderBackend, C::Api: ApiExt + BlockBuilderApi, { /// Returns a new [`Self`] from the arguments. @@ -131,12 +134,15 @@ where fn consumed_weight(&self, block: &BlockId) -> Result { // Hard-coded key for System::BlockWeight. It could also be passed in as argument // for the benchmark, but I think this should work as well. - let hash = hex::decode("26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96")?; + let hash = array_bytes::hex2bytes( + "26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96", + )?; let key = StorageKey(hash); + let block_hash = self.client.expect_block_hash_from_id(block)?; let mut raw_weight = &self .client - .storage(&block, &key)? + .storage(&block_hash, &key)? .ok_or(format!("Could not find System::BlockWeight for block: {}", block))? .0[..]; diff --git a/utils/frame/benchmarking-cli/src/block/cmd.rs b/utils/frame/benchmarking-cli/src/block/cmd.rs index e4e1716b1c5ac..8bac04110f7ab 100644 --- a/utils/frame/benchmarking-cli/src/block/cmd.rs +++ b/utils/frame/benchmarking-cli/src/block/cmd.rs @@ -22,6 +22,7 @@ use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; use sc_client_api::{Backend as ClientBackend, BlockBackend, StorageProvider, UsageProvider}; use sp_api::{ApiExt, ProvideRuntimeApi}; +use sp_blockchain::HeaderBackend; use sp_runtime::{traits::Block as BlockT, OpaqueExtrinsic}; use clap::Parser; @@ -67,6 +68,12 @@ pub struct BlockCmd { #[allow(missing_docs)] #[clap(flatten)] pub params: BenchmarkParams, + + /// Enable the Trie cache. + /// + /// This should only be used for performance analysis and not for final results. + #[arg(long)] + pub enable_trie_cache: bool, } impl BlockCmd { @@ -81,7 +88,8 @@ impl BlockCmd { + BlockBackend + ProvideRuntimeApi + StorageProvider - + UsageProvider, + + UsageProvider + + HeaderBackend, C::Api: ApiExt + BlockBuilderApi, { // Put everything in the benchmark type to have the generic types handy. @@ -98,4 +106,12 @@ impl CliConfiguration for BlockCmd { fn import_params(&self) -> Option<&ImportParams> { Some(&self.import_params) } + + fn trie_cache_maximum_size(&self) -> Result> { + if self.enable_trie_cache { + Ok(self.import_params().map(|x| x.trie_cache_maximum_size()).unwrap_or_default()) + } else { + Ok(None) + } + } } diff --git a/utils/frame/benchmarking-cli/src/extrinsic/bench.rs b/utils/frame/benchmarking-cli/src/extrinsic/bench.rs index 9b76108fdeccf..f67cadffd7e2b 100644 --- a/utils/frame/benchmarking-cli/src/extrinsic/bench.rs +++ b/utils/frame/benchmarking-cli/src/extrinsic/bench.rs @@ -55,17 +55,17 @@ use crate::shared::{StatSelect, Stats}; #[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] pub struct BenchmarkParams { /// Rounds of warmups before measuring. - #[clap(long, default_value = "10")] + #[arg(long, default_value_t = 10)] pub warmup: u32, /// How many times the benchmark should be repeated. - #[clap(long, default_value = "100")] + #[arg(long, default_value_t = 100)] pub repeat: u32, /// Maximal number of extrinsics that should be put into a block. /// /// Only useful for debugging. - #[clap(long)] + #[arg(long)] pub max_ext_per_block: Option, } diff --git a/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs b/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs index 2c94a6be50255..b95cd6b5c2e42 100644 --- a/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs +++ b/utils/frame/benchmarking-cli/src/extrinsic/cmd.rs @@ -62,16 +62,22 @@ pub struct ExtrinsicParams { /// List all available pallets and extrinsics. /// /// The format is CSV with header `pallet, extrinsic`. - #[clap(long)] + #[arg(long)] pub list: bool, /// Pallet name of the extrinsic to benchmark. - #[clap(long, value_name = "PALLET", required_unless_present = "list")] + #[arg(long, value_name = "PALLET", required_unless_present = "list")] pub pallet: Option, /// Extrinsic to benchmark. - #[clap(long, value_name = "EXTRINSIC", required_unless_present = "list")] + #[arg(long, value_name = "EXTRINSIC", required_unless_present = "list")] pub extrinsic: Option, + + /// Enable the Trie cache. + /// + /// This should only be used for performance analysis and not for final results. + #[arg(long)] + pub enable_trie_cache: bool, } impl ExtrinsicCmd { @@ -132,4 +138,12 @@ impl CliConfiguration for ExtrinsicCmd { fn import_params(&self) -> Option<&ImportParams> { Some(&self.import_params) } + + fn trie_cache_maximum_size(&self) -> Result> { + if self.params.enable_trie_cache { + Ok(self.import_params().map(|x| x.trie_cache_maximum_size()).unwrap_or_default()) + } else { + Ok(None) + } + } } diff --git a/utils/frame/benchmarking-cli/src/lib.rs b/utils/frame/benchmarking-cli/src/lib.rs index 81e3e8c128401..11f4b480768cf 100644 --- a/utils/frame/benchmarking-cli/src/lib.rs +++ b/utils/frame/benchmarking-cli/src/lib.rs @@ -31,6 +31,7 @@ pub use extrinsic::{ExtrinsicBuilder, ExtrinsicCmd, ExtrinsicFactory}; pub use machine::{MachineCmd, Requirements, SUBSTRATE_REFERENCE_HARDWARE}; pub use overhead::OverheadCmd; pub use pallet::PalletCmd; +pub use sc_service::BasePath; pub use storage::StorageCmd; use sc_cli::{CliConfiguration, DatabaseParams, ImportParams, PruningParams, Result, SharedParams}; @@ -88,6 +89,19 @@ impl CliConfiguration for BenchmarkCmd { } } + fn base_path(&self) -> Result> { + let inner = unwrap_cmd! { + self, cmd, cmd.base_path() + }; + + // If the base path was not provided, benchmark command shall use temporary path. Otherwise + // we may end up using shared path, which may be inappropriate for benchmarking. + match inner { + Ok(None) => Some(BasePath::new_temp_dir()).transpose().map_err(|e| e.into()), + e => e, + } + } + fn pruning_params(&self) -> Option<&PruningParams> { unwrap_cmd! { self, cmd, cmd.pruning_params() diff --git a/utils/frame/benchmarking-cli/src/machine/hardware.rs b/utils/frame/benchmarking-cli/src/machine/hardware.rs index 5c62660cc7cf4..53cb0f51392f7 100644 --- a/utils/frame/benchmarking-cli/src/machine/hardware.rs +++ b/utils/frame/benchmarking-cli/src/machine/hardware.rs @@ -152,8 +152,9 @@ impl fmt::Display for Throughput { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let normalized = self.normalize(); match normalized { - Self::KiBs(s) | Self::MiBs(s) | Self::GiBs(s) => - write!(f, "{:.2?} {}", s, normalized.unit()), + Self::KiBs(s) | Self::MiBs(s) | Self::GiBs(s) => { + write!(f, "{:.2?} {}", s, normalized.unit()) + }, } } } @@ -161,7 +162,7 @@ impl fmt::Display for Throughput { #[cfg(test)] mod tests { use super::*; - use sp_runtime::assert_eq_error_rate; + use sp_runtime::assert_eq_error_rate_float; /// `SUBSTRATE_REFERENCE_HARDWARE` can be en- and decoded. #[test] @@ -179,9 +180,9 @@ mod tests { const EPS: f64 = 0.1; let gib = Throughput::GiBs(14.324); - assert_eq_error_rate!(14.324, gib.to_gibs(), EPS); - assert_eq_error_rate!(14667.776, gib.to_mibs(), EPS); - assert_eq_error_rate!(14667.776 * 1024.0, gib.to_kibs(), EPS); + assert_eq_error_rate_float!(14.324, gib.to_gibs(), EPS); + assert_eq_error_rate_float!(14667.776, gib.to_mibs(), EPS); + assert_eq_error_rate_float!(14667.776 * 1024.0, gib.to_kibs(), EPS); assert_eq!("14.32 GiB/s", gib.to_string()); assert_eq!("14.32 GiB/s", gib.normalize().to_string()); diff --git a/utils/frame/benchmarking-cli/src/machine/mod.rs b/utils/frame/benchmarking-cli/src/machine/mod.rs index 5f27c71983905..a19db671f3cd1 100644 --- a/utils/frame/benchmarking-cli/src/machine/mod.rs +++ b/utils/frame/benchmarking-cli/src/machine/mod.rs @@ -53,30 +53,30 @@ pub struct MachineCmd { /// Do not return an error if any check fails. /// /// Should only be used for debugging. - #[clap(long)] + #[arg(long)] pub allow_fail: bool, /// Set a fault tolerance for passing a requirement. /// /// 10% means that the test would pass even when only 90% score was archived. /// Can be used to mitigate outliers of the benchmarks. - #[clap(long, default_value = "10.0", value_name = "PERCENT")] + #[arg(long, default_value_t = 10.0, value_name = "PERCENT")] pub tolerance: f64, /// Time limit for the verification benchmark. - #[clap(long, default_value = "5.0", value_name = "SECONDS")] + #[arg(long, default_value_t = 5.0, value_name = "SECONDS")] pub verify_duration: f32, /// Time limit for the hash function benchmark. - #[clap(long, default_value = "5.0", value_name = "SECONDS")] + #[arg(long, default_value_t = 5.0, value_name = "SECONDS")] pub hash_duration: f32, /// Time limit for the memory benchmark. - #[clap(long, default_value = "5.0", value_name = "SECONDS")] + #[arg(long, default_value_t = 5.0, value_name = "SECONDS")] pub memory_duration: f32, /// Time limit for each disk benchmark. - #[clap(long, default_value = "5.0", value_name = "SECONDS")] + #[arg(long, default_value_t = 5.0, value_name = "SECONDS")] pub disk_duration: f32, } diff --git a/utils/frame/benchmarking-cli/src/overhead/README.md b/utils/frame/benchmarking-cli/src/overhead/README.md index 9d723c3424f7b..b21d051e9d44c 100644 --- a/utils/frame/benchmarking-cli/src/overhead/README.md +++ b/utils/frame/benchmarking-cli/src/overhead/README.md @@ -126,6 +126,7 @@ Minimizing this is important to have a large transaction throughput. - [`--add`](../shared/README.md#arguments) - [`--metric`](../shared/README.md#arguments) - [`--weight-path`](../shared/README.md#arguments) +- [`--header`](../shared/README.md#arguments) License: Apache-2.0 diff --git a/utils/frame/benchmarking-cli/src/overhead/cmd.rs b/utils/frame/benchmarking-cli/src/overhead/cmd.rs index 836aec3354215..40ed00c1a8f45 100644 --- a/utils/frame/benchmarking-cli/src/overhead/cmd.rs +++ b/utils/frame/benchmarking-cli/src/overhead/cmd.rs @@ -38,7 +38,7 @@ use ver_api::VerApi; use clap::{Args, Parser}; use log::info; use serde::Serialize; -use std::{fmt::Debug, sync::Arc}; +use std::{fmt::Debug, path::PathBuf, sync::Arc}; use crate::{ extrinsic::{ @@ -79,6 +79,18 @@ pub struct OverheadParams { #[allow(missing_docs)] #[clap(flatten)] pub hostinfo: HostInfoParams, + + /// Add a header to the generated weight output file. + /// + /// Good for adding LICENSE headers. + #[arg(long, value_name = "PATH")] + pub header: Option, + + /// Enable the Trie cache. + /// + /// This should only be used for performance analysis and not for final results. + #[arg(long)] + pub enable_trie_cache: bool, } /// Type of a benchmark. @@ -203,4 +215,12 @@ impl CliConfiguration for OverheadCmd { fn import_params(&self) -> Option<&ImportParams> { Some(&self.import_params) } + + fn trie_cache_maximum_size(&self) -> Result> { + if self.params.enable_trie_cache { + Ok(self.import_params().map(|x| x.trie_cache_maximum_size()).unwrap_or_default()) + } else { + Ok(None) + } + } } diff --git a/utils/frame/benchmarking-cli/src/overhead/template.rs b/utils/frame/benchmarking-cli/src/overhead/template.rs index aa82e45cf6db9..ceed34d1981f9 100644 --- a/utils/frame/benchmarking-cli/src/overhead/template.rs +++ b/utils/frame/benchmarking-cli/src/overhead/template.rs @@ -51,6 +51,8 @@ pub(crate) struct TemplateData { hostname: String, /// CPU name of the machine that executed the benchmarks. cpuname: String, + /// Header for the generated file. + header: String, /// Command line arguments that were passed to the CLI. args: Vec, /// Params of the executed command. @@ -70,6 +72,12 @@ impl TemplateData { stats: &Stats, ) -> Result { let weight = params.weight.calc_weight(stats)?; + let header = params + .header + .as_ref() + .map(|p| std::fs::read_to_string(p)) + .transpose()? + .unwrap_or_default(); Ok(TemplateData { short_name: t.short_name().into(), @@ -79,6 +87,7 @@ impl TemplateData { date: chrono::Utc::now().format("%Y-%m-%d (Y/M/D)").to_string(), hostname: params.hostinfo.hostname(), cpuname: params.hostinfo.cpuname(), + header, args: env::args().collect::>(), params: params.clone(), stats: stats.clone(), diff --git a/utils/frame/benchmarking-cli/src/overhead/weights.hbs b/utils/frame/benchmarking-cli/src/overhead/weights.hbs index bddaa642a5a29..8d1a369372721 100644 --- a/utils/frame/benchmarking-cli/src/overhead/weights.hbs +++ b/utils/frame/benchmarking-cli/src/overhead/weights.hbs @@ -1,20 +1,4 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +{{header}} //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} //! DATE: {{date}} //! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}` @@ -29,10 +13,8 @@ // {{arg}} {{/each}} -use frame_support::{ - parameter_types, - weights::{constants::WEIGHT_PER_NANOS, Weight}, -}; +use sp_core::parameter_types; +use sp_weights::{constants::WEIGHT_PER_NANOS, Weight}; parameter_types! { {{#if (eq short_name "block")}} @@ -57,8 +39,7 @@ parameter_types! { #[cfg(test)] mod test_weights { - use super::*; - use frame_support::weights::constants; + use sp_weights::constants; /// Checks that the weight exists and is sane. // NOTE: If this test fails but you are sure that the generated values are fine, @@ -69,14 +50,26 @@ mod test_weights { {{#if (eq short_name "block")}} // At least 100 µs. - assert!(w >= Weight::from_ref_time(100 * constants::WEIGHT_PER_MICROS), "Weight should be at least 100 µs."); + assert!( + w.ref_time() >= 100u64 * constants::WEIGHT_PER_MICROS.ref_time(), + "Weight should be at least 100 µs." + ); // At most 50 ms. - assert!(w <= Weight::from_ref_time(50 * constants::WEIGHT_PER_MILLIS), "Weight should be at most 50 ms."); + assert!( + w.ref_time() <= 50u64 * constants::WEIGHT_PER_MILLIS.ref_time(), + "Weight should be at most 50 ms." + ); {{else}} // At least 10 µs. - assert!(w >= Weight::from_ref_time(10 * constants::WEIGHT_PER_MICROS), "Weight should be at least 10 µs."); + assert!( + w.ref_time() >= 10u64 * constants::WEIGHT_PER_MICROS.ref_time(), + "Weight should be at least 10 µs." + ); // At most 1 ms. - assert!(w <= Weight::from_ref_time(constants::WEIGHT_PER_MILLIS), "Weight should be at most 1 ms."); + assert!( + w.ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), + "Weight should be at most 1 ms." + ); {{/if}} } } diff --git a/utils/frame/benchmarking-cli/src/pallet/command.rs b/utils/frame/benchmarking-cli/src/pallet/command.rs index 0fc7cc4d783f7..6e413bdf7e2c5 100644 --- a/utils/frame/benchmarking-cli/src/pallet/command.rs +++ b/utils/frame/benchmarking-cli/src/pallet/command.rs @@ -134,6 +134,20 @@ impl PalletCmd { }; } + if let Some(json_input) = &self.json_input { + let raw_data = match std::fs::read(json_input) { + Ok(raw_data) => raw_data, + Err(error) => + return Err(format!("Failed to read {:?}: {}", json_input, error).into()), + }; + let batches: Vec = match serde_json::from_slice(&raw_data) { + Ok(batches) => batches, + Err(error) => + return Err(format!("Failed to deserialize {:?}: {}", json_input, error).into()), + }; + return self.output_from_results(&batches) + } + let spec = config.chain_spec; let strategy = self.execution.unwrap_or(ExecutionStrategy::Native); let pallet = self.pallet.clone().unwrap_or_default(); @@ -228,7 +242,7 @@ impl PalletCmd { let mut component_ranges = HashMap::<(Vec, Vec), Vec>::new(); for (pallet, extrinsic, components) in benchmarks_to_run { - log::info!( + println!( "Starting benchmark: {}::{}", String::from_utf8(pallet.clone()).expect("Encoded from String; qed"), String::from_utf8(extrinsic.clone()).expect("Encoded from String; qed"), @@ -254,9 +268,8 @@ impl PalletCmd { for s in 0..self.steps { // This is the value we will be testing for component `name` - let component_value = ((lowest as f32 + step_size * s as f32) as u32) - .min(highest) - .max(lowest); + let component_value = + ((lowest as f32 + step_size * s as f32) as u32).clamp(lowest, highest); // Select the max value for all the other components. let c: Vec<(BenchmarkParameter, u32)> = components @@ -283,16 +296,15 @@ impl PalletCmd { for (s, selected_components) in all_components.iter().enumerate() { // First we run a verification if !self.no_verify { - // Dont use these results since verification code will add overhead let state = &state_without_tracking; - let _results = StateMachine::new( + let result = StateMachine::new( state, &mut changes, &executor, "Benchmark_dispatch_benchmark", &( - &pallet.clone(), - &extrinsic.clone(), + &pallet, + &extrinsic, &selected_components.clone(), true, // run verification code 1, // no need to do internal repeats @@ -307,6 +319,20 @@ impl PalletCmd { .map_err(|e| { format!("Error executing and verifying runtime benchmark: {}", e) })?; + // Dont use these results since verification code will add overhead. + let _batch = + , String> as Decode>::decode( + &mut &result[..], + ) + .map_err(|e| format!("Failed to decode benchmark results: {:?}", e))? + .map_err(|e| { + format!( + "Benchmark {}::{} failed: {}", + String::from_utf8_lossy(&pallet), + String::from_utf8_lossy(&extrinsic), + e + ) + })?; } // Do one loop of DB tracking. { @@ -376,7 +402,7 @@ impl PalletCmd { if let Ok(elapsed) = timer.elapsed() { if elapsed >= time::Duration::from_secs(5) { timer = time::SystemTime::now(); - log::info!( + println!( "Running Benchmark: {}.{}({} args) {}/{} {}/{}", String::from_utf8(pallet.clone()) .expect("Encoded from String; qed"), @@ -396,25 +422,69 @@ impl PalletCmd { // Combine all of the benchmark results, so that benchmarks of the same pallet/function // are together. - let batches: Vec = combine_batches(batches, batches_db); - - // Create the weights.rs file. - if let Some(output_path) = &self.output { - writer::write_results(&batches, &storage_info, &component_ranges, output_path, self)?; - } + let batches = combine_batches(batches, batches_db); + self.output(&batches, &storage_info, &component_ranges) + } + fn output( + &self, + batches: &[BenchmarkBatchSplitResults], + storage_info: &[StorageInfo], + component_ranges: &HashMap<(Vec, Vec), Vec>, + ) -> Result<()> { // Jsonify the result and write it to a file or stdout if desired. if !self.jsonify(&batches)? { // Print the summary only if `jsonify` did not write to stdout. self.print_summary(&batches, &storage_info) } + + // Create the weights.rs file. + if let Some(output_path) = &self.output { + writer::write_results(&batches, &storage_info, &component_ranges, output_path, self)?; + } + Ok(()) } + fn output_from_results(&self, batches: &[BenchmarkBatchSplitResults]) -> Result<()> { + let mut component_ranges = + HashMap::<(Vec, Vec), HashMap>::new(); + for batch in batches { + let range = component_ranges + .entry((batch.pallet.clone(), batch.benchmark.clone())) + .or_default(); + for result in &batch.time_results { + for (param, value) in &result.components { + let name = param.to_string(); + let (ref mut min, ref mut max) = range.entry(name).or_insert((*value, *value)); + if *value < *min { + *min = *value; + } + if *value > *max { + *max = *value; + } + } + } + } + + let component_ranges: HashMap<_, _> = component_ranges + .into_iter() + .map(|(key, ranges)| { + let ranges = ranges + .into_iter() + .map(|(name, (min, max))| ComponentRange { name, min, max }) + .collect(); + (key, ranges) + }) + .collect(); + + self.output(batches, &[], &component_ranges) + } + /// Jsonifies the passed batches and writes them to stdout or into a file. /// Can be configured via `--json` and `--json-file`. /// Returns whether it wrote to stdout. - fn jsonify(&self, batches: &Vec) -> Result { + fn jsonify(&self, batches: &[BenchmarkBatchSplitResults]) -> Result { if self.json_output || self.json_file.is_some() { let json = serde_json::to_string_pretty(&batches) .map_err(|e| format!("Serializing into JSON: {:?}", e))?; @@ -431,11 +501,7 @@ impl PalletCmd { } /// Prints the results as human-readable summary without raw timing data. - fn print_summary( - &self, - batches: &Vec, - storage_info: &Vec, - ) { + fn print_summary(&self, batches: &[BenchmarkBatchSplitResults], storage_info: &[StorageInfo]) { for batch in batches.iter() { // Print benchmark metadata println!( diff --git a/utils/frame/benchmarking-cli/src/pallet/mod.rs b/utils/frame/benchmarking-cli/src/pallet/mod.rs index 7beaf321a2927..b10f531bc0aed 100644 --- a/utils/frame/benchmarking-cli/src/pallet/mod.rs +++ b/utils/frame/benchmarking-cli/src/pallet/mod.rs @@ -27,69 +27,69 @@ use std::{fmt::Debug, path::PathBuf}; // Add a more relaxed parsing for pallet names by allowing pallet directory names with `-` to be // used like crate names with `_` -fn parse_pallet_name(pallet: &str) -> String { - pallet.replace("-", "_") +fn parse_pallet_name(pallet: &str) -> std::result::Result { + Ok(pallet.replace("-", "_")) } /// Benchmark the extrinsic weight of FRAME Pallets. #[derive(Debug, clap::Parser)] pub struct PalletCmd { /// Select a FRAME Pallet to benchmark, or `*` for all (in which case `extrinsic` must be `*`). - #[clap(short, long, parse(from_str = parse_pallet_name), required_unless_present = "list")] + #[arg(short, long, value_parser = parse_pallet_name, required_unless_present_any = ["list", "json_input"])] pub pallet: Option, /// Select an extrinsic inside the pallet to benchmark, or `*` for all. - #[clap(short, long, required_unless_present = "list")] + #[arg(short, long, required_unless_present_any = ["list", "json_input"])] pub extrinsic: Option, /// Select how many samples we should take across the variable components. - #[clap(short, long, default_value = "1")] + #[arg(short, long, default_value_t = 2)] pub steps: u32, /// Indicates lowest values for each of the component ranges. - #[clap(long = "low", use_value_delimiter = true)] + #[arg(long = "low", value_delimiter = ',')] pub lowest_range_values: Vec, /// Indicates highest values for each of the component ranges. - #[clap(long = "high", use_value_delimiter = true)] + #[arg(long = "high", value_delimiter = ',')] pub highest_range_values: Vec, /// Select how many repetitions of this benchmark should run from within the wasm. - #[clap(short, long, default_value = "1")] + #[arg(short, long, default_value_t = 1)] pub repeat: u32, /// Select how many repetitions of this benchmark should run from the client. /// /// NOTE: Using this alone may give slower results, but will afford you maximum Wasm memory. - #[clap(long, default_value = "1")] + #[arg(long, default_value_t = 1)] pub external_repeat: u32, /// Print the raw results in JSON format. - #[clap(long = "json")] + #[arg(long = "json")] pub json_output: bool, /// Write the raw results in JSON format into the given file. - #[clap(long, conflicts_with = "json-output")] + #[arg(long, conflicts_with = "json_output")] pub json_file: Option, /// Don't print the median-slopes linear regression analysis. - #[clap(long)] + #[arg(long)] pub no_median_slopes: bool, /// Don't print the min-squares linear regression analysis. - #[clap(long)] + #[arg(long)] pub no_min_squares: bool, /// Output the benchmarks to a Rust file at the given path. - #[clap(long)] + #[arg(long)] pub output: Option, /// Add a header file to your outputted benchmarks. - #[clap(long)] + #[arg(long)] pub header: Option, /// Path to Handlebars template file used for outputting benchmark results. (Optional) - #[clap(long)] + #[arg(long)] pub template: Option, #[allow(missing_docs)] @@ -100,25 +100,25 @@ pub struct PalletCmd { /// * min-squares (default) /// * median-slopes /// * max (max of min squares and median slopes for each value) - #[clap(long)] + #[arg(long)] pub output_analysis: Option, /// Set the heap pages while running benchmarks. If not set, the default value from the client /// is used. - #[clap(long)] + #[arg(long)] pub heap_pages: Option, /// Disable verification logic when running benchmarks. - #[clap(long)] + #[arg(long)] pub no_verify: bool, /// Display and run extra benchmarks that would otherwise not be needed for weight /// construction. - #[clap(long)] + #[arg(long)] pub extra: bool, /// Estimate PoV size. - #[clap(long)] + #[arg(long)] pub record_proof: bool, #[allow(missing_docs)] @@ -126,44 +126,50 @@ pub struct PalletCmd { pub shared_params: sc_cli::SharedParams, /// The execution strategy that should be used for benchmarks. - #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true)] + #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true)] pub execution: Option, /// Method for executing Wasm runtime code. - #[clap( + #[arg( long = "wasm-execution", value_name = "METHOD", - possible_values = WasmExecutionMethod::variants(), + value_enum, ignore_case = true, - default_value = DEFAULT_WASM_EXECUTION_METHOD, + default_value_t = DEFAULT_WASM_EXECUTION_METHOD, )] pub wasm_method: WasmExecutionMethod, /// The WASM instantiation method to use. /// /// Only has an effect when `wasm-execution` is set to `compiled`. - #[clap( + #[arg( long = "wasm-instantiation-strategy", value_name = "STRATEGY", default_value_t = DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, - arg_enum, + value_enum, )] pub wasmtime_instantiation_strategy: WasmtimeInstantiationStrategy, /// Limit the memory the database cache can use. - #[clap(long = "db-cache", value_name = "MiB", default_value = "1024")] + #[arg(long = "db-cache", value_name = "MiB", default_value_t = 1024)] pub database_cache_size: u32, /// List the benchmarks that match your query rather than running them. /// /// When nothing is provided, we list all benchmarks. - #[clap(long)] + #[arg(long)] pub list: bool, /// If enabled, the storage info is not displayed in the output next to the analysis. /// /// This is independent of the storage info appearing in the *output file*. Use a Handlebar /// template for that purpose. - #[clap(long)] + #[arg(long)] pub no_storage_info: bool, + + /// A path to a `.json` file with existing benchmark results generated with `--json` or + /// `--json-file`. When specified the benchmarks are not actually executed, and the data for + /// the analysis is read from this file. + #[arg(long)] + pub json_input: Option, } diff --git a/utils/frame/benchmarking-cli/src/pallet/template.hbs b/utils/frame/benchmarking-cli/src/pallet/template.hbs index 6e016c47ef010..7e2e0688d654f 100644 --- a/utils/frame/benchmarking-cli/src/pallet/template.hbs +++ b/utils/frame/benchmarking-cli/src/pallet/template.hbs @@ -15,7 +15,7 @@ #![allow(unused_parens)] #![allow(unused_imports)] -use frame_support::{traits::Get, weights::{Weight}}; +use frame_support::{traits::Get, weights::Weight}; use sp_std::marker::PhantomData; /// Weight functions for `{{pallet}}`. @@ -33,6 +33,7 @@ impl {{pallet}}::WeightInfo for WeightInfo { {{~#each benchmark.components as |c| ~}} {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} ) -> Weight { + // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. Weight::from_ref_time({{underscore benchmark.base_weight}} as u64) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} diff --git a/utils/frame/benchmarking-cli/src/pallet/writer.rs b/utils/frame/benchmarking-cli/src/pallet/writer.rs index 42a237fcf3ce3..a52bbcd229cb1 100644 --- a/utils/frame/benchmarking-cli/src/pallet/writer.rs +++ b/utils/frame/benchmarking-cli/src/pallet/writer.rs @@ -24,12 +24,12 @@ use std::{ }; use inflector::Inflector; +use itertools::Itertools; use serde::Serialize; use crate::{pallet::command::ComponentRange, shared::UnderscoreHelper, PalletCmd}; use frame_benchmarking::{ Analysis, AnalysisChoice, BenchmarkBatchSplitResults, BenchmarkResult, BenchmarkSelector, - RegressionModel, }; use frame_support::traits::StorageInfo; use sp_core::hexdisplay::HexDisplay; @@ -69,6 +69,8 @@ struct BenchmarkData { component_writes: Vec, component_ranges: Vec, comments: Vec, + #[serde(serialize_with = "string_serialize")] + min_execution_time: u128, } // This forwards some specific metadata from the `PalletCmd` @@ -145,13 +147,15 @@ fn map_results( Ok(all_benchmarks) } -// Get an iterator of errors from a model. If the model is `None` all errors are zero. -fn extract_errors(model: &Option) -> impl Iterator + '_ { - let mut errors = model.as_ref().map(|m| m.se.regressor_values.iter()); - std::iter::from_fn(move || match &mut errors { - Some(model) => model.next().map(|val| *val as u128), - _ => Some(0), - }) +// Get an iterator of errors. +fn extract_errors(errors: &Option>) -> impl Iterator + '_ { + errors + .as_ref() + .map(|e| e.as_slice()) + .unwrap_or(&[]) + .iter() + .copied() + .chain(std::iter::repeat(0)) } // Analyze and return the relevant results for a given benchmark. @@ -190,24 +194,20 @@ fn get_benchmark_data( .slopes .into_iter() .zip(extrinsic_time.names.iter()) - .zip(extract_errors(&extrinsic_time.model)) + .zip(extract_errors(&extrinsic_time.errors)) .for_each(|((slope, name), error)| { if !slope.is_zero() { if !used_components.contains(&name) { used_components.push(name); } - used_extrinsic_time.push(ComponentSlope { - name: name.clone(), - slope: slope.saturating_mul(1000), - error: error.saturating_mul(1000), - }); + used_extrinsic_time.push(ComponentSlope { name: name.clone(), slope, error }); } }); reads .slopes .into_iter() .zip(reads.names.iter()) - .zip(extract_errors(&reads.model)) + .zip(extract_errors(&reads.errors)) .for_each(|((slope, name), error)| { if !slope.is_zero() { if !used_components.contains(&name) { @@ -220,7 +220,7 @@ fn get_benchmark_data( .slopes .into_iter() .zip(writes.names.iter()) - .zip(extract_errors(&writes.model)) + .zip(extract_errors(&writes.errors)) .for_each(|((slope, name), error)| { if !slope.is_zero() { if !used_components.contains(&name) { @@ -251,7 +251,7 @@ fn get_benchmark_data( BenchmarkData { name: String::from_utf8(batch.benchmark.clone()).unwrap(), components, - base_weight: extrinsic_time.base.saturating_mul(1000), + base_weight: extrinsic_time.base, base_reads: reads.base, base_writes: writes.base, component_weight: used_extrinsic_time, @@ -259,6 +259,7 @@ fn get_benchmark_data( component_writes: used_writes, component_ranges, comments, + min_execution_time: extrinsic_time.minimum, } } @@ -317,18 +318,21 @@ pub(crate) fn write_results( // Organize results by pallet into a JSON map let all_results = map_results(batches, storage_info, component_ranges, &analysis_choice)?; + let mut created_files = Vec::new(); + for ((pallet, instance), results) in all_results.iter() { let mut file_path = path.clone(); // If a user only specified a directory... if file_path.is_dir() { + // Start with "path/to/pallet_name". + let mut file_name = pallet.clone(); // Check if there might be multiple instances benchmarked. if all_results.keys().any(|(p, i)| p == pallet && i != instance) { - // Create new file: "path/to/pallet_name_instance_name.rs". - file_path.push(pallet.clone() + "_" + instance.to_snake_case().as_str()); - } else { - // Create new file: "path/to/pallet_name.rs". - file_path.push(pallet.clone()); + // Append "_instance_name". + file_name = format!("{}_{}", file_name, instance.to_snake_case()); } + // "mod::pallet_name.rs" becomes "mod_pallet_name.rs". + file_path.push(file_name.replace("::", "_")); file_path.set_extension("rs"); } @@ -345,10 +349,18 @@ pub(crate) fn write_results( benchmarks: results.clone(), }; - let mut output_file = fs::File::create(file_path)?; + let mut output_file = fs::File::create(&file_path)?; handlebars .render_template_to_write(&template, &hbs_data, &mut output_file) .map_err(|e| io_error(&e.to_string()))?; + println!("Created file: {:?}", &file_path); + created_files.push(file_path); + } + + for file in created_files.iter().duplicates() { + // This can happen when there are multiple instances of a pallet deployed + // and `--output` forces the output of all instances into the same file. + println!("Multiple benchmarks were written to the same file: {:?}.", file); } Ok(()) } diff --git a/utils/frame/benchmarking-cli/src/shared/README.md b/utils/frame/benchmarking-cli/src/shared/README.md index 2a3719b85498c..08e25b0e08f76 100644 --- a/utils/frame/benchmarking-cli/src/shared/README.md +++ b/utils/frame/benchmarking-cli/src/shared/README.md @@ -11,5 +11,6 @@ Contains code that is shared among multiple sub-commands. - `--db` The database backend to use. This depends on your snapshot. - `--pruning` Set the pruning mode of the node. Some benchmarks require you to set this to `archive`. - `--base-path` The location on the disk that should be used for the benchmarks. You can try this on different disks or even on a mounted RAM-disk. It is important to use the same location that will later-on be used to store the chain data to get the correct results. +- `--header` Optional file header which will be prepended to the weight output file. Can be used for adding LICENSE headers. License: Apache-2.0 diff --git a/utils/frame/benchmarking-cli/src/shared/mod.rs b/utils/frame/benchmarking-cli/src/shared/mod.rs index 33189792c4008..ea5415f33f020 100644 --- a/utils/frame/benchmarking-cli/src/shared/mod.rs +++ b/utils/frame/benchmarking-cli/src/shared/mod.rs @@ -95,22 +95,22 @@ pub fn check_build_profile() -> Result<(), String> { /// Parameters to configure how the host info will be determined. #[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] -#[clap(rename_all = "kebab-case")] +#[command(rename_all = "kebab-case")] pub struct HostInfoParams { /// Manually override the hostname to use. - #[clap(long)] + #[arg(long)] pub hostname_override: Option, /// Specify a fallback hostname if no-one could be detected automatically. /// /// Note: This only exists to make the `hostname` function infallible. - #[clap(long, default_value = "")] + #[arg(long, default_value = "")] pub hostname_fallback: String, /// Specify a fallback CPU name if no-one could be detected automatically. /// /// Note: This only exists to make the `cpuname` function infallible. - #[clap(long, default_value = "")] + #[arg(long, default_value = "")] pub cpuname_fallback: String, } diff --git a/utils/frame/benchmarking-cli/src/shared/stats.rs b/utils/frame/benchmarking-cli/src/shared/stats.rs index 3234d5f2f94f7..ffae4a17724f8 100644 --- a/utils/frame/benchmarking-cli/src/shared/stats.rs +++ b/utils/frame/benchmarking-cli/src/shared/stats.rs @@ -112,7 +112,7 @@ impl Stats { /// Returns the specified percentile for the given data. /// This is best effort since it ignores the interpolation case. fn percentile(mut xs: Vec, p: f64) -> u64 { - xs.sort_unstable(); + xs.sort(); let index = (xs.len() as f64 * p).ceil() as usize - 1; xs[index.clamp(0, xs.len() - 1)] } diff --git a/utils/frame/benchmarking-cli/src/shared/weight_params.rs b/utils/frame/benchmarking-cli/src/shared/weight_params.rs index 4dd80cd41ff3d..030bbfa00d468 100644 --- a/utils/frame/benchmarking-cli/src/shared/weight_params.rs +++ b/utils/frame/benchmarking-cli/src/shared/weight_params.rs @@ -31,23 +31,23 @@ pub struct WeightParams { /// File or directory to write the *weight* files to. /// /// For Substrate this should be `frame/support/src/weights`. - #[clap(long)] + #[arg(long)] pub weight_path: Option, /// Select a specific metric to calculate the final weight output. - #[clap(long = "metric", default_value = "average")] + #[arg(long = "metric", default_value = "average")] pub weight_metric: StatSelect, /// Multiply the resulting weight with the given factor. Must be positive. /// /// Is applied before `weight_add`. - #[clap(long = "mul", default_value = "1")] + #[arg(long = "mul", default_value_t = 1.0)] pub weight_mul: f64, /// Add the given offset to the resulting weight. /// /// Is applied after `weight_mul`. - #[clap(long = "add", default_value = "0")] + #[arg(long = "add", default_value_t = 0)] pub weight_add: u64, } diff --git a/utils/frame/benchmarking-cli/src/storage/README.md b/utils/frame/benchmarking-cli/src/storage/README.md index 820785f7ea20c..ecaf4edadab38 100644 --- a/utils/frame/benchmarking-cli/src/storage/README.md +++ b/utils/frame/benchmarking-cli/src/storage/README.md @@ -97,6 +97,7 @@ write: 71_347 * constants::WEIGHT_PER_NANOS, - [`--weight-path`](../shared/README.md#arguments) - `--json-read-path` Write the raw 'read' results to this file or directory. - `--json-write-path` Write the raw 'write' results to this file or directory. +- [`--header`](../shared/README.md#arguments) License: Apache-2.0 diff --git a/utils/frame/benchmarking-cli/src/storage/cmd.rs b/utils/frame/benchmarking-cli/src/storage/cmd.rs index de5e189b40db0..32fd5da7f95f0 100644 --- a/utils/frame/benchmarking-cli/src/storage/cmd.rs +++ b/utils/frame/benchmarking-cli/src/storage/cmd.rs @@ -68,42 +68,54 @@ pub struct StorageParams { pub hostinfo: HostInfoParams, /// Skip the `read` benchmark. - #[clap(long)] + #[arg(long)] pub skip_read: bool, /// Skip the `write` benchmark. - #[clap(long)] + #[arg(long)] pub skip_write: bool, /// Specify the Handlebars template to use for outputting benchmark results. - #[clap(long)] + #[arg(long)] pub template_path: Option, + /// Add a header to the generated weight output file. + /// + /// Good for adding LICENSE headers. + #[arg(long, value_name = "PATH")] + pub header: Option, + /// Path to write the raw 'read' results in JSON format to. Can be a file or directory. - #[clap(long)] + #[arg(long)] pub json_read_path: Option, /// Path to write the raw 'write' results in JSON format to. Can be a file or directory. - #[clap(long)] + #[arg(long)] pub json_write_path: Option, /// Rounds of warmups before measuring. - #[clap(long, default_value = "1")] + #[arg(long, default_value_t = 1)] pub warmups: u32, /// The `StateVersion` to use. Substrate `--dev` should use `V1` and Polkadot `V0`. /// Selecting the wrong version can corrupt the DB. - #[clap(long, possible_values = ["0", "1"])] + #[arg(long, value_parser = clap::value_parser!(u8).range(0..=1))] pub state_version: u8, /// Trie cache size in bytes. /// /// Providing `0` will disable the cache. - #[clap(long, default_value = "1024")] + #[arg(long, value_name = "Bytes", default_value_t = 67108864)] pub trie_cache_size: usize, + /// Enable the Trie cache. + /// + /// This should only be used for performance analysis and not for final results. + #[arg(long)] + pub enable_trie_cache: bool, + /// Include child trees in benchmark. - #[clap(long)] + #[arg(long)] pub include_child_trees: bool, } @@ -122,7 +134,7 @@ impl StorageCmd { Block: BlockT, C: UsageProvider + StorageProvider + HeaderBackend, { - let mut template = TemplateData::new(&cfg, &self.params); + let mut template = TemplateData::new(&cfg, &self.params)?; let block_id = BlockId::::Number(client.usage_info().chain.best_number); template.set_block_number(block_id.to_string()); @@ -179,9 +191,9 @@ impl StorageCmd { B: BlockT + Debug, BA: ClientBackend, { - let block = BlockId::Number(client.usage_info().chain.best_number); + let hash = client.usage_info().chain.best_hash; let empty_prefix = StorageKey(Vec::new()); - let mut keys = client.storage_keys(&block, &empty_prefix)?; + let mut keys = client.storage_keys(&hash, &empty_prefix)?; let (mut rng, _) = new_rng(None); keys.shuffle(&mut rng); @@ -189,7 +201,7 @@ impl StorageCmd { info!("Warmup round {}/{}", i + 1, self.params.warmups); for key in keys.as_slice() { let _ = client - .storage(&block, &key) + .storage(&hash, &key) .expect("Checked above to exist") .ok_or("Value unexpectedly empty"); } @@ -214,10 +226,10 @@ impl CliConfiguration for StorageCmd { } fn trie_cache_maximum_size(&self) -> Result> { - if self.params.trie_cache_size == 0 { - Ok(None) - } else { + if self.params.enable_trie_cache && self.params.trie_cache_size > 0 { Ok(Some(self.params.trie_cache_size)) + } else { + Ok(None) } } } diff --git a/utils/frame/benchmarking-cli/src/storage/read.rs b/utils/frame/benchmarking-cli/src/storage/read.rs index cba318f87ea98..2df7e697039e8 100644 --- a/utils/frame/benchmarking-cli/src/storage/read.rs +++ b/utils/frame/benchmarking-cli/src/storage/read.rs @@ -18,10 +18,7 @@ use sc_cli::Result; use sc_client_api::{Backend as ClientBackend, StorageProvider, UsageProvider}; use sp_core::storage::StorageKey; -use sp_runtime::{ - generic::BlockId, - traits::{Block as BlockT, Header as HeaderT}, -}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use log::info; use rand::prelude::*; @@ -41,12 +38,12 @@ impl StorageCmd { <::Header as HeaderT>::Number: From, { let mut record = BenchRecord::default(); - let block = BlockId::Number(client.usage_info().chain.best_number); + let best_hash = client.usage_info().chain.best_hash; - info!("Preparing keys from block {}", block); + info!("Preparing keys from block {}", best_hash); // Load all keys and randomly shuffle them. let empty_prefix = StorageKey(Vec::new()); - let mut keys = client.storage_keys(&block, &empty_prefix)?; + let mut keys = client.storage_keys(&best_hash, &empty_prefix)?; let (mut rng, _) = new_rng(None); keys.shuffle(&mut rng); @@ -58,7 +55,7 @@ impl StorageCmd { match (self.params.include_child_trees, self.is_child_key(key.clone().0)) { (true, Some(info)) => { // child tree key - let child_keys = client.child_storage_keys(&block, &info, &empty_prefix)?; + let child_keys = client.child_storage_keys(&best_hash, &info, &empty_prefix)?; for ck in child_keys { child_nodes.push((ck.clone(), info.clone())); } @@ -67,7 +64,7 @@ impl StorageCmd { // regular key let start = Instant::now(); let v = client - .storage(&block, &key) + .storage(&best_hash, &key) .expect("Checked above to exist") .ok_or("Value unexpectedly empty")?; record.append(v.0.len(), start.elapsed())?; @@ -82,7 +79,7 @@ impl StorageCmd { for (key, info) in child_nodes.as_slice() { let start = Instant::now(); let v = client - .child_storage(&block, info, key) + .child_storage(&best_hash, info, key) .expect("Checked above to exist") .ok_or("Value unexpectedly empty")?; record.append(v.0.len(), start.elapsed())?; diff --git a/utils/frame/benchmarking-cli/src/storage/template.rs b/utils/frame/benchmarking-cli/src/storage/template.rs index 20fbd58134f20..ebc415ccb8189 100644 --- a/utils/frame/benchmarking-cli/src/storage/template.rs +++ b/utils/frame/benchmarking-cli/src/storage/template.rs @@ -45,6 +45,8 @@ pub(crate) struct TemplateData { hostname: String, /// CPU name of the machine that executed the benchmarks. cpuname: String, + /// Header for the generated file. + header: String, /// Command line arguments that were passed to the CLI. args: Vec, /// Storage params of the executed command. @@ -63,18 +65,26 @@ pub(crate) struct TemplateData { impl TemplateData { /// Returns a new [`Self`] from the given configuration. - pub fn new(cfg: &Configuration, params: &StorageParams) -> Self { - TemplateData { + pub fn new(cfg: &Configuration, params: &StorageParams) -> Result { + let header = params + .header + .as_ref() + .map(|p| std::fs::read_to_string(p)) + .transpose()? + .unwrap_or_default(); + + Ok(TemplateData { db_name: format!("{}", cfg.database), runtime_name: cfg.chain_spec.name().into(), version: VERSION.into(), date: chrono::Utc::now().format("%Y-%m-%d (Y/M/D)").to_string(), hostname: params.hostinfo.hostname(), cpuname: params.hostinfo.cpuname(), + header, args: env::args().collect::>(), params: params.clone(), ..Default::default() - } + }) } /// Sets the stats and calculates the final weights. diff --git a/utils/frame/benchmarking-cli/src/storage/weights.hbs b/utils/frame/benchmarking-cli/src/storage/weights.hbs index 8c19aaa0dff36..82e581cf990c8 100644 --- a/utils/frame/benchmarking-cli/src/storage/weights.hbs +++ b/utils/frame/benchmarking-cli/src/storage/weights.hbs @@ -1,20 +1,4 @@ -// This file is part of Substrate. - -// Copyright (C) 2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +{{header}} //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} //! DATE: {{date}} //! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}` @@ -33,10 +17,9 @@ /// Storage DB weights for the `{{runtime_name}}` runtime and `{{db_name}}`. pub mod constants { - use frame_support::{ - parameter_types, - weights::{constants, RuntimeDbWeight}, - }; + use frame_support::weights::constants; + use sp_core::parameter_types; + use sp_weights::RuntimeDbWeight; parameter_types! { {{#if (eq db_name "ParityDb")}} @@ -82,7 +65,7 @@ pub mod constants { #[cfg(test)] mod test_db_weights { use super::constants::{{db_name}}Weight as W; - use frame_support::weights::constants; + use sp_weights::constants; /// Checks that all weights exist and have sane values. // NOTE: If this test fails but you are sure that the generated values are fine, @@ -91,20 +74,20 @@ pub mod constants { fn bound() { // At least 1 µs. assert!( - W::get().reads(1) >= constants::WEIGHT_PER_MICROS, + W::get().reads(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), "Read weight should be at least 1 µs." ); assert!( - W::get().writes(1) >= constants::WEIGHT_PER_MICROS, + W::get().writes(1).ref_time() >= constants::WEIGHT_PER_MICROS.ref_time(), "Write weight should be at least 1 µs." ); // At most 1 ms. assert!( - W::get().reads(1) <= constants::WEIGHT_PER_MILLIS, + W::get().reads(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), "Read weight should be at most 1 ms." ); assert!( - W::get().writes(1) <= constants::WEIGHT_PER_MILLIS, + W::get().writes(1).ref_time() <= constants::WEIGHT_PER_MILLIS.ref_time(), "Write weight should be at most 1 ms." ); } diff --git a/utils/frame/benchmarking-cli/src/storage/write.rs b/utils/frame/benchmarking-cli/src/storage/write.rs index 9a3821a7095f8..2ee37a5619136 100644 --- a/utils/frame/benchmarking-cli/src/storage/write.rs +++ b/utils/frame/benchmarking-cli/src/storage/write.rs @@ -57,12 +57,12 @@ impl StorageCmd { // Store the time that it took to write each value. let mut record = BenchRecord::default(); - let block = BlockId::Number(client.usage_info().chain.best_number); - let header = client.header(block)?.ok_or("Header not found")?; + let best_hash = client.usage_info().chain.best_hash; + let header = client.header(BlockId::Hash(best_hash))?.ok_or("Header not found")?; let original_root = *header.state_root(); let trie = DbStateBuilder::::new(storage.clone(), original_root).build(); - info!("Preparing keys from block {}", block); + info!("Preparing keys from block {}", best_hash); // Load all KV pairs and randomly shuffle them. let mut kvs = trie.pairs(); let (mut rng, _) = new_rng(None); @@ -77,7 +77,7 @@ impl StorageCmd { match (self.params.include_child_trees, self.is_child_key(k.to_vec())) { (true, Some(info)) => { let child_keys = - client.child_storage_keys_iter(&block, info.clone(), None, None)?; + client.child_storage_keys_iter(&best_hash, info.clone(), None, None)?; for ck in child_keys { child_nodes.push((ck.clone(), info.clone())); } @@ -124,7 +124,7 @@ impl StorageCmd { for (key, info) in child_nodes { if let Some(original_v) = client - .child_storage(&block, &info.clone(), &key) + .child_storage(&best_hash, &info.clone(), &key) .expect("Checked above to exist") { let mut new_v = vec![0; original_v.0.len()]; diff --git a/utils/frame/frame-utilities-cli/Cargo.toml b/utils/frame/frame-utilities-cli/Cargo.toml index f01e2f1a5d51f..89e9ee79db214 100644 --- a/utils/frame/frame-utilities-cli/Cargo.toml +++ b/utils/frame/frame-utilities-cli/Cargo.toml @@ -11,7 +11,7 @@ documentation = "https://docs.rs/substrate-frame-cli" readme = "README.md" [dependencies] -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } sc-cli = { version = "0.10.0-dev", path = "../../../client/cli" } diff --git a/utils/frame/frame-utilities-cli/src/pallet_id.rs b/utils/frame/frame-utilities-cli/src/pallet_id.rs index 4ad82a01c2433..2a80e3a3d312d 100644 --- a/utils/frame/frame-utilities-cli/src/pallet_id.rs +++ b/utils/frame/frame-utilities-cli/src/pallet_id.rs @@ -28,31 +28,30 @@ use sp_runtime::traits::AccountIdConversion; /// The `palletid` command #[derive(Debug, Parser)] -#[clap(name = "palletid", about = "Inspect a module ID address")] +#[command(name = "palletid", about = "Inspect a module ID address")] pub struct PalletIdCmd { /// The module ID used to derive the account id: String, /// network address format - #[clap( + #[arg( long, value_name = "NETWORK", - possible_values = &Ss58AddressFormat::all_names()[..], - parse(try_from_str = Ss58AddressFormat::try_from), + value_parser = sc_cli::parse_ss58_address_format, ignore_case = true, )] pub network: Option, #[allow(missing_docs)] - #[clap(flatten)] + #[command(flatten)] pub output_scheme: OutputTypeFlag, #[allow(missing_docs)] - #[clap(flatten)] + #[command(flatten)] pub crypto_scheme: CryptoSchemeFlag, #[allow(missing_docs)] - #[clap(flatten)] + #[command(flatten)] pub keystore_params: KeystoreParams, } diff --git a/utils/frame/generate-bags/Cargo.toml b/utils/frame/generate-bags/Cargo.toml index 34d62ab0d8b5f..18f668485114b 100644 --- a/utils/frame/generate-bags/Cargo.toml +++ b/utils/frame/generate-bags/Cargo.toml @@ -12,7 +12,7 @@ readme = "README.md" [dependencies] # FRAME frame-support = { version = "4.0.0-dev", path = "../../../frame/support" } -frame-election-provider-support = { version = "4.0.0-dev", path = "../../../frame/election-provider-support", features = ["runtime-benchmarks"] } +frame-election-provider-support = { version = "4.0.0-dev", path = "../../../frame/election-provider-support" } frame-system = { version = "4.0.0-dev", path = "../../../frame/system" } pallet-staking = { version = "4.0.0-dev", path = "../../../frame/staking" } diff --git a/utils/frame/generate-bags/node-runtime/Cargo.toml b/utils/frame/generate-bags/node-runtime/Cargo.toml index 5af7dd78a08e8..6cc14a0595501 100644 --- a/utils/frame/generate-bags/node-runtime/Cargo.toml +++ b/utils/frame/generate-bags/node-runtime/Cargo.toml @@ -14,4 +14,4 @@ kitchensink-runtime = { version = "3.0.0-dev", path = "../../../../bin/node/runt generate-bags = { version = "4.0.0-dev", path = "../" } # third-party -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } diff --git a/utils/frame/generate-bags/node-runtime/src/main.rs b/utils/frame/generate-bags/node-runtime/src/main.rs index 5ea1262d95d34..27e51b205f8ce 100644 --- a/utils/frame/generate-bags/node-runtime/src/main.rs +++ b/utils/frame/generate-bags/node-runtime/src/main.rs @@ -25,19 +25,19 @@ use std::path::PathBuf; // #[clap(author, version, about)] struct Opt { /// How many bags to generate. - #[clap(long, default_value = "200")] + #[arg(long, default_value_t = 200)] n_bags: usize, /// Where to write the output. output: PathBuf, /// The total issuance of the currency used to create `VoteWeight`. - #[clap(short, long)] + #[arg(short, long)] total_issuance: u128, /// The minimum account balance (i.e. existential deposit) for the currency used to create /// `VoteWeight`. - #[clap(short, long)] + #[arg(short, long)] minimum_balance: u128, } diff --git a/utils/frame/generate-bags/src/lib.rs b/utils/frame/generate-bags/src/lib.rs index d4507c3be33ef..23da131a668d8 100644 --- a/utils/frame/generate-bags/src/lib.rs +++ b/utils/frame/generate-bags/src/lib.rs @@ -207,6 +207,10 @@ pub fn generate_thresholds( writeln!(buf, "//! Autogenerated bag thresholds.")?; writeln!(buf, "//!")?; writeln!(buf, "//! Generated on {}", now.to_rfc3339())?; + writeln!(buf, "//! Arguments")?; + writeln!(buf, "//! Total issuance: {}", &total_issuance)?; + writeln!(buf, "//! Minimum balance: {}", &minimum_balance)?; + writeln!( buf, "//! for the {} runtime.", @@ -234,6 +238,17 @@ pub fn generate_thresholds( writeln!(buf)?; writeln!(buf, "/// Upper thresholds delimiting the bag list.")?; writeln!(buf, "pub const THRESHOLDS: [u64; {}] = [", thresholds.len())?; + for threshold in &thresholds { + num_buf.write_formatted(threshold, &format); + // u64::MAX, with spacers every 3 digits, is 26 characters wide + writeln!(buf, " {:>26},", num_buf.as_str())?; + } + writeln!(buf, "];")?; + + // thresholds balance + writeln!(buf)?; + writeln!(buf, "/// Upper thresholds delimiting the bag list.")?; + writeln!(buf, "pub const THRESHOLDS_BALANCES: [u128; {}] = [", thresholds.len())?; for threshold in thresholds { num_buf.write_formatted(&threshold, &format); // u64::MAX, with spacers every 3 digits, is 26 characters wide diff --git a/utils/frame/remote-externalities/Cargo.toml b/utils/frame/remote-externalities/Cargo.toml index 3121157df68d8..3d7471bf4d680 100644 --- a/utils/frame/remote-externalities/Cargo.toml +++ b/utils/frame/remote-externalities/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" license = "Apache-2.0" homepage = "https://substrate.io" repository = "https://github.com/paritytech/substrate/" -description = "An externalities provided environemnt that can load itself from remote nodes or cache files" +description = "An externalities provided environment that can load itself from remote nodes or cached files" readme = "README.md" [package.metadata.docs.rs] @@ -15,7 +15,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0" } env_logger = "0.9" -jsonrpsee = { version = "0.15.1", features = ["ws-client", "macros"] } log = "0.4.17" serde = "1.0.136" serde_json = "1.0" @@ -24,6 +23,7 @@ sp-core = { version = "6.0.0", path = "../../../primitives/core" } sp-io = { version = "6.0.0", path = "../../../primitives/io" } sp-runtime = { version = "6.0.0", path = "../../../primitives/runtime" } sp-version = { version = "5.0.0", path = "../../../primitives/version" } +substrate-rpc-client = { path = "../rpc/client" } [dev-dependencies] tokio = { version = "1.17.0", features = ["macros", "rt-multi-thread"] } diff --git a/utils/frame/remote-externalities/src/lib.rs b/utils/frame/remote-externalities/src/lib.rs index 83481e745f5ee..86cfc767bf3b5 100644 --- a/utils/frame/remote-externalities/src/lib.rs +++ b/utils/frame/remote-externalities/src/lib.rs @@ -22,13 +22,6 @@ use codec::{Decode, Encode}; -use jsonrpsee::{ - core::{client::ClientT, Error as RpcError}, - proc_macros::rpc, - rpc_params, - ws_client::{WsClient, WsClientBuilder}, -}; - use log::*; use serde::de::DeserializeOwned; use sp_core::{ @@ -46,8 +39,7 @@ use std::{ path::{Path, PathBuf}, sync::Arc, }; - -pub mod rpc_api; +use substrate_rpc_client::{rpc_params, ws_client, ChainApi, ClientT, StateApi, WsClient}; type KeyValue = (StorageKey, StorageData); type TopKeyValues = Vec; @@ -58,40 +50,6 @@ const DEFAULT_TARGET: &str = "wss://rpc.polkadot.io:443"; const BATCH_SIZE: usize = 1000; const PAGE: u32 = 1000; -#[rpc(client)] -pub trait RpcApi { - #[method(name = "childstate_getKeys")] - fn child_get_keys( - &self, - child_key: PrefixedStorageKey, - prefix: StorageKey, - hash: Option, - ) -> Result, RpcError>; - - #[method(name = "childstate_getStorage")] - fn child_get_storage( - &self, - child_key: PrefixedStorageKey, - prefix: StorageKey, - hash: Option, - ) -> Result; - - #[method(name = "state_getStorage")] - fn get_storage(&self, prefix: StorageKey, hash: Option) -> Result; - - #[method(name = "state_getKeysPaged")] - fn get_keys_paged( - &self, - prefix: Option, - count: u32, - start_key: Option, - hash: Option, - ) -> Result, RpcError>; - - #[method(name = "chain_getFinalizedHead")] - fn finalized_head(&self) -> Result; -} - /// The execution mode. #[derive(Clone)] pub enum Mode { @@ -140,14 +98,10 @@ impl Transport { if let Self::Uri(uri) = self { log::debug!(target: LOG_TARGET, "initializing remote client to {:?}", uri); - let ws_client = WsClientBuilder::default() - .max_request_body_size(u32::MAX) - .build(&uri) - .await - .map_err(|e| { - log::error!(target: LOG_TARGET, "error: {:?}", e); - "failed to build ws client" - })?; + let ws_client = ws_client(uri).await.map_err(|e| { + log::error!(target: LOG_TARGET, "error: {:?}", e); + "failed to build ws client" + })?; *self = Self::RemoteClient(Arc::new(ws_client)) } @@ -258,7 +212,7 @@ pub struct Builder { // NOTE: ideally we would use `DefaultNoBound` here, but not worth bringing in frame-support for // that. -impl Default for Builder { +impl Default for Builder { fn default() -> Self { Self { mode: Default::default(), @@ -272,7 +226,7 @@ impl Default for Builder { } // Mode methods -impl Builder { +impl Builder { fn as_online(&self) -> &OnlineConfig { match &self.mode { Mode::Online(config) => config, @@ -291,26 +245,38 @@ impl Builder { } // RPC methods -impl Builder { +impl Builder +where + B::Hash: DeserializeOwned, + B::Header: DeserializeOwned, +{ async fn rpc_get_storage( &self, key: StorageKey, maybe_at: Option, ) -> Result { trace!(target: LOG_TARGET, "rpc: get_storage"); - self.as_online().rpc_client().get_storage(key, maybe_at).await.map_err(|e| { - error!(target: LOG_TARGET, "Error = {:?}", e); - "rpc get_storage failed." - }) + match self.as_online().rpc_client().storage(key, maybe_at).await { + Ok(Some(res)) => Ok(res), + Ok(None) => Err("get_storage not found"), + Err(e) => { + error!(target: LOG_TARGET, "Error = {:?}", e); + Err("rpc get_storage failed.") + }, + } } /// Get the latest finalized head. async fn rpc_get_head(&self) -> Result { trace!(target: LOG_TARGET, "rpc: finalized_head"); - self.as_online().rpc_client().finalized_head().await.map_err(|e| { - error!(target: LOG_TARGET, "Error = {:?}", e); - "rpc finalized_head failed." - }) + + // sadly this pretty much unreadable... + ChainApi::<(), _, B::Header, ()>::finalized_head(self.as_online().rpc_client()) + .await + .map_err(|e| { + error!(target: LOG_TARGET, "Error = {:?}", e); + "rpc finalized_head failed." + }) } /// Get all the keys at `prefix` at `hash` using the paged, safe RPC methods. @@ -325,7 +291,7 @@ impl Builder { let page = self .as_online() .rpc_client() - .get_keys_paged(Some(prefix.clone()), PAGE, last_key.clone(), Some(at)) + .storage_keys_paged(Some(prefix.clone()), PAGE, last_key.clone(), Some(at)) .await .map_err(|e| { error!(target: LOG_TARGET, "Error = {:?}", e); @@ -471,19 +437,19 @@ impl Builder { child_prefix: StorageKey, at: B::Hash, ) -> Result, &'static str> { - let child_keys = self - .as_online() - .rpc_client() - .child_get_keys( - PrefixedStorageKey::new(prefixed_top_key.as_ref().to_vec()), - child_prefix, - Some(at), - ) - .await - .map_err(|e| { - error!(target: LOG_TARGET, "Error = {:?}", e); - "rpc child_get_keys failed." - })?; + // This is deprecated and will generate a warning which causes the CI to fail. + #[allow(warnings)] + let child_keys = substrate_rpc_client::ChildStateApi::storage_keys( + self.as_online().rpc_client(), + PrefixedStorageKey::new(prefixed_top_key.as_ref().to_vec()), + child_prefix, + Some(at), + ) + .await + .map_err(|e| { + error!(target: LOG_TARGET, "Error = {:?}", e); + "rpc child_get_keys failed." + })?; debug!( target: LOG_TARGET, @@ -497,7 +463,11 @@ impl Builder { } // Internal methods -impl Builder { +impl Builder +where + B::Hash: DeserializeOwned, + B::Header: DeserializeOwned, +{ /// Save the given data to the top keys snapshot. fn save_top_snapshot(&self, data: &[KeyValue], path: &PathBuf) -> Result<(), &'static str> { let mut path = path.clone(); @@ -726,12 +696,13 @@ impl Builder { let child_kv = match self.mode.clone() { Mode::Online(_) => self.load_child_remote_and_maybe_save(&top_kv).await?, - Mode::OfflineOrElseOnline(offline_config, _) => + Mode::OfflineOrElseOnline(offline_config, _) => { if let Ok(kv) = self.load_child_snapshot(&offline_config.state_snapshot.path) { kv } else { self.load_child_remote_and_maybe_save(&top_kv).await? - }, + } + }, Mode::Offline(ref config) => self .load_child_snapshot(&config.state_snapshot.path) .map_err(|why| { @@ -749,7 +720,7 @@ impl Builder { } // Public methods -impl Builder { +impl Builder { /// Create a new builder. pub fn new() -> Self { Default::default() @@ -824,7 +795,13 @@ impl Builder { } self } +} +// Public methods +impl Builder +where + B::Header: DeserializeOwned, +{ /// Build the test externalities. pub async fn build(self) -> Result { let state_version = self.state_version; diff --git a/utils/frame/remote-externalities/src/rpc_api.rs b/utils/frame/remote-externalities/src/rpc_api.rs deleted file mode 100644 index 3ea30a30221a2..0000000000000 --- a/utils/frame/remote-externalities/src/rpc_api.rs +++ /dev/null @@ -1,149 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! WS RPC API for one off RPC calls to a substrate node. -// TODO: Consolidate one off RPC calls https://github.com/paritytech/substrate/issues/8988 - -use jsonrpsee::{ - core::client::{Client, ClientT}, - rpc_params, - types::ParamsSer, - ws_client::{WsClient, WsClientBuilder}, -}; -use serde::de::DeserializeOwned; -use sp_runtime::{generic::SignedBlock, traits::Block as BlockT}; -use std::sync::Arc; - -enum RpcCall { - GetHeader, - GetFinalizedHead, - GetBlock, - GetRuntimeVersion, -} - -impl RpcCall { - fn as_str(&self) -> &'static str { - match self { - RpcCall::GetHeader => "chain_getHeader", - RpcCall::GetFinalizedHead => "chain_getFinalizedHead", - RpcCall::GetBlock => "chain_getBlock", - RpcCall::GetRuntimeVersion => "state_getRuntimeVersion", - } - } -} - -/// General purpose method for making RPC calls. -async fn make_request<'a, T: DeserializeOwned>( - client: &Arc, - call: RpcCall, - params: Option>, -) -> Result { - client - .request::(call.as_str(), params) - .await - .map_err(|e| format!("{} request failed: {:?}", call.as_str(), e)) -} - -enum ConnectionPolicy { - Reuse(Arc), - Reconnect, -} - -/// Simple RPC service that is capable of keeping the connection. -/// -/// Service will connect to `uri` for the first time already during initialization. -/// -/// Be careful with reusing the connection in a multithreaded environment. -pub struct RpcService { - uri: String, - policy: ConnectionPolicy, -} - -impl RpcService { - /// Creates a new RPC service. If `keep_connection`, then connects to `uri` right away. - pub async fn new>(uri: S, keep_connection: bool) -> Result { - let policy = if keep_connection { - ConnectionPolicy::Reuse(Arc::new(Self::build_client(uri.as_ref()).await?)) - } else { - ConnectionPolicy::Reconnect - }; - Ok(Self { uri: uri.as_ref().to_string(), policy }) - } - - /// Returns the address at which requests are sent. - pub fn uri(&self) -> String { - self.uri.clone() - } - - /// Build a websocket client that connects to `self.uri`. - async fn build_client>(uri: S) -> Result { - WsClientBuilder::default() - .max_request_body_size(u32::MAX) - .build(uri) - .await - .map_err(|e| format!("`WsClientBuilder` failed to build: {:?}", e)) - } - - /// Generic method for making RPC requests. - async fn make_request<'a, T: DeserializeOwned>( - &self, - call: RpcCall, - params: Option>, - ) -> Result { - match self.policy { - // `self.keep_connection` must have been `true`. - ConnectionPolicy::Reuse(ref client) => make_request(client, call, params).await, - ConnectionPolicy::Reconnect => { - let client = Arc::new(Self::build_client(&self.uri).await?); - make_request(&client, call, params).await - }, - } - } - - /// Get the header of the block identified by `at`. - pub async fn get_header(&self, at: Block::Hash) -> Result - where - Block: BlockT, - Block::Header: DeserializeOwned, - { - self.make_request(RpcCall::GetHeader, rpc_params!(at)).await - } - - /// Get the finalized head. - pub async fn get_finalized_head(&self) -> Result { - self.make_request(RpcCall::GetFinalizedHead, None).await - } - - /// Get the signed block identified by `at`. - pub async fn get_block( - &self, - at: Block::Hash, - ) -> Result { - Ok(self - .make_request::>(RpcCall::GetBlock, rpc_params!(at)) - .await? - .block) - } - - /// Get the runtime version of a given chain. - pub async fn get_runtime_version( - &self, - at: Option, - ) -> Result { - self.make_request(RpcCall::GetRuntimeVersion, rpc_params!(at)).await - } -} diff --git a/utils/frame/rpc/client/Cargo.toml b/utils/frame/rpc/client/Cargo.toml new file mode 100644 index 0000000000000..80aa60f199f1f --- /dev/null +++ b/utils/frame/rpc/client/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "substrate-rpc-client" +version = "0.10.0-dev" +authors = ["Parity Technologies "] +edition = "2021" +license = "Apache-2.0" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +description = "Shared JSON-RPC client" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +jsonrpsee = { version = "0.15.1", features = ["ws-client"] } +sc-rpc-api = { version = "0.10.0-dev", path = "../../../../client/rpc-api" } +async-trait = "0.1.57" +serde = "1" +sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } +log = "0.4" + +[dev-dependencies] +tokio = { version = "1.17.0", features = ["macros", "rt-multi-thread", "sync"] } +sp-core = { path = "../../../../primitives/core" } \ No newline at end of file diff --git a/utils/frame/rpc/client/src/lib.rs b/utils/frame/rpc/client/src/lib.rs new file mode 100644 index 0000000000000..254cc193c0e67 --- /dev/null +++ b/utils/frame/rpc/client/src/lib.rs @@ -0,0 +1,265 @@ +// This file is part of Substrate. + +// Copyright (C) 2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Shared JSON-RPC client related code and abstractions. +//! +//! It exposes a `WebSocket JSON-RPC` client that implements the RPC interface in [`sc-rpc-api`] +//! along with some abstractions. +//! +//! ## Usage +//! +//! ```no_run +//! # use substrate_rpc_client::{ws_client, StateApi}; +//! # use sp_core::{H256, storage::StorageKey}; +//! +//! #[tokio::main] +//! async fn main() { +//! +//! let client = ws_client("ws://127.0.0.1:9944").await.unwrap(); +//! client.storage(StorageKey(vec![]), Some(H256::zero())).await.unwrap(); +//! +//! // if all type params are not known you need to provide type params +//! StateApi::::storage(&client, StorageKey(vec![]), None).await.unwrap(); +//! } +//! ``` + +use async_trait::async_trait; +use serde::de::DeserializeOwned; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; +use std::collections::VecDeque; + +pub use jsonrpsee::{ + core::client::{ClientT, Subscription, SubscriptionClientT}, + rpc_params, + ws_client::{WsClient, WsClientBuilder}, +}; +pub use sc_rpc_api::{ + author::AuthorApiClient as AuthorApi, chain::ChainApiClient as ChainApi, + child_state::ChildStateApiClient as ChildStateApi, dev::DevApiClient as DevApi, + offchain::OffchainApiClient as OffchainApi, state::StateApiClient as StateApi, + system::SystemApiClient as SystemApi, +}; + +/// Create a new `WebSocket` connection with shared settings. +pub async fn ws_client(uri: impl AsRef) -> Result { + WsClientBuilder::default() + .max_request_body_size(u32::MAX) + .request_timeout(std::time::Duration::from_secs(60 * 10)) + .connection_timeout(std::time::Duration::from_secs(60)) + .max_notifs_per_subscription(1024) + .build(uri) + .await + .map_err(|e| format!("`WsClientBuilder` failed to build: {:?}", e)) +} + +/// Abstraction over RPC calling for headers. +#[async_trait] +pub trait HeaderProvider +where + Block::Header: HeaderT, +{ + /// Awaits for the header of the block with hash `hash`. + async fn get_header(&self, hash: Block::Hash) -> Block::Header; +} + +#[async_trait] +impl HeaderProvider for WsClient +where + Block::Header: DeserializeOwned, +{ + async fn get_header(&self, hash: Block::Hash) -> Block::Header { + ChainApi::<(), Block::Hash, Block::Header, ()>::header(self, Some(hash)) + .await + .unwrap() + .unwrap() + } +} + +/// Abstraction over RPC subscription for finalized headers. +#[async_trait] +pub trait HeaderSubscription +where + Block::Header: HeaderT, +{ + /// Await for the next finalized header from the subscription. + /// + /// Returns `None` if either the subscription has been closed or there was an error when reading + /// an object from the client. + async fn next_header(&mut self) -> Option; +} + +#[async_trait] +impl HeaderSubscription for Subscription +where + Block::Header: DeserializeOwned, +{ + async fn next_header(&mut self) -> Option { + match self.next().await { + Some(Ok(header)) => Some(header), + None => { + log::warn!("subscription closed"); + None + }, + Some(Err(why)) => { + log::warn!("subscription returned error: {:?}. Probably decoding has failed.", why); + None + }, + } + } +} + +/// Stream of all finalized headers. +/// +/// Returned headers are guaranteed to be ordered. There are no missing headers (even if some of +/// them lack justification). +pub struct FinalizedHeaders< + 'a, + Block: BlockT, + HP: HeaderProvider, + HS: HeaderSubscription, +> { + header_provider: &'a HP, + subscription: HS, + fetched_headers: VecDeque, + last_returned: Option<::Hash>, +} + +impl<'a, Block: BlockT, HP: HeaderProvider, HS: HeaderSubscription> + FinalizedHeaders<'a, Block, HP, HS> +where + ::Header: DeserializeOwned, +{ + pub fn new(header_provider: &'a HP, subscription: HS) -> Self { + Self { + header_provider, + subscription, + fetched_headers: VecDeque::new(), + last_returned: None, + } + } + + /// Reads next finalized header from the subscription. If some headers (without justification) + /// have been skipped, fetches them as well. Returns number of headers that have been fetched. + /// + /// All fetched headers are stored in `self.fetched_headers`. + async fn fetch(&mut self) -> usize { + let last_finalized = match self.subscription.next_header().await { + Some(header) => header, + None => return 0, + }; + + self.fetched_headers.push_front(last_finalized.clone()); + + let mut last_finalized_parent = *last_finalized.parent_hash(); + let last_returned = self.last_returned.unwrap_or(last_finalized_parent); + + while last_finalized_parent != last_returned { + let parent_header = self.header_provider.get_header(last_finalized_parent).await; + self.fetched_headers.push_front(parent_header.clone()); + last_finalized_parent = *parent_header.parent_hash(); + } + + self.fetched_headers.len() + } + + /// Get the next finalized header. + pub async fn next(&mut self) -> Option { + if self.fetched_headers.is_empty() { + self.fetch().await; + } + + if let Some(header) = self.fetched_headers.pop_front() { + self.last_returned = Some(header.hash()); + Some(header) + } else { + None + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sp_runtime::testing::{Block as TBlock, ExtrinsicWrapper, Header, H256}; + use std::sync::Arc; + use tokio::sync::Mutex; + + type Block = TBlock>; + type BlockNumber = u64; + type Hash = H256; + + struct MockHeaderProvider(pub Arc>>); + + fn headers() -> Vec
{ + let mut headers = vec![Header::new_from_number(0)]; + for n in 1..11 { + headers.push(Header { + parent_hash: headers.last().unwrap().hash(), + ..Header::new_from_number(n) + }) + } + headers + } + + #[async_trait] + impl HeaderProvider for MockHeaderProvider { + async fn get_header(&self, _hash: Hash) -> Header { + let height = self.0.lock().await.pop_front().unwrap(); + headers()[height as usize].clone() + } + } + + struct MockHeaderSubscription(pub VecDeque); + + #[async_trait] + impl HeaderSubscription for MockHeaderSubscription { + async fn next_header(&mut self) -> Option
{ + self.0.pop_front().map(|h| headers()[h as usize].clone()) + } + } + + #[tokio::test] + async fn finalized_headers_works_when_every_block_comes_from_subscription() { + let heights = vec![4, 5, 6, 7]; + + let provider = MockHeaderProvider(Default::default()); + let subscription = MockHeaderSubscription(heights.clone().into()); + let mut headers = FinalizedHeaders::new(&provider, subscription); + + for h in heights { + assert_eq!(h, headers.next().await.unwrap().number); + } + assert_eq!(None, headers.next().await); + } + + #[tokio::test] + async fn finalized_headers_come_from_subscription_and_provider_if_in_need() { + let all_heights = 3..11; + let heights_in_subscription = vec![3, 4, 6, 10]; + // Consecutive headers will be requested in the reversed order. + let heights_not_in_subscription = vec![5, 9, 8, 7]; + + let provider = MockHeaderProvider(Arc::new(Mutex::new(heights_not_in_subscription.into()))); + let subscription = MockHeaderSubscription(heights_in_subscription.into()); + let mut headers = FinalizedHeaders::new(&provider, subscription); + + for h in all_heights { + assert_eq!(h, headers.next().await.unwrap().number); + } + assert_eq!(None, headers.next().await); + } +} diff --git a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs index f9a57206ece4d..c3d3ec816f97e 100644 --- a/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs +++ b/utils/frame/rpc/state-trie-migration-rpc/src/lib.rs @@ -24,7 +24,7 @@ use jsonrpsee::{ }; use sc_rpc_api::DenyUnsafe; use serde::{Deserialize, Serialize}; -use sp_runtime::{generic::BlockId, traits::Block as BlockT}; +use sp_runtime::traits::Block as BlockT; use std::sync::Arc; use sp_core::{ @@ -144,8 +144,8 @@ where fn call(&self, at: Option<::Hash>) -> RpcResult { self.deny_unsafe.check_if_safe()?; - let block_id = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash)); - let state = self.backend.state_at(block_id).map_err(error_into_rpc_err)?; + let hash = at.unwrap_or_else(|| self.client.info().best_hash); + let state = self.backend.state_at(&hash).map_err(error_into_rpc_err)?; let (top, child) = migration_status(&state).map_err(error_into_rpc_err)?; Ok(MigrationStatusResult { diff --git a/utils/frame/rpc/support/Cargo.toml b/utils/frame/rpc/support/Cargo.toml index 2104774bd2605..38e40a33d9c7f 100644 --- a/utils/frame/rpc/support/Cargo.toml +++ b/utils/frame/rpc/support/Cargo.toml @@ -27,4 +27,6 @@ sp-storage = { version = "6.0.0", path = "../../../../primitives/storage" } scale-info = "2.1.1" jsonrpsee = { version = "0.15.1", features = ["ws-client", "jsonrpsee-types"] } tokio = "1.17.0" +sp-core = { version = "6.0.0", path = "../../../../primitives/core" } +sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } frame-system = { version = "4.0.0-dev", path = "../../../../frame/system" } diff --git a/utils/frame/rpc/support/src/lib.rs b/utils/frame/rpc/support/src/lib.rs index 2ee007c84f0aa..fdf6fe0be8172 100644 --- a/utils/frame/rpc/support/src/lib.rs +++ b/utils/frame/rpc/support/src/lib.rs @@ -34,50 +34,104 @@ use sp_storage::{StorageData, StorageKey}; /// # use jsonrpsee::core::Error as RpcError; /// # use jsonrpsee::ws_client::WsClientBuilder; /// # use codec::Encode; -/// # use frame_support::{decl_storage, decl_module}; +/// # use frame_support::{construct_runtime, traits::ConstU32}; /// # use substrate_frame_rpc_support::StorageQuery; -/// # use frame_system::Config; /// # use sc_rpc_api::state::StateApiClient; +/// # use sp_runtime::{traits::{BlakeTwo256, IdentityLookup}, testing::Header}; /// # -/// # // Hash would normally be ::Hash, but we don't have -/// # // frame_system::Config implemented for TestRuntime. Here we just pretend. -/// # type Hash = (); +/// # construct_runtime!( +/// # pub enum TestRuntime where +/// # Block = frame_system::mocking::MockBlock, +/// # NodeBlock = frame_system::mocking::MockBlock, +/// # UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic, +/// # { +/// # System: frame_system::{Pallet, Call, Config, Storage, Event}, +/// # Test: pallet_test::{Pallet, Storage}, +/// # } +/// # ); /// # +/// # type Hash = sp_core::H256; /// # -/// # struct TestRuntime; -/// # -/// # decl_module! { -/// # pub struct Module for enum Call where origin: T::Origin {} +/// # impl frame_system::Config for TestRuntime { +/// # type BaseCallFilter = (); +/// # type BlockWeights = (); +/// # type BlockLength = (); +/// # type RuntimeOrigin = RuntimeOrigin; +/// # type RuntimeCall = RuntimeCall; +/// # type Index = u64; +/// # type BlockNumber = u64; +/// # type Hash = Hash; +/// # type Hashing = BlakeTwo256; +/// # type AccountId = u64; +/// # type Lookup = IdentityLookup; +/// # type Header = Header; +/// # type RuntimeEvent = RuntimeEvent; +/// # type BlockHashCount = (); +/// # type DbWeight = (); +/// # type Version = (); +/// # type PalletInfo = PalletInfo; +/// # type AccountData = (); +/// # type OnNewAccount = (); +/// # type OnKilledAccount = (); +/// # type SystemWeightInfo = (); +/// # type SS58Prefix = (); +/// # type OnSetCode = (); +/// # type MaxConsumers = ConstU32<16>; /// # } /// # +/// # impl pallet_test::Config for TestRuntime {} +/// # +/// /// pub type Loc = (i64, i64, i64); /// pub type Block = u8; /// /// // Note that all fields are marked pub. -/// decl_storage! { -/// trait Store for Module as TestRuntime { -/// pub LastActionId: u64; -/// pub Voxels: map hasher(blake2_128_concat) Loc => Block; -/// pub Actions: map hasher(blake2_128_concat) u64 => Loc; -/// pub Prefab: double_map hasher(blake2_128_concat) u128, hasher(blake2_128_concat) (i8, i8, i8) => Block; -/// } +/// pub use self::pallet_test::*; +/// +/// #[frame_support::pallet] +/// mod pallet_test { +/// use super::*; +/// use frame_support::pallet_prelude::*; +/// +/// #[pallet::pallet] +/// #[pallet::generate_store(pub(super) trait Store)] +/// pub struct Pallet(PhantomData); +/// +/// #[pallet::config] +/// pub trait Config: frame_system::Config {} +/// +/// #[pallet::storage] +/// pub type LastActionId = StorageValue<_, u64, ValueQuery>; +/// +/// #[pallet::storage] +/// pub type Voxels = StorageMap<_, Blake2_128Concat, Loc, Block>; +/// +/// #[pallet::storage] +/// pub type Actions = StorageMap<_, Blake2_128Concat, u64, Loc>; +/// +/// #[pallet::storage] +/// pub type Prefab = StorageDoubleMap< +/// _, +/// Blake2_128Concat, u128, +/// Blake2_128Concat, (i8, i8, i8), Block +/// >; /// } /// /// #[tokio::main] /// async fn main() -> Result<(), RpcError> { /// let cl = WsClientBuilder::default().build("ws://[::1]:9944").await?; /// -/// let q = StorageQuery::value::(); +/// let q = StorageQuery::value::>(); /// let hash = None::; /// let _: Option = q.get(&cl, hash).await?; /// -/// let q = StorageQuery::map::((0, 0, 0)); +/// let q = StorageQuery::map::, _>((0, 0, 0)); /// let _: Option = q.get(&cl, hash).await?; /// -/// let q = StorageQuery::map::(12); +/// let q = StorageQuery::map::, _>(12); /// let _: Option = q.get(&cl, hash).await?; /// -/// let q = StorageQuery::double_map::(3, (0, 0, 0)); +/// let q = StorageQuery::double_map::, _, _>(3, (0, 0, 0)); /// let _: Option = q.get(&cl, hash).await?; /// /// Ok(()) diff --git a/utils/frame/try-runtime/cli/Cargo.toml b/utils/frame/try-runtime/cli/Cargo.toml index 56ead30644d86..24d64d4aa4373 100644 --- a/utils/frame/try-runtime/cli/Cargo.toml +++ b/utils/frame/try-runtime/cli/Cargo.toml @@ -13,13 +13,12 @@ readme = "README.md" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -clap = { version = "3.1.18", features = ["derive"] } +clap = { version = "4.0.9", features = ["derive"] } log = "0.4.17" parity-scale-codec = "3.0.0" serde = "1.0.136" zstd = { version = "0.11.2", default-features = false } remote-externalities = { version = "0.10.0-dev", path = "../../remote-externalities" } -jsonrpsee = { version = "0.15.1", default-features = false, features = ["ws-client"] } sc-chain-spec = { version = "4.0.0-dev", path = "../../../../client/chain-spec" } sc-cli = { version = "0.10.0-dev", path = "../../../../client/cli" } sc-executor = { version = "0.10.0-dev", path = "../../../../client/executor" } @@ -31,7 +30,9 @@ sp-keystore = { version = "0.12.0", path = "../../../../primitives/keystore" } sp-runtime = { version = "6.0.0", path = "../../../../primitives/runtime" } sp-state-machine = { version = "0.12.0", path = "../../../../primitives/state-machine" } sp-version = { version = "5.0.0", path = "../../../../primitives/version" } +sp-weights = { version = "4.0.0", path = "../../../../primitives/weights" } frame-try-runtime = { path = "../../../../frame/try-runtime" } +substrate-rpc-client = { path = "../../rpc/client" } [dev-dependencies] tokio = "1.17.0" diff --git a/utils/frame/try-runtime/cli/src/commands/execute_block.rs b/utils/frame/try-runtime/cli/src/commands/execute_block.rs index 70ba3615f874a..56d88b9cb8919 100644 --- a/utils/frame/try-runtime/cli/src/commands/execute_block.rs +++ b/utils/frame/try-runtime/cli/src/commands/execute_block.rs @@ -20,11 +20,11 @@ use crate::{ state_machine_call_with_proof, SharedParams, State, LOG_TARGET, }; use parity_scale_codec::Encode; -use remote_externalities::rpc_api; use sc_service::{Configuration, NativeExecutionDispatch}; use sp_core::storage::well_known_keys; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; use std::{fmt::Debug, str::FromStr}; +use substrate_rpc_client::{ws_client, ChainApi}; /// Configurations of the [`Command::ExecuteBlock`]. /// @@ -33,11 +33,11 @@ use std::{fmt::Debug, str::FromStr}; #[derive(Debug, Clone, clap::Parser)] pub struct ExecuteBlockCmd { /// Overwrite the wasm code in state or not. - #[clap(long)] + #[arg(long)] overwrite_wasm_code: bool, /// If set the state root check is disabled. - #[clap(long)] + #[arg(long)] no_state_root_check: bool, /// Which try-state targets to execute when running this command. @@ -49,17 +49,16 @@ pub struct ExecuteBlockCmd { /// `Staking, System`). /// - `rr-[x]` where `[x]` is a number. Then, the given number of pallets are checked in a /// round-robin fashion. - #[clap(long, default_value = "none")] + #[arg(long, default_value = "none")] try_state: frame_try_runtime::TryStateSelect, /// The block hash at which to fetch the block. /// /// If the `live` state type is being used, then this can be omitted, and is equal to whatever /// the `state::at` is. Only use this (with care) when combined with a snapshot. - #[clap( + #[arg( long, - multiple_values = false, - parse(try_from_str = crate::parse::hash) + value_parser = crate::parse::hash )] block_at: Option, @@ -67,10 +66,9 @@ pub struct ExecuteBlockCmd { /// /// If the `live` state type is being used, then this can be omitted, and is equal to whatever /// the `state::uri` is. Only use this (with care) when combined with a snapshot. - #[clap( + #[arg( long, - multiple_values = false, - parse(try_from_str = crate::parse::url) + value_parser = crate::parse::url )] block_ws_uri: Option, @@ -79,17 +77,18 @@ pub struct ExecuteBlockCmd { /// For this command only, if the `live` is used, then state of the parent block is fetched. /// /// If `block_at` is provided, then the [`State::Live::at`] is being ignored. - #[clap(subcommand)] + #[command(subcommand)] state: State, } impl ExecuteBlockCmd { async fn block_at(&self, ws_uri: String) -> sc_cli::Result where - Block::Hash: FromStr, + Block::Hash: FromStr + serde::de::DeserializeOwned, ::Err: Debug, + Block::Header: serde::de::DeserializeOwned, { - let rpc_service = rpc_api::RpcService::new(ws_uri, false).await?; + let rpc = ws_client(&ws_uri).await?; match (&self.block_at, &self.state) { (Some(block_at), State::Snap { .. }) => hash_of::(block_at), @@ -102,7 +101,9 @@ impl ExecuteBlockCmd { target: LOG_TARGET, "No --block-at or --at provided, using the latest finalized block instead" ); - rpc_service.get_finalized_head::().await.map_err(Into::into) + ChainApi::<(), Block::Hash, Block::Header, ()>::finalized_head(&rpc) + .await + .map_err(|e| e.to_string().into()) }, (None, State::Live { at: Some(at), .. }) => hash_of::(at), _ => { @@ -139,6 +140,8 @@ where Block: BlockT + serde::de::DeserializeOwned, Block::Hash: FromStr, ::Err: Debug, + Block::Hash: serde::de::DeserializeOwned, + Block::Header: serde::de::DeserializeOwned, NumberFor: FromStr, as FromStr>::Err: Debug, ExecDispatch: NativeExecutionDispatch + 'static, @@ -148,8 +151,11 @@ where let block_ws_uri = command.block_ws_uri::(); let block_at = command.block_at::(block_ws_uri.clone()).await?; - let rpc_service = rpc_api::RpcService::new(block_ws_uri.clone(), false).await?; - let block: Block = rpc_service.get_block::(block_at).await?; + let rpc = ws_client(&block_ws_uri).await?; + let block: Block = ChainApi::<(), Block::Hash, Block::Header, _>::block(&rpc, Some(block_at)) + .await + .unwrap() + .unwrap(); let parent_hash = block.header().parent_hash(); log::info!( target: LOG_TARGET, @@ -195,7 +201,7 @@ where block_ws_uri.clone(), expected_spec_name, expected_spec_version, - shared.no_spec_name_check, + shared.no_spec_check_panic, ) .await; diff --git a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs index f493d5c10cd29..1cc371c8f22fd 100644 --- a/utils/frame/try-runtime/cli/src/commands/follow_chain.rs +++ b/utils/frame/try-runtime/cli/src/commands/follow_chain.rs @@ -19,21 +19,15 @@ use crate::{ build_executor, ensure_matching_spec, extract_code, full_extensions, local_spec, parse, state_machine_call_with_proof, SharedParams, LOG_TARGET, }; -use jsonrpsee::{ - core::{ - async_trait, - client::{Client, Subscription, SubscriptionClientT}, - }, - ws_client::WsClientBuilder, -}; use parity_scale_codec::{Decode, Encode}; -use remote_externalities::{rpc_api::RpcService, Builder, Mode, OnlineConfig}; +use remote_externalities::{Builder, Mode, OnlineConfig}; use sc_executor::NativeExecutionDispatch; use sc_service::Configuration; -use serde::de::DeserializeOwned; +use serde::{de::DeserializeOwned, Serialize}; use sp_core::H256; use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; -use std::{collections::VecDeque, fmt::Debug, str::FromStr}; +use std::{fmt::Debug, str::FromStr}; +use substrate_rpc_client::{ws_client, ChainApi, FinalizedHeaders, Subscription, WsClient}; const SUB: &str = "chain_subscribeFinalizedHeads"; const UN_SUB: &str = "chain_unsubscribeFinalizedHeads"; @@ -42,11 +36,11 @@ const UN_SUB: &str = "chain_unsubscribeFinalizedHeads"; #[derive(Debug, Clone, clap::Parser)] pub struct FollowChainCmd { /// The url to connect to. - #[clap(short, long, parse(try_from_str = parse::url))] + #[arg(short, long, value_parser = parse::url)] uri: String, /// If set, then the state root check is enabled. - #[clap(long)] + #[arg(long)] state_root_check: bool, /// Which try-state targets to execute when running this command. @@ -58,11 +52,11 @@ pub struct FollowChainCmd { /// `Staking, System`). /// - `rr-[x]` where `[x]` is a number. Then, the given number of pallets are checked in a /// round-robin fashion. - #[clap(long, default_value = "none")] + #[arg(long, default_value = "none")] try_state: frame_try_runtime::TryStateSelect, /// If present, a single connection to a node will be kept and reused for fetching blocks. - #[clap(long)] + #[arg(long)] keep_connection: bool, } @@ -70,144 +64,19 @@ pub struct FollowChainCmd { /// /// Returns a pair `(client, subscription)` - `subscription` alone will be useless, because it /// relies on the related alive `client`. -async fn start_subscribing( +async fn start_subscribing( url: &str, -) -> sc_cli::Result<(Client, Subscription
)> { - let client = WsClientBuilder::default() - .connection_timeout(std::time::Duration::new(20, 0)) - .max_notifs_per_subscription(1024) - .max_request_body_size(u32::MAX) - .build(url) - .await - .map_err(|e| sc_cli::Error::Application(e.into()))?; +) -> sc_cli::Result<(WsClient, Subscription
)> { + let client = ws_client(url).await.map_err(|e| sc_cli::Error::Application(e.into()))?; log::info!(target: LOG_TARGET, "subscribing to {:?} / {:?}", SUB, UN_SUB); - let sub = client - .subscribe(SUB, None, UN_SUB) + let sub = ChainApi::<(), (), Header, ()>::subscribe_finalized_heads(&client) .await .map_err(|e| sc_cli::Error::Application(e.into()))?; Ok((client, sub)) } -/// Abstraction over RPC calling for headers. -#[async_trait] -trait HeaderProvider -where - Block::Header: HeaderT, -{ - /// Awaits for the header of the block with hash `hash`. - async fn get_header(&self, hash: Block::Hash) -> Block::Header; -} - -#[async_trait] -impl HeaderProvider for RpcService -where - Block::Header: DeserializeOwned, -{ - async fn get_header(&self, hash: Block::Hash) -> Block::Header { - self.get_header::(hash).await.unwrap() - } -} - -/// Abstraction over RPC subscription for finalized headers. -#[async_trait] -trait HeaderSubscription -where - Block::Header: HeaderT, -{ - /// Await for the next finalized header from the subscription. - /// - /// Returns `None` if either the subscription has been closed or there was an error when reading - /// an object from the client. - async fn next_header(&mut self) -> Option; -} - -#[async_trait] -impl HeaderSubscription for Subscription -where - Block::Header: DeserializeOwned, -{ - async fn next_header(&mut self) -> Option { - match self.next().await { - Some(Ok(header)) => Some(header), - None => { - log::warn!("subscription closed"); - None - }, - Some(Err(why)) => { - log::warn!("subscription returned error: {:?}. Probably decoding has failed.", why); - None - }, - } - } -} - -/// Stream of all finalized headers. -/// -/// Returned headers are guaranteed to be ordered. There are no missing headers (even if some of -/// them lack justification). -struct FinalizedHeaders<'a, Block: BlockT, HP: HeaderProvider, HS: HeaderSubscription> -{ - header_provider: &'a HP, - subscription: HS, - fetched_headers: VecDeque, - last_returned: Option<::Hash>, -} - -impl<'a, Block: BlockT, HP: HeaderProvider, HS: HeaderSubscription> - FinalizedHeaders<'a, Block, HP, HS> -where - ::Header: DeserializeOwned, -{ - pub fn new(header_provider: &'a HP, subscription: HS) -> Self { - Self { - header_provider, - subscription, - fetched_headers: VecDeque::new(), - last_returned: None, - } - } - - /// Reads next finalized header from the subscription. If some headers (without justification) - /// have been skipped, fetches them as well. Returns number of headers that have been fetched. - /// - /// All fetched headers are stored in `self.fetched_headers`. - async fn fetch(&mut self) -> usize { - let last_finalized = match self.subscription.next_header().await { - Some(header) => header, - None => return 0, - }; - - self.fetched_headers.push_front(last_finalized.clone()); - - let mut last_finalized_parent = *last_finalized.parent_hash(); - let last_returned = self.last_returned.unwrap_or(last_finalized_parent); - - while last_finalized_parent != last_returned { - let parent_header = self.header_provider.get_header(last_finalized_parent).await; - self.fetched_headers.push_front(parent_header.clone()); - last_finalized_parent = *parent_header.parent_hash(); - } - - self.fetched_headers.len() - } - - /// Get the next finalized header. - pub async fn next(&mut self) -> Option { - if self.fetched_headers.is_empty() { - self.fetch().await; - } - - if let Some(header) = self.fetched_headers.pop_front() { - self.last_returned = Some(header.hash()); - Some(header) - } else { - None - } - } -} - pub(crate) async fn follow_chain( shared: SharedParams, command: FollowChainCmd, @@ -223,22 +92,23 @@ where ExecDispatch: NativeExecutionDispatch + 'static, { let mut maybe_state_ext = None; - let (_client, subscription) = start_subscribing::(&command.uri).await?; + let (rpc, subscription) = start_subscribing::(&command.uri).await?; let (code_key, code) = extract_code(&config.chain_spec)?; let executor = build_executor::(&shared, &config); let execution = shared.execution; - let rpc_service = RpcService::new(&command.uri, command.keep_connection).await?; - - let mut finalized_headers: FinalizedHeaders> = - FinalizedHeaders::new(&rpc_service, subscription); + let mut finalized_headers: FinalizedHeaders = + FinalizedHeaders::new(&rpc, subscription); while let Some(header) = finalized_headers.next().await { let hash = header.hash(); let number = header.number(); - let block = rpc_service.get_block::(hash).await.unwrap(); + let block: Block = ChainApi::<(), Block::Hash, Block::Header, _>::block(&rpc, Some(hash)) + .await + .unwrap() + .unwrap(); log::debug!( target: LOG_TARGET, @@ -275,7 +145,7 @@ where command.uri.clone(), expected_spec_name, expected_spec_version, - shared.no_spec_name_check, + shared.no_spec_check_panic, ) .await; @@ -294,8 +164,8 @@ where full_extensions(), )?; - let consumed_weight = ::decode(&mut &*encoded_result) - .map_err(|e| format!("failed to decode output: {:?}", e))?; + let consumed_weight = ::decode(&mut &*encoded_result) + .map_err(|e| format!("failed to decode weight: {:?}", e))?; let storage_changes = changes .drain_storage_changes( @@ -325,76 +195,3 @@ where log::error!(target: LOG_TARGET, "ws subscription must have terminated."); Ok(()) } - -#[cfg(test)] -mod tests { - use super::*; - use sp_runtime::testing::{Block as TBlock, ExtrinsicWrapper, Header}; - use std::sync::Arc; - use tokio::sync::Mutex; - - type Block = TBlock>; - type BlockNumber = u64; - type Hash = H256; - - struct MockHeaderProvider(pub Arc>>); - - fn headers() -> Vec
{ - let mut headers = vec![Header::new_from_number(0)]; - for n in 1..11 { - headers.push(Header { - parent_hash: headers.last().unwrap().hash(), - ..Header::new_from_number(n) - }) - } - headers - } - - #[async_trait] - impl HeaderProvider for MockHeaderProvider { - async fn get_header(&self, _hash: Hash) -> Header { - let height = self.0.lock().await.pop_front().unwrap(); - headers()[height as usize].clone() - } - } - - struct MockHeaderSubscription(pub VecDeque); - - #[async_trait] - impl HeaderSubscription for MockHeaderSubscription { - async fn next_header(&mut self) -> Option
{ - self.0.pop_front().map(|h| headers()[h as usize].clone()) - } - } - - #[tokio::test] - async fn finalized_headers_works_when_every_block_comes_from_subscription() { - let heights = vec![4, 5, 6, 7]; - - let provider = MockHeaderProvider(Default::default()); - let subscription = MockHeaderSubscription(heights.clone().into()); - let mut headers = FinalizedHeaders::new(&provider, subscription); - - for h in heights { - assert_eq!(h, headers.next().await.unwrap().number); - } - assert_eq!(None, headers.next().await); - } - - #[tokio::test] - async fn finalized_headers_come_from_subscription_and_provider_if_in_need() { - let all_heights = 3..11; - let heights_in_subscription = vec![3, 4, 6, 10]; - // Consecutive headers will be requested in the reversed order. - let heights_not_in_subscription = vec![5, 9, 8, 7]; - - let provider = MockHeaderProvider(Arc::new(Mutex::new(heights_not_in_subscription.into()))); - let subscription = MockHeaderSubscription(heights_in_subscription.into()); - let mut headers = FinalizedHeaders::new(&provider, subscription); - - for h in all_heights { - assert_eq!(h, headers.next().await.unwrap().number); - } - assert_eq!(None, headers.next().await); - } -} diff --git a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs index a579692abd9e2..8d2585372b4a8 100644 --- a/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs +++ b/utils/frame/try-runtime/cli/src/commands/offchain_worker.rs @@ -20,28 +20,27 @@ use crate::{ parse, state_machine_call, SharedParams, State, LOG_TARGET, }; use parity_scale_codec::Encode; -use remote_externalities::rpc_api; use sc_executor::NativeExecutionDispatch; use sc_service::Configuration; use sp_core::storage::well_known_keys; use sp_runtime::traits::{Block as BlockT, Header, NumberFor}; use std::{fmt::Debug, str::FromStr}; +use substrate_rpc_client::{ws_client, ChainApi}; /// Configurations of the [`Command::OffchainWorker`]. #[derive(Debug, Clone, clap::Parser)] pub struct OffchainWorkerCmd { /// Overwrite the wasm code in state or not. - #[clap(long)] + #[arg(long)] overwrite_wasm_code: bool, /// The block hash at which to fetch the header. /// /// If the `live` state type is being used, then this can be omitted, and is equal to whatever /// the `state::at` is. Only use this (with care) when combined with a snapshot. - #[clap( + #[arg( long, - multiple_values = false, - parse(try_from_str = parse::hash) + value_parser = parse::hash )] header_at: Option, @@ -49,15 +48,14 @@ pub struct OffchainWorkerCmd { /// /// If the `live` state type is being used, then this can be omitted, and is equal to whatever /// the `state::uri` is. Only use this (with care) when combined with a snapshot. - #[clap( + #[arg( long, - multiple_values = false, - parse(try_from_str = parse::url) + value_parser = parse::url )] header_ws_uri: Option, /// The state type to use. - #[clap(subcommand)] + #[command(subcommand)] pub state: State, } @@ -119,8 +117,11 @@ where let header_at = command.header_at::()?; let header_ws_uri = command.header_ws_uri::(); - let rpc_service = rpc_api::RpcService::new(header_ws_uri.clone(), false).await?; - let header = rpc_service.get_header::(header_at).await?; + let rpc = ws_client(&header_ws_uri).await?; + let header = ChainApi::<(), Block::Hash, Block::Header, ()>::header(&rpc, Some(header_at)) + .await + .unwrap() + .unwrap(); log::info!( target: LOG_TARGET, "fetched header from {:?}, block number: {:?}", @@ -152,7 +153,7 @@ where header_ws_uri, expected_spec_name, expected_spec_version, - shared.no_spec_name_check, + shared.no_spec_check_panic, ) .await; diff --git a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs index 9bc6d32d4762a..fba34ddfb5060 100644 --- a/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs +++ b/utils/frame/try-runtime/cli/src/commands/on_runtime_upgrade.rs @@ -21,6 +21,7 @@ use parity_scale_codec::Decode; use sc_executor::NativeExecutionDispatch; use sc_service::Configuration; use sp_runtime::traits::{Block as BlockT, NumberFor}; +use sp_weights::Weight; use crate::{ build_executor, ensure_matching_spec, extract_code, local_spec, state_machine_call_with_proof, @@ -31,7 +32,7 @@ use crate::{ #[derive(Debug, Clone, clap::Parser)] pub struct OnRuntimeUpgradeCmd { /// The state type to use. - #[clap(subcommand)] + #[command(subcommand)] pub state: State, } @@ -44,6 +45,7 @@ where Block: BlockT + serde::de::DeserializeOwned, Block::Hash: FromStr, ::Err: Debug, + Block::Header: serde::de::DeserializeOwned, NumberFor: FromStr, as FromStr>::Err: Debug, ExecDispatch: NativeExecutionDispatch + 'static, @@ -64,7 +66,7 @@ where uri, expected_spec_name, expected_spec_version, - shared.no_spec_name_check, + shared.no_spec_check_panic, ) .await; } @@ -78,14 +80,15 @@ where Default::default(), // we don't really need any extensions here. )?; - let (weight, total_weight) = <(u64, u64) as Decode>::decode(&mut &*encoded_result) - .map_err(|e| format!("failed to decode output: {:?}", e))?; + let (weight, total_weight) = <(Weight, Weight) as Decode>::decode(&mut &*encoded_result) + .map_err(|e| format!("failed to decode weight: {:?}", e))?; log::info!( target: LOG_TARGET, - "TryRuntime_on_runtime_upgrade executed without errors. Consumed weight = {}, total weight = {} ({})", - weight, - total_weight, - weight as f64 / total_weight.max(1) as f64 + "TryRuntime_on_runtime_upgrade executed without errors. Consumed weight = ({} ps, {} byte), total weight = ({} ps, {} byte) ({:.2} %, {:.2} %).", + weight.ref_time(), weight.proof_size(), + total_weight.ref_time(), total_weight.proof_size(), + (weight.ref_time() as f64 / total_weight.ref_time().max(1) as f64) * 100.0, + (weight.proof_size() as f64 / total_weight.proof_size().max(1) as f64) * 100.0, ); Ok(()) diff --git a/utils/frame/try-runtime/cli/src/lib.rs b/utils/frame/try-runtime/cli/src/lib.rs index c71496e0b850c..0732c8618fc15 100644 --- a/utils/frame/try-runtime/cli/src/lib.rs +++ b/utils/frame/try-runtime/cli/src/lib.rs @@ -132,20 +132,20 @@ //! added, given the right flag: //! //! ```ignore +//! //! #[cfg(feature = try-runtime)] -//! fn pre_upgrade() -> Result<(), &'static str> {} +//! fn pre_upgrade() -> Result, &'static str> {} //! //! #[cfg(feature = try-runtime)] -//! fn post_upgrade() -> Result<(), &'static str> {} +//! fn post_upgrade(state: Vec) -> Result<(), &'static str> {} //! ``` //! //! (The pallet macro syntax will support this simply as a part of `#[pallet::hooks]`). //! //! These hooks allow you to execute some code, only within the `on-runtime-upgrade` command, before -//! and after the migration. If any data needs to be temporarily stored between the pre/post -//! migration hooks, `OnRuntimeUpgradeHelpersExt` can help with that. Note that you should be -//! mindful with any mutable storage ops in the pre/post migration checks, as you almost certainly -//! will not want to mutate any of the storage that is to be migrated. +//! and after the migration. Moreover, `pre_upgrade` can return a `Vec` that contains arbitrary +//! encoded data (usually some pre-upgrade state) which will be passed to `post_upgrade` after +//! upgrading and used for post checking. //! //! #### Logging //! @@ -267,8 +267,7 @@ use parity_scale_codec::Decode; use remote_externalities::{ - rpc_api::RpcService, Builder, Mode, OfflineConfig, OnlineConfig, SnapshotConfig, - TestExternalities, + Builder, Mode, OfflineConfig, OnlineConfig, SnapshotConfig, TestExternalities, }; use sc_chain_spec::ChainSpec; use sc_cli::{ @@ -297,6 +296,7 @@ use sp_runtime::{ use sp_state_machine::{OverlayedChanges, StateMachine, TrieBackendBuilder}; use sp_version::StateVersion; use std::{fmt::Debug, path::PathBuf, str::FromStr}; +use substrate_rpc_client::{ws_client, StateApi}; mod commands; pub(crate) mod parse; @@ -385,6 +385,7 @@ pub enum Command { /// Shared parameters of the `try-runtime` commands #[derive(Debug, Clone, clap::Parser)] +#[group(skip)] pub struct SharedParams { /// Shared parameters of substrate cli. #[allow(missing_docs)] @@ -392,41 +393,41 @@ pub struct SharedParams { pub shared_params: sc_cli::SharedParams, /// The execution strategy that should be used. - #[clap(long, value_name = "STRATEGY", arg_enum, ignore_case = true, default_value = "wasm")] + #[arg(long, value_name = "STRATEGY", value_enum, ignore_case = true, default_value_t = ExecutionStrategy::Wasm)] pub execution: ExecutionStrategy, /// Type of wasm execution used. - #[clap( + #[arg( long = "wasm-execution", value_name = "METHOD", - possible_values = WasmExecutionMethod::variants(), + value_enum, ignore_case = true, - default_value = DEFAULT_WASM_EXECUTION_METHOD, + default_value_t = DEFAULT_WASM_EXECUTION_METHOD, )] pub wasm_method: WasmExecutionMethod, /// The WASM instantiation method to use. /// /// Only has an effect when `wasm-execution` is set to `compiled`. - #[clap( + #[arg( long = "wasm-instantiation-strategy", value_name = "STRATEGY", default_value_t = DEFAULT_WASMTIME_INSTANTIATION_STRATEGY, - arg_enum, + value_enum, )] pub wasmtime_instantiation_strategy: WasmtimeInstantiationStrategy, /// The number of 64KB pages to allocate for Wasm execution. Defaults to /// [`sc_service::Configuration.default_heap_pages`]. - #[clap(long)] + #[arg(long)] pub heap_pages: Option, - /// When enabled, the spec name check will not panic, and instead only show a warning. - #[clap(long)] - pub no_spec_name_check: bool, + /// When enabled, the spec check will not panic, and instead only show a warning. + #[arg(long)] + pub no_spec_check_panic: bool, /// State version that is used by the chain. - #[clap(long, default_value = "1", parse(try_from_str = parse::state_version))] + #[arg(long, default_value_t = StateVersion::V1, value_parser = parse::state_version)] pub state_version: StateVersion, } @@ -438,7 +439,7 @@ pub struct TryRuntimeCmd { #[clap(flatten)] pub shared: SharedParams, - #[clap(subcommand)] + #[command(subcommand)] pub command: Command, } @@ -449,17 +450,17 @@ pub enum State { /// /// This can be crated by passing a value to [`State::Live::snapshot_path`]. Snap { - #[clap(short, long)] + #[arg(short, long)] snapshot_path: PathBuf, }, /// Use a live chain as the source of runtime state. Live { /// The url to connect to. - #[clap( + #[arg( short, long, - parse(try_from_str = parse::url), + value_parser = parse::url, )] uri: String, @@ -467,21 +468,20 @@ pub enum State { /// /// If non provided, then the latest finalized head is used. This is particularly useful /// for [`Command::OnRuntimeUpgrade`]. - #[clap( + #[arg( short, long, - multiple_values = false, - parse(try_from_str = parse::hash), + value_parser = parse::hash, )] at: Option, /// An optional state snapshot file to WRITE to. Not written if set to `None`. - #[clap(short, long)] + #[arg(short, long)] snapshot_path: Option, /// A pallet to scrape. Can be provided multiple times. If empty, entire chain state will /// be scraped. - #[clap(short, long, multiple_values = true)] + #[arg(short, long, num_args = 1..)] pallet: Vec, /// Fetch the child-keys as well. @@ -489,7 +489,7 @@ pub enum State { /// Default is `false`, if specific `--pallets` are specified, `true` otherwise. In other /// words, if you scrape the whole state the child tree data is included out of the box. /// Otherwise, it must be enabled explicitly using this flag. - #[clap(long)] + #[arg(long)] child_tree: bool, }, } @@ -633,9 +633,8 @@ pub(crate) async fn ensure_matching_spec( expected_spec_version: u32, relaxed: bool, ) { - let rpc_service = RpcService::new(uri.clone(), false).await.unwrap(); - match rpc_service - .get_runtime_version::(None) + let rpc = ws_client(&uri).await.unwrap(); + match StateApi::::runtime_version(&rpc, None) .await .map(|version| (String::from(version.spec_name.clone()), version.spec_version)) .map(|(spec_name, spec_version)| (spec_name.to_lowercase(), spec_version))