diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs index 09a7fe280..5db697617 100644 --- a/.maintain/frame-weight-template.hbs +++ b/.maintain/frame-weight-template.hbs @@ -20,9 +20,10 @@ //! Autogenerated weights for {{pallet}} //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} -//! DATE: {{date}}, STEPS: `{{cmd.steps}}`, REPEAT: {{cmd.repeat}}, LOW RANGE: `{{cmd.lowest_range_values}}`, HIGH RANGE: `{{cmd.highest_range_values}}` +//! DATE: {{date}}, STEPS: `{{cmd.steps}}`, REPEAT: `{{cmd.repeat}}`, LOW RANGE: `{{cmd.lowest_range_values}}`, HIGH RANGE: `{{cmd.highest_range_values}}` +//! WORST CASE MAP SIZE: `{{cmd.worst_case_map_values}}` //! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}` -//! EXECUTION: {{cmd.execution}}, WASM-EXECUTION: {{cmd.wasm_execution}}, CHAIN: {{cmd.chain}}, DB CACHE: {{cmd.db_cache}} +//! EXECUTION: `{{cmd.execution}}`, WASM-EXECUTION: `{{cmd.wasm_execution}}`, CHAIN: `{{cmd.chain}}`, DB CACHE: `{{cmd.db_cache}}` // Executed Command: {{#each args as |arg|}} @@ -32,9 +33,10 @@ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] +#![allow(missing_docs)] use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use sp_std::marker::PhantomData; +use core::marker::PhantomData; /// Weight functions needed for {{pallet}}. pub trait WeightInfo { @@ -56,7 +58,7 @@ impl WeightInfo for SubstrateWeight { {{/if}} {{#each benchmarks as |benchmark|}} {{#each benchmark.comments as |comment|}} - // {{comment}} + /// {{comment}} {{/each}} {{#each benchmark.component_ranges as |range|}} /// The range of component `{{range.name}}` is `[{{range.min}}, {{range.max}}]`. @@ -66,59 +68,29 @@ 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}}) + // Proof Size summary in bytes: + // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Minimum execution time: {{underscore benchmark.min_execution_time}}_000 picoseconds. + Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}}) {{#each benchmark.component_weight as |cw|}} // Standard Error: {{underscore cw.error}} - .saturating_add(Weight::from_ref_time({{underscore cw.slope}}).saturating_mul({{cw.name}}.into())) + .saturating_add(Weight::from_parts({{underscore cw.slope}}, 0).saturating_mul({{cw.name}}.into())) {{/each}} {{#if (ne benchmark.base_reads "0")}} - .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}})) + .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}}_u64)) {{/if}} {{#each benchmark.component_reads as |cr|}} .saturating_add(T::DbWeight::get().reads(({{cr.slope}}_u64).saturating_mul({{cr.name}}.into()))) {{/each}} {{#if (ne benchmark.base_writes "0")}} - .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}})) + .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}}_u64)) {{/if}} {{#each benchmark.component_writes as |cw|}} .saturating_add(T::DbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) {{/each}} - } - {{/each}} -} - -// For backwards compatibility and tests -impl WeightInfo for () { - {{#each benchmarks as |benchmark|}} - {{#each benchmark.comments as |comment|}} - // {{comment}} - {{/each}} - {{#each benchmark.component_ranges as |range|}} - /// The range of component `{{range.name}}` is `[{{range.min}}, {{range.max}}]`. - {{/each}} - fn {{benchmark.name~}} - ( - {{~#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}}) - {{#each benchmark.component_weight as |cw|}} - // Standard Error: {{underscore cw.error}} - .saturating_add(Weight::from_ref_time({{underscore cw.slope}}).saturating_mul({{cw.name}}.into())) - {{/each}} - {{#if (ne benchmark.base_reads "0")}} - .saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}})) - {{/if}} - {{#each benchmark.component_reads as |cr|}} - .saturating_add(RocksDbWeight::get().reads(({{cr.slope}}_u64).saturating_mul({{cr.name}}.into()))) - {{/each}} - {{#if (ne benchmark.base_writes "0")}} - .saturating_add(RocksDbWeight::get().writes({{benchmark.base_writes}})) - {{/if}} - {{#each benchmark.component_writes as |cw|}} - .saturating_add(RocksDbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) + {{#each benchmark.component_calculated_proof_size as |cp|}} + .saturating_add(Weight::from_parts(0, {{cp.slope}}).saturating_mul({{cp.name}}.into())) {{/each}} } {{/each}} diff --git a/Cargo.lock b/Cargo.lock index b66c71d01..59c63407c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,11 +23,11 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" dependencies = [ - "gimli 0.27.2", + "gimli 0.27.3", ] [[package]] @@ -90,9 +90,9 @@ dependencies = [ [[package]] name = "aes" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" dependencies = [ "cfg-if", "cipher 0.4.4", @@ -120,7 +120,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "209b47e8954a928e1d72e86eca7000ebb6655fe1436d33eefc2201cad027e237" dependencies = [ "aead 0.5.2", - "aes 0.8.2", + "aes 0.8.3", "cipher 0.4.4", "ctr 0.9.2", "ghash 0.5.0", @@ -153,7 +153,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.10", "once_cell", "version_check", ] @@ -165,25 +165,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ "cfg-if", - "getrandom 0.2.9", + "getrandom 0.2.10", "once_cell", "version_check", ] [[package]] name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - -[[package]] -name = "aho-corasick" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] @@ -194,6 +185,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4436e0292ab1bb631b42973c61205e704475fe8126af845c8d923c0996328127" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -229,15 +226,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" [[package]] name = "anstyle-parse" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" dependencies = [ "utf8parse", ] @@ -308,9 +305,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "asn1-rs" @@ -325,7 +322,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.21", + "time 0.3.23", ] [[package]] @@ -341,7 +338,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.21", + "time 0.3.23", ] [[package]] @@ -391,6 +388,37 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" +[[package]] +name = "assets-common" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "log", + "pallet-xcm", + "parachains-common", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-std", + "substrate-wasm-builder", + "xcm", + "xcm-builder", + "xcm-executor", +] + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + [[package]] name = "async-io" version = "1.13.0" @@ -405,9 +433,9 @@ dependencies = [ "log", "parking", "polling", - "rustix 0.37.19", + "rustix 0.37.23", "slab", - "socket2", + "socket2 0.4.9", "waker-fn", ] @@ -420,15 +448,26 @@ dependencies = [ "event-listener", ] +[[package]] +name = "async-recursion" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.25", +] + [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.25", ] [[package]] @@ -441,7 +480,7 @@ dependencies = [ "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", ] [[package]] @@ -450,26 +489,6 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" -[[package]] -name = "attestation" -version = "1.11.0-dev" -source = "git+https://github.com/KILTprotocol/kilt-node?branch=aa/dip#17c587e7cfd39e79ee06c7a568271ee8beecc505" -dependencies = [ - "ctype", - "frame-benchmarking", - "frame-support", - "frame-system", - "kilt-support", - "log", - "pallet-balances", - "parity-scale-codec", - "scale-info", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", -] - [[package]] name = "atty" version = "0.2.14" @@ -489,16 +508,16 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" dependencies = [ - "addr2line 0.19.0", + "addr2line 0.20.0", "cc", "cfg-if", "libc", - "miniz_oxide 0.6.2", - "object 0.30.3", + "miniz_oxide", + "object 0.31.1", "rustc-demangle", ] @@ -515,10 +534,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" [[package]] -name = "base58" +name = "base16ct" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" @@ -528,9 +547,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.1" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f1e31e207a6b8fb791a38ea3105e6cb541f55e4d029902d3039a4ad07cc4105" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "base64ct" @@ -547,63 +566,10 @@ dependencies = [ "serde", ] -[[package]] -name = "beefy-gadget" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" -dependencies = [ - "array-bytes 4.2.0", - "async-trait", - "fnv", - "futures", - "log", - "parity-scale-codec", - "parking_lot 0.12.1", - "sc-client-api", - "sc-consensus", - "sc-keystore", - "sc-network", - "sc-network-common", - "sc-network-gossip", - "sc-utils", - "sp-api", - "sp-application-crypto", - "sp-arithmetic", - "sp-beefy", - "sp-blockchain", - "sp-consensus", - "sp-core", - "sp-keystore", - "sp-mmr-primitives", - "sp-runtime", - "substrate-prometheus-endpoint", - "thiserror", - "wasm-timer", -] - -[[package]] -name = "beefy-gadget-rpc" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" -dependencies = [ - "beefy-gadget", - "futures", - "jsonrpsee", - "log", - "parity-scale-codec", - "parking_lot 0.12.1", - "sc-rpc", - "serde", - "sp-beefy", - "sp-core", - "sp-runtime", - "thiserror", -] - [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "hash-db", "log", @@ -624,7 +590,7 @@ version = "0.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static", @@ -644,6 +610,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" + [[package]] name = "bitvec" version = "1.0.1" @@ -672,8 +644,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" dependencies = [ "arrayref", - "arrayvec 0.7.2", - "constant_time_eq", + "arrayvec 0.7.4", + "constant_time_eq 0.2.6", ] [[package]] @@ -683,21 +655,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637f448b9e61dfadbdcbae9a885fadee1f3eaffb1f8d3c1965d3ade8bdfd44f" dependencies = [ "arrayref", - "arrayvec 0.7.2", - "constant_time_eq", + "arrayvec 0.7.4", + "constant_time_eq 0.2.6", ] [[package]] name = "blake3" -version = "1.3.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ae2468a89544a466886840aa467a25b766499f4f04bf7d9fcd10ecee9fccef" +checksum = "199c42ab6972d92c9f8995f086273d25c42fc0f7b2a1fcefba465c1352d25ba5" dependencies = [ "arrayref", - "arrayvec 0.7.2", + "arrayvec 0.7.4", "cc", "cfg-if", - "constant_time_eq", + "constant_time_eq 0.3.0", "digest 0.10.7", ] @@ -758,9 +730,9 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "bounded-collections" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07fbd1d11282a1eb134d3c3b7cf8ce213b5161c6e5f73fb1b98618482c606b64" +checksum = "eb5b05133427c07c4776906f673ccf36c21b102c9829c641a5b56bd151d44fd6" dependencies = [ "log", "parity-scale-codec", @@ -785,9 +757,20 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bstr" -version = "1.5.0" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "lazy_static", + "memchr", + "regex-automata 0.1.10", +] + +[[package]] +name = "bstr" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" dependencies = [ "memchr", "serde", @@ -851,18 +834,18 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.4" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" dependencies = [ "serde", ] [[package]] name = "cargo-platform" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" dependencies = [ "serde", ] @@ -958,13 +941,13 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ + "android-tzdata", "iana-time-zone", "js-sys", - "num-integer", "num-traits", "time 0.1.45", "wasm-bindgen", @@ -1034,9 +1017,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.0" +version = "4.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc" +checksum = "1640e5cc7fb47dbb8338fd471b105e7ed6c3cb2aeb00c2e067127ffd3764a05d" dependencies = [ "clap_builder", "clap_derive", @@ -1045,27 +1028,26 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.0" +version = "4.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990" +checksum = "98c59138d527eeaf9b53f35a77fcc1fad9d883116070c63d5de1c7dc7b00c72b" dependencies = [ "anstream", "anstyle", - "bitflags", "clap_lex", "strsim", ] [[package]] name = "clap_derive" -version = "4.3.0" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "191d9573962933b4027f932c600cd252ce27a8ad5979418fe78e43c07996f27b" +checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.25", ] [[package]] @@ -1104,9 +1086,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "comfy-table" -version = "6.1.4" +version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e7b787b0dc42e8111badfdbe4c3059158ccb2db8780352fa1b01e8ccf45cc4d" +checksum = "7e959d788268e3bf9d35ace83e81b124190378e4c91c9067524675e33394b8ba" dependencies = [ "strum", "strum_macros", @@ -1122,17 +1104,36 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "console" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.45.0", +] + [[package]] name = "const-oid" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" +checksum = "795bc6e66a8e340f075fcf6227e417a2dc976b92b91f3cdc778bb858778b6747" [[package]] name = "constant_time_eq" -version = "0.2.5" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a53c0a4d288377e7415b53dcfc3c04da5cdc2cc95c8d5ac178b58f0b861ad6" + +[[package]] +name = "constant_time_eq" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] name = "convert_case" @@ -1186,9 +1187,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -1208,7 +1209,7 @@ version = "0.93.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "253531aca9b6f56103c9420369db3263e784df39aa1c90685a1f69cfbba0623e" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", "bumpalo", "cranelift-bforest", "cranelift-codegen-meta", @@ -1339,14 +1340,14 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.14" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset 0.8.0", + "memoffset 0.9.0", "scopeguard", ] @@ -1362,9 +1363,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -1387,6 +1388,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "crypto-bigint" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" +dependencies = [ + "generic-array 0.14.7", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -1395,7 +1408,7 @@ checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array 0.14.7", "rand_core 0.6.4", - "typenum", + "typenum 1.16.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1436,30 +1449,10 @@ dependencies = [ "cipher 0.4.4", ] -[[package]] -name = "ctype" -version = "1.11.0-dev" -source = "git+https://github.com/KILTprotocol/kilt-node?branch=aa/dip#17c587e7cfd39e79ee06c7a568271ee8beecc505" -dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "kilt-support", - "log", - "pallet-balances", - "parity-scale-codec", - "scale-info", - "sp-core", - "sp-io", - "sp-keystore", - "sp-runtime", - "sp-std", -] - [[package]] name = "cumulus-client-cli" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "clap", "parity-scale-codec", @@ -1474,7 +1467,7 @@ dependencies = [ [[package]] name = "cumulus-client-collator" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "cumulus-client-consensus-common", "cumulus-client-network", @@ -1497,7 +1490,7 @@ dependencies = [ [[package]] name = "cumulus-client-consensus-aura" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "async-trait", "cumulus-client-consensus-common", @@ -1526,7 +1519,7 @@ dependencies = [ [[package]] name = "cumulus-client-consensus-common" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "async-trait", "cumulus-client-pov-recovery", @@ -1550,7 +1543,7 @@ dependencies = [ [[package]] name = "cumulus-client-network" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "async-trait", "cumulus-relay-chain-interface", @@ -1573,7 +1566,7 @@ dependencies = [ [[package]] name = "cumulus-client-pov-recovery" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -1597,7 +1590,7 @@ dependencies = [ [[package]] name = "cumulus-client-service" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "cumulus-client-cli", "cumulus-client-collator", @@ -1609,11 +1602,11 @@ dependencies = [ "cumulus-relay-chain-interface", "cumulus-relay-chain-minimal-node", "futures", - "parking_lot 0.12.1", "polkadot-primitives", "sc-client-api", "sc-consensus", "sc-network", + "sc-network-sync", "sc-network-transactions", "sc-rpc", "sc-service", @@ -1632,7 +1625,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-aura-ext" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "frame-support", "frame-system", @@ -1648,7 +1641,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-dmp-queue" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -1665,7 +1658,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-parachain-system" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "bytes", "cumulus-pallet-parachain-system-proc-macro", @@ -1694,18 +1687,18 @@ dependencies = [ [[package]] name = "cumulus-pallet-parachain-system-proc-macro" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.25", ] [[package]] name = "cumulus-pallet-session-benchmarking" version = "3.0.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "frame-benchmarking", "frame-support", @@ -1719,7 +1712,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-xcm" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -1735,7 +1728,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-xcmp-queue" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "cumulus-primitives-core", "frame-benchmarking", @@ -1756,12 +1749,13 @@ dependencies = [ [[package]] name = "cumulus-primitives-core" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain", "polkadot-primitives", + "scale-info", "sp-api", "sp-runtime", "sp-std", @@ -1772,7 +1766,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-parachain-inherent" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -1795,7 +1789,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-timestamp" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "cumulus-primitives-core", "futures", @@ -1808,7 +1802,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-utility" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -1826,7 +1820,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-inprocess-interface" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -1851,7 +1845,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-interface" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -1859,19 +1853,17 @@ dependencies = [ "jsonrpsee-core", "parity-scale-codec", "polkadot-overseer", - "polkadot-service", "sc-client-api", "sp-api", "sp-blockchain", "sp-state-machine", "thiserror", - "tokio", ] [[package]] name = "cumulus-relay-chain-minimal-node" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "array-bytes 6.1.0", "async-trait", @@ -1880,24 +1872,23 @@ dependencies = [ "cumulus-relay-chain-rpc-interface", "futures", "lru 0.9.0", + "polkadot-availability-recovery", + "polkadot-collator-protocol", "polkadot-core-primitives", "polkadot-network-bridge", + "polkadot-node-collation-generation", + "polkadot-node-core-runtime-api", "polkadot-node-network-protocol", "polkadot-node-subsystem-util", "polkadot-overseer", "polkadot-primitives", - "polkadot-service", "sc-authority-discovery", "sc-client-api", - "sc-consensus", - "sc-keystore", "sc-network", "sc-network-common", "sc-service", - "sc-telemetry", "sc-tracing", - "sc-transaction-pool", - "sc-transaction-pool-api", + "sc-utils", "sp-api", "sp-blockchain", "sp-consensus", @@ -1905,13 +1896,12 @@ dependencies = [ "sp-runtime", "tokio", "tracing", - "url", ] [[package]] name = "cumulus-relay-chain-rpc-interface" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -1921,9 +1911,10 @@ dependencies = [ "jsonrpsee", "lru 0.9.0", "parity-scale-codec", - "polkadot-service", + "polkadot-overseer", "sc-client-api", "sc-rpc-api", + "sc-service", "serde", "serde_json", "sp-api", @@ -1940,7 +1931,7 @@ dependencies = [ [[package]] name = "cumulus-test-relay-sproof-builder" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "cumulus-primitives-core", "parity-scale-codec", @@ -1992,9 +1983,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.94" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" +checksum = "e928d50d5858b744d1ea920b790641129c347a770d1530c3a85b77705a5ee031" dependencies = [ "cc", "cxxbridge-flags", @@ -2004,9 +1995,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.94" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" +checksum = "8332ba63f8a8040ca479de693150129067304a3496674477fff6d0c372cc34ae" dependencies = [ "cc", "codespan-reporting", @@ -2014,24 +2005,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.16", + "syn 2.0.25", ] [[package]] name = "cxxbridge-flags" -version = "1.0.94" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" +checksum = "5966a5a87b6e9bb342f5fab7170a93c77096efe199872afffc4b477cfeb86957" [[package]] name = "cxxbridge-macro" -version = "1.0.94" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" +checksum = "81b2dab6991c7ab1572fea8cb049db819b1aeea1e2dac74c0869f244d9f21a7c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.25", ] [[package]] @@ -2106,6 +2097,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "der" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7ed52955ce76b1554f509074bb357d3fb8ac9b51288a65a3fd480d1dfba946" +dependencies = [ + "const-oid", + "zeroize", +] + [[package]] name = "der-parser" version = "7.0.0" @@ -2200,26 +2201,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "did" -version = "1.11.0-dev" -source = "git+https://github.com/KILTprotocol/kilt-node?branch=aa/dip#17c587e7cfd39e79ee06c7a568271ee8beecc505" -dependencies = [ - "ctype", - "frame-support", - "frame-system", - "kilt-support", - "log", - "pallet-balances", - "parity-scale-codec", - "scale-info", - "sp-core", - "sp-io", - "sp-keystore", - "sp-runtime", - "sp-std", -] - [[package]] name = "difflib" version = "0.4.0" @@ -2251,77 +2232,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", + "const-oid", "crypto-common", "subtle", ] [[package]] -name = "dip-provider-runtime-template" -version = "1.11.0-dev" -source = "git+https://github.com/KILTprotocol/kilt-node?branch=aa/dip#17c587e7cfd39e79ee06c7a568271ee8beecc505" -dependencies = [ - "cumulus-pallet-aura-ext", - "cumulus-pallet-dmp-queue", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-core", - "cumulus-primitives-timestamp", - "cumulus-primitives-utility", - "did", - "dip-support", - "frame-executive", - "frame-support", - "frame-system", - "frame-system-rpc-runtime-api", - "kilt-runtime-api-dip-provider", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-dip-provider", - "pallet-session", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-xcm", - "parachain-info", - "parity-scale-codec", - "runtime-common 1.11.0-dev", - "scale-info", - "sp-api", - "sp-block-builder", - "sp-consensus-aura", - "sp-core", - "sp-inherents", - "sp-offchain", - "sp-runtime", - "sp-session", - "sp-std", - "sp-transaction-pool", - "sp-version", - "substrate-wasm-builder", - "xcm", - "xcm-builder", - "xcm-executor", -] - -[[package]] -name = "dip-support" -version = "1.11.0-dev" -source = "git+https://github.com/KILTprotocol/kilt-node?branch=aa/dip#17c587e7cfd39e79ee06c7a568271ee8beecc505" -dependencies = [ - "frame-support", - "parity-scale-codec", - "scale-info", -] - -[[package]] -name = "directories" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210" +name = "directories" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210" dependencies = [ "dirs-sys", ] @@ -2366,7 +2286,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.25", ] [[package]] @@ -2383,9 +2303,9 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "dtoa" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65d09067bfacaa79114679b279d7f5885b53295b1e2cfb4e79c8e4bd3d633169" +checksum = "519b83cd10f5f6e969625a409f735182bea5558cd8b64c655806ceaae36f1999" [[package]] name = "dyn-clonable" @@ -2420,10 +2340,24 @@ version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", + "der 0.6.1", + "elliptic-curve 0.12.3", + "rfc6979 0.3.1", + "signature 1.6.4", +] + +[[package]] +name = "ecdsa" +version = "0.16.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" +dependencies = [ + "der 0.7.7", + "digest 0.10.7", + "elliptic-curve 0.13.5", + "rfc6979 0.4.0", + "signature 2.1.0", + "spki 0.7.2", ] [[package]] @@ -2432,7 +2366,7 @@ version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ - "signature", + "signature 1.6.4", ] [[package]] @@ -2475,22 +2409,47 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" dependencies = [ - "base16ct", - "crypto-bigint", - "der", + "base16ct 0.1.1", + "crypto-bigint 0.4.9", + "der 0.6.1", "digest 0.10.7", - "ff", + "ff 0.12.1", "generic-array 0.14.7", - "group", + "group 0.12.1", "hkdf", "pem-rfc7468", - "pkcs8", + "pkcs8 0.9.0", + "rand_core 0.6.4", + "sec1 0.3.0", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +dependencies = [ + "base16ct 0.2.0", + "crypto-bigint 0.5.2", + "digest 0.10.7", + "ff 0.13.0", + "generic-array 0.14.7", + "group 0.13.0", + "pkcs8 0.10.2", "rand_core 0.6.4", - "sec1", + "sec1 0.7.2", "subtle", "zeroize", ] +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "enum-as-inner" version = "0.5.1" @@ -2520,18 +2479,18 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.25", ] [[package]] name = "enumn" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48016319042fb7c87b78d2993084a831793a897a5cd1a2a67cab9d1eeb4b7d76" +checksum = "c9838a970f5de399d3070ae1739e131986b2f5dcc223c7423ca0927e3a878522" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.25", ] [[package]] @@ -2566,6 +2525,12 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.1" @@ -2619,6 +2584,18 @@ name = "expander" version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3774182a5df13c3d1690311ad32fbe913feef26baba609fa2dd5f72042bd2ab6" +dependencies = [ + "blake2", + "fs-err", + "proc-macro2", + "quote", +] + +[[package]] +name = "expander" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f360349150728553f92e4c997a16af8915f418d3a0f21b440d34c5632f16ed84" dependencies = [ "blake2", "fs-err", @@ -2627,6 +2604,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "expander" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f86a749cf851891866c10515ef6c299b5c69661465e9c3bbe7e07a2b77fb0f7" +dependencies = [ + "blake2", + "fs-err", + "proc-macro2", + "quote", + "syn 2.0.25", +] + [[package]] name = "fake-simd" version = "0.1.2" @@ -2665,7 +2655,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5aa1e3ae159e592ad222dc90c5acbad632b527779ba88486abe92782ab268bd" dependencies = [ "expander 0.0.4", - "indexmap", + "indexmap 1.9.3", "proc-macro-crate", "proc-macro2", "quote", @@ -2692,6 +2682,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "fiat-crypto" version = "0.1.20" @@ -2762,7 +2762,7 @@ checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" dependencies = [ "crc32fast", "libz-sys", - "miniz_oxide 0.7.1", + "miniz_oxide", ] [[package]] @@ -2783,16 +2783,16 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", ] [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -2806,7 +2806,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-support-procedural", @@ -2831,7 +2831,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "Inflector", "array-bytes 4.2.0", @@ -2878,18 +2878,18 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.25", ] [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -2906,7 +2906,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -2935,15 +2935,19 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ + "async-recursion", "futures", + "indicatif", + "jsonrpsee", "log", "parity-scale-codec", "serde", "sp-core", "sp-io", "sp-runtime", + "spinners", "substrate-rpc-client", "tokio", ] @@ -2951,9 +2955,10 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ - "bitflags", + "bitflags 1.3.2", + "environmental", "frame-metadata", "frame-support-procedural", "impl-trait-for-tuples", @@ -2983,44 +2988,45 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "Inflector", "cfg-expr", "derive-syn-parse", "frame-support-procedural-tools", "itertools", + "proc-macro-warning", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.25", ] [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.25", ] [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.25", ] [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "log", @@ -3038,7 +3044,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -3053,7 +3059,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", "sp-api", @@ -3062,7 +3068,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "parity-scale-codec", @@ -3087,6 +3093,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "fs4" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eeb4ed9e12f43b7fa0baae3f9cdda28352770132ef2e09a23760c29cae8bd47" +dependencies = [ + "rustix 0.38.4", + "windows-sys 0.48.0", +] + [[package]] name = "funty" version = "2.0.0" @@ -3153,7 +3169,7 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", "waker-fn", ] @@ -3165,7 +3181,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.25", ] [[package]] @@ -3210,7 +3226,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", "pin-utils", "slab", ] @@ -3230,7 +3246,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" dependencies = [ - "typenum", + "typenum 1.16.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3239,8 +3255,9 @@ version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ - "typenum", + "typenum 1.16.0 (registry+https://github.com/rust-lang/crates.io-index)", "version_check", + "zeroize", ] [[package]] @@ -3266,9 +3283,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", @@ -3292,7 +3309,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" dependencies = [ "opaque-debug 0.3.0", - "polyval 0.6.0", + "polyval 0.6.1", ] [[package]] @@ -3302,15 +3319,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" dependencies = [ "fallible-iterator", - "indexmap", + "indexmap 1.9.3", "stable_deref_trait", ] [[package]] name = "gimli" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" [[package]] name = "glob" @@ -3320,12 +3337,12 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" +checksum = "1391ab1f92ffcc08911957149833e682aa3fe252b9f45f966d2ef972274c97df" dependencies = [ - "aho-corasick 0.7.20", - "bstr", + "aho-corasick", + "bstr 1.6.0", "fnv", "log", "regex", @@ -3337,16 +3354,27 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ - "ff", + "ff 0.12.1", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", "rand_core 0.6.4", "subtle", ] [[package]] name = "h2" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" dependencies = [ "bytes", "fnv", @@ -3354,7 +3382,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -3377,9 +3405,9 @@ dependencies = [ [[package]] name = "hash-db" -version = "0.15.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" +checksum = "8e7d7786361d7425ae2fe4f9e407eb0efaa0840f5212d109cc018c40c35c6ab4" [[package]] name = "hash256-std-hasher" @@ -3408,6 +3436,12 @@ dependencies = [ "ahash 0.8.3", ] +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + [[package]] name = "heck" version = "0.4.1" @@ -3425,18 +3459,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" @@ -3450,6 +3475,12 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + [[package]] name = "hkdf" version = "0.12.3" @@ -3529,7 +3560,7 @@ checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", ] [[package]] @@ -3558,9 +3589,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.26" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -3572,8 +3603,8 @@ dependencies = [ "httparse", "httpdate", "itoa", - "pin-project-lite 0.2.9", - "socket2", + "pin-project-lite 0.2.10", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -3593,13 +3624,14 @@ dependencies = [ "rustls-native-certs", "tokio", "tokio-rustls", + "webpki-roots", ] [[package]] name = "iana-time-zone" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -3637,9 +3669,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -3714,6 +3746,29 @@ dependencies = [ "serde", ] +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + +[[package]] +name = "indicatif" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ff8cc23a7393a397ed1d7f56e6365cba772aba9f9912ab968b03043c395d057" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", +] + [[package]] name = "inout" version = "0.1.3" @@ -3753,16 +3808,10 @@ version = "0.1.0" dependencies = [ "cumulus-pallet-xcm", "cumulus-primitives-core", - "did", - "dip-provider-runtime-template", - "dip-support", "frame-support", "frame-system", - "kilt-dip-support", - "kilt-support", "pallet-assets", "pallet-balances", - "pallet-did-lookup", "pallet-xcm", "parachain-info", "parity-scale-codec", @@ -3772,8 +3821,6 @@ dependencies = [ "polkadot-parachain", "polkadot-runtime", "polkadot-runtime-parachains", - "runtime-common 0.1.0", - "runtime-common 1.11.0-dev", "scale-info", "sp-core", "sp-io", @@ -3808,11 +3855,11 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi 0.3.2", "libc", "windows-sys 0.48.0", ] @@ -3825,31 +3872,30 @@ checksum = "aa2f047c0a98b2f299aa5d6d7088443570faae494e9ae1305e48be000c9e0eb1" [[package]] name = "ipconfig" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd302af1b90f2463a98fa5ad469fc212c8e3175a41c3068601bfa2727591c5be" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2", + "socket2 0.5.3", "widestring", - "winapi", + "windows-sys 0.48.0", "winreg", ] [[package]] name = "ipnet" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "is-terminal" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix 0.37.19", + "hermit-abi 0.3.2", + "rustix 0.38.4", "windows-sys 0.48.0", ] @@ -3864,9 +3910,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" [[package]] name = "jobserver" @@ -3879,9 +3925,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -3893,6 +3939,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d291e3a5818a2384645fd9756362e6d89cf0541b0b916fa7702ea4a9833608e" dependencies = [ "jsonrpsee-core", + "jsonrpsee-http-client", "jsonrpsee-proc-macros", "jsonrpsee-server", "jsonrpsee-types", @@ -3928,7 +3975,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4e70b4439a751a5de7dd5ed55eacff78ebf4ffe0fc009cb1ebb11417f5b536b" dependencies = [ "anyhow", - "arrayvec 0.7.2", + "arrayvec 0.7.4", "async-lock", "async-trait", "beef", @@ -3949,6 +3996,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "jsonrpsee-http-client" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc345b0a43c6bc49b947ebeb936e886a419ee3d894421790c969cc56040542ad" +dependencies = [ + "async-trait", + "hyper", + "hyper-rustls", + "jsonrpsee-core", + "jsonrpsee-types", + "rustc-hash", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "jsonrpsee-proc-macros" version = "0.16.2" @@ -4012,14 +4078,15 @@ dependencies = [ [[package]] name = "k256" -version = "0.11.6" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" dependencies = [ "cfg-if", - "ecdsa", - "elliptic-curve", - "sha2 0.10.6", + "ecdsa 0.16.7", + "elliptic-curve 0.13.5", + "once_cell", + "sha2 0.10.7", ] [[package]] @@ -4031,89 +4098,10 @@ dependencies = [ "cpufeatures", ] -[[package]] -name = "kilt-asset-dids" -version = "1.11.0-dev" -source = "git+https://github.com/KILTprotocol/kilt-node?branch=aa/dip#17c587e7cfd39e79ee06c7a568271ee8beecc505" -dependencies = [ - "base58", - "frame-support", - "hex", - "hex-literal", - "log", - "parity-scale-codec", - "scale-info", - "sp-core", - "sp-std", -] - -[[package]] -name = "kilt-dip-support" -version = "1.11.0-dev" -source = "git+https://github.com/KILTprotocol/kilt-node?branch=aa/dip#17c587e7cfd39e79ee06c7a568271ee8beecc505" -dependencies = [ - "did", - "frame-support", - "frame-system", - "pallet-dip-consumer", - "parity-scale-codec", - "scale-info", - "sp-core", - "sp-runtime", - "sp-std", - "sp-trie", -] - -[[package]] -name = "kilt-runtime-api-dip-provider" -version = "1.11.0-dev" -source = "git+https://github.com/KILTprotocol/kilt-node?branch=aa/dip#17c587e7cfd39e79ee06c7a568271ee8beecc505" -dependencies = [ - "parity-scale-codec", - "sp-api", -] - -[[package]] -name = "kilt-runtime-api-staking" -version = "0.1.0" -dependencies = [ - "parity-scale-codec", - "scale-info", - "sp-api", - "sp-runtime", -] - -[[package]] -name = "kilt-runtime-api-staking" -version = "1.11.0-dev" -source = "git+https://github.com/KILTprotocol/kilt-node?branch=aa/dip#17c587e7cfd39e79ee06c7a568271ee8beecc505" -dependencies = [ - "parity-scale-codec", - "scale-info", - "sp-api", - "sp-runtime", -] - -[[package]] -name = "kilt-support" -version = "1.11.0-dev" -source = "git+https://github.com/KILTprotocol/kilt-node?branch=aa/dip#17c587e7cfd39e79ee06c7a568271ee8beecc505" -dependencies = [ - "frame-support", - "frame-system", - "log", - "parity-scale-codec", - "scale-info", - "serde", - "sp-core", - "sp-runtime", - "sp-std", -] - [[package]] name = "kusama-runtime" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "bitvec", "frame-benchmarking", @@ -4124,7 +4112,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.4.1", "kusama-runtime-constants", "log", "pallet-authority-discovery", @@ -4186,9 +4174,9 @@ dependencies = [ "sp-api", "sp-arithmetic", "sp-authority-discovery", - "sp-beefy", "sp-block-builder", "sp-consensus-babe", + "sp-consensus-beefy", "sp-core", "sp-inherents", "sp-io", @@ -4210,8 +4198,8 @@ dependencies = [ [[package]] name = "kusama-runtime-constants" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "frame-support", "polkadot-primitives", @@ -4243,9 +4231,9 @@ dependencies = [ [[package]] name = "kvdb-rocksdb" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2182b8219fee6bd83aacaab7344e840179ae079d5216aa4e249b4d704646a844" +checksum = "fe7a749456510c45f795e8b04a6a3e0976d0139213ecbf465843830ad55e2217" dependencies = [ "kvdb", "num_cpus", @@ -4269,9 +4257,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libloading" @@ -4304,7 +4292,7 @@ dependencies = [ "bytes", "futures", "futures-timer", - "getrandom 0.2.9", + "getrandom 0.2.10", "instant", "libp2p-core 0.38.0", "libp2p-dns", @@ -4354,8 +4342,8 @@ dependencies = [ "prost-build", "rand 0.8.5", "rw-stream-sink", - "sec1", - "sha2 0.10.6", + "sec1 0.3.0", + "sha2 0.10.7", "smallvec", "thiserror", "unsigned-varint", @@ -4439,7 +4427,7 @@ dependencies = [ "multihash 0.17.0", "quick-protobuf", "rand 0.8.5", - "sha2 0.10.6", + "sha2 0.10.7", "thiserror", "zeroize", ] @@ -4450,7 +4438,7 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2766dcd2be8c87d5e1f35487deb22d765f49c6ae1251b3633efe3b25698bd3d2" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", "asynchronous-codec", "bytes", "either", @@ -4464,7 +4452,7 @@ dependencies = [ "prost", "prost-build", "rand 0.8.5", - "sha2 0.10.6", + "sha2 0.10.7", "smallvec", "thiserror", "uint", @@ -4486,7 +4474,7 @@ dependencies = [ "log", "rand 0.8.5", "smallvec", - "socket2", + "socket2 0.4.9", "tokio", "trust-dns-proto", "void", @@ -4539,7 +4527,7 @@ dependencies = [ "prost", "prost-build", "rand 0.8.5", - "sha2 0.10.6", + "sha2 0.10.7", "snow", "static_assertions", "thiserror", @@ -4647,7 +4635,7 @@ dependencies = [ "libc", "libp2p-core 0.38.0", "log", - "socket2", + "socket2 0.4.9", "tokio", ] @@ -4750,9 +4738,9 @@ dependencies = [ [[package]] name = "librocksdb-sys" -version = "0.8.3+7.4.4" +version = "0.10.0+7.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "557b255ff04123fcc176162f56ed0c9cd42d8f357cf55b3fabeb60f7413741b3" +checksum = "0fe4d5874f5ff2bc616e55e8c6086d478fcda13faf9495768a4aa1c22042d30b" dependencies = [ "bindgen", "bzip2-sys", @@ -4779,7 +4767,7 @@ dependencies = [ "rand 0.8.5", "serde", "sha2 0.9.9", - "typenum", + "typenum 1.16.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4824,9 +4812,9 @@ dependencies = [ [[package]] name = "link-cplusplus" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" dependencies = [ "cc", ] @@ -4848,9 +4836,9 @@ dependencies = [ [[package]] name = "linregress" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "475015a7f8f017edb28d2e69813be23500ad4b32cfe3421c4148efc97324ee52" +checksum = "4de0b5f52a9f84544d268f5fabb71b38962d6aa3c6600b8bcd27d44ccf9c9c45" dependencies = [ "nalgebra", ] @@ -4867,11 +4855,17 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +[[package]] +name = "linux-raw-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" + [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -4879,12 +4873,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "lru" @@ -4942,6 +4933,12 @@ dependencies = [ "libc", ] +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + [[package]] name = "match_cfg" version = "0.1.0" @@ -4954,7 +4951,7 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", ] [[package]] @@ -4994,7 +4991,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffc89ccdc6e10d6907450f753537ebc5c5d3460d2e4e62ea74bd571db62c0f9e" dependencies = [ - "rustix 0.37.19", + "rustix 0.37.23", ] [[package]] @@ -5017,30 +5014,20 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - -[[package]] -name = "memoffset" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ "autocfg", ] [[package]] name = "memory-db" -version = "0.31.0" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e0c7cba9ce19ac7ffd2053ac9f49843bbd3f4318feedfd74e85c19d5fb0ba66" +checksum = "808b50db46293432a45e63bc15ea51e0ab4c0a1647b8eb114e31a3e698dd6fbe" dependencies = [ "hash-db", - "hashbrown 0.12.3", ] [[package]] @@ -5078,15 +5065,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.7.1" @@ -5098,20 +5076,19 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "futures", "log", @@ -5119,9 +5096,9 @@ dependencies = [ "sc-client-api", "sc-offchain", "sp-api", - "sp-beefy", "sp-blockchain", "sp-consensus", + "sp-consensus-beefy", "sp-core", "sp-mmr-primitives", "sp-runtime", @@ -5130,7 +5107,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "anyhow", "jsonrpsee", @@ -5230,7 +5207,7 @@ dependencies = [ "core2", "digest 0.10.7", "multihash-derive", - "sha2 0.10.6", + "sha2 0.10.7", "sha3", "unsigned-varint", ] @@ -5282,9 +5259,9 @@ dependencies = [ [[package]] name = "nalgebra" -version = "0.32.2" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d68d47bba83f9e2006d117a9a33af1524e655516b8919caac694427a6fb1e511" +checksum = "307ed9b18cc2423f29e83f84fd23a8e73628727990181f18641a8b5dc2ab1caa" dependencies = [ "approx", "matrixmultiply", @@ -5293,14 +5270,14 @@ dependencies = [ "num-rational", "num-traits", "simba", - "typenum", + "typenum 1.16.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "nalgebra-macros" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d232c68884c0c99810a5a4d333ef7e47689cfd0edc85efc9e54e1e6bf5212766" +checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" dependencies = [ "proc-macro2", "quote", @@ -5341,7 +5318,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" dependencies = [ "anyhow", - "bitflags", + "bitflags 1.3.2", "byteorder", "libc", "netlink-packet-core", @@ -5394,26 +5371,12 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", "memoffset 0.6.5", ] -[[package]] -name = "nix" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" -dependencies = [ - "bitflags", - "cfg-if", - "libc", - "memoffset 0.7.1", - "pin-utils", - "static_assertions", -] - [[package]] name = "nohash-hasher" version = "0.2.0" @@ -5462,7 +5425,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", "itoa", ] @@ -5499,14 +5462,20 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi 0.3.2", "libc", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "object" version = "0.29.0" @@ -5515,15 +5484,15 @@ checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" dependencies = [ "crc32fast", "hashbrown 0.12.3", - "indexmap", + "indexmap 1.9.3", "memchr", ] [[package]] name = "object" -version = "0.30.3" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" dependencies = [ "memchr", ] @@ -5548,9 +5517,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "opaque-debug" @@ -5572,9 +5541,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "orchestra" -version = "0.0.4" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17e7d5b6bb115db09390bed8842c94180893dd83df3dfce7354f2a2aa090a4ee" +checksum = "227585216d05ba65c7ab0a0450a3cf2cbd81a98862a54c4df8e14d5ac6adb015" dependencies = [ "async-trait", "dyn-clonable", @@ -5589,9 +5558,9 @@ dependencies = [ [[package]] name = "orchestra-proc-macro" -version = "0.0.4" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2af4dabb2286b0be0e9711d2d24e25f6217048b71210cffd3daddc3b5c84e1f" +checksum = "2871aadd82a2c216ee68a69837a526dfe788ecbe74c4c5038a6acdbff6653066" dependencies = [ "expander 0.0.6", "itertools", @@ -5617,9 +5586,9 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" dependencies = [ - "ecdsa", - "elliptic-curve", - "sha2 0.10.6", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", + "sha2 0.10.7", ] [[package]] @@ -5628,9 +5597,9 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc8c5bf642dde52bb9e87c0ecd8ca5a76faac2eeed98dedb7c717997e1080aa" dependencies = [ - "ecdsa", - "elliptic-curve", - "sha2 0.10.6", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", + "sha2 0.10.7", ] [[package]] @@ -5643,41 +5612,10 @@ dependencies = [ "libm 0.1.4", ] -[[package]] -name = "pallet-asset-registry" -version = "0.0.1" -dependencies = [ - "cumulus-pallet-dmp-queue", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-core", - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-assets", - "pallet-balances", - "pallet-xcm", - "parachain-info", - "parachains-common", - "parity-scale-codec", - "polkadot-core-primitives", - "polkadot-parachain", - "polkadot-runtime-parachains", - "scale-info", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", - "xcm", - "xcm-builder", - "xcm-executor", - "xcm-primitives", - "xcm-simulator", -] - [[package]] name = "pallet-asset-tx-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -5695,7 +5633,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -5710,7 +5648,7 @@ dependencies = [ [[package]] name = "pallet-aura" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -5726,7 +5664,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -5742,7 +5680,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -5756,7 +5694,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -5769,7 +5707,7 @@ dependencies = [ "scale-info", "sp-application-crypto", "sp-consensus-babe", - "sp-consensus-vrf", + "sp-core", "sp-io", "sp-runtime", "sp-session", @@ -5780,7 +5718,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5800,7 +5738,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -5815,7 +5753,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -5824,7 +5762,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-beefy", + "sp-consensus-beefy", "sp-runtime", "sp-session", "sp-staking", @@ -5834,7 +5772,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "array-bytes 4.2.0", "binary-merkle-tree", @@ -5848,7 +5786,7 @@ dependencies = [ "scale-info", "serde", "sp-api", - "sp-beefy", + "sp-consensus-beefy", "sp-core", "sp-io", "sp-runtime", @@ -5858,7 +5796,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -5876,7 +5814,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -5895,7 +5833,7 @@ dependencies = [ [[package]] name = "pallet-collator-selection" version = "3.0.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "frame-benchmarking", "frame-support", @@ -5914,7 +5852,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -5931,7 +5869,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "assert_matches", "frame-benchmarking", @@ -5945,98 +5883,28 @@ dependencies = [ "sp-std", ] -[[package]] -name = "pallet-credentials" -version = "0.1.0" -dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "pallet-balances", - "parity-scale-codec", - "polimec-traits", - "scale-info", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", -] - [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" -dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "log", - "parity-scale-codec", - "scale-info", - "serde", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "pallet-did-lookup" -version = "1.11.0-dev" -source = "git+https://github.com/KILTprotocol/kilt-node?branch=aa/dip#17c587e7cfd39e79ee06c7a568271ee8beecc505" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ - "base58", - "blake2", "frame-benchmarking", "frame-support", "frame-system", - "hex", - "kilt-support", - "libsecp256k1", "log", "parity-scale-codec", "scale-info", "serde", - "sha3", "sp-core", "sp-io", "sp-runtime", "sp-std", ] -[[package]] -name = "pallet-dip-consumer" -version = "1.11.0-dev" -source = "git+https://github.com/KILTprotocol/kilt-node?branch=aa/dip#17c587e7cfd39e79ee06c7a568271ee8beecc505" -dependencies = [ - "cumulus-pallet-xcm", - "dip-support", - "frame-support", - "frame-system", - "kilt-support", - "parity-scale-codec", - "scale-info", - "sp-std", -] - -[[package]] -name = "pallet-dip-provider" -version = "1.11.0-dev" -source = "git+https://github.com/KILTprotocol/kilt-node?branch=aa/dip#17c587e7cfd39e79ee06c7a568271ee8beecc505" -dependencies = [ - "dip-support", - "frame-support", - "frame-system", - "parity-scale-codec", - "scale-info", - "sp-std", - "xcm", -] - [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6059,7 +5927,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6072,7 +5940,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6090,7 +5958,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6114,10 +5982,8 @@ dependencies = [ "frame-system", "pallet-assets", "pallet-balances", - "pallet-credentials", "pallet-insecure-randomness-collective-flip", "parity-scale-codec", - "polimec-traits", "scale-info", "sp-arithmetic", "sp-core", @@ -6129,7 +5995,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6140,8 +6006,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-application-crypto", + "sp-consensus-grandpa", "sp-core", - "sp-finality-grandpa", "sp-io", "sp-runtime", "sp-session", @@ -6152,7 +6018,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6168,7 +6034,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6188,7 +6054,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6205,7 +6071,7 @@ dependencies = [ [[package]] name = "pallet-insecure-randomness-collective-flip" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -6219,7 +6085,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6236,7 +6102,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6253,7 +6119,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6269,7 +6135,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6285,7 +6151,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -6302,7 +6168,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6322,7 +6188,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -6333,7 +6199,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -6350,7 +6216,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6371,10 +6237,36 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-parachain-staking" +version = "0.1.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-aura", + "pallet-authorship", + "pallet-balances", + "pallet-session", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "serde", + "similar-asserts", + "sp-consensus-aura", + "sp-core", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std", + "substrate-fixed", +] + [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6391,7 +6283,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6406,7 +6298,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6424,7 +6316,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6439,7 +6331,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6464,12 +6356,10 @@ dependencies = [ "frame-system", "pallet-assets", "pallet-balances", - "pallet-credentials", "pallet-funding", "pallet-insecure-randomness-collective-flip", "parachains-common", "parity-scale-codec", - "polimec-traits", "scale-info", "serde", "sp-arithmetic", @@ -6482,7 +6372,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6499,7 +6389,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -6520,7 +6410,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6536,7 +6426,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -6550,7 +6440,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6573,18 +6463,18 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.25", ] [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "log", "sp-arithmetic", @@ -6593,7 +6483,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", "sp-api", @@ -6602,7 +6492,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6619,7 +6509,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -6633,7 +6523,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6651,7 +6541,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6670,7 +6560,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-support", "frame-system", @@ -6686,7 +6576,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -6702,7 +6592,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -6714,7 +6604,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6731,7 +6621,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6746,7 +6636,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6762,7 +6652,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6774,24 +6664,10 @@ dependencies = [ "sp-std", ] -[[package]] -name = "pallet-web3-names" -version = "1.11.0-dev" -source = "git+https://github.com/KILTprotocol/kilt-node?branch=aa/dip#17c587e7cfd39e79ee06c7a568271ee8beecc505" -dependencies = [ - "frame-support", - "frame-system", - "kilt-support", - "parity-scale-codec", - "scale-info", - "sp-runtime", - "sp-std", -] - [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-benchmarking", "frame-support", @@ -6805,8 +6681,8 @@ dependencies = [ [[package]] name = "pallet-xcm" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "bounded-collections", "frame-benchmarking", @@ -6826,8 +6702,8 @@ dependencies = [ [[package]] name = "pallet-xcm-benchmarks" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "frame-benchmarking", "frame-support", @@ -6846,7 +6722,7 @@ dependencies = [ [[package]] name = "parachain-info" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -6855,57 +6731,10 @@ dependencies = [ "scale-info", ] -[[package]] -name = "parachain-staking" -version = "1.9.0-dev" -dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "kilt-runtime-api-staking 0.1.0", - "log", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-session", - "pallet-timestamp", - "parity-scale-codec", - "scale-info", - "serde", - "sp-consensus-aura", - "sp-core", - "sp-io", - "sp-runtime", - "sp-staking", - "sp-std", -] - -[[package]] -name = "parachain-staking" -version = "1.11.0-dev" -source = "git+https://github.com/KILTprotocol/kilt-node?branch=aa/dip#17c587e7cfd39e79ee06c7a568271ee8beecc505" -dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "kilt-runtime-api-staking 1.11.0-dev", - "kilt-support", - "log", - "pallet-authorship", - "pallet-balances", - "pallet-session", - "parity-scale-codec", - "scale-info", - "serde", - "sp-runtime", - "sp-staking", - "sp-std", -] - [[package]] name = "parachains-common" version = "1.0.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ "cumulus-primitives-utility", "frame-support", @@ -6931,9 +6760,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4890dcb9556136a4ec2b0c51fa4a08c8b733b829506af8fff2e853f3a065985b" +checksum = "0dab3ac198341b2f0fec6e7f8a6eeed07a41201d98a124260611598c142e76df" dependencies = [ "blake2", "crc32fast", @@ -6951,11 +6780,11 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.5.0" +version = "3.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ddb756ca205bd108aee3c62c6d3c994e1df84a59b9d6d4a5ea42ee1fd5a9a28" +checksum = "756d439303e94fae44f288ba881ad29670c65b0c4b0e05674ca81061bb65f2c5" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", "bitvec", "byte-slice-cast", "bytes", @@ -6966,9 +6795,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.1.4" +version = "3.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" +checksum = "9d884d78fcf214d70b1e239fcd1c6e5e95aa3be1881918da2e488cc946c7a476" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -7012,7 +6841,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.7", + "parking_lot_core 0.9.8", ] [[package]] @@ -7031,22 +6860,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall 0.3.5", "smallvec", - "windows-sys 0.45.0", + "windows-targets 0.48.1", ] [[package]] name = "paste" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" [[package]] name = "pbkdf2" @@ -7110,7 +6939,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.3.4", "log", "pallet-asset-tx-payment", "pallet-assets", @@ -7151,15 +6980,15 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e68e84bfb01f0507134eac1e9b410a12ba379d064eab48c50ba4ce329a527b70" +checksum = "f73935e4d55e2abf7f130186537b19e7a4abc886a0252380b59248af473a3fc9" dependencies = [ "thiserror", "ucd-trie", @@ -7167,9 +6996,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b79d4c71c865a25a4322296122e3924d30bc8ee0834c8bfc8b95f7f054afbfb" +checksum = "aef623c9bbfa0eedf5a0efba11a5ee83209c326653ca31ff019bec3a95bfff2b" dependencies = [ "pest", "pest_generator", @@ -7177,26 +7006,26 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c435bf1076437b851ebc8edc3a18442796b30f1728ffea6262d59bbe28b077e" +checksum = "b3e8cba4ec22bada7fc55ffe51e2deb6a0e0db2d0b7ab0b103acc80d2510c190" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.25", ] [[package]] name = "pest_meta" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "745a452f8eb71e39ffd8ee32b3c5f51d03845f99786fa9b68db6ff509c505411" +checksum = "a01f71cb40bd8bb94232df14b946909e14660e33fc05db3e50ae2a82d7ea0ca0" dependencies = [ "once_cell", "pest", - "sha2 0.10.6", + "sha2 0.10.7", ] [[package]] @@ -7206,27 +7035,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", - "indexmap", + "indexmap 1.9.3", ] [[package]] name = "pin-project" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.25", ] [[package]] @@ -7237,9 +7066,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" [[package]] name = "pin-utils" @@ -7253,8 +7082,18 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" dependencies = [ - "der", - "spki", + "der 0.6.1", + "spki 0.6.0", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der 0.7.7", + "spki 0.7.2", ] [[package]] @@ -7295,11 +7134,12 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.3.4", "log", "pallet-aura", "pallet-authorship", "pallet-balances", + "pallet-parachain-staking", "pallet-session", "pallet-sudo", "pallet-timestamp", @@ -7308,16 +7148,16 @@ dependencies = [ "pallet-treasury", "pallet-xcm", "parachain-info", - "parachain-staking 1.9.0-dev", "parachains-common", "parity-scale-codec", "polkadot-parachain", "polkadot-primitives", "polkadot-runtime-common", - "runtime-common 0.1.0", "scale-info", + "shared-configuration", "smallvec", "sp-api", + "sp-arithmetic", "sp-block-builder", "sp-consensus-aura", "sp-core", @@ -7351,6 +7191,7 @@ dependencies = [ "cumulus-relay-chain-minimal-node", "frame-benchmarking", "frame-benchmarking-cli", + "hex-literal 0.3.4", "jsonrpsee", "log", "pallet-transaction-payment-rpc", @@ -7368,6 +7209,7 @@ dependencies = [ "sc-executor", "sc-network", "sc-network-common", + "sc-network-sync", "sc-rpc", "sc-rpc-api", "sc-service", @@ -7410,7 +7252,6 @@ dependencies = [ "cumulus-primitives-core", "cumulus-primitives-timestamp", "cumulus-primitives-utility", - "did", "frame-benchmarking", "frame-executive", "frame-support", @@ -7418,23 +7259,19 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", - "kilt-dip-support", + "hex-literal 0.3.4", "log", - "pallet-asset-registry", "pallet-asset-tx-payment", "pallet-assets", "pallet-aura", "pallet-authorship", "pallet-balances", "pallet-collective", - "pallet-credentials", "pallet-democracy", - "pallet-did-lookup", - "pallet-dip-consumer", "pallet-funding", "pallet-insecure-randomness-collective-flip", "pallet-multisig", + "pallet-parachain-staking", "pallet-preimage", "pallet-scheduler", "pallet-session", @@ -7447,16 +7284,14 @@ dependencies = [ "pallet-vesting", "pallet-xcm", "parachain-info", - "parachain-staking 1.9.0-dev", "parachains-common", "parity-scale-codec", - "polimec-traits", "polkadot-parachain", "polkadot-primitives", "polkadot-runtime-common", - "runtime-common 0.1.0", "scale-info", "serde", + "shared-configuration", "smallvec", "sp-api", "sp-block-builder", @@ -7474,7 +7309,6 @@ dependencies = [ "xcm", "xcm-builder", "xcm-executor", - "xcm-primitives", ] [[package]] @@ -7496,8 +7330,8 @@ dependencies = [ "sc-client-api", "sc-consensus", "sc-consensus-aura", + "sc-consensus-grandpa", "sc-executor", - "sc-finality-grandpa", "sc-keystore", "sc-rpc", "sc-rpc-api", @@ -7511,8 +7345,8 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-consensus-aura", + "sp-consensus-grandpa", "sp-core", - "sp-finality-grandpa", "sp-inherents", "sp-keyring", "sp-runtime", @@ -7533,13 +7367,12 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.3.4", "pallet-assets", "pallet-aura", "pallet-authorship", "pallet-balances", "pallet-collective", - "pallet-credentials", "pallet-democracy", "pallet-funding", "pallet-grandpa", @@ -7555,12 +7388,12 @@ dependencies = [ "pallet-utility", "pallet-vesting", "parity-scale-codec", - "polimec-traits", - "runtime-common 0.1.0", "scale-info", + "shared-configuration", "sp-api", "sp-block-builder", "sp-consensus-aura", + "sp-consensus-grandpa", "sp-core", "sp-inherents", "sp-offchain", @@ -7572,28 +7405,13 @@ dependencies = [ "substrate-wasm-builder", ] -[[package]] -name = "polimec-traits" -version = "0.1.0" -dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", - "parity-scale-codec", - "scale-info", - "serde", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", -] - [[package]] name = "polkadot-approval-distribution" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "futures", + "polkadot-node-jaeger", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -7605,8 +7423,8 @@ dependencies = [ [[package]] name = "polkadot-availability-bitfield-distribution" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "futures", "polkadot-node-network-protocol", @@ -7619,8 +7437,8 @@ dependencies = [ [[package]] name = "polkadot-availability-distribution" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "derive_more", "fatality", @@ -7642,8 +7460,8 @@ dependencies = [ [[package]] name = "polkadot-availability-recovery" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "fatality", "futures", @@ -7663,15 +7481,15 @@ dependencies = [ [[package]] name = "polkadot-cli" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "clap", "frame-benchmarking-cli", "futures", "log", "polkadot-client", - "polkadot-node-core-pvf", + "polkadot-node-core-pvf-worker", "polkadot-node-metrics", "polkadot-performance-test", "polkadot-service", @@ -7684,6 +7502,7 @@ dependencies = [ "sp-core", "sp-io", "sp-keyring", + "sp-maybe-compressed-blob", "substrate-build-script-utils", "thiserror", "try-runtime-cli", @@ -7691,8 +7510,8 @@ dependencies = [ [[package]] name = "polkadot-client" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "async-trait", "frame-benchmarking", @@ -7713,13 +7532,13 @@ dependencies = [ "sc-service", "sp-api", "sp-authority-discovery", - "sp-beefy", "sp-block-builder", "sp-blockchain", "sp-consensus", "sp-consensus-babe", + "sp-consensus-beefy", + "sp-consensus-grandpa", "sp-core", - "sp-finality-grandpa", "sp-inherents", "sp-keyring", "sp-mmr-primitives", @@ -7733,8 +7552,8 @@ dependencies = [ [[package]] name = "polkadot-collator-protocol" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "always-assert", "bitvec", @@ -7755,8 +7574,8 @@ dependencies = [ [[package]] name = "polkadot-core-primitives" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "parity-scale-codec", "scale-info", @@ -7767,14 +7586,14 @@ dependencies = [ [[package]] name = "polkadot-dispute-distribution" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "derive_more", "fatality", "futures", "futures-timer", - "indexmap", + "indexmap 1.9.3", "lru 0.9.0", "parity-scale-codec", "polkadot-erasure-coding", @@ -7792,8 +7611,8 @@ dependencies = [ [[package]] name = "polkadot-erasure-coding" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "parity-scale-codec", "polkadot-node-primitives", @@ -7806,8 +7625,8 @@ dependencies = [ [[package]] name = "polkadot-gossip-support" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "futures", "futures-timer", @@ -7826,8 +7645,8 @@ dependencies = [ [[package]] name = "polkadot-network-bridge" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "always-assert", "async-trait", @@ -7842,7 +7661,6 @@ dependencies = [ "polkadot-overseer", "polkadot-primitives", "sc-network", - "sc-network-common", "sp-consensus", "thiserror", "tracing-gum", @@ -7850,8 +7668,8 @@ dependencies = [ [[package]] name = "polkadot-node-collation-generation" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "futures", "parity-scale-codec", @@ -7868,8 +7686,8 @@ dependencies = [ [[package]] name = "polkadot-node-core-approval-voting" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "bitvec", "derive_more", @@ -7897,8 +7715,8 @@ dependencies = [ [[package]] name = "polkadot-node-core-av-store" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "bitvec", "futures", @@ -7918,8 +7736,8 @@ dependencies = [ [[package]] name = "polkadot-node-core-backing" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "bitvec", "fatality", @@ -7937,8 +7755,8 @@ dependencies = [ [[package]] name = "polkadot-node-core-bitfield-signing" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "futures", "polkadot-node-subsystem", @@ -7952,8 +7770,8 @@ dependencies = [ [[package]] name = "polkadot-node-core-candidate-validation" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "async-trait", "futures", @@ -7972,8 +7790,8 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-api" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "futures", "polkadot-node-metrics", @@ -7987,8 +7805,8 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-selection" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "futures", "futures-timer", @@ -8004,8 +7822,8 @@ dependencies = [ [[package]] name = "polkadot-node-core-dispute-coordinator" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "fatality", "futures", @@ -8023,8 +7841,8 @@ dependencies = [ [[package]] name = "polkadot-node-core-parachains-inherent" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "async-trait", "futures", @@ -8040,8 +7858,8 @@ dependencies = [ [[package]] name = "polkadot-node-core-provisioner" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "bitvec", "fatality", @@ -8058,12 +7876,10 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "always-assert", - "assert_matches", - "cpu-time", "futures", "futures-timer", "libc", @@ -8075,27 +7891,20 @@ dependencies = [ "polkadot-parachain", "polkadot-primitives", "rand 0.8.5", - "rayon", - "sc-executor", - "sc-executor-common", - "sc-executor-wasmtime", "slotmap", "sp-core", - "sp-externalities", - "sp-io", "sp-maybe-compressed-blob", "sp-tracing", "sp-wasm-interface", - "tempfile", - "tikv-jemalloc-ctl", + "substrate-build-script-utils", "tokio", "tracing-gum", ] [[package]] name = "polkadot-node-core-pvf-checker" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "futures", "polkadot-node-primitives", @@ -8108,10 +7917,39 @@ dependencies = [ "tracing-gum", ] +[[package]] +name = "polkadot-node-core-pvf-worker" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" +dependencies = [ + "assert_matches", + "cpu-time", + "futures", + "libc", + "parity-scale-codec", + "polkadot-node-core-pvf", + "polkadot-parachain", + "polkadot-primitives", + "rayon", + "sc-executor", + "sc-executor-common", + "sc-executor-wasmtime", + "sp-core", + "sp-externalities", + "sp-io", + "sp-maybe-compressed-blob", + "sp-tracing", + "substrate-build-script-utils", + "tempfile", + "tikv-jemalloc-ctl", + "tokio", + "tracing-gum", +] + [[package]] name = "polkadot-node-core-runtime-api" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "futures", "lru 0.9.0", @@ -8125,8 +7963,8 @@ dependencies = [ [[package]] name = "polkadot-node-jaeger" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "lazy_static", "log", @@ -8143,8 +7981,8 @@ dependencies = [ [[package]] name = "polkadot-node-metrics" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "bs58", "futures", @@ -8162,8 +8000,8 @@ dependencies = [ [[package]] name = "polkadot-node-network-protocol" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "async-trait", "derive_more", @@ -8177,7 +8015,6 @@ dependencies = [ "rand 0.8.5", "sc-authority-discovery", "sc-network", - "sc-network-common", "strum", "thiserror", "tracing-gum", @@ -8185,8 +8022,8 @@ dependencies = [ [[package]] name = "polkadot-node-primitives" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "bounded-vec", "futures", @@ -8197,19 +8034,18 @@ dependencies = [ "serde", "sp-application-crypto", "sp-consensus-babe", - "sp-consensus-vrf", "sp-core", "sp-keystore", "sp-maybe-compressed-blob", "sp-runtime", "thiserror", - "zstd", + "zstd 0.11.2+zstd.1.5.2", ] [[package]] name = "polkadot-node-subsystem" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "polkadot-node-jaeger", "polkadot-node-subsystem-types", @@ -8218,8 +8054,8 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-types" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "async-trait", "derive_more", @@ -8241,8 +8077,8 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-util" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "async-trait", "derive_more", @@ -8274,8 +8110,8 @@ dependencies = [ [[package]] name = "polkadot-overseer" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "async-trait", "futures", @@ -8297,8 +8133,8 @@ dependencies = [ [[package]] name = "polkadot-parachain" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "bounded-collections", "derive_more", @@ -8314,27 +8150,29 @@ dependencies = [ [[package]] name = "polkadot-performance-test" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "env_logger 0.9.3", "kusama-runtime", "log", "polkadot-erasure-coding", - "polkadot-node-core-pvf", + "polkadot-node-core-pvf-worker", "polkadot-node-primitives", "polkadot-primitives", "quote", + "sc-executor-common", + "sp-maybe-compressed-blob", "thiserror", ] [[package]] name = "polkadot-primitives" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "bitvec", - "hex-literal", + "hex-literal 0.4.1", "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain", @@ -8356,11 +8194,9 @@ dependencies = [ [[package]] name = "polkadot-rpc" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ - "beefy-gadget", - "beefy-gadget-rpc", "jsonrpsee", "mmr-rpc", "pallet-transaction-payment-rpc", @@ -8369,9 +8205,11 @@ dependencies = [ "sc-client-api", "sc-consensus-babe", "sc-consensus-babe-rpc", + "sc-consensus-beefy", + "sc-consensus-beefy-rpc", "sc-consensus-epochs", - "sc-finality-grandpa", - "sc-finality-grandpa-rpc", + "sc-consensus-grandpa", + "sc-consensus-grandpa-rpc", "sc-rpc", "sc-sync-state-rpc", "sc-transaction-pool-api", @@ -8388,8 +8226,8 @@ dependencies = [ [[package]] name = "polkadot-runtime" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "bitvec", "frame-benchmarking", @@ -8400,7 +8238,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.4.1", "log", "pallet-authority-discovery", "pallet-authorship", @@ -8410,6 +8248,7 @@ dependencies = [ "pallet-bounties", "pallet-child-bounties", "pallet-collective", + "pallet-conviction-voting", "pallet-democracy", "pallet-election-provider-multi-phase", "pallet-election-provider-support-benchmarking", @@ -8428,6 +8267,7 @@ dependencies = [ "pallet-offences-benchmarking", "pallet-preimage", "pallet-proxy", + "pallet-referenda", "pallet-scheduler", "pallet-session", "pallet-session-benchmarking", @@ -8441,6 +8281,7 @@ dependencies = [ "pallet-treasury", "pallet-utility", "pallet-vesting", + "pallet-whitelist", "pallet-xcm", "parity-scale-codec", "polkadot-primitives", @@ -8453,10 +8294,11 @@ dependencies = [ "serde_derive", "smallvec", "sp-api", + "sp-arithmetic", "sp-authority-discovery", - "sp-beefy", "sp-block-builder", "sp-consensus-babe", + "sp-consensus-beefy", "sp-core", "sp-inherents", "sp-io", @@ -8478,8 +8320,8 @@ dependencies = [ [[package]] name = "polkadot-runtime-common" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "bitvec", "frame-benchmarking", @@ -8492,7 +8334,6 @@ dependencies = [ "pallet-authorship", "pallet-babe", "pallet-balances", - "pallet-beefy-mmr", "pallet-election-provider-multi-phase", "pallet-fast-unstake", "pallet-session", @@ -8511,7 +8352,6 @@ dependencies = [ "serde_derive", "slot-range-helper", "sp-api", - "sp-beefy", "sp-core", "sp-inherents", "sp-io", @@ -8526,8 +8366,8 @@ dependencies = [ [[package]] name = "polkadot-runtime-constants" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "frame-support", "polkadot-primitives", @@ -8540,8 +8380,8 @@ dependencies = [ [[package]] name = "polkadot-runtime-metrics" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "bs58", "parity-scale-codec", @@ -8552,10 +8392,10 @@ dependencies = [ [[package]] name = "polkadot-runtime-parachains" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ - "bitflags", + "bitflags 1.3.2", "bitvec", "derive_more", "frame-benchmarking", @@ -8596,16 +8436,15 @@ dependencies = [ [[package]] name = "polkadot-service" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "async-trait", - "beefy-gadget", "frame-benchmarking-cli", "frame-support", "frame-system-rpc-runtime-api", "futures", - "hex-literal", + "hex-literal 0.4.1", "kusama-runtime", "kvdb", "kvdb-rocksdb", @@ -8661,12 +8500,14 @@ dependencies = [ "sc-client-db", "sc-consensus", "sc-consensus-babe", + "sc-consensus-beefy", + "sc-consensus-grandpa", "sc-consensus-slots", "sc-executor", - "sc-finality-grandpa", "sc-keystore", "sc-network", "sc-network-common", + "sc-network-sync", "sc-offchain", "sc-service", "sc-sync-state-rpc", @@ -8677,13 +8518,13 @@ dependencies = [ "serde_json", "sp-api", "sp-authority-discovery", - "sp-beefy", "sp-block-builder", "sp-blockchain", "sp-consensus", "sp-consensus-babe", + "sp-consensus-beefy", + "sp-consensus-grandpa", "sp-core", - "sp-finality-grandpa", "sp-inherents", "sp-io", "sp-keystore", @@ -8704,13 +8545,13 @@ dependencies = [ [[package]] name = "polkadot-statement-distribution" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "arrayvec 0.5.2", "fatality", "futures", - "indexmap", + "indexmap 1.9.3", "parity-scale-codec", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -8725,8 +8566,8 @@ dependencies = [ [[package]] name = "polkadot-statement-table" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "parity-scale-codec", "polkadot-primitives", @@ -8740,12 +8581,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ "autocfg", - "bitflags", + "bitflags 1.3.2", "cfg-if", "concurrent-queue", "libc", "log", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", "windows-sys 0.48.0", ] @@ -8774,9 +8615,9 @@ dependencies = [ [[package]] name = "polyval" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef234e08c11dfcb2e56f79fd70f6f2eb7f025c0ce2333e82f4f0518ecad30c6" +checksum = "d52cff9d1d4dee5fe6d03729099f4a310a41179e0a10dbf542039873f2e826fb" dependencies = [ "cfg-if", "cpufeatures", @@ -8784,6 +8625,12 @@ dependencies = [ "universal-hash 0.5.1", ] +[[package]] +name = "portable-atomic" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d220334a184db82b31b83f5ff093e3315280fb2b6bbc032022b2304a509aab7a" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -8893,11 +8740,22 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-warning" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e99670bafb56b9a106419397343bdbc8b8742c3cc449fec6345f86173f47cd4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.25", +] + [[package]] name = "proc-macro2" -version = "1.0.58" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" +checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" dependencies = [ "unicode-ident", ] @@ -9015,24 +8873,6 @@ dependencies = [ "cc", ] -[[package]] -name = "public-credentials" -version = "1.11.0-dev" -source = "git+https://github.com/KILTprotocol/kilt-node?branch=aa/dip#17c587e7cfd39e79ee06c7a568271ee8beecc505" -dependencies = [ - "ctype", - "frame-benchmarking", - "frame-support", - "frame-system", - "kilt-support", - "parity-scale-codec", - "scale-info", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", -] - [[package]] name = "quick-error" version = "1.2.3" @@ -9079,9 +8919,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.27" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] @@ -9151,7 +8991,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.10", ] [[package]] @@ -9208,7 +9048,7 @@ checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" dependencies = [ "pem", "ring", - "time 0.3.21", + "time 0.3.23", "x509-parser 0.13.2", "yasna", ] @@ -9221,7 +9061,7 @@ checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", "ring", - "time 0.3.21", + "time 0.3.23", "yasna", ] @@ -9231,7 +9071,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -9240,7 +9080,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -9249,7 +9089,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.10", "redox_syscall 0.2.16", "thiserror", ] @@ -9269,22 +9109,22 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.16" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43faa91b1c8b36841ee70e97188a869d37ae21759da6846d4be66de5bf7b12c" +checksum = "1641819477c319ef452a075ac34a4be92eb9ba09f6841f62d594d50fdcf0bf6b" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.16" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d2275aab483050ab2a7364c1a46604865ee7d6906684e08db0f090acf74f9e7" +checksum = "68bf53dad9b6086826722cdc99140793afd9f62faa14a1ad07eb4f955e7a7216" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.25", ] [[package]] @@ -9301,13 +9141,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.2" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1a59b5d8e97dee33696bf13c5ba8ab85341c002922fba050069326b9c498974" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ - "aho-corasick 1.0.1", + "aho-corasick", "memchr", - "regex-syntax 0.7.2", + "regex-automata 0.3.3", + "regex-syntax 0.7.4", ] [[package]] @@ -9319,6 +9160,17 @@ dependencies = [ "regex-syntax 0.6.29", ] +[[package]] +name = "regex-automata" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.4", +] + [[package]] name = "regex-syntax" version = "0.6.29" @@ -9327,9 +9179,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "region" @@ -9337,7 +9189,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", "mach", "winapi", @@ -9359,11 +9211,21 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" dependencies = [ - "crypto-bigint", + "crypto-bigint 0.4.9", "hmac 0.12.1", "zeroize", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + [[package]] name = "ring" version = "0.16.20" @@ -9381,9 +9243,9 @@ dependencies = [ [[package]] name = "rocksdb" -version = "0.19.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9562ea1d70c0cc63a34a22d977753b50cca91cc6b6527750463bd5dd8697bc" +checksum = "015439787fce1e75d55f279078d33ff14b4af5d93d995e8838ee4631301c8a99" dependencies = [ "libc", "librocksdb-sys", @@ -9391,8 +9253,8 @@ dependencies = [ [[package]] name = "rococo-runtime" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "binary-merkle-tree", "frame-benchmarking", @@ -9402,7 +9264,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.4.1", "log", "pallet-authority-discovery", "pallet-authorship", @@ -9454,9 +9316,9 @@ dependencies = [ "smallvec", "sp-api", "sp-authority-discovery", - "sp-beefy", "sp-block-builder", "sp-consensus-babe", + "sp-consensus-beefy", "sp-core", "sp-inherents", "sp-io", @@ -9477,8 +9339,8 @@ dependencies = [ [[package]] name = "rococo-runtime-constants" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "frame-support", "polkadot-primitives", @@ -9521,7 +9383,7 @@ dependencies = [ "log", "netlink-packet-route", "netlink-proto", - "nix 0.24.3", + "nix", "thiserror", "tokio", ] @@ -9550,79 +9412,6 @@ dependencies = [ "webrtc-util", ] -[[package]] -name = "runtime-common" -version = "0.1.0" -dependencies = [ - "cumulus-primitives-core", - "did", - "dip-support", - "frame-support", - "frame-system", - "log", - "pallet-authorship", - "pallet-balances", - "pallet-did-lookup", - "pallet-dip-consumer", - "pallet-dip-provider", - "pallet-membership", - "pallet-transaction-payment", - "parachain-staking 1.9.0-dev", - "parachains-common", - "parity-scale-codec", - "polkadot-parachain", - "scale-info", - "smallvec", - "sp-consensus-aura", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", - "sp-trie", - "xcm", - "xcm-builder", - "xcm-executor", -] - -[[package]] -name = "runtime-common" -version = "1.11.0-dev" -source = "git+https://github.com/KILTprotocol/kilt-node?branch=aa/dip#17c587e7cfd39e79ee06c7a568271ee8beecc505" -dependencies = [ - "attestation", - "ctype", - "cumulus-primitives-core", - "did", - "frame-support", - "frame-system", - "kilt-asset-dids", - "kilt-dip-support", - "kilt-support", - "log", - "pallet-authorship", - "pallet-balances", - "pallet-dip-consumer", - "pallet-dip-provider", - "pallet-membership", - "pallet-transaction-payment", - "pallet-web3-names", - "parachain-staking 1.11.0-dev", - "parity-scale-codec", - "polkadot-parachain", - "public-credentials", - "scale-info", - "smallvec", - "sp-consensus-aura", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std", - "sp-trie", - "xcm", - "xcm-builder", - "xcm-executor", -] - [[package]] name = "rustc-demangle" version = "0.1.23" @@ -9670,11 +9459,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.14" +version = "0.36.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14e4d67015953998ad0eb82887a0eb0129e18a7e2f3b7b0f6c422fddcd503d62" +checksum = "c37f1bd5ef1b5422177b7646cba67430579cfe2ace80f284fee876bca52ad941" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", @@ -9684,11 +9473,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.19" +version = "0.37.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", @@ -9696,6 +9485,19 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "rustix" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +dependencies = [ + "bitflags 2.3.3", + "errno", + "libc", + "linux-raw-sys 0.4.3", + "windows-sys 0.48.0", +] + [[package]] name = "rustls" version = "0.19.1" @@ -9723,9 +9525,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", "rustls-pemfile", @@ -9735,18 +9537,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.1", + "base64 0.21.2", ] [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "dc31bd9b61a32c31f9650d18add92aa83a49ba979c143eefd27fe7177b05bd5f" [[package]] name = "rw-stream-sink" @@ -9761,9 +9563,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" [[package]] name = "safe-mix" @@ -9776,9 +9578,9 @@ dependencies = [ [[package]] name = "safe_arch" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794821e4ccb0d9f979512f9c1973480123f9bd62a90d74ab0f9426fcf8f4a529" +checksum = "62a7484307bd40f8f7ccbacccac730108f2cae119a3b11c74485b48aa9ea650f" dependencies = [ "bytemuck", ] @@ -9795,7 +9597,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "log", "sp-core", @@ -9806,7 +9608,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "async-trait", "futures", @@ -9819,6 +9621,7 @@ dependencies = [ "prost-build", "rand 0.8.5", "sc-client-api", + "sc-network", "sc-network-common", "sp-api", "sp-authority-discovery", @@ -9833,7 +9636,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "futures", "futures-timer", @@ -9856,7 +9659,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -9866,39 +9669,42 @@ dependencies = [ "sp-core", "sp-inherents", "sp-runtime", - "sp-state-machine", ] [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "memmap2", "sc-chain-spec-derive", - "sc-network-common", + "sc-client-api", + "sc-executor", + "sc-network", "sc-telemetry", "serde", "serde_json", + "sp-blockchain", "sp-core", "sp-runtime", + "sp-state-machine", ] [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.25", ] [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "array-bytes 4.2.0", "chrono", @@ -9938,7 +9744,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "fnv", "futures", @@ -9964,7 +9770,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "hash-db", "kvdb", @@ -9990,7 +9796,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "async-trait", "futures", @@ -10015,7 +9821,7 @@ dependencies = [ [[package]] name = "sc-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "async-trait", "futures", @@ -10044,13 +9850,12 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "async-trait", "fork-tree", "futures", "log", - "merlin", "num-bigint", "num-rational", "num-traits", @@ -10063,7 +9868,6 @@ dependencies = [ "sc-keystore", "sc-telemetry", "scale-info", - "schnorrkel", "sp-api", "sp-application-crypto", "sp-block-builder", @@ -10071,7 +9875,6 @@ dependencies = [ "sp-consensus", "sp-consensus-babe", "sp-consensus-slots", - "sp-consensus-vrf", "sp-core", "sp-inherents", "sp-keystore", @@ -10083,7 +9886,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "futures", "jsonrpsee", @@ -10102,10 +9905,64 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sc-consensus-beefy" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "array-bytes 4.2.0", + "async-trait", + "fnv", + "futures", + "log", + "parity-scale-codec", + "parking_lot 0.12.1", + "sc-client-api", + "sc-consensus", + "sc-keystore", + "sc-network", + "sc-network-common", + "sc-network-gossip", + "sc-network-sync", + "sc-utils", + "sp-api", + "sp-application-crypto", + "sp-arithmetic", + "sp-blockchain", + "sp-consensus", + "sp-consensus-beefy", + "sp-core", + "sp-keystore", + "sp-mmr-primitives", + "sp-runtime", + "substrate-prometheus-endpoint", + "thiserror", + "wasm-timer", +] + +[[package]] +name = "sc-consensus-beefy-rpc" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "futures", + "jsonrpsee", + "log", + "parity-scale-codec", + "parking_lot 0.12.1", + "sc-consensus-beefy", + "sc-rpc", + "serde", + "sp-consensus-beefy", + "sp-core", + "sp-runtime", + "thiserror", +] + [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "fork-tree", "parity-scale-codec", @@ -10115,10 +9972,70 @@ dependencies = [ "sp-runtime", ] +[[package]] +name = "sc-consensus-grandpa" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "ahash 0.8.3", + "array-bytes 4.2.0", + "async-trait", + "dyn-clone", + "finality-grandpa", + "fork-tree", + "futures", + "futures-timer", + "log", + "parity-scale-codec", + "parking_lot 0.12.1", + "rand 0.8.5", + "sc-block-builder", + "sc-chain-spec", + "sc-client-api", + "sc-consensus", + "sc-network", + "sc-network-common", + "sc-network-gossip", + "sc-telemetry", + "sc-utils", + "serde_json", + "sp-api", + "sp-application-crypto", + "sp-arithmetic", + "sp-blockchain", + "sp-consensus", + "sp-consensus-grandpa", + "sp-core", + "sp-keystore", + "sp-runtime", + "substrate-prometheus-endpoint", + "thiserror", +] + +[[package]] +name = "sc-consensus-grandpa-rpc" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "finality-grandpa", + "futures", + "jsonrpsee", + "log", + "parity-scale-codec", + "sc-client-api", + "sc-consensus-grandpa", + "sc-rpc", + "serde", + "sp-blockchain", + "sp-core", + "sp-runtime", + "thiserror", +] + [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "async-trait", "futures", @@ -10141,7 +10058,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "lru 0.8.1", "parity-scale-codec", @@ -10165,7 +10082,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -10178,7 +10095,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "log", "sc-allocator", @@ -10191,14 +10108,14 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "anyhow", "cfg-if", "libc", "log", "once_cell", - "rustix 0.36.14", + "rustix 0.36.15", "sc-allocator", "sc-executor-common", "sp-runtime-interface", @@ -10206,76 +10123,17 @@ dependencies = [ "wasmtime", ] -[[package]] -name = "sc-finality-grandpa" -version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" -dependencies = [ - "ahash 0.8.3", - "array-bytes 4.2.0", - "async-trait", - "dyn-clone", - "finality-grandpa", - "fork-tree", - "futures", - "futures-timer", - "log", - "parity-scale-codec", - "parking_lot 0.12.1", - "rand 0.8.5", - "sc-block-builder", - "sc-chain-spec", - "sc-client-api", - "sc-consensus", - "sc-network", - "sc-network-common", - "sc-network-gossip", - "sc-telemetry", - "sc-utils", - "serde_json", - "sp-api", - "sp-application-crypto", - "sp-arithmetic", - "sp-blockchain", - "sp-consensus", - "sp-core", - "sp-finality-grandpa", - "sp-keystore", - "sp-runtime", - "substrate-prometheus-endpoint", - "thiserror", -] - -[[package]] -name = "sc-finality-grandpa-rpc" -version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" -dependencies = [ - "finality-grandpa", - "futures", - "jsonrpsee", - "log", - "parity-scale-codec", - "sc-client-api", - "sc-finality-grandpa", - "sc-rpc", - "serde", - "sp-blockchain", - "sp-core", - "sp-runtime", - "thiserror", -] - [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "ansi_term", "futures", "futures-timer", "log", "sc-client-api", + "sc-network", "sc-network-common", "sp-blockchain", "sp-runtime", @@ -10284,7 +10142,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10299,12 +10157,12 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "array-bytes 4.2.0", + "async-channel", "async-trait", "asynchronous-codec", - "backtrace", "bytes", "either", "fnv", @@ -10312,6 +10170,7 @@ dependencies = [ "futures-timer", "ip_network", "libp2p", + "linked_hash_set", "log", "lru 0.8.1", "mockall", @@ -10328,6 +10187,7 @@ dependencies = [ "serde", "serde_json", "smallvec", + "snow", "sp-arithmetic", "sp-blockchain", "sp-consensus", @@ -10342,7 +10202,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "cid", "futures", @@ -10351,6 +10211,7 @@ dependencies = [ "prost", "prost-build", "sc-client-api", + "sc-network", "sc-network-common", "sp-blockchain", "sp-runtime", @@ -10361,33 +10222,35 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ + "array-bytes 4.2.0", "async-trait", - "bitflags", + "bitflags 1.3.2", "bytes", "futures", "futures-timer", "libp2p", - "linked_hash_set", "parity-scale-codec", "prost-build", "sc-consensus", "sc-peerset", + "sc-utils", "serde", "smallvec", "sp-blockchain", "sp-consensus", - "sp-finality-grandpa", + "sp-consensus-grandpa", "sp-runtime", "substrate-prometheus-endpoint", "thiserror", + "zeroize", ] [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "ahash 0.8.3", "futures", @@ -10395,6 +10258,7 @@ dependencies = [ "libp2p", "log", "lru 0.8.1", + "sc-network", "sc-network-common", "sc-peerset", "sp-runtime", @@ -10405,7 +10269,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10415,6 +10279,7 @@ dependencies = [ "prost", "prost-build", "sc-client-api", + "sc-network", "sc-network-common", "sc-peerset", "sp-blockchain", @@ -10426,12 +10291,13 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "array-bytes 4.2.0", "async-trait", "fork-tree", "futures", + "futures-timer", "libp2p", "log", "lru 0.8.1", @@ -10441,6 +10307,7 @@ dependencies = [ "prost-build", "sc-client-api", "sc-consensus", + "sc-network", "sc-network-common", "sc-peerset", "sc-utils", @@ -10448,8 +10315,8 @@ dependencies = [ "sp-arithmetic", "sp-blockchain", "sp-consensus", + "sp-consensus-grandpa", "sp-core", - "sp-finality-grandpa", "sp-runtime", "substrate-prometheus-endpoint", "thiserror", @@ -10458,7 +10325,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10466,6 +10333,7 @@ dependencies = [ "log", "parity-scale-codec", "pin-project", + "sc-network", "sc-network-common", "sc-peerset", "sc-utils", @@ -10477,7 +10345,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "array-bytes 4.2.0", "bytes", @@ -10493,6 +10361,7 @@ dependencies = [ "parking_lot 0.12.1", "rand 0.8.5", "sc-client-api", + "sc-network", "sc-network-common", "sc-peerset", "sc-utils", @@ -10507,7 +10376,7 @@ dependencies = [ [[package]] name = "sc-peerset" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "futures", "libp2p", @@ -10520,7 +10389,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10529,7 +10398,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "futures", "jsonrpsee", @@ -10559,7 +10428,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10578,7 +10447,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "http", "jsonrpsee", @@ -10593,7 +10462,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10619,7 +10488,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "async-trait", "directories", @@ -10685,7 +10554,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "log", "parity-scale-codec", @@ -10696,12 +10565,12 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "clap", + "fs4", "futures", "log", - "nix 0.26.2", "sc-client-db", "sc-utils", "sp-core", @@ -10712,7 +10581,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10720,7 +10589,7 @@ dependencies = [ "sc-client-api", "sc-consensus-babe", "sc-consensus-epochs", - "sc-finality-grandpa", + "sc-consensus-grandpa", "serde", "serde_json", "sp-blockchain", @@ -10731,7 +10600,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "futures", "libc", @@ -10750,7 +10619,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "chrono", "futures", @@ -10769,7 +10638,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "ansi_term", "atty", @@ -10800,18 +10669,18 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.25", ] [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "async-trait", "futures", @@ -10838,7 +10707,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "async-trait", "futures", @@ -10852,22 +10721,23 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ - "backtrace", + "async-channel", "futures", "futures-timer", "lazy_static", "log", "parking_lot 0.12.1", "prometheus", + "sp-arithmetic", ] [[package]] name = "scale-info" -version = "2.7.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b569c32c806ec3abdf3b5869fb8bf1e0d275a7c1c9b0b05603d9464632649edf" +checksum = "35c0a159d0c45c12b20c5a844feb1fe4bea86e28f17b92a5f0c42193634d3782" dependencies = [ "bitvec", "cfg-if", @@ -10879,9 +10749,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53012eae69e5aa5c14671942a5dd47de59d4cdcff8532a6dd0e081faf1119482" +checksum = "912e55f6d20e0e80d63733872b40e1227c0bce1e1ab81ba67d696339bfd7fd29" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10891,11 +10761,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys 0.42.0", + "windows-sys 0.48.0", ] [[package]] @@ -10935,9 +10805,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "scratch" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" +checksum = "764cad9e7e1ca5fe15b552859ff5d96a314e6ed2934f2260168cd5dfa5891409" [[package]] name = "sct" @@ -10977,10 +10847,24 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ - "base16ct", - "der", + "base16ct 0.1.1", + "der 0.6.1", "generic-array 0.14.7", - "pkcs8", + "pkcs8 0.9.0", + "subtle", + "zeroize", +] + +[[package]] +name = "sec1" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e" +dependencies = [ + "base16ct 0.2.0", + "der 0.7.7", + "generic-array 0.14.7", + "pkcs8 0.10.2", "subtle", "zeroize", ] @@ -11018,7 +10902,7 @@ version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -11070,32 +10954,41 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.163" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.25", +] + +[[package]] +name = "serde_json" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5062a995d481b2308b6064e9af76011f2921c35f97b0468811ed9f6cd91dfed" +dependencies = [ + "itoa", + "ryu", + "serde", ] [[package]] -name = "serde_json" -version = "1.0.96" +name = "serde_spanned" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" dependencies = [ - "itoa", - "ryu", "serde", ] @@ -11150,9 +11043,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", @@ -11178,6 +11071,17 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shared-configuration" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", + "parachains-common", + "smallvec", + "sp-arithmetic", +] + [[package]] name = "shlex" version = "1.1.0" @@ -11203,6 +11107,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + [[package]] name = "simba" version = "0.8.1" @@ -11216,6 +11130,26 @@ dependencies = [ "wide", ] +[[package]] +name = "similar" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" +dependencies = [ + "bstr 0.2.17", + "unicode-segmentation", +] + +[[package]] +name = "similar-asserts" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbf644ad016b75129f01a34a355dcb8d66a5bc803e417c7a77cc5d5ee9fa0f18" +dependencies = [ + "console", + "similar", +] + [[package]] name = "siphasher" version = "0.3.10" @@ -11239,8 +11173,8 @@ checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" [[package]] name = "slot-range-helper" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "enumn", "parity-scale-codec", @@ -11260,9 +11194,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "snap" @@ -11283,7 +11217,7 @@ dependencies = [ "rand_core 0.6.4", "ring", "rustc_version 0.4.0", - "sha2 0.10.6", + "sha2 0.10.7", "subtle", ] @@ -11297,6 +11231,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "soketto" version = "0.7.1" @@ -11317,13 +11261,15 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "hash-db", "log", "parity-scale-codec", + "scale-info", "sp-api-proc-macro", "sp-core", + "sp-metadata-ir", "sp-runtime", "sp-state-machine", "sp-std", @@ -11335,19 +11281,21 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ + "Inflector", "blake2", + "expander 1.0.0", "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.25", ] [[package]] name = "sp-application-crypto" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", "scale-info", @@ -11360,7 +11308,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "integer-sqrt", "num-traits", @@ -11374,39 +11322,20 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" -dependencies = [ - "parity-scale-codec", - "scale-info", - "sp-api", - "sp-application-crypto", - "sp-runtime", - "sp-std", -] - -[[package]] -name = "sp-beefy" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ - "lazy_static", "parity-scale-codec", "scale-info", - "serde", "sp-api", "sp-application-crypto", - "sp-core", - "sp-io", - "sp-mmr-primitives", "sp-runtime", "sp-std", - "strum", ] [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", "sp-api", @@ -11418,7 +11347,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "futures", "log", @@ -11436,25 +11365,22 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "async-trait", "futures", "log", - "parity-scale-codec", "sp-core", "sp-inherents", "sp-runtime", "sp-state-machine", - "sp-std", - "sp-version", "thiserror", ] [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "async-trait", "parity-scale-codec", @@ -11472,10 +11398,9 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "async-trait", - "merlin", "parity-scale-codec", "scale-info", "serde", @@ -11483,7 +11408,6 @@ dependencies = [ "sp-application-crypto", "sp-consensus", "sp-consensus-slots", - "sp-consensus-vrf", "sp-core", "sp-inherents", "sp-keystore", @@ -11493,40 +11417,64 @@ dependencies = [ ] [[package]] -name = "sp-consensus-slots" -version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +name = "sp-consensus-beefy" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ + "lazy_static", "parity-scale-codec", "scale-info", "serde", + "sp-api", + "sp-application-crypto", + "sp-core", + "sp-io", + "sp-mmr-primitives", + "sp-runtime", "sp-std", - "sp-timestamp", + "strum", ] [[package]] -name = "sp-consensus-vrf" -version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +name = "sp-consensus-grandpa" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ + "finality-grandpa", + "log", "parity-scale-codec", "scale-info", - "schnorrkel", + "serde", + "sp-api", + "sp-application-crypto", "sp-core", + "sp-keystore", "sp-runtime", "sp-std", ] +[[package]] +name = "sp-consensus-slots" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-std", + "sp-timestamp", +] + [[package]] name = "sp-core" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "array-bytes 4.2.0", - "base58", - "bitflags", + "bitflags 1.3.2", "blake2", "bounded-collections", + "bs58", "dyn-clonable", "ed25519-zebra", "futures", @@ -11539,6 +11487,7 @@ dependencies = [ "merlin", "parity-scale-codec", "parking_lot 0.12.1", + "paste", "primitive-types", "rand 0.8.5", "regex", @@ -11563,12 +11512,12 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ - "blake2", + "blake2b_simd", "byteorder", "digest 0.10.7", - "sha2 0.10.6", + "sha2 0.10.7", "sha3", "sp-std", "twox-hash", @@ -11577,18 +11526,18 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "proc-macro2", "quote", "sp-core-hashing", - "syn 1.0.109", + "syn 2.0.25", ] [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -11597,17 +11546,17 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.25", ] [[package]] name = "sp-externalities" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "environmental", "parity-scale-codec", @@ -11615,28 +11564,10 @@ dependencies = [ "sp-storage", ] -[[package]] -name = "sp-finality-grandpa" -version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" -dependencies = [ - "finality-grandpa", - "log", - "parity-scale-codec", - "scale-info", - "serde", - "sp-api", - "sp-application-crypto", - "sp-core", - "sp-keystore", - "sp-runtime", - "sp-std", -] - [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -11651,7 +11582,7 @@ dependencies = [ [[package]] name = "sp-io" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "bytes", "ed25519", @@ -11660,6 +11591,7 @@ dependencies = [ "libsecp256k1", "log", "parity-scale-codec", + "rustversion", "secp256k1", "sp-core", "sp-externalities", @@ -11676,7 +11608,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "lazy_static", "sp-core", @@ -11687,14 +11619,11 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ - "async-trait", "futures", - "merlin", "parity-scale-codec", "parking_lot 0.12.1", - "schnorrkel", "serde", "sp-core", "sp-externalities", @@ -11704,16 +11633,27 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "thiserror", - "zstd", + "zstd 0.12.3+zstd.1.5.2", +] + +[[package]] +name = "sp-metadata-ir" +version = "0.1.0" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" +dependencies = [ + "frame-metadata", + "parity-scale-codec", + "scale-info", + "sp-std", ] [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -11731,7 +11671,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", "scale-info", @@ -11745,7 +11685,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "sp-api", "sp-core", @@ -11755,7 +11695,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "backtrace", "lazy_static", @@ -11765,7 +11705,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "rustc-hash", "serde", @@ -11775,7 +11715,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "either", "hash256-std-hasher", @@ -11797,7 +11737,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -11815,19 +11755,19 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "Inflector", "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.25", ] [[package]] name = "sp-serializer" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "serde", "serde_json", @@ -11836,7 +11776,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", "scale-info", @@ -11850,10 +11790,11 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", "scale-info", + "serde", "sp-core", "sp-runtime", "sp-std", @@ -11862,7 +11803,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "hash-db", "log", @@ -11882,12 +11823,12 @@ dependencies = [ [[package]] name = "sp-std" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" [[package]] name = "sp-storage" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "impl-serde", "parity-scale-codec", @@ -11900,7 +11841,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "async-trait", "futures-timer", @@ -11915,7 +11856,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", "sp-std", @@ -11927,7 +11868,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "sp-api", "sp-runtime", @@ -11936,7 +11877,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "async-trait", "log", @@ -11952,11 +11893,11 @@ dependencies = [ [[package]] name = "sp-trie" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "ahash 0.8.3", "hash-db", - "hashbrown 0.12.3", + "hashbrown 0.13.2", "lazy_static", "memory-db", "nohash-hasher", @@ -11975,7 +11916,7 @@ dependencies = [ [[package]] name = "sp-version" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "impl-serde", "parity-scale-codec", @@ -11992,18 +11933,18 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.25", ] [[package]] name = "sp-wasm-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -12017,7 +11958,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "parity-scale-codec", "scale-info", @@ -12035,6 +11976,17 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spinners" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08615eea740067d9899969bc2891c68a19c315cb1f66640af9a9ecb91b13bcab" +dependencies = [ + "lazy_static", + "maplit", + "strum", +] + [[package]] name = "spki" version = "0.6.0" @@ -12042,14 +11994,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" dependencies = [ "base64ct", - "der", + "der 0.6.1", +] + +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der 0.7.7", ] [[package]] name = "ss58-registry" -version = "1.40.0" +version = "1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47a8ad42e5fc72d5b1eb104a5546937eaf39843499948bb666d6e93c62423b" +checksum = "bfc443bad666016e012538782d9e3006213a7db43e9fb1dda91657dc06a6fa08" dependencies = [ "Inflector", "num-format", @@ -12069,8 +12031,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "statemint-runtime" version = "1.0.0" -source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.39#d6eef144421ef5c3f339f681484d06bb729dfa82" +source = "git+https://github.com/paritytech/cumulus?branch=polkadot-v0.9.42#f603a61ff370fc33740c9373833c3c6ba1486846" dependencies = [ + "assets-common", "cumulus-pallet-aura-ext", "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", @@ -12086,7 +12049,7 @@ dependencies = [ "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", - "hex-literal", + "hex-literal 0.4.1", "log", "pallet-asset-tx-payment", "pallet-assets", @@ -12124,6 +12087,7 @@ dependencies = [ "sp-std", "sp-transaction-pool", "sp-version", + "sp-weights", "substrate-wasm-builder", "xcm", "xcm-builder", @@ -12154,7 +12118,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a2a1c578e98c1c16fc3b8ec1328f7659a500737d7a0c6d625e73e830ff9c1f6" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg_aliases", "libc", "parking_lot 0.11.2", @@ -12252,15 +12216,25 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "platforms 2.0.0", ] +[[package]] +name = "substrate-fixed" +version = "0.5.9" +source = "git+https://github.com/encointer/substrate-fixed#a4fb461aae6205ffc55bed51254a40c52be04e5d" +dependencies = [ + "parity-scale-codec", + "scale-info", + "typenum 1.16.0 (git+https://github.com/encointer/typenum?tag=v1.16.0)", +] + [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -12279,7 +12253,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "hyper", "log", @@ -12291,7 +12265,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "async-trait", "jsonrpsee", @@ -12304,7 +12278,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "jsonrpsee", "log", @@ -12323,7 +12297,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "ansi_term", "build-helper", @@ -12332,7 +12306,7 @@ dependencies = [ "sp-maybe-compressed-blob", "strum", "tempfile", - "toml", + "toml 0.7.6", "walkdir", "wasm-opt", ] @@ -12365,9 +12339,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.16" +version = "2.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" +checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" dependencies = [ "proc-macro2", "quote", @@ -12392,7 +12366,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "system-configuration-sys", ] @@ -12415,21 +12389,22 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.7" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5" +checksum = "df8e77cb757a61f51b947ec4a7e3646efd825b73561db1c232a8ccb639e611a0" [[package]] name = "tempfile" -version = "3.5.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix 0.37.19", - "windows-sys 0.45.0", + "rustix 0.37.23", + "windows-sys 0.48.0", ] [[package]] @@ -12449,22 +12424,22 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.25", ] [[package]] @@ -12539,9 +12514,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.21" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" +checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" dependencies = [ "itoa", "serde", @@ -12557,9 +12532,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" dependencies = [ "time-core", ] @@ -12576,7 +12551,7 @@ dependencies = [ "pbkdf2 0.11.0", "rand 0.8.5", "rustc-hash", - "sha2 0.10.6", + "sha2 0.10.7", "thiserror", "unicode-normalization", "wasm-bindgen", @@ -12610,19 +12585,20 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.1" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", + "backtrace", "bytes", "libc", "mio", "num_cpus", "parking_lot 0.12.1", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", "signal-hook-registry", - "socket2", + "socket2 0.4.9", "tokio-macros", "windows-sys 0.48.0", ] @@ -12635,7 +12611,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.25", ] [[package]] @@ -12656,7 +12632,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", "tokio", "tokio-util", ] @@ -12671,7 +12647,7 @@ dependencies = [ "futures-core", "futures-io", "futures-sink", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", "tokio", "tracing", ] @@ -12685,19 +12661,36 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + [[package]] name = "toml_datetime" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" -version = "0.19.9" +version = "0.19.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d964908cec0d030b812013af25a0e57fddfadb1e066ecc6681d86253129d4f" +checksum = "5f8751d9c1b03c6500c387e96f81f815a4f8e72d142d2d4a9ffa6fedd51ddee7" dependencies = [ - "indexmap", + "indexmap 2.0.0", + "serde", + "serde_spanned", "toml_datetime", "winnow", ] @@ -12719,14 +12712,14 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" dependencies = [ - "bitflags", + "bitflags 1.3.2", "bytes", "futures-core", "futures-util", "http", "http-body", "http-range-header", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", "tower-layer", "tower-service", ] @@ -12751,20 +12744,20 @@ checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "log", - "pin-project-lite 0.2.9", + "pin-project-lite 0.2.10", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-attributes" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.25", ] [[package]] @@ -12789,8 +12782,8 @@ dependencies = [ [[package]] name = "tracing-gum" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "polkadot-node-jaeger", "polkadot-primitives", @@ -12800,14 +12793,14 @@ dependencies = [ [[package]] name = "tracing-gum-proc-macro" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ - "expander 0.0.6", + "expander 2.0.0", "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.25", ] [[package]] @@ -12856,9 +12849,9 @@ dependencies = [ [[package]] name = "trie-db" -version = "0.25.1" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3390c0409daaa6027d6681393316f4ccd3ff82e1590a1e4725014e3ae2bf1920" +checksum = "767abe6ffed88a1889671a102c2861ae742726f52e0a5a425b92c9fbfa7e9c85" dependencies = [ "hash-db", "hashbrown 0.13.2", @@ -12869,9 +12862,9 @@ dependencies = [ [[package]] name = "trie-root" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a36c5ca3911ed3c9a5416ee6c679042064b93fc637ded67e25f92e68d783891" +checksum = "d4ed310ef5ab98f5fa467900ed906cb9232dd5376597e00fd4cba2a449d06c0b" dependencies = [ "hash-db", ] @@ -12894,7 +12887,7 @@ dependencies = [ "lazy_static", "rand 0.8.5", "smallvec", - "socket2", + "socket2 0.4.9", "thiserror", "tinyvec", "tokio", @@ -12931,7 +12924,7 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.39#8c4b84520cee2d7de53cc33cb67605ce4efefba8" +source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.42#ff24c60ac7d9f87727ecdd0ded9a80c56e4f4b65" dependencies = [ "async-trait", "clap", @@ -12962,7 +12955,7 @@ dependencies = [ "sp-version", "sp-weights", "substrate-rpc-client", - "zstd", + "zstd 0.12.3+zstd.1.5.2", ] [[package]] @@ -13008,11 +13001,20 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "typenum" +version = "1.16.0" +source = "git+https://github.com/encointer/typenum?tag=v1.16.0#4c8dddaa8bdd13130149e43b4085ad14e960617f" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + [[package]] name = "ucd-trie" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "uint" @@ -13034,9 +13036,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" [[package]] name = "unicode-normalization" @@ -13047,6 +13049,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + [[package]] name = "unicode-width" version = "0.1.10" @@ -13099,12 +13107,12 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", - "idna 0.3.0", + "idna 0.4.0", "percent-encoding", ] @@ -13116,11 +13124,11 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.3.3" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2" +checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.10", ] [[package]] @@ -13174,11 +13182,10 @@ dependencies = [ [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -13202,9 +13209,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -13212,24 +13219,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.25", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.36" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" dependencies = [ "cfg-if", "js-sys", @@ -13239,9 +13246,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -13249,22 +13256,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.25", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasm-instrument" @@ -13371,7 +13378,7 @@ version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64b20236ab624147dfbb62cf12a19aaf66af0e41b8398838b66e997d07d269d4" dependencies = [ - "indexmap", + "indexmap 1.9.3", "url", ] @@ -13384,7 +13391,7 @@ dependencies = [ "anyhow", "bincode", "cfg-if", - "indexmap", + "indexmap 1.9.3", "libc", "log", "object 0.29.0", @@ -13424,12 +13431,12 @@ dependencies = [ "directories-next", "file-per-thread-logger", "log", - "rustix 0.36.14", + "rustix 0.36.15", "serde", - "sha2 0.10.6", - "toml", + "sha2 0.10.7", + "toml 0.5.11", "windows-sys 0.42.0", - "zstd", + "zstd 0.11.2+zstd.1.5.2", ] [[package]] @@ -13462,7 +13469,7 @@ dependencies = [ "anyhow", "cranelift-entity", "gimli 0.26.2", - "indexmap", + "indexmap 1.9.3", "log", "object 0.29.0", "serde", @@ -13504,7 +13511,7 @@ checksum = "eed41cbcbf74ce3ff6f1d07d1b707888166dc408d1a880f651268f4f7c9194b2" dependencies = [ "object 0.29.0", "once_cell", - "rustix 0.36.14", + "rustix 0.36.15", ] [[package]] @@ -13527,7 +13534,7 @@ dependencies = [ "anyhow", "cc", "cfg-if", - "indexmap", + "indexmap 1.9.3", "libc", "log", "mach", @@ -13535,7 +13542,7 @@ dependencies = [ "memoffset 0.6.5", "paste", "rand 0.8.5", - "rustix 0.36.14", + "rustix 0.36.15", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-jit-debug", @@ -13556,9 +13563,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.63" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", @@ -13616,10 +13623,10 @@ dependencies = [ "sdp", "serde", "serde_json", - "sha2 0.10.6", + "sha2 0.10.7", "stun", "thiserror", - "time 0.3.21", + "time 0.3.23", "tokio", "turn", "url", @@ -13664,7 +13671,7 @@ dependencies = [ "ccm", "curve25519-dalek 3.2.0", "der-parser 8.2.0", - "elliptic-curve", + "elliptic-curve 0.12.3", "hkdf", "hmac 0.12.1", "log", @@ -13676,11 +13683,11 @@ dependencies = [ "rcgen 0.9.3", "ring", "rustls 0.19.1", - "sec1", + "sec1 0.3.0", "serde", "sha1", - "sha2 0.10.6", - "signature", + "sha2 0.10.7", + "signature 1.6.4", "subtle", "thiserror", "tokio", @@ -13721,7 +13728,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f08dfd7a6e3987e255c4dbe710dde5d94d0f0574f8a21afa95d171376c143106" dependencies = [ "log", - "socket2", + "socket2 0.4.9", "thiserror", "tokio", "webrtc-util", @@ -13788,14 +13795,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f1db1727772c05cf7a2cfece52c3aca8045ca1e176cd517d323489aa3c6d87" dependencies = [ "async-trait", - "bitflags", + "bitflags 1.3.2", "bytes", "cc", "ipnet", "lazy_static", "libc", "log", - "nix 0.24.3", + "nix", "rand 0.8.5", "thiserror", "tokio", @@ -13804,8 +13811,8 @@ dependencies = [ [[package]] name = "westend-runtime" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "bitvec", "frame-benchmarking", @@ -13816,7 +13823,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.4.1", "log", "pallet-authority-discovery", "pallet-authorship", @@ -13872,9 +13879,9 @@ dependencies = [ "smallvec", "sp-api", "sp-authority-discovery", - "sp-beefy", "sp-block-builder", "sp-consensus-babe", + "sp-consensus-beefy", "sp-core", "sp-inherents", "sp-io", @@ -13896,8 +13903,8 @@ dependencies = [ [[package]] name = "westend-runtime-constants" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "frame-support", "polkadot-primitives", @@ -13921,9 +13928,9 @@ dependencies = [ [[package]] name = "wide" -version = "0.7.9" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cd0496a71f3cc6bc4bf0ed91346426a5099e93d89807e663162dc5a1069ff65" +checksum = "aa469ffa65ef7e0ba0f164183697b89b854253fd31aeb92358b7b6155177d62f" dependencies = [ "bytemuck", "safe_arch", @@ -13931,9 +13938,9 @@ dependencies = [ [[package]] name = "widestring" -version = "0.5.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" [[package]] name = "winapi" @@ -13985,7 +13992,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.1", ] [[package]] @@ -14018,7 +14025,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.1", ] [[package]] @@ -14038,9 +14045,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ "windows_aarch64_gnullvm 0.48.0", "windows_aarch64_msvc 0.48.0", @@ -14167,20 +14174,21 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.6" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" +checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" dependencies = [ "memchr", ] [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys 0.48.0", ] [[package]] @@ -14230,7 +14238,7 @@ dependencies = [ "ring", "rusticata-macros", "thiserror", - "time 0.3.21", + "time 0.3.23", ] [[package]] @@ -14248,13 +14256,13 @@ dependencies = [ "oid-registry 0.6.1", "rusticata-macros", "thiserror", - "time 0.3.21", + "time 0.3.23", ] [[package]] name = "xcm" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "bounded-collections", "derivative", @@ -14269,8 +14277,8 @@ dependencies = [ [[package]] name = "xcm-builder" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "frame-support", "frame-system", @@ -14291,7 +14299,7 @@ dependencies = [ [[package]] name = "xcm-emulator" version = "0.1.0" -source = "git+https://github.com/shaunxw/xcm-simulator?rev=aa13dce47596e150806dfc3af99096dae6ffc65e#aa13dce47596e150806dfc3af99096dae6ffc65e" +source = "git+https://github.com/shaunxw/xcm-simulator?rev=d011e5ca62b93e8f688c2042c1f92cdbafc5d1d0#d011e5ca62b93e8f688c2042c1f92cdbafc5d1d0" dependencies = [ "cumulus-pallet-dmp-queue", "cumulus-pallet-parachain-system", @@ -14316,8 +14324,8 @@ dependencies = [ [[package]] name = "xcm-executor" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "environmental", "frame-benchmarking", @@ -14334,41 +14342,15 @@ dependencies = [ "xcm", ] -[[package]] -name = "xcm-primitives" -version = "0.0.1" -dependencies = [ - "sp-std", - "xcm", - "xcm-executor", -] - [[package]] name = "xcm-procedural" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" +version = "0.9.42" +source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.42#6f991987c0b4cbbd7d4badc9ef08d83da5fefbfd" dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 1.0.109", -] - -[[package]] -name = "xcm-simulator" -version = "0.9.39-1" -source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.39#c22e1c4173bf6966f5d1980f4299f7abe836f0c1" -dependencies = [ - "frame-support", - "parity-scale-codec", - "paste", - "polkadot-core-primitives", - "polkadot-parachain", - "polkadot-runtime-parachains", - "sp-io", - "sp-std", - "xcm", - "xcm-executor", + "syn 2.0.25", ] [[package]] @@ -14391,7 +14373,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" dependencies = [ - "time 0.3.21", + "time 0.3.23", ] [[package]] @@ -14411,7 +14393,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.16", + "syn 2.0.25", ] [[package]] @@ -14420,7 +14402,16 @@ version = "0.11.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" dependencies = [ - "zstd-safe", + "zstd-safe 5.0.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.12.3+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806" +dependencies = [ + "zstd-safe 6.0.5+zstd.1.5.4", ] [[package]] @@ -14433,6 +14424,16 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "zstd-safe" +version = "6.0.5+zstd.1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56d9e60b4b1758206c238a10165fbcae3ca37b01744e394c463463f6529d23b" +dependencies = [ + "libc", + "zstd-sys", +] + [[package]] name = "zstd-sys" version = "2.0.8+zstd.1.5.5" diff --git a/Cargo.toml b/Cargo.toml index b6ca4f082..2bb3e5a8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,10 @@ [workspace] -members = ["nodes/*", "pallets/*", "runtimes/*", "traits", "integration-tests"] +members = [ + "nodes/*", + "pallets/*", + "runtimes/*", + "integration-tests" +] [workspace.package] authors = ['Polimec Foundation '] @@ -36,30 +41,27 @@ overflow-checks = true [workspace.dependencies] # Build deps -substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } +substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } # Internal pallets (with default disabled) -parachain-staking = { path = "pallets/parachain-staking", default-features = false } -pallet-credentials = { path = "pallets/credentials", default-features = false } pallet-funding = { path = "pallets/funding", default-features = false } pallet-sandbox = { path = "pallets/sandbox", default-features = false } -pallet-asset-registry = { path = "pallets/asset-registry", default-features = false } +pallet-parachain-staking = { path = "pallets/parachain-staking", default-features = false} + # Internal support (with default disabled) -runtime-common = { path = "runtimes/common", default-features = false } -polimec-traits = { path = "traits", default-features = false } -xcm-primitives = { path = "primitives/xcm", default-features = false } +shared-configuration = { path = "runtimes/shared-configuration", default-features = false } # External support (with default disabled) -dip-support = { git = "https://github.com/KILTprotocol/kilt-node", default-features = false, branch = "aa/dip" } -kilt-support = { git = "https://github.com/KILTprotocol/kilt-node", default-features = false, branch = "aa/dip" } -kilt-dip-support = { git = "https://github.com/KILTprotocol/kilt-node", default-features = false, branch = "aa/dip" } -did = { git = "https://github.com/KILTprotocol/kilt-node", default-features = false, branch = "aa/dip" } -pallet-did-lookup = { git = "https://github.com/KILTprotocol/kilt-node", default-features = false, branch = "aa/dip" } -pallet-dip-provider = { git = "https://github.com/KILTprotocol/kilt-node", default-features = false, branch = "aa/dip" } -pallet-dip-consumer = { git = "https://github.com/KILTprotocol/kilt-node", default-features = false, branch = "aa/dip" } -# Internal runtime API (with default disabled) -kilt-runtime-api-staking = { path = "runtime-api/staking", default-features = false } +substrate-fixed = { git = "https://github.com/encointer/substrate-fixed", default-features = false } +# dip-support = { git = "https://github.com/KILTprotocol/kilt-node", default-features = false, branch = "aa/dip" } +# kilt-support = { git = "https://github.com/KILTprotocol/kilt-node", default-features = false, branch = "aa/dip" } +# kilt-dip-support = { git = "https://github.com/KILTprotocol/kilt-node", default-features = false, branch = "aa/dip" } +# did = { git = "https://github.com/KILTprotocol/kilt-node", default-features = false, branch = "aa/dip" } +# pallet-did-lookup = { git = "https://github.com/KILTprotocol/kilt-node", default-features = false, branch = "aa/dip" } +# pallet-dip-provider = { git = "https://github.com/KILTprotocol/kilt-node", default-features = false, branch = "aa/dip" } +# pallet-dip-consumer = { git = "https://github.com/KILTprotocol/kilt-node", default-features = false, branch = "aa/dip" } + # External (without extra features and with default disabled if necessary) parity-scale-codec = { version = "3.3.0", default-features = false } @@ -75,134 +77,133 @@ smallvec = "1.10.0" log = "0.4.17" # Emulations -xcm-emulator = { git = "https://github.com/shaunxw/xcm-simulator", default-features = false, rev = "aa13dce47596e150806dfc3af99096dae6ffc65e" } -dip-provider-runtime-template = { git = "https://github.com/KILTprotocol/kilt-node", default-features = false, branch = "aa/dip" } -kilt-runtime-common = { package = "runtime-common", default-features = false, git = "https://github.com/KILTprotocol/kilt-node", branch = "aa/dip" } +# TODO: Replace it from the one in the Cumulus Repo +xcm-emulator = { git = "https://github.com/shaunxw/xcm-simulator", default-features = false, rev = "d011e5ca62b93e8f688c2042c1f92cdbafc5d1d0" } # Substrate (with default disabled) -frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -frame-try-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -sp-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -sp-staking = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -sp-arithmetic = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -sp-blockchain = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -sp-consensus-aura = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -sp-block-builder = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -sp-offchain = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -sp-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -sp-transaction-pool = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -sp-trie = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -sp-version = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -try-runtime-cli = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } +frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +frame-try-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +sp-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +sp-staking = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +sp-arithmetic = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +sp-core = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +sp-blockchain = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +sp-consensus-aura = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +sp-block-builder = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +sp-offchain = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +sp-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +sp-transaction-pool = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +sp-trie = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +sp-version = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +sp-consensus-grandpa = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +try-runtime-cli = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } # FRAME -pallet-aura = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-insecure-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-assets = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-authorship = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-asset-tx-payment = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-collective = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-democracy = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-scheduler = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-treasury = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-utility = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-membership = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-multisig = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-preimage = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-grandpa = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } -pallet-vesting = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } +pallet-aura = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-balances = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-insecure-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-assets = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-authorship = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-asset-tx-payment = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-collective = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-democracy = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-scheduler = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-sudo = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-treasury = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-utility = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-membership = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-multisig = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-preimage = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-grandpa = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } +pallet-vesting = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } # Polkadot (with default disabled) -pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.39" } -polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.39" } -polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.39" } -polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.39" } -xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.39" } -xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.39" } -xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.39" } -xcm-simulator = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.39" } -polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.39" } -polkadot-runtime = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.39" } -polkadot-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.39" } +pallet-xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.42" } +polkadot-parachain = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.42" } +polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.42" } +polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.42" } +xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.42" } +xcm-builder = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.42" } +xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.42" } +xcm-simulator = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.42" } +polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.42" } +polkadot-runtime = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.42" } +polkadot-primitives = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "release-v0.9.42" } # Cumulus (with default disabled) -cumulus-pallet-aura-ext = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.39" } -cumulus-pallet-dmp-queue = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.39" } -cumulus-pallet-solo-to-para = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.39" } -cumulus-pallet-parachain-system = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.39" } -cumulus-pallet-xcm = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.39" } -cumulus-pallet-xcmp-queue = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.39" } -cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.39" } -cumulus-primitives-timestamp = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.39" } -cumulus-primitives-utility = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.39" } -pallet-collator-selection = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.39" } -parachain-info = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.39" } -parachains-common = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.39" } -statemint-runtime = { git = 'https://github.com/paritytech/cumulus', default-features = false, branch = 'polkadot-v0.9.39' } +cumulus-pallet-aura-ext = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.42" } +cumulus-pallet-dmp-queue = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.42" } +cumulus-pallet-solo-to-para = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.42" } +cumulus-pallet-parachain-system = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.42" } +cumulus-pallet-xcm = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.42" } +cumulus-pallet-xcmp-queue = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.42" } +cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.42" } +cumulus-primitives-timestamp = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.42" } +cumulus-primitives-utility = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.42" } +pallet-collator-selection = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.42" } +parachain-info = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.42" } +parachains-common = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.42" } +statemint-runtime = { git = 'https://github.com/paritytech/cumulus', default-features = false, branch = 'polkadot-v0.9.42' } # Client-only (with default enabled) -cumulus-client-cli = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.39" } -cumulus-client-consensus-aura = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.39" } -cumulus-client-consensus-common = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.39" } -cumulus-client-network = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.39" } -cumulus-client-service = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.39" } -cumulus-primitives-parachain-inherent = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.39" } -cumulus-relay-chain-interface = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.39" } -cumulus-relay-chain-inprocess-interface = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.39" } -cumulus-relay-chain-minimal-node = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.39" } -polkadot-cli = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.39" } -polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.39" } -sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-network = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-cli = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-executor = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sp-serializer = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-service = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-sysinfo = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-transaction-pool-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -sc-network-common = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } - -substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } -substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } +cumulus-client-cli = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.42" } +cumulus-client-consensus-aura = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.42" } +cumulus-client-consensus-common = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.42" } +cumulus-client-network = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.42" } +cumulus-client-service = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.42" } +cumulus-primitives-parachain-inherent = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.42" } +cumulus-relay-chain-interface = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.42" } +cumulus-relay-chain-inprocess-interface = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.42" } +cumulus-relay-chain-minimal-node = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.42" } +polkadot-cli = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.42" } +polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.42" } +sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-network = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-network-sync = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-cli = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-executor = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sp-serializer = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-service = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-sysinfo = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-transaction-pool-api = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-network-common = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +sc-consensus-grandpa = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } +substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } # Benchmarking (with default disabled) -cumulus-pallet-session-benchmarking = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.39" } -frame-system-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.39" } +cumulus-pallet-session-benchmarking = { git = "https://github.com/paritytech/cumulus", default-features = false, branch = "polkadot-v0.9.42" } +frame-system-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-v0.9.42" } # Runtimes polimec-parachain-runtime = { path = "runtimes/testnet" } diff --git a/README.md b/README.md index cf6ebf1f6..cb326bbcd 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ ### Step 1: Compile the relay chain and add it to $PATH - Clone the [Polkadot Repository](https://github.com/paritytech/polkadot) -- Checkout the `release-v0.9.39` branch +- Checkout the `release-v0.9.42` branch - Compile it using `cargo b -r -p polkadot` - Add the binary to your $PATH, e.g. `cp target/release/polkadot ~/.local/bin/polkadot` @@ -48,7 +48,7 @@ $ cargo run --release -- --dev You can use [srtool](https://github.com/paritytech/srtool) to compile the runtime and generate the WASM blob. -> TODO: Rust 1.69.0 broke `srtool` and `polkadot-v0.9.39` - we need to wait `polkadot-v0.9.42`. [src](https://github.com/paritytech/srtool/issues/62) +> TODO: Rust 1.69.0 broke `srtool` and `polkadot-v0.9.42` - we need to wait `polkadot-v0.9.42`. [src](https://github.com/paritytech/srtool/issues/62) ``` == Compact diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 2b641803c..4776bedfa 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -46,14 +46,14 @@ polkadot-runtime.workspace = true statemint-runtime.workspace = true polimec-parachain-runtime.workspace = true penpal-runtime.workspace = true -dip-provider-runtime-template = { workspace = true, features = ["std"] } -did = { workspace = true, features = ["std"] } -kilt-support = { workspace = true, features = ["std"] } -pallet-did-lookup = { workspace = true, features = ["std"] } -dip-support = { workspace = true, features = ["std"] } -runtime-common = { workspace = true, features = ["std"] } -kilt-dip-support = { workspace = true, features = ["std"] } -kilt-runtime-common = { workspace = true, features = ["std"] } +# dip-provider-runtime-template = { workspace = true, features = ["std"] } +# did = { workspace = true, features = ["std"] } +# kilt-support = { workspace = true, features = ["std"] } +# pallet-did-lookup = { workspace = true, features = ["std"] } +# dip-support = { workspace = true, features = ["std"] } +# runtime-common = { workspace = true, features = ["std"] } +# kilt-dip-support = { workspace = true, features = ["std"] } +# kilt-runtime-common = { workspace = true, features = ["std"] } [features] default = ["std"] diff --git a/integration-tests/modified-penpal/Cargo.toml b/integration-tests/modified-penpal/Cargo.toml index 790852360..ed71efba0 100644 --- a/integration-tests/modified-penpal/Cargo.toml +++ b/integration-tests/modified-penpal/Cargo.toml @@ -12,7 +12,7 @@ edition = "2021" targets = ["x86_64-unknown-linux-gnu"] [build-dependencies] -substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.39" } +substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.42" } [dependencies] parity-scale-codec = { version = "3.0.0", default-features = false, features = ["derive"] } diff --git a/integration-tests/modified-penpal/build.rs b/integration-tests/modified-penpal/build.rs index fe1a2ea91..e02e83524 100644 --- a/integration-tests/modified-penpal/build.rs +++ b/integration-tests/modified-penpal/build.rs @@ -17,9 +17,5 @@ use substrate_wasm_builder::WasmBuilder; fn main() { - WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build() + WasmBuilder::new().with_current_project().export_heap_base().import_memory().build() } diff --git a/integration-tests/modified-penpal/src/lib.rs b/integration-tests/modified-penpal/src/lib.rs index e320f5376..781bfb980 100644 --- a/integration-tests/modified-penpal/src/lib.rs +++ b/integration-tests/modified-penpal/src/lib.rs @@ -153,6 +153,7 @@ pub type Executive = frame_executive::Executive< pub struct WeightToFee; impl WeightToFeePolynomial for WeightToFee { type Balance = Balance; + fn polynomial() -> WeightToFeeCoefficients { // in Rococo, extrinsic base weight (smallest non-zero weight) is mapped to 1 MILLIUNIT: // in our template, we map to 1/10 of that, or 1/10 MILLIUNIT @@ -244,10 +245,7 @@ const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts( /// The version information used to identify this runtime when compiled natively. #[cfg(feature = "std")] pub fn native_version() -> NativeVersion { - NativeVersion { - runtime_version: VERSION, - can_author_with: Default::default(), - } + NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } parameter_types! { @@ -283,66 +281,66 @@ parameter_types! { // Configure FRAME pallets to include in runtime. impl frame_system::Config for Runtime { + /// The data to be stored in an account. + type AccountData = pallet_balances::AccountData; /// The identifier used to distinguish between accounts. type AccountId = AccountId; - /// The aggregated dispatch type that is available for extrinsics. - 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. - type Index = Index; + /// The basic call filter to use in dispatchable. + type BaseCallFilter = Everything; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = BlockHashCount; + /// The maximum length of a block (in bytes). + type BlockLength = RuntimeBlockLength; /// The index type for blocks. type BlockNumber = BlockNumber; + /// Block & extrinsics weights: base values and limits. + type BlockWeights = RuntimeBlockWeights; + /// The weight of database operations that the runtime can invoke. + type DbWeight = RocksDbWeight; /// The type for hashing blocks and tries. type Hash = Hash; /// The hashing algorithm used. type Hashing = BlakeTwo256; /// The header type. type Header = generic::Header; + /// The index type for storing how many extrinsics an account has signed. + type Index = Index; + /// The lookup mechanism to get account ID from whatever is passed in dispatchers. + type Lookup = AccountIdLookup; + type MaxConsumers = frame_support::traits::ConstU32<16>; + /// What to do if an account is fully reaped from the system. + type OnKilledAccount = (); + /// What to do if a new account is created. + type OnNewAccount = (); + /// The action to take on a Runtime Upgrade + type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + /// Converts a module to an index of this module in the runtime. + type PalletInfo = PalletInfo; + /// The aggregated dispatch type that is available for extrinsics. + type RuntimeCall = RuntimeCall; /// The ubiquitous event type. type RuntimeEvent = RuntimeEvent; /// The ubiquitous origin type. type RuntimeOrigin = RuntimeOrigin; - /// Maximum number of block number to block hash mappings to keep (oldest pruned first). - type BlockHashCount = BlockHashCount; - /// Runtime version. - type Version = Version; - /// Converts a module to an index of this module in the runtime. - type PalletInfo = PalletInfo; - /// The data to be stored in an account. - type AccountData = pallet_balances::AccountData; - /// What to do if a new account is created. - type OnNewAccount = (); - /// What to do if an account is fully reaped from the system. - type OnKilledAccount = (); - /// The weight of database operations that the runtime can invoke. - type DbWeight = RocksDbWeight; - /// The basic call filter to use in dispatchable. - type BaseCallFilter = Everything; - /// Weight information for the extrinsics of this pallet. - type SystemWeightInfo = (); - /// Block & extrinsics weights: base values and limits. - type BlockWeights = RuntimeBlockWeights; - /// The maximum length of a block (in bytes). - type BlockLength = RuntimeBlockLength; /// This is used as an identifier of the chain. 42 is the generic substrate prefix. type SS58Prefix = SS58Prefix; - /// The action to take on a Runtime Upgrade - type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; - type MaxConsumers = frame_support::traits::ConstU32<16>; + /// Weight information for the extrinsics of this pallet. + type SystemWeightInfo = (); + /// Runtime version. + type Version = Version; } impl pallet_timestamp::Config for Runtime { + type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; /// A timestamp: milliseconds since the unix epoch. type Moment = u64; type OnTimestampSet = Aura; - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = (); } impl pallet_authorship::Config for Runtime { - type FindAuthor = pallet_session::FindAccountFromAuthorIndex; type EventHandler = (CollatorSelection,); + type FindAuthor = pallet_session::FindAccountFromAuthorIndex; } parameter_types! { @@ -350,17 +348,21 @@ parameter_types! { } impl pallet_balances::Config for Runtime { - type MaxLocks = ConstU32<50>; + type AccountStore = System; /// The type for recording an account's balance. type Balance = Balance; - /// The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = pallet_balances::weights::SubstrateWeight; + type FreezeIdentifier = (); + type HoldIdentifier = (); + type MaxFreezes = ConstU32<0>; + type MaxHolds = ConstU32<0>; + type MaxLocks = ConstU32<50>; type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_balances::weights::SubstrateWeight; } parameter_types! { @@ -369,12 +371,12 @@ parameter_types! { } impl pallet_transaction_payment::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; - type WeightToFee = WeightToFee; - type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type LengthToFee = ConstantMultiplier; + type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; type OperationalFeeMultiplier = ConstU8<5>; + type RuntimeEvent = RuntimeEvent; + type WeightToFee = WeightToFee; } parameter_types! { @@ -391,26 +393,26 @@ parameter_types! { // EnsureOneOf, EnsureXcm>>; impl pallet_assets::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Balance = Balance; + type ApprovalDeposit = ApprovalDeposit; + type AssetAccountDeposit = AssetAccountDeposit; + type AssetDeposit = AssetDeposit; type AssetId = AssetId; type AssetIdParameter = parity_scale_codec::Compact; - type Currency = Balances; + type Balance = Balance; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); + type CallbackHandle = (); type CreateOrigin = AsEnsureOriginWithArg>; + type Currency = Balances; + type Extra = (); type ForceOrigin = EnsureRoot; - type AssetDeposit = AssetDeposit; + type Freezer = (); type MetadataDepositBase = MetadataDepositBase; type MetadataDepositPerByte = MetadataDepositPerByte; - type ApprovalDeposit = ApprovalDeposit; + type RemoveItemsLimit = frame_support::traits::ConstU32<1000>; + type RuntimeEvent = RuntimeEvent; type StringLimit = AssetsStringLimit; - type Freezer = (); - type Extra = (); type WeightInfo = pallet_assets::weights::SubstrateWeight; - type CallbackHandle = (); - type AssetAccountDeposit = AssetAccountDeposit; - type RemoveItemsLimit = frame_support::traits::ConstU32<1000>; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); } parameter_types! { @@ -419,15 +421,15 @@ parameter_types! { } impl cumulus_pallet_parachain_system::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OnSystemEvent = (); - type SelfParaId = parachain_info::Pallet; + type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; type DmpMessageHandler = DmpQueue; - type ReservedDmpWeight = ReservedDmpWeight; + type OnSystemEvent = (); type OutboundXcmpMessageSource = XcmpQueue; - type XcmpMessageHandler = XcmpQueue; + type ReservedDmpWeight = ReservedDmpWeight; type ReservedXcmpWeight = ReservedXcmpWeight; - type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; + type RuntimeEvent = RuntimeEvent; + type SelfParaId = parachain_info::Pallet; + type XcmpMessageHandler = XcmpQueue; } impl parachain_info::Config for Runtime {} @@ -435,21 +437,21 @@ impl parachain_info::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {} impl cumulus_pallet_xcmp_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; - type VersionWrapper = PolkadotXcm; - type ExecuteOverweightOrigin = EnsureRoot; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; - type WeightInfo = (); + type ExecuteOverweightOrigin = EnsureRoot; type PriceForSiblingDelivery = (); + type RuntimeEvent = RuntimeEvent; + type VersionWrapper = PolkadotXcm; + type WeightInfo = (); + type XcmExecutor = XcmExecutor; } impl cumulus_pallet_dmp_queue::Config for Runtime { + type ExecuteOverweightOrigin = EnsureRoot; type RuntimeEvent = RuntimeEvent; type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = EnsureRoot; } parameter_types! { @@ -458,16 +460,16 @@ parameter_types! { } impl pallet_session::Config for Runtime { + type Keys = SessionKeys; + type NextSessionRotation = pallet_session::PeriodicSessions; type RuntimeEvent = RuntimeEvent; + // Essentially just Aura, but let's be pedantic. + type SessionHandler = ::KeyTypeIdProviders; + type SessionManager = CollatorSelection; + type ShouldEndSession = pallet_session::PeriodicSessions; type ValidatorId = ::AccountId; // we don't have stash and controller, thus we don't need the convert as well. type ValidatorIdOf = pallet_collator_selection::IdentityCollator; - type ShouldEndSession = pallet_session::PeriodicSessions; - type NextSessionRotation = pallet_session::PeriodicSessions; - type SessionManager = CollatorSelection; - // Essentially just Aura, but let's be pedantic. - type SessionHandler = ::KeyTypeIdProviders; - type Keys = SessionKeys; type WeightInfo = (); } @@ -490,15 +492,15 @@ parameter_types! { pub type CollatorSelectionUpdateOrigin = EnsureRoot; impl pallet_collator_selection::Config for Runtime { - type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type UpdateOrigin = CollatorSelectionUpdateOrigin; - type PotId = PotId; - type MaxCandidates = MaxCandidates; - type MinCandidates = MinCandidates; - type MaxInvulnerables = MaxInvulnerables; // should be a multiple of session or things will get inconsistent type KickThreshold = Period; + type MaxCandidates = MaxCandidates; + type MaxInvulnerables = MaxInvulnerables; + type MinCandidates = MinCandidates; + type PotId = PotId; + type RuntimeEvent = RuntimeEvent; + type UpdateOrigin = CollatorSelectionUpdateOrigin; type ValidatorId = ::AccountId; type ValidatorIdOf = pallet_collator_selection::IdentityCollator; type ValidatorRegistration = Session; @@ -506,17 +508,17 @@ impl pallet_collator_selection::Config for Runtime { } impl pallet_asset_tx_payment::Config for Runtime { - type RuntimeEvent = RuntimeEvent; type Fungibles = Assets; type OnChargeAssetTransaction = pallet_asset_tx_payment::FungiblesAdapter< pallet_assets::BalanceToAssetBalance, AssetsToBlockAuthor, >; + type RuntimeEvent = RuntimeEvent; } impl pallet_sudo::Config for Runtime { - type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; } // Create the runtime by composing the FRAME pallets that were previously configured. @@ -604,6 +606,14 @@ impl_runtime_apis! { fn metadata() -> OpaqueMetadata { OpaqueMetadata::new(Runtime::metadata().into()) } + + fn metadata_at_version(version: u32) -> Option { + Runtime::metadata_at_version(version) + } + + fn metadata_versions() -> sp_std::vec::Vec { + Runtime::metadata_versions() + } } impl sp_block_builder::BlockBuilder for Runtime { @@ -786,11 +796,11 @@ struct CheckInherents; impl cumulus_pallet_parachain_system::CheckInherents for CheckInherents { fn check_inherents( - block: &Block, relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof, + block: &Block, + relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof, ) -> sp_inherents::CheckInherentsResult { - let relay_chain_slot = relay_state_proof - .read_slot() - .expect("Could not read the relay chain slot from the proof"); + let relay_chain_slot = + relay_state_proof.read_slot().expect("Could not read the relay chain slot from the proof"); let inherent_data = cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration( relay_chain_slot, diff --git a/integration-tests/modified-penpal/src/weights/block_weights.rs b/integration-tests/modified-penpal/src/weights/block_weights.rs index ea8a341b5..4aee7fb93 100644 --- a/integration-tests/modified-penpal/src/weights/block_weights.rs +++ b/integration-tests/modified-penpal/src/weights/block_weights.rs @@ -44,10 +44,7 @@ pub mod constants { "Weight should be at least 100 µs." ); // At most 50 ms. - assert!( - w.ref_time() <= 50u64 * constants::WEIGHT_REF_TIME_PER_MILLIS, - "Weight should be at most 50 ms." - ); + assert!(w.ref_time() <= 50u64 * constants::WEIGHT_REF_TIME_PER_MILLIS, "Weight should be at most 50 ms."); } } } diff --git a/integration-tests/modified-penpal/src/weights/extrinsic_weights.rs b/integration-tests/modified-penpal/src/weights/extrinsic_weights.rs index 0512efb60..f7008216c 100644 --- a/integration-tests/modified-penpal/src/weights/extrinsic_weights.rs +++ b/integration-tests/modified-penpal/src/weights/extrinsic_weights.rs @@ -39,15 +39,9 @@ pub mod constants { let w = super::constants::ExtrinsicBaseWeight::get(); // At least 10 µs. - assert!( - w.ref_time() >= 10u64 * constants::WEIGHT_REF_TIME_PER_MICROS, - "Weight should be at least 10 µs." - ); + assert!(w.ref_time() >= 10u64 * constants::WEIGHT_REF_TIME_PER_MICROS, "Weight should be at least 10 µs."); // At most 1 ms. - assert!( - w.ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Weight should be at most 1 ms." - ); + assert!(w.ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, "Weight should be at most 1 ms."); } } } diff --git a/integration-tests/modified-penpal/src/xcm_config.rs b/integration-tests/modified-penpal/src/xcm_config.rs index 7810eb65b..c6ee42a9e 100644 --- a/integration-tests/modified-penpal/src/xcm_config.rs +++ b/integration-tests/modified-penpal/src/xcm_config.rs @@ -22,14 +22,15 @@ //! with statemine as the reserve. At present no derivative tokens are minted on receipt of a //! ReserveAssetTransferDeposited message but that will but the intension will be to support this soon. use super::{ - AccountId, AllPalletsWithSystem, AssetId as AssetIdPalletAssets, Assets, Balance, Balances, ParachainInfo, - ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, + AccountId, AllPalletsWithSystem, AssetId as AssetIdPalletAssets, Assets, Balance, Balances, EnsureRoot, + ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, + XcmpQueue, }; use core::marker::PhantomData; use frame_support::{ match_types, parameter_types, traits::{ - fungibles::{self, Balanced, CreditOf}, + fungibles::{self, Balanced, Credit}, ConstU32, Contains, ContainsPair, Everything, Get, Nothing, }, weights::Weight, @@ -176,8 +177,8 @@ pub struct AssetsFrom(PhantomData); impl> ContainsPair for AssetsFrom { fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { let loc = T::get(); - &loc == origin - && matches!(asset, MultiAsset { id: AssetId::Concrete(asset_loc), fun: Fungible(_a) } + &loc == origin && + matches!(asset, MultiAsset { id: AssetId::Concrete(asset_loc), fun: Fungible(_a) } if asset_loc.match_and_split(&loc).is_some()) } } @@ -202,7 +203,7 @@ where R: pallet_authorship::Config + pallet_assets::Config, AccountIdOf: From + Into, { - fn handle_credit(credit: CreditOf, pallet_assets::Pallet>) { + fn handle_credit(credit: Credit, pallet_assets::Pallet>) { if let Some(author) = pallet_authorship::Pallet::::author() { // In case of error: Will drop the result triggering the `OnDrop` of the imbalance. let _ = pallet_assets::Pallet::::resolve(&author, credit); @@ -240,7 +241,7 @@ impl ContainsPair for MultiNativeAsset { fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { if let Some(ref reserve) = asset.reserve() { if reserve == origin { - return true; + return true } } false @@ -262,23 +263,13 @@ impl ContainsPair for StatemintAssets { // location must be the statemint parachain let loc = MultiLocation::new(1, X1(Parachain(1000))); // asset must be either a fungible asset from `pallet_assets` or the native token of the relay chain - &loc == origin - && match asset { + &loc == origin && + match asset { MultiAsset { - id: - Concrete(MultiLocation { - parents: 0, - interior: X2(PalletInstance(50), GeneralIndex(_)), - }), - .. - } => true, - MultiAsset { - id: Concrete(MultiLocation { - parents: 1, - interior: Here, - }), + id: Concrete(MultiLocation { parents: 0, interior: X2(PalletInstance(50), GeneralIndex(_)) }), .. } => true, + MultiAsset { id: Concrete(MultiLocation { parents: 1, interior: Here }), .. } => true, _ => false, } @@ -289,30 +280,30 @@ pub type Reserves = (NativeAsset, StatemintAssets); pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { - type RuntimeCall = RuntimeCall; - type XcmSender = XcmRouter; + type AssetClaims = PolkadotXcm; + type AssetExchanger = (); + type AssetLocker = (); // How to withdraw and deposit an asset. type AssetTransactor = AssetTransactors; - type OriginConverter = XcmOriginToTransactDispatchOrigin; + type AssetTrap = PolkadotXcm; + type Barrier = Barrier; + type CallDispatcher = RuntimeCall; + type FeeManager = (); type IsReserve = Reserves; type IsTeleporter = NativeAsset; - type UniversalLocation = UniversalLocation; - type Barrier = Barrier; - type Weigher = FixedWeightBounds; - type Trader = UsingComponents>; - type ResponseHandler = PolkadotXcm; - type AssetTrap = PolkadotXcm; - type AssetClaims = PolkadotXcm; - type SubscriptionService = PolkadotXcm; - type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type AssetLocker = (); - type AssetExchanger = (); - type FeeManager = (); type MessageExporter = (); - type UniversalAliases = Nothing; - type CallDispatcher = RuntimeCall; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type PalletInstancesInfo = AllPalletsWithSystem; + type ResponseHandler = PolkadotXcm; + type RuntimeCall = RuntimeCall; type SafeCallFilter = Everything; + type SubscriptionService = PolkadotXcm; + type Trader = UsingComponents>; + type UniversalAliases = Nothing; + type UniversalLocation = UniversalLocation; + type Weigher = FixedWeightBounds; + type XcmSender = XcmRouter; } /// No local origins on this chain are allowed to dispatch XCM sends/executions. @@ -333,32 +324,33 @@ parameter_types! { } impl pallet_xcm::Config for Runtime { + type AdminOrigin = EnsureRoot; + // ^ Override for AdvertisedXcmVersion default + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type ExecuteXcmOrigin = EnsureXcmOrigin; + type MaxLockers = ConstU32<8>; + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + type RuntimeCall = RuntimeCall; type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; type SendXcmOrigin = EnsureXcmOrigin; - type XcmRouter = XcmRouter; - type ExecuteXcmOrigin = EnsureXcmOrigin; + type SovereignAccountOf = LocationToAccountId; + type TrustedLockers = (); + type UniversalLocation = UniversalLocation; + type Weigher = FixedWeightBounds; + type WeightInfo = pallet_xcm::TestWeightInfo; type XcmExecuteFilter = Everything; // ^ Disable dispatchable execute on the XCM pallet. // Needs to be `Everything` for local testing. type XcmExecutor = XcmExecutor; - type XcmTeleportFilter = Everything; type XcmReserveTransferFilter = Everything; - type Weigher = FixedWeightBounds; - type UniversalLocation = UniversalLocation; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; + type XcmRouter = XcmRouter; + type XcmTeleportFilter = Everything; const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; - // ^ Override for AdvertisedXcmVersion default - type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; - type Currency = Balances; - type CurrencyMatcher = (); - type TrustedLockers = (); - type SovereignAccountOf = LocationToAccountId; - type MaxLockers = ConstU32<8>; - type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/integration-tests/src/lib.rs b/integration-tests/src/lib.rs index dd2f3374f..7ea151ac7 100644 --- a/integration-tests/src/lib.rs +++ b/integration-tests/src/lib.rs @@ -28,11 +28,6 @@ use xcm_emulator::{ TestExt, }; -// DIP -use did::did_details::{DidDetails, DidEncryptionKey, DidVerificationKey}; -use dip_provider_runtime_template::DidIdentifier; -use kilt_support::deposit::Deposit; - const RELAY_ASSET_ID: u32 = 0; const RESERVE_TRANSFER_AMOUNT: u128 = 10_0_000_000_000; //10 UNITS when 10 decimals pub const INITIAL_BALANCE: u128 = 100_0_000_000_000; @@ -81,16 +76,6 @@ decl_test_parachain! { } } -decl_test_parachain! { - pub struct ProviderParachain { - Runtime = dip_provider_runtime_template::Runtime, - RuntimeOrigin = dip_provider_runtime_template::RuntimeOrigin, - XcmpMessageHandler = dip_provider_runtime_template::XcmpQueue, - DmpMessageHandler = dip_provider_runtime_template::DmpQueue, - new_ext = provider_ext(provider_id()), - } -} - decl_test_network! { pub struct Network { relay_chain = PolkadotNet, @@ -98,7 +83,6 @@ decl_test_network! { (2000u32, PolimecNet), (1000u32, StatemintNet), (3000u32, PenpalNet), - (2001u32, ProviderParachain), ], } } @@ -113,9 +97,6 @@ fn statemint_id() -> u32 { fn penpal_id() -> u32 { _para_ids()[2] } -fn provider_id() -> u32 { - _para_ids()[3] -} // Helper functions to calculate chain accounts struct ParachainAccounts; @@ -123,6 +104,7 @@ impl ParachainAccounts { fn polimec_child_account() -> RuntimeAccountId32 { ParaId::new(polimec_id()).into_account_truncating() } + fn polimec_sibling_account() -> RuntimeAccountId32 { SiblingId::from(polimec_id()).into_account_truncating() } @@ -130,6 +112,7 @@ impl ParachainAccounts { fn statemint_child_account() -> RuntimeAccountId32 { ParaId::from(statemint_id()).into_account_truncating() } + fn statemint_sibling_account() -> RuntimeAccountId32 { SiblingId::from(statemint_id()).into_account_truncating() } @@ -137,17 +120,15 @@ impl ParachainAccounts { fn penpal_child_account() -> RuntimeAccountId32 { ParaId::from(penpal_id()).into_account_truncating() } + fn penpal_sibling_account() -> RuntimeAccountId32 { SiblingId::from(penpal_id()).into_account_truncating() } - fn provider_sibling_account() -> RuntimeAccountId32 { - SiblingId::from(provider_id()).into_account_truncating() - } } fn default_parachains_host_configuration( -) -> polkadot_runtime_parachains::configuration::HostConfiguration { - use polkadot_primitives::v2::{MAX_CODE_SIZE, MAX_POV_SIZE}; +) -> polkadot_runtime_parachains::configuration::HostConfiguration { + use polkadot_primitives::v4::{MAX_CODE_SIZE, MAX_POV_SIZE}; polkadot_runtime_parachains::configuration::HostConfiguration { minimum_validation_upgrade_delay: 5, @@ -189,9 +170,7 @@ fn default_parachains_host_configuration( pub fn polkadot_ext() -> sp_io::TestExternalities { use polkadot_runtime::{Runtime, System}; - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); pallet_balances::GenesisConfig:: { balances: vec![ @@ -210,9 +189,7 @@ pub fn polkadot_ext() -> sp_io::TestExternalities { .assimilate_storage(&mut t) .unwrap(); - let xcm_config = pallet_xcm::GenesisConfig { - safe_xcm_version: Some(3), - }; + let xcm_config = pallet_xcm::GenesisConfig { safe_xcm_version: Some(3) }; >::assimilate_storage(&xcm_config, &mut t).unwrap(); let mut ext = sp_io::TestExternalities::new(t); @@ -223,20 +200,14 @@ pub fn polkadot_ext() -> sp_io::TestExternalities { pub fn polimec_ext(para_id: u32) -> sp_io::TestExternalities { use polimec_runtime::{Runtime, System}; - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - let parachain_info_config = parachain_info::GenesisConfig { - parachain_id: para_id.into(), - }; + let parachain_info_config = parachain_info::GenesisConfig { parachain_id: para_id.into() }; >::assimilate_storage(¶chain_info_config, &mut t) .unwrap(); - let xcm_config = pallet_xcm::GenesisConfig { - safe_xcm_version: Some(3), - }; + let xcm_config = pallet_xcm::GenesisConfig { safe_xcm_version: Some(3) }; >::assimilate_storage(&xcm_config, &mut t).unwrap(); pallet_balances::GenesisConfig:: { @@ -245,26 +216,20 @@ pub fn polimec_ext(para_id: u32) -> sp_io::TestExternalities { (DISPATCHER_ACCOUNT, INITIAL_BALANCE), (ParachainAccounts::penpal_sibling_account(), INITIAL_BALANCE), (ParachainAccounts::statemint_sibling_account(), INITIAL_BALANCE), - (ParachainAccounts::provider_sibling_account(), INITIAL_BALANCE), ], } .assimilate_storage(&mut t) .unwrap(); pallet_assets::GenesisConfig:: { + metadata: vec![(RELAY_ASSET_ID, "Local DOT".as_bytes().to_vec(), "DOT".as_bytes().to_vec(), 12)], + accounts: vec![(RELAY_ASSET_ID, ALICE, INITIAL_BALANCE)], assets: vec![( RELAY_ASSET_ID, - polimec_runtime::AssetsPalletId::get().into_account_truncating(), + frame_support::PalletId(*b"assetsid").into_account_truncating(), false, 1_0_000_000_000, )], - metadata: vec![( - RELAY_ASSET_ID, - "Local DOT".as_bytes().to_vec(), - "DOT".as_bytes().to_vec(), - 12, - )], - accounts: vec![(RELAY_ASSET_ID, ALICE, INITIAL_BALANCE)], } .assimilate_storage(&mut t) .unwrap(); @@ -277,20 +242,14 @@ pub fn polimec_ext(para_id: u32) -> sp_io::TestExternalities { pub fn statemint_ext(para_id: u32) -> sp_io::TestExternalities { use statemint_runtime::{Runtime, System}; - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - let parachain_info_config = parachain_info::GenesisConfig { - parachain_id: para_id.into(), - }; + let parachain_info_config = parachain_info::GenesisConfig { parachain_id: para_id.into() }; >::assimilate_storage(¶chain_info_config, &mut t) .unwrap(); - let xcm_config = pallet_xcm::GenesisConfig { - safe_xcm_version: Some(3), - }; + let xcm_config = pallet_xcm::GenesisConfig { safe_xcm_version: Some(3) }; >::assimilate_storage(&xcm_config, &mut t).unwrap(); pallet_balances::GenesisConfig:: { @@ -311,19 +270,13 @@ pub fn statemint_ext(para_id: u32) -> sp_io::TestExternalities { pub fn penpal_ext(para_id: u32) -> sp_io::TestExternalities { use penpal_runtime::{Runtime, System}; - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - let parachain_info_config = parachain_info::GenesisConfig { - parachain_id: para_id.into(), - }; + let parachain_info_config = parachain_info::GenesisConfig { parachain_id: para_id.into() }; >::assimilate_storage(¶chain_info_config, &mut t) .unwrap(); - let xcm_config = pallet_xcm::GenesisConfig { - safe_xcm_version: Some(3), - }; + let xcm_config = pallet_xcm::GenesisConfig { safe_xcm_version: Some(3) }; >::assimilate_storage(&xcm_config, &mut t).unwrap(); pallet_balances::GenesisConfig:: { @@ -341,55 +294,6 @@ pub fn penpal_ext(para_id: u32) -> sp_io::TestExternalities { ext } -pub fn provider_ext(para_id: u32) -> sp_io::TestExternalities { - use dip_provider_runtime_template::{Runtime, System}; - - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); - - let parachain_info_config = parachain_info::GenesisConfig { - parachain_id: para_id.into(), - }; - >::assimilate_storage(¶chain_info_config, &mut t) - .unwrap(); - - let mut ext = sp_io::TestExternalities::new(t); - let did: DidIdentifier = did_auth_key().public().into(); - let details = generate_did_details(); - ext.execute_with(|| { - did::pallet::Did::::insert(&did, details); - System::set_block_number(1); - }); - ext -} - -pub(crate) fn did_auth_key() -> ed25519::Pair { - ed25519::Pair::from_seed(&[200u8; 32]) -} - -fn generate_did_details() -> DidDetails { - let auth_key: DidVerificationKey = did_auth_key().public().into(); - let att_key: DidVerificationKey = sr25519::Pair::from_seed(&[100u8; 32]).public().into(); - let del_key: DidVerificationKey = ecdsa::Pair::from_seed(&[101u8; 32]).public().into(); - - let mut details = DidDetails::new( - auth_key, - 0u32, - Deposit { - amount: 1u64.into(), - owner: dip_provider_runtime_template::AccountId::new([1u8; 32]), - }, - ) - .unwrap(); - details.update_attestation_key(att_key, 0u32).unwrap(); - details.update_delegation_key(del_key, 0u32).unwrap(); - details - .add_key_agreement_key(DidEncryptionKey::X25519([100u8; 32]), 0u32) - .unwrap(); - details -} - /// Shortcuts to reduce boilerplate on runtime types pub mod shortcuts { use super::*; @@ -398,7 +302,6 @@ pub mod shortcuts { pub type PolimecRuntime = polimec_runtime::Runtime; pub type StatemintRuntime = statemint_runtime::Runtime; pub type PenpalRuntime = penpal_runtime::Runtime; - pub type ProviderRuntime = dip_provider_runtime_template::Runtime; pub type PolkadotXcmPallet = polkadot_runtime::XcmPallet; pub type PolimecXcmPallet = polimec_runtime::PolkadotXcm; @@ -429,7 +332,6 @@ pub mod shortcuts { pub type PolimecAccountId = polkadot_primitives::AccountId; pub type StatemintAccountId = polkadot_primitives::AccountId; pub type PenpalAccountId = polkadot_primitives::AccountId; - pub type ProviderAccountId = dip_provider_runtime_template::AccountId; } #[cfg(test)] @@ -449,10 +351,7 @@ mod network_tests { Here, Parachain(polimec_id()), Xcm(vec![ - UnpaidExecution { - weight_limit: WeightLimit::Unlimited, - check_origin: None - }, + UnpaidExecution { weight_limit: WeightLimit::Unlimited, check_origin: None }, Transact { origin_kind: OriginKind::SovereignAccount, require_weight_at_most: Weight::from_parts(INITIAL_BALANCE as u64, 1024 * 1024), @@ -484,20 +383,14 @@ mod network_tests { let here_asset: MultiAsset = (MultiLocation::here(), INITIAL_BALANCE / 2).into(); PolimecNet::execute_with(|| { - assert_ok!(PolimecXcmPallet::force_default_xcm_version( - PolimecOrigin::root(), - Some(3) - )); + assert_ok!(PolimecXcmPallet::force_default_xcm_version(PolimecOrigin::root(), Some(3))); assert_ok!(PolimecXcmPallet::send_xcm( Here, Parent, Xcm(vec![ WithdrawAsset(vec![here_asset.clone()].into()), - BuyExecution { - fees: here_asset.clone(), - weight_limit: Unlimited - }, + BuyExecution { fees: here_asset.clone(), weight_limit: Unlimited }, Transact { origin_kind: OriginKind::SovereignAccount, require_weight_at_most: Weight::from_parts(INITIAL_BALANCE as u64, 1024 * 1024), @@ -512,10 +405,7 @@ mod network_tests { let events = System::events(); assert!(events.iter().any(|r| matches!( r.event, - RuntimeEvent::Ump(polkadot_runtime_parachains::ump::Event::ExecutedUpward( - _, - Outcome::Complete(_), - )) + RuntimeEvent::Ump(polkadot_runtime_parachains::ump::Event::ExecutedUpward(_, Outcome::Complete(_),)) ))); }); } @@ -537,10 +427,7 @@ mod network_tests { MultiLocation::new(1, X1(Parachain(polimec_id()))), Xcm(vec![ WithdrawAsset(vec![here_asset.clone()].into()), - BuyExecution { - fees: here_asset.clone(), - weight_limit: Unlimited - }, + BuyExecution { fees: here_asset.clone(), weight_limit: Unlimited }, Transact { origin_kind: OriginKind::SovereignAccount, require_weight_at_most: Weight::from_parts(INITIAL_BALANCE as u64, 1024 * 1024), @@ -553,10 +440,9 @@ mod network_tests { PolimecNet::execute_with(|| { use polimec_runtime::{RuntimeEvent, System}; let events = System::events(); - assert!(events.iter().any(|r| matches!( - r.event, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) - ))); + assert!(events + .iter() + .any(|r| matches!(r.event, RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. })))); }); } } @@ -601,10 +487,7 @@ mod reserve_backed_transfers { StatemintNet::execute_with(|| { assert_ok!(StatemintXcmPallet::limited_reserve_transfer_assets( StatemintOrigin::signed(ALICE), - Box::new(VersionedMultiLocation::V3(MultiLocation::new( - 1, - X1(Parachain(polimec_id())), - ))), + Box::new(VersionedMultiLocation::V3(MultiLocation::new(1, X1(Parachain(polimec_id())),))), Box::new(VersionedMultiLocation::V3(MultiLocation::from(AccountId32 { network: None, id: ALICE.into(), @@ -619,10 +502,9 @@ mod reserve_backed_transfers { PolimecNet::execute_with(|| { use polimec_runtime::{RuntimeEvent, System}; let events = System::events(); - assert!(events.iter().any(|r| matches!( - r.event, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) - ))); + assert!(events + .iter() + .any(|r| matches!(r.event, RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. })))); }); // check Polimec's post transfer balances and issuance @@ -663,16 +545,15 @@ mod reserve_backed_transfers { let statemint_delta_dot_issuance = statemint_prev_dot_issuance - statemint_post_dot_issuance; assert!( - polimec_delta_alice_dot_balance >= RESERVE_TRANSFER_AMOUNT - polimec_runtime::WeightToFee::::weight_to_fee(&MAX_XCM_WEIGHT) && + polimec_delta_alice_dot_balance >= RESERVE_TRANSFER_AMOUNT - polimec_runtime::WeightToFee::weight_to_fee(&MAX_XCM_WEIGHT) && polimec_delta_alice_dot_balance <= RESERVE_TRANSFER_AMOUNT, "Polimec ALICE DOT balance should have increased by at least the transfer amount minus the XCM execution fee" ); assert!( - polimec_delta_dot_issuance - >= RESERVE_TRANSFER_AMOUNT - - polimec_runtime::WeightToFee::::weight_to_fee(&MAX_XCM_WEIGHT) - && polimec_delta_dot_issuance <= RESERVE_TRANSFER_AMOUNT, + polimec_delta_dot_issuance >= + RESERVE_TRANSFER_AMOUNT - polimec_runtime::WeightToFee::weight_to_fee(&MAX_XCM_WEIGHT) && + polimec_delta_dot_issuance <= RESERVE_TRANSFER_AMOUNT, "Polimec DOT issuance should have increased by at least the transfer amount minus the XCM execution fee" ); @@ -691,15 +572,9 @@ mod reserve_backed_transfers { "Statemint's DOT issuance should not change, since it acts as a reserve for that asset (except for fees which are burnt)" ); - assert_eq!( - polimec_delta_alice_plmc_balance, 0, - "Polimec ALICE PLMC balance should not have changed" - ); + assert_eq!(polimec_delta_alice_plmc_balance, 0, "Polimec ALICE PLMC balance should not have changed"); - assert_eq!( - polimec_delta_plmc_issuance, 0, - "Polimec PLMC issuance should not have changed" - ); + assert_eq!(polimec_delta_plmc_issuance, 0, "Polimec PLMC issuance should not have changed"); } #[test] @@ -727,36 +602,21 @@ mod reserve_backed_transfers { // check Statemint's pre transfer balances and issuance let (statemint_prev_alice_dot_balance, statemint_prev_dot_issuance) = StatemintNet::execute_with(|| { - ( - StatemintBalances::free_balance(ALICE), - StatemintBalances::total_issuance(), - ) + (StatemintBalances::free_balance(ALICE), StatemintBalances::total_issuance()) }); // construct the XCM to transfer from Polimec to Statemint's reserve let transfer_xcm: Xcm = Xcm(vec![ WithdrawAsset(vec![dot.clone()].into()), - BuyExecution { - fees: execution_dot.clone(), - weight_limit: Limited(MAX_XCM_WEIGHT), - }, + BuyExecution { fees: execution_dot.clone(), weight_limit: Limited(MAX_XCM_WEIGHT) }, InitiateReserveWithdraw { assets: All.into(), reserve: MultiLocation::new(1, X1(Parachain(statemint_id()))), xcm: Xcm(vec![ - BuyExecution { - fees: execution_dot.clone(), - weight_limit: Limited(MAX_XCM_WEIGHT), - }, + BuyExecution { fees: execution_dot.clone(), weight_limit: Limited(MAX_XCM_WEIGHT) }, DepositAsset { assets: All.into(), - beneficiary: MultiLocation::new( - 0, - AccountId32 { - network: None, - id: ALICE.into(), - }, - ), + beneficiary: MultiLocation::new(0, AccountId32 { network: None, id: ALICE.into() }), }, ]), }, @@ -775,10 +635,9 @@ mod reserve_backed_transfers { StatemintNet::execute_with(|| { use statemint_runtime::{RuntimeEvent, System}; let events = System::events(); - assert!(events.iter().any(|r| matches!( - r.event, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) - ))); + assert!(events + .iter() + .any(|r| matches!(r.event, RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. })))); }); // check Polimec's post transfer balances and issuance @@ -798,10 +657,7 @@ mod reserve_backed_transfers { // check Statemint's post transfer balances and issuance let (statemint_post_alice_dot_balance, statemint_post_dot_issuance) = StatemintNet::execute_with(|| { - ( - StatemintBalances::free_balance(ALICE), - StatemintBalances::total_issuance(), - ) + (StatemintBalances::free_balance(ALICE), StatemintBalances::total_issuance()) }); let polimec_delta_dot_issuance = polimec_prev_dot_issuance - polimec_post_dot_issuance; @@ -823,16 +679,13 @@ mod reserve_backed_transfers { ); assert_eq!(polimec_delta_plmc_issuance, 0, "Polimec's PLMC issuance should not change, since all xcm token transfer are done in DOT, and no fees are burnt since no extrinsics are dispatched"); - assert_eq!( - polimec_delta_alice_plmc_balance, 0, - "Polimec's Alice PLMC should not change" - ); + assert_eq!(polimec_delta_alice_plmc_balance, 0, "Polimec's Alice PLMC should not change"); assert!( - statemint_delta_alice_dot_balance - >= RESERVE_TRANSFER_AMOUNT - - statemint_runtime::constants::fee::WeightToFee::weight_to_fee(&MAX_XCM_WEIGHT) - && statemint_delta_alice_dot_balance <= RESERVE_TRANSFER_AMOUNT, + statemint_delta_alice_dot_balance >= + RESERVE_TRANSFER_AMOUNT - + statemint_runtime::constants::fee::WeightToFee::weight_to_fee(&MAX_XCM_WEIGHT) && + statemint_delta_alice_dot_balance <= RESERVE_TRANSFER_AMOUNT, "Statemint's ALICE DOT balance should increase by at least the transfer amount minus the max allowed fees" ); @@ -866,10 +719,7 @@ mod reserve_backed_transfers { StatemintNet::execute_with(|| { assert_ok!(StatemintXcmPallet::limited_reserve_transfer_assets( StatemintOrigin::signed(ALICE), - Box::new(VersionedMultiLocation::V3(MultiLocation::new( - 1, - X1(Parachain(penpal_id())), - ))), + Box::new(VersionedMultiLocation::V3(MultiLocation::new(1, X1(Parachain(penpal_id())),))), Box::new(VersionedMultiLocation::V3(MultiLocation::from(AccountId32 { network: None, id: ALICE.into(), @@ -884,10 +734,9 @@ mod reserve_backed_transfers { PenpalNet::execute_with(|| { use penpal_runtime::{RuntimeEvent, System}; let events = System::events(); - assert!(events.iter().any(|r| matches!( - r.event, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) - ))); + assert!(events + .iter() + .any(|r| matches!(r.event, RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. })))); }); // check Penpal's post transfer balances and issuance @@ -921,9 +770,9 @@ mod reserve_backed_transfers { ); assert!( - penpal_delta_dot_issuance - >= RESERVE_TRANSFER_AMOUNT - penpal_runtime::WeightToFee::weight_to_fee(&MAX_XCM_WEIGHT) - && penpal_delta_dot_issuance <= RESERVE_TRANSFER_AMOUNT, + penpal_delta_dot_issuance >= + RESERVE_TRANSFER_AMOUNT - penpal_runtime::WeightToFee::weight_to_fee(&MAX_XCM_WEIGHT) && + penpal_delta_dot_issuance <= RESERVE_TRANSFER_AMOUNT, "Penpal DOT issuance should have increased by at least the transfer amount minus the XCM execution fee" ); @@ -957,36 +806,21 @@ mod reserve_backed_transfers { // check Statemint's pre transfer balances and issuance let (statemint_prev_alice_dot_balance, statemint_prev_dot_issuance) = StatemintNet::execute_with(|| { - ( - StatemintBalances::free_balance(ALICE), - StatemintBalances::total_issuance(), - ) + (StatemintBalances::free_balance(ALICE), StatemintBalances::total_issuance()) }); // construct the XCM to transfer from Penpal to Statemint's reserve let transfer_xcm: Xcm = Xcm(vec![ WithdrawAsset(vec![dot.clone()].into()), - BuyExecution { - fees: execution_dot.clone(), - weight_limit: Limited(MAX_XCM_WEIGHT), - }, + BuyExecution { fees: execution_dot.clone(), weight_limit: Limited(MAX_XCM_WEIGHT) }, InitiateReserveWithdraw { assets: All.into(), reserve: MultiLocation::new(1, X1(Parachain(statemint_id()))), xcm: Xcm(vec![ - BuyExecution { - fees: execution_dot.clone(), - weight_limit: Limited(MAX_XCM_WEIGHT), - }, + BuyExecution { fees: execution_dot.clone(), weight_limit: Limited(MAX_XCM_WEIGHT) }, DepositAsset { assets: All.into(), - beneficiary: MultiLocation::new( - 0, - AccountId32 { - network: None, - id: ALICE.into(), - }, - ), + beneficiary: MultiLocation::new(0, AccountId32 { network: None, id: ALICE.into() }), }, ]), }, @@ -1005,10 +839,9 @@ mod reserve_backed_transfers { StatemintNet::execute_with(|| { use statemint_runtime::{RuntimeEvent, System}; let events = System::events(); - assert!(events.iter().any(|r| matches!( - r.event, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) - ))); + assert!(events + .iter() + .any(|r| matches!(r.event, RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. })))); }); // check Penpal's post transfer balances and issuance @@ -1017,10 +850,7 @@ mod reserve_backed_transfers { // check Statemint's post transfer balances and issuance let (statemint_post_alice_dot_balance, statemint_post_dot_issuance) = StatemintNet::execute_with(|| { - ( - StatemintBalances::free_balance(ALICE), - StatemintBalances::total_issuance(), - ) + (StatemintBalances::free_balance(ALICE), StatemintBalances::total_issuance()) }); let penpal_delta_dot_issuance = penpal_prev_dot_issuance - penpal_post_dot_issuance; @@ -1040,10 +870,10 @@ mod reserve_backed_transfers { ); assert!( - statemint_delta_alice_dot_balance - >= RESERVE_TRANSFER_AMOUNT - - statemint_runtime::constants::fee::WeightToFee::weight_to_fee(&MAX_XCM_WEIGHT) - && statemint_delta_alice_dot_balance <= RESERVE_TRANSFER_AMOUNT, + statemint_delta_alice_dot_balance >= + RESERVE_TRANSFER_AMOUNT - + statemint_runtime::constants::fee::WeightToFee::weight_to_fee(&MAX_XCM_WEIGHT) && + statemint_delta_alice_dot_balance <= RESERVE_TRANSFER_AMOUNT, "Statemint's ALICE DOT balance should increase by at least the transfer amount minus the max allowed fees" ); @@ -1062,33 +892,20 @@ mod reserve_backed_transfers { let transfer_xcm: Xcm = Xcm(vec![ WithdrawAsset(vec![dot.clone()].into()), - BuyExecution { - fees: execution_dot.clone(), - weight_limit: Limited(MAX_XCM_WEIGHT), - }, + BuyExecution { fees: execution_dot.clone(), weight_limit: Limited(MAX_XCM_WEIGHT) }, InitiateReserveWithdraw { assets: All.into(), reserve: MultiLocation::new(1, X1(Parachain(statemint_id()))), xcm: Xcm::<()>(vec![ - BuyExecution { - fees: execution_dot.clone(), - weight_limit: Limited(MAX_XCM_WEIGHT), - }, + BuyExecution { fees: execution_dot.clone(), weight_limit: Limited(MAX_XCM_WEIGHT) }, DepositReserveAsset { assets: All.into(), dest: MultiLocation::new(1, X1(Parachain(penpal_id()))), xcm: Xcm::<()>(vec![ - BuyExecution { - fees: execution_dot.clone(), - weight_limit: Limited(MAX_XCM_WEIGHT), - }, + BuyExecution { fees: execution_dot.clone(), weight_limit: Limited(MAX_XCM_WEIGHT) }, DepositAsset { assets: All.into(), - beneficiary: X1(AccountId32 { - network: None, - id: ALICE.into(), - }) - .into(), + beneficiary: X1(AccountId32 { network: None, id: ALICE.into() }).into(), }, ]), }, @@ -1113,10 +930,7 @@ mod reserve_backed_transfers { // check Statemint's pre transfer balances and issuance let (statemint_prev_alice_dot_balance, statemint_prev_dot_issuance) = StatemintNet::execute_with(|| { - ( - StatemintBalances::free_balance(ALICE), - StatemintBalances::total_issuance(), - ) + (StatemintBalances::free_balance(ALICE), StatemintBalances::total_issuance()) }); // check Penpal's pre transfer balances and issuance @@ -1135,19 +949,17 @@ mod reserve_backed_transfers { StatemintNet::execute_with(|| { use statemint_runtime::{RuntimeEvent, System}; let events = System::events(); - assert!(events.iter().any(|r| matches!( - r.event, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) - ))); + assert!(events + .iter() + .any(|r| matches!(r.event, RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. })))); }); PenpalNet::execute_with(|| { use penpal_runtime::{RuntimeEvent, System}; let events = System::events(); - assert!(events.iter().any(|r| matches!( - r.event, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) - ))); + assert!(events + .iter() + .any(|r| matches!(r.event, RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. })))); }); // check Polimec's pre transfer balances and issuance @@ -1167,10 +979,7 @@ mod reserve_backed_transfers { // check Statemint's pre transfer balances and issuance let (statemint_post_alice_dot_balance, statemint_post_dot_issuance) = StatemintNet::execute_with(|| { - ( - StatemintBalances::free_balance(ALICE), - StatemintBalances::total_issuance(), - ) + (StatemintBalances::free_balance(ALICE), StatemintBalances::total_issuance()) }); // check Penpal's pre transfer balances and issuance @@ -1189,8 +998,8 @@ mod reserve_backed_transfers { let statemint_delta_alice_dot_balance = statemint_prev_alice_dot_balance - statemint_post_alice_dot_balance; assert!( - penpal_delta_alice_dot_balance > RESERVE_TRANSFER_AMOUNT - MAX_XCM_FEE * 3 - && penpal_delta_alice_dot_balance < RESERVE_TRANSFER_AMOUNT, + penpal_delta_alice_dot_balance > RESERVE_TRANSFER_AMOUNT - MAX_XCM_FEE * 3 && + penpal_delta_alice_dot_balance < RESERVE_TRANSFER_AMOUNT, "Expected funds are not received by Alice on Penpal" ); @@ -1214,20 +1023,11 @@ mod reserve_backed_transfers { "Statemint's DOT issuance should not change, since it acts as a reserve for that asset (except for fees which are burnt)" ); - assert_eq!( - statemint_delta_alice_dot_balance, 0, - "ALICE account on Statemint should not have changed" - ); + assert_eq!(statemint_delta_alice_dot_balance, 0, "ALICE account on Statemint should not have changed"); - assert_eq!( - polimec_delta_alice_plmc_balance, 0, - "Polimec ALICE PLMC balance should not have changed" - ); + assert_eq!(polimec_delta_alice_plmc_balance, 0, "Polimec ALICE PLMC balance should not have changed"); - assert_eq!( - polimec_delta_plmc_issuance, 0, - "Polimec PLMC issuance should not have changed" - ); + assert_eq!(polimec_delta_plmc_issuance, 0, "Polimec PLMC issuance should not have changed"); } #[test] @@ -1239,33 +1039,20 @@ mod reserve_backed_transfers { let transfer_xcm: Xcm = Xcm(vec![ WithdrawAsset(vec![dot.clone()].into()), - BuyExecution { - fees: execution_dot.clone(), - weight_limit: Limited(MAX_XCM_WEIGHT), - }, + BuyExecution { fees: execution_dot.clone(), weight_limit: Limited(MAX_XCM_WEIGHT) }, InitiateReserveWithdraw { assets: All.into(), reserve: MultiLocation::new(1, X1(Parachain(statemint_id()))), xcm: Xcm::<()>(vec![ - BuyExecution { - fees: execution_dot.clone(), - weight_limit: Limited(MAX_XCM_WEIGHT), - }, + BuyExecution { fees: execution_dot.clone(), weight_limit: Limited(MAX_XCM_WEIGHT) }, DepositReserveAsset { assets: All.into(), dest: MultiLocation::new(1, X1(Parachain(polimec_id()))), xcm: Xcm::<()>(vec![ - BuyExecution { - fees: execution_dot.clone(), - weight_limit: Limited(MAX_XCM_WEIGHT), - }, + BuyExecution { fees: execution_dot.clone(), weight_limit: Limited(MAX_XCM_WEIGHT) }, DepositAsset { assets: All.into(), - beneficiary: X1(AccountId32 { - network: None, - id: ALICE.into(), - }) - .into(), + beneficiary: X1(AccountId32 { network: None, id: ALICE.into() }).into(), }, ]), }, @@ -1290,10 +1077,7 @@ mod reserve_backed_transfers { // check Statemint's pre transfer balances and issuance let (statemint_prev_alice_dot_balance, statemint_prev_dot_issuance) = StatemintNet::execute_with(|| { - ( - StatemintBalances::free_balance(ALICE), - StatemintBalances::total_issuance(), - ) + (StatemintBalances::free_balance(ALICE), StatemintBalances::total_issuance()) }); // check Penpal's pre transfer balances and issuance @@ -1312,19 +1096,17 @@ mod reserve_backed_transfers { StatemintNet::execute_with(|| { use statemint_runtime::{RuntimeEvent, System}; let events = System::events(); - assert!(events.iter().any(|r| matches!( - r.event, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) - ))); + assert!(events + .iter() + .any(|r| matches!(r.event, RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. })))); }); PolimecNet::execute_with(|| { use polimec_runtime::{RuntimeEvent, System}; let events = System::events(); - assert!(events.iter().any(|r| matches!( - r.event, - RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. }) - ))); + assert!(events + .iter() + .any(|r| matches!(r.event, RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::Success { .. })))); }); // check Polimec's pre transfer balances and issuance @@ -1344,10 +1126,7 @@ mod reserve_backed_transfers { // check Statemint's pre transfer balances and issuance let (statemint_post_alice_dot_balance, statemint_post_dot_issuance) = StatemintNet::execute_with(|| { - ( - StatemintBalances::free_balance(ALICE), - StatemintBalances::total_issuance(), - ) + (StatemintBalances::free_balance(ALICE), StatemintBalances::total_issuance()) }); // check Penpal's pre transfer balances and issuance @@ -1366,8 +1145,8 @@ mod reserve_backed_transfers { let statemint_delta_alice_dot_balance = statemint_prev_alice_dot_balance - statemint_post_alice_dot_balance; assert!( - polimec_delta_alice_dot_balance > RESERVE_TRANSFER_AMOUNT - MAX_XCM_FEE * 3 - && polimec_delta_alice_dot_balance < RESERVE_TRANSFER_AMOUNT, + polimec_delta_alice_dot_balance > RESERVE_TRANSFER_AMOUNT - MAX_XCM_FEE * 3 && + polimec_delta_alice_dot_balance < RESERVE_TRANSFER_AMOUNT, "Expected funds are not received by Alice on Polimec" ); @@ -1391,115 +1170,10 @@ mod reserve_backed_transfers { "Statemint's DOT issuance should not change, since it acts as a reserve for that asset (except for fees which are burnt)" ); - assert_eq!( - statemint_delta_alice_dot_balance, 0, - "ALICE account on Statemint should not have changed" - ); - - assert_eq!( - polimec_delta_alice_plmc_balance, 0, - "Polimec ALICE PLMC balance should not have changed" - ); - - assert_eq!( - polimec_delta_plmc_issuance, 0, - "Polimec PLMC issuance should not have changed" - ); - } -} + assert_eq!(statemint_delta_alice_dot_balance, 0, "ALICE account on Statemint should not have changed"); -#[cfg(test)] -mod dip { - use super::*; - use did::{Did, DidSignature}; - use dip_provider_runtime_template::DipProvider; - use pallet_did_lookup::linkable_account::LinkableAccountId; - use polimec_runtime::DipConsumer; + assert_eq!(polimec_delta_alice_plmc_balance, 0, "Polimec ALICE PLMC balance should not have changed"); - #[test] - fn commit_identity() { - Network::reset(); - use frame_system::RawOrigin; - use kilt_dip_support::{ - did::{MerkleEntriesAndDidSignature, TimeBoundDidSignature}, - merkle::MerkleProof, - }; - use kilt_runtime_common::dip::merkle::CompleteMerkleProof; - use kilt_runtime_common::dip::merkle::DidMerkleRootGenerator; - use polimec_parachain_runtime::{ - BlockNumber, DidLookup, Runtime as ConsumerRuntime, RuntimeCall as ConsumerRuntimeCall, RuntimeEvent, - System, - }; - use sp_runtime::traits::Zero; - - let did: DidIdentifier = did_auth_key().public().into(); - - // 1. Send identity proof from DIP provider to DIP consumer. - ProviderParachain::execute_with(|| { - assert_ok!(DipProvider::commit_identity( - RawOrigin::Signed(ProviderAccountId::from([0u8; 32])).into(), - did.clone(), - Box::new(ParentThen(X1(Parachain(polimec_id()))).into()), - Box::new((Here, 1_000_000_000).into()), - Weight::from_ref_time(4_000), - )); - }); - // 2. Verify that the proof has made it to the DIP consumer. - PolimecNet::execute_with(|| { - // 2.1 Verify that there was no XCM error. - assert!(!System::events().iter().any(|r| matches!( - r.event, - RuntimeEvent::XcmpQueue(XcmpEvent::Fail { - error: _, - message_hash: _, - weight: _ - }) - ))); - // 2.2 Verify the proof digest was stored correctly. - assert!(DipConsumer::identity_proofs(&did).is_some()); - }); - // 3. Call an extrinsic on the consumer chain with a valid proof and signature - let did_details = ProviderParachain::execute_with(|| { - Did::get(&did).expect("DID details should be stored on the provider chain.") - }); - let call = ConsumerRuntimeCall::DidLookup(pallet_did_lookup::Call::::associate_sender {}); - // 3.1 Generate a proof - let CompleteMerkleProof { proof, .. } = DidMerkleRootGenerator::::generate_proof( - &did_details, - [did_details.authentication_key].iter(), - ) - .expect("Proof generation should not fail"); - // 3.2 Generate a DID signature - let genesis_hash = - PolimecNet::execute_with(|| frame_system::Pallet::::block_hash(BlockNumber::zero())); - let system_block = PolimecNet::execute_with(frame_system::Pallet::::block_number); - let payload = (call.clone(), 0u128, DISPATCHER_ACCOUNT, system_block, genesis_hash); - let signature: DidSignature = did_auth_key().sign(&payload.encode()).into(); - // 3.3 Call the `dispatch_as` extrinsic on the consumer chain with the generated - // proof - PolimecNet::execute_with(|| { - assert_ok!(DipConsumer::dispatch_as( - RawOrigin::Signed(DISPATCHER_ACCOUNT).into(), - did.clone(), - MerkleEntriesAndDidSignature { - merkle_entries: MerkleProof { - blinded: proof.blinded, - revealed: proof.revealed, - }, - did_signature: TimeBoundDidSignature { - signature, - block_number: system_block - } - }, - Box::new(call), - )); - // Verify the account -> DID link exists and contains the right information - let linked_did = - DidLookup::connected_dids::(DISPATCHER_ACCOUNT.into()).map(|link| link.did); - assert_eq!(linked_did, Some(did.clone())); - // Verify that the details of the DID subject have been bumped - let details = DipConsumer::identity_proofs(&did).map(|entry| entry.details); - assert_eq!(details, Some(1u128)); - }); + assert_eq!(polimec_delta_plmc_issuance, 0, "Polimec PLMC issuance should not have changed"); } } diff --git a/nodes/parachain/Cargo.toml b/nodes/parachain/Cargo.toml index bcbf88b45..8a1316d20 100644 --- a/nodes/parachain/Cargo.toml +++ b/nodes/parachain/Cargo.toml @@ -16,6 +16,7 @@ log.workspace = true parity-scale-codec = { workspace = true } serde = { workspace = true, features = ["derive"] } jsonrpsee = { workspace = true, features = ["server"] } +hex-literal.workspace = true # Local polimec-parachain-runtime.workspace = true @@ -41,6 +42,7 @@ sc-telemetry.workspace = true sc-tracing.workspace = true sc-transaction-pool.workspace = true sc-transaction-pool-api.workspace = true +sc-network-sync.workspace = true sp-api.workspace = true sp-block-builder.workspace = true sp-blockchain.workspace = true diff --git a/nodes/parachain/src/chain_spec.rs b/nodes/parachain/src/chain_spec.rs index 67fd4a24c..920f71dbd 100644 --- a/nodes/parachain/src/chain_spec.rs +++ b/nodes/parachain/src/chain_spec.rs @@ -18,7 +18,7 @@ use cumulus_primitives_core::ParaId; use polimec_parachain_runtime::{AccountId, Signature}; -use polkadot_primitives::v2::LOWEST_PUBLIC_ID; +use polkadot_primitives::v4::LOWEST_PUBLIC_ID; use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup}; use sc_service::Properties; use serde::{Deserialize, Serialize}; @@ -28,15 +28,11 @@ use sp_runtime::traits::{IdentifyAccount, Verify}; pub mod base; pub mod testnet; -// TODO: Set a proper TELEMETRY_URL -const TELEMETRY_URL: &str = "wss://tbd"; const DEFAULT_PARA_ID: ParaId = LOWEST_PUBLIC_ID; /// Helper function to generate a crypto pair from seed pub fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{seed}"), None) - .expect("static values are valid; qed") - .public() + TPublic::Pair::from_string(&format!("//{seed}"), None).expect("static values are valid; qed").public() } /// The extensions for the [`ChainSpec`]. diff --git a/nodes/parachain/src/chain_spec/base.rs b/nodes/parachain/src/chain_spec/base.rs index f10a85790..c1e167fa7 100644 --- a/nodes/parachain/src/chain_spec/base.rs +++ b/nodes/parachain/src/chain_spec/base.rs @@ -22,13 +22,17 @@ use crate::chain_spec::Extensions; use cumulus_primitives_core::ParaId; use polimec_base_runtime as base_runtime; use sc_service::ChainType; -use sp_core::sr25519; +use sp_core::{crypto::UncheckedInto, sr25519}; +use sp_runtime::{Perbill, Percent}; -use crate::chain_spec::{get_account_id_from_seed, get_from_seed, get_properties, DEFAULT_PARA_ID}; +use crate::chain_spec::{get_account_id_from_seed, get_properties, DEFAULT_PARA_ID}; use base_runtime::{ - polimec_inflation_config, staking::MinCollatorStake, AccountId, AuraId as AuthorityId, Balance, BalancesConfig, - GenesisConfig, InflationInfo, ParachainInfoConfig, ParachainStakingConfig, PolkadotXcmConfig, SessionConfig, - SudoConfig, SystemConfig, MAX_COLLATOR_STAKE, PLMC, + pallet_parachain_staking::{ + inflation::{perbill_annual_to_perbill_round, BLOCKS_PER_YEAR}, + InflationInfo, Range, + }, + AccountId, AuraId as AuthorityId, Balance, BalancesConfig, GenesisConfig, MinCandidateStk, ParachainInfoConfig, + ParachainStakingConfig, PolkadotXcmConfig, SessionConfig, SudoConfig, SystemConfig, PLMC, }; /// The default XCM version to set in genesis config. @@ -37,73 +41,64 @@ const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; /// Specialized `ChainSpec` for the shell parachain runtime. pub type ChainSpec = sc_service::GenericChainSpec; +const COLLATOR_COMMISSION: Perbill = Perbill::from_percent(30); +const PARACHAIN_BOND_RESERVE_PERCENT: Percent = Percent::from_percent(0); +const BLOCKS_PER_ROUND: u32 = 2 * 10; +const NUM_SELECTED_CANDIDATES: u32 = 5; +pub fn polimec_inflation_config() -> InflationInfo { + fn to_round_inflation(annual: Range) -> Range { + perbill_annual_to_perbill_round( + annual, + // rounds per year + BLOCKS_PER_YEAR / BLOCKS_PER_ROUND, + ) + } + + let annual = + Range { min: Perbill::from_percent(2), ideal: Perbill::from_percent(3), max: Perbill::from_percent(3) }; + + InflationInfo { + // staking expectations + expect: Range { min: 100_000 * PLMC, ideal: 200_000 * PLMC, max: 500_000 * PLMC }, + // annual inflation + annual, + round: to_round_inflation(annual), + } +} + +pub fn get_base_session_keys(keys: AuthorityId) -> base_runtime::SessionKeys { + base_runtime::SessionKeys { aura: keys } +} + pub fn get_local_base_chain_spec() -> Result { let properties = get_properties("PLMC", 10, 41); let wasm = base_runtime::WASM_BINARY.ok_or("No WASM")?; Ok(ChainSpec::from_genesis( "Polimec Base Develop", - "polimec", + "polimec-base", ChainType::Local, move || { base_testnet_genesis( wasm, vec![ - ( - get_account_id_from_seed::("Alice"), - None, - 2 * MinCollatorStake::get(), - ), - ( - get_account_id_from_seed::("Bob"), - None, - 2 * MinCollatorStake::get(), - ), + (get_account_id_from_seed::("Alice"), None, 2 * MinCandidateStk::get()), + (get_account_id_from_seed::("Bob"), None, 2 * MinCandidateStk::get()), ], polimec_inflation_config(), - MAX_COLLATOR_STAKE, vec![ - ( - get_account_id_from_seed::("Alice"), - get_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_from_seed::("Bob"), - ), + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), ], vec![ - (get_account_id_from_seed::("Alice"), 10000000 * PLMC), - (get_account_id_from_seed::("Bob"), 10000000 * PLMC), - (get_account_id_from_seed::("Charlie"), 10000000 * PLMC), - (get_account_id_from_seed::("Dave"), 10000000 * PLMC), - (get_account_id_from_seed::("Eve"), 10000000 * PLMC), - (get_account_id_from_seed::("Ferdie"), 10000000 * PLMC), - ( - get_account_id_from_seed::("Alice//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Bob//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Charlie//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Dave//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Eve//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Ferdie//stash"), - 10000000 * PLMC, - ), + (get_account_id_from_seed::("Alice"), 5 * MinCandidateStk::get()), + (get_account_id_from_seed::("Bob"), 5 * MinCandidateStk::get()), + (get_account_id_from_seed::("Charlie"), 5 * MinCandidateStk::get()), + (get_account_id_from_seed::("Dave"), 5 * MinCandidateStk::get()), + (get_account_id_from_seed::("Eve"), 5 * MinCandidateStk::get()), + (get_account_id_from_seed::("Ferdie"), 5 * MinCandidateStk::get()), ], + get_account_id_from_seed::("Alice"), DEFAULT_PARA_ID, ) }, @@ -112,58 +107,42 @@ pub fn get_local_base_chain_spec() -> Result { Some("polimec"), None, Some(properties), - Extensions { - relay_chain: "rococo_local_testnet".into(), - para_id: DEFAULT_PARA_ID.into(), - }, + Extensions { relay_chain: "rococo_local_testnet".into(), para_id: DEFAULT_PARA_ID.into() }, )) } -pub fn get_live_base_chain_spec() -> Result { +pub fn get_kusama_base_chain_spec() -> Result { let properties = get_properties("PLMC", 10, 41); let wasm = base_runtime::WASM_BINARY.ok_or("No WASM")?; // TODO: Update this after reserving a ParaId - let id: u32 = 2105; + let id: u32 = 4261; + + const PLMC_SUDO_ACC: [u8; 32] = + hex_literal::hex!["d4192a54c9caa4a38eeb3199232ed0d8568b22956cafb76c7d5a1afbf4e2dc38"]; + const PLMC_COL_ACC_1: [u8; 32] = + hex_literal::hex!["6603f63a4091ba074b4384e64c6bba1dd96f6af49331ebda686b0a0f27dd961c"]; + const PLMC_COL_ACC_2: [u8; 32] = + hex_literal::hex!["ba48ab77461ef53f9ebfdc94a12c780b57354f986e31eb2504b9e3ed580fab51"]; Ok(ChainSpec::from_genesis( - "Polimec Base", + "Polimec Kusama Testnet", "polimec", ChainType::Live, move || { base_testnet_genesis( wasm, - // TODO: Update stakers vec![ - ( - get_account_id_from_seed::("Alice"), - None, - 2 * MinCollatorStake::get(), - ), - ( - get_account_id_from_seed::("Bob"), - None, - 2 * MinCollatorStake::get(), - ), + (PLMC_COL_ACC_1.into(), None, 2 * MinCandidateStk::get()), + (PLMC_COL_ACC_2.into(), None, 2 * MinCandidateStk::get()), ], polimec_inflation_config(), - MAX_COLLATOR_STAKE, - // TODO: Update initial authorities - vec![ - ( - get_account_id_from_seed::("Alice"), - get_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_from_seed::("Bob"), - ), - ], - // TODO: Update initial balances + vec![(PLMC_COL_ACC_1.into()), (PLMC_COL_ACC_2.into())], vec![ - (get_account_id_from_seed::("Alice"), 10000000 * PLMC), - (get_account_id_from_seed::("Bob"), 10000000 * PLMC), + (PLMC_COL_ACC_1.into(), 3 * MinCandidateStk::get()), + (PLMC_COL_ACC_2.into(), 3 * MinCandidateStk::get()), ], + PLMC_SUDO_ACC.into(), id.into(), ) }, @@ -172,35 +151,34 @@ pub fn get_live_base_chain_spec() -> Result { Some("polimec"), None, Some(properties), - Extensions { - relay_chain: "polkadot".into(), - para_id: id, - }, + Extensions { relay_chain: "kusama".into(), para_id: id }, )) } fn base_testnet_genesis( - wasm_binary: &[u8], stakers: Vec<(AccountId, Option, Balance)>, inflation_config: InflationInfo, - max_candidate_stake: Balance, initial_authorities: Vec<(AccountId, AuthorityId)>, - endowed_accounts: Vec<(AccountId, Balance)>, id: ParaId, + wasm_binary: &[u8], + stakers: Vec<(AccountId, Option, Balance)>, + inflation_config: InflationInfo, + initial_authorities: Vec, + endowed_accounts: Vec<(AccountId, Balance)>, + sudo_account: AccountId, + id: ParaId, ) -> GenesisConfig { - let accounts = endowed_accounts - .iter() - .map(|(account, _)| account.clone()) - .collect::>(); - GenesisConfig { - system: SystemConfig { - code: wasm_binary.to_vec(), - }, - balances: BalancesConfig { - balances: endowed_accounts.clone(), - }, + system: SystemConfig { code: wasm_binary.to_vec() }, + balances: BalancesConfig { balances: endowed_accounts.clone() }, parachain_info: ParachainInfoConfig { parachain_id: id }, parachain_staking: ParachainStakingConfig { - stakers, + candidates: stakers + .iter() + .map(|(accunt, _, balance)| (accunt.clone(), balance.clone())) + .collect::>(), inflation_config, - max_candidate_stake, + delegations: vec![], + collator_commission: COLLATOR_COMMISSION, + parachain_bond_reserve_percent: PARACHAIN_BOND_RESERVE_PERCENT, + blocks_per_round: BLOCKS_PER_ROUND, + num_selected_candidates: NUM_SELECTED_CANDIDATES, }, aura: Default::default(), aura_ext: Default::default(), @@ -208,22 +186,17 @@ fn base_testnet_genesis( session: SessionConfig { keys: initial_authorities .iter() - .map(|(acc, key)| { + .map(|acc| { ( acc.clone(), acc.clone(), - base_runtime::SessionKeys { aura: key.clone() }, + get_base_session_keys(Into::<[u8; 32]>::into(acc.clone()).unchecked_into()), ) }) .collect::>(), }, - treasury: Default::default(), - polkadot_xcm: PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - }, - sudo: SudoConfig { - key: Some(accounts.first().expect("").to_owned()), - }, + polkadot_xcm: PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION) }, + sudo: SudoConfig { key: Some(sudo_account) }, transaction_payment: Default::default(), } } diff --git a/nodes/parachain/src/chain_spec/testnet.rs b/nodes/parachain/src/chain_spec/testnet.rs index 0e13db10b..e32191cf0 100644 --- a/nodes/parachain/src/chain_spec/testnet.rs +++ b/nodes/parachain/src/chain_spec/testnet.rs @@ -20,19 +20,22 @@ use cumulus_primitives_core::ParaId; use polimec_parachain_runtime::{ - polimec_inflation_config, AuraId as AuthorityId, MinCollatorStake, MAX_COLLATOR_STAKE, PLMC, + pallet_parachain_staking::{ + inflation::{perbill_annual_to_perbill_round, BLOCKS_PER_YEAR}, + InflationInfo, Range, + }, + AuraId as AuthorityId, MinCandidateStk, ParachainStakingConfig, PLMC, }; use polimec_parachain_runtime::{ - AccountId, Balance, BalancesConfig, CouncilConfig, CredentialsConfig, GenesisConfig, InflationInfo, - ParachainInfoConfig, PolkadotXcmConfig, SessionConfig, SessionKeys, SudoConfig, SystemConfig, - TechnicalCommitteeConfig, VestingConfig, WASM_BINARY, + AccountId, Balance, BalancesConfig, CouncilConfig, GenesisConfig, ParachainInfoConfig, PolkadotXcmConfig, + SessionConfig, SudoConfig, SystemConfig, TechnicalCommitteeConfig, VestingConfig, }; use sc_service::ChainType; -use sc_telemetry::TelemetryEndpoints; -use sp_core::sr25519; +use sp_core::{crypto::UncheckedInto, sr25519}; +use sp_runtime::{Perbill, Percent}; -use crate::chain_spec::{get_account_id_from_seed, get_from_seed, DEFAULT_PARA_ID, TELEMETRY_URL}; +use crate::chain_spec::{get_account_id_from_seed, DEFAULT_PARA_ID}; use super::{get_properties, Extensions}; @@ -41,9 +44,38 @@ const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; /// Specialized `ChainSpec` for the normal parachain runtime. pub type ChainSpec = sc_service::GenericChainSpec; +const COLLATOR_COMMISSION: Perbill = Perbill::from_percent(30); +const PARACHAIN_BOND_RESERVE_PERCENT: Percent = Percent::from_percent(0); +const BLOCKS_PER_ROUND: u32 = 2 * 10; +const NUM_SELECTED_CANDIDATES: u32 = 5; +pub fn polimec_inflation_config() -> InflationInfo { + fn to_round_inflation(annual: Range) -> Range { + perbill_annual_to_perbill_round( + annual, + // rounds per year + BLOCKS_PER_YEAR / BLOCKS_PER_ROUND, + ) + } + + let annual = + Range { min: Perbill::from_percent(2), ideal: Perbill::from_percent(3), max: Perbill::from_percent(3) }; + + InflationInfo { + // staking expectations + expect: Range { min: 100_000 * PLMC, ideal: 200_000 * PLMC, max: 500_000 * PLMC }, + // annual inflation + annual, + round: to_round_inflation(annual), + } +} + +pub fn get_testnet_session_keys(keys: AuthorityId) -> polimec_parachain_runtime::SessionKeys { + polimec_parachain_runtime::SessionKeys { aura: keys } +} + pub fn get_chain_spec_dev() -> Result { let properties = get_properties("PLMC", 10, 41); - let wasm = WASM_BINARY.ok_or("No WASM")?; + let wasm = polimec_parachain_runtime::WASM_BINARY.ok_or("No WASM")?; Ok(ChainSpec::from_genesis( "Polimec Develop", @@ -53,61 +85,23 @@ pub fn get_chain_spec_dev() -> Result { testnet_genesis( wasm, vec![ - ( - get_account_id_from_seed::("Alice"), - None, - 2 * MinCollatorStake::get(), - ), - ( - get_account_id_from_seed::("Bob"), - None, - 2 * MinCollatorStake::get(), - ), + (get_account_id_from_seed::("Alice"), None, 2 * MinCandidateStk::get()), + (get_account_id_from_seed::("Bob"), None, 2 * MinCandidateStk::get()), ], polimec_inflation_config(), - MAX_COLLATOR_STAKE, vec![ - ( - get_account_id_from_seed::("Alice"), - get_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_from_seed::("Bob"), - ), + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), ], vec![ - (get_account_id_from_seed::("Alice"), 10000000 * PLMC), - (get_account_id_from_seed::("Bob"), 10000000 * PLMC), - (get_account_id_from_seed::("Charlie"), 10000000 * PLMC), - (get_account_id_from_seed::("Dave"), 10000000 * PLMC), - (get_account_id_from_seed::("Eve"), 10000000 * PLMC), - (get_account_id_from_seed::("Ferdie"), 10000000 * PLMC), - ( - get_account_id_from_seed::("Alice//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Bob//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Charlie//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Dave//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Eve//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Ferdie//stash"), - 10000000 * PLMC, - ), + (get_account_id_from_seed::("Alice"), 5 * MinCandidateStk::get()), + (get_account_id_from_seed::("Bob"), 5 * MinCandidateStk::get()), + (get_account_id_from_seed::("Charlie"), 5 * MinCandidateStk::get()), + (get_account_id_from_seed::("Dave"), 5 * MinCandidateStk::get()), + (get_account_id_from_seed::("Eve"), 5 * MinCandidateStk::get()), + (get_account_id_from_seed::("Ferdie"), 5 * MinCandidateStk::get()), ], + get_account_id_from_seed::("Alice"), DEFAULT_PARA_ID, ) }, @@ -116,252 +110,105 @@ pub fn get_chain_spec_dev() -> Result { None, None, Some(properties), - Extensions { - relay_chain: "rococo-local".into(), - para_id: DEFAULT_PARA_ID.into(), - }, + Extensions { relay_chain: "rococo-local".into(), para_id: DEFAULT_PARA_ID.into() }, )) } pub fn get_prod_chain_spec() -> Result { let properties = get_properties("PLMC", 10, 41); - let wasm = WASM_BINARY.ok_or("No WASM")?; - let id: ParaId = 2105.into(); + let wasm = polimec_parachain_runtime::WASM_BINARY.ok_or("No WASM")?; - Ok(ChainSpec::from_genesis( - "Polimec", - "polimec", - ChainType::Live, - move || { - testnet_genesis( - wasm, - vec![ - ( - get_account_id_from_seed::("Alice"), - None, - 2 * MinCollatorStake::get(), - ), - ( - get_account_id_from_seed::("Bob"), - None, - 2 * MinCollatorStake::get(), - ), - ], - polimec_inflation_config(), - MAX_COLLATOR_STAKE, - vec![ - ( - get_account_id_from_seed::("Alice"), - get_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_from_seed::("Bob"), - ), - ], - vec![ - (get_account_id_from_seed::("Alice"), 10000000 * PLMC), - (get_account_id_from_seed::("Bob"), 10000000 * PLMC), - (get_account_id_from_seed::("Charlie"), 10000000 * PLMC), - (get_account_id_from_seed::("Dave"), 10000000 * PLMC), - (get_account_id_from_seed::("Eve"), 10000000 * PLMC), - (get_account_id_from_seed::("Ferdie"), 10000000 * PLMC), - ( - get_account_id_from_seed::("Alice//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Bob//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Charlie//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Dave//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Eve//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Ferdie//stash"), - 10000000 * PLMC, - ), - ], - id, - ) - }, - vec![], - Some( - TelemetryEndpoints::new(vec![(TELEMETRY_URL.to_string(), 0)]).expect("Polimec telemetry url is valid; qed"), - ), - Some("polimec"), - None, - Some(properties), - Extensions { - relay_chain: "polkadot".into(), - para_id: id.into(), - }, - )) -} + // TODO: Update this after reserving a ParaId + let id: u32 = 4261; -pub fn get_local_prod_chain_spec() -> Result { - let properties = get_properties("PLMC", 10, 41); - let wasm = WASM_BINARY.ok_or("No WASM")?; - let id: ParaId = 2000.into(); + const PLMC_SUDO_ACC: [u8; 32] = + hex_literal::hex!["d4192a54c9caa4a38eeb3199232ed0d8568b22956cafb76c7d5a1afbf4e2dc38"]; + const PLMC_COL_ACC_1: [u8; 32] = + hex_literal::hex!["6603f63a4091ba074b4384e64c6bba1dd96f6af49331ebda686b0a0f27dd961c"]; + const PLMC_COL_ACC_2: [u8; 32] = + hex_literal::hex!["ba48ab77461ef53f9ebfdc94a12c780b57354f986e31eb2504b9e3ed580fab51"]; Ok(ChainSpec::from_genesis( - "Polimec", + "Polimec Kusama Testnet", "polimec", ChainType::Live, move || { testnet_genesis( wasm, vec![ - ( - get_account_id_from_seed::("Alice"), - None, - 2 * MinCollatorStake::get(), - ), - ( - get_account_id_from_seed::("Bob"), - None, - 2 * MinCollatorStake::get(), - ), + (PLMC_COL_ACC_1.into(), None, 2 * MinCandidateStk::get()), + (PLMC_COL_ACC_2.into(), None, 2 * MinCandidateStk::get()), ], polimec_inflation_config(), - MAX_COLLATOR_STAKE, - vec![ - ( - get_account_id_from_seed::("Alice"), - get_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_from_seed::("Bob"), - ), - ], + vec![(PLMC_COL_ACC_1.into()), (PLMC_COL_ACC_2.into())], vec![ - (get_account_id_from_seed::("Alice"), 10000000 * PLMC), - (get_account_id_from_seed::("Bob"), 10000000 * PLMC), - (get_account_id_from_seed::("Charlie"), 10000000 * PLMC), - (get_account_id_from_seed::("Dave"), 10000000 * PLMC), - (get_account_id_from_seed::("Eve"), 10000000 * PLMC), - (get_account_id_from_seed::("Ferdie"), 10000000 * PLMC), - ( - get_account_id_from_seed::("Alice//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Bob//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Charlie//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Dave//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Eve//stash"), - 10000000 * PLMC, - ), - ( - get_account_id_from_seed::("Ferdie//stash"), - 10000000 * PLMC, - ), + (PLMC_COL_ACC_1.into(), 3 * MinCandidateStk::get()), + (PLMC_COL_ACC_2.into(), 3 * MinCandidateStk::get()), ], - id, + PLMC_SUDO_ACC.into(), + id.into(), ) }, vec![], - Some( - TelemetryEndpoints::new(vec![(TELEMETRY_URL.to_string(), 0)]).expect("Polimec telemetry url is valid; qed"), - ), + None, Some("polimec"), None, Some(properties), - Extensions { - relay_chain: "rococo-local".into(), - para_id: id.into(), - }, + Extensions { relay_chain: "polkadot".into(), para_id: id }, )) } #[allow(clippy::too_many_arguments)] fn testnet_genesis( - wasm_binary: &[u8], _stakers: Vec<(AccountId, Option, Balance)>, _inflation_config: InflationInfo, - _max_candidate_stake: Balance, initial_authorities: Vec<(AccountId, AuthorityId)>, - endowed_accounts: Vec<(AccountId, Balance)>, id: ParaId, + wasm_binary: &[u8], + stakers: Vec<(AccountId, Option, Balance)>, + inflation_config: InflationInfo, + initial_authorities: Vec, + endowed_accounts: Vec<(AccountId, Balance)>, + sudo_account: AccountId, + id: ParaId, ) -> GenesisConfig { - // type VestingPeriod = BlockNumber; - // type LockingPeriod = BlockNumber; - - // // vesting and locks as initially designed - // let claimable_accounts_json = &include_bytes!("../../res/genesis/claimable-accounts.json")[..]; - // let claimable_accounts: Vec<(AccountId, Balance, VestingPeriod, LockingPeriod)> = - // serde_json::from_slice(claimable_accounts_json) - // .expect("The file genesis_accounts.json exists and is valid; qed"); - - // // botlabs account should not be migrated but some have vesting - // let owned_accounts_json = &include_bytes!("../../res/genesis/owned-accounts.json")[..]; - // let owned_accounts: Vec<(AccountId, Balance, VestingPeriod, LockingPeriod)> = - // serde_json::from_slice(owned_accounts_json) - // .expect("The file botlabs_accounts.json exists and is valid; qed"); - - let accounts = endowed_accounts - .iter() - .map(|(account, _)| account.clone()) - .collect::>(); + let accounts = endowed_accounts.iter().map(|(account, _)| account.clone()).collect::>(); GenesisConfig { - system: SystemConfig { - code: wasm_binary.to_vec(), - }, - balances: BalancesConfig { - balances: endowed_accounts.clone(), - }, + system: SystemConfig { code: wasm_binary.to_vec() }, + balances: BalancesConfig { balances: endowed_accounts.clone() }, parachain_info: ParachainInfoConfig { parachain_id: id }, - parachain_staking: Default::default(), + parachain_staking: ParachainStakingConfig { + candidates: stakers + .iter() + .map(|(accunt, _, balance)| (accunt.clone(), balance.clone())) + .collect::>(), + inflation_config, + delegations: vec![], + collator_commission: COLLATOR_COMMISSION, + parachain_bond_reserve_percent: PARACHAIN_BOND_RESERVE_PERCENT, + blocks_per_round: BLOCKS_PER_ROUND, + num_selected_candidates: NUM_SELECTED_CANDIDATES, + }, // no need to pass anything to aura, in fact it will panic if we do. Session will take care // of this. aura: Default::default(), aura_ext: Default::default(), parachain_system: Default::default(), - credentials: CredentialsConfig { - issuers: accounts.clone(), - retails: accounts.clone(), - professionals: accounts.clone(), - institutionals: accounts.clone(), - }, session: SessionConfig { keys: initial_authorities .iter() - .map(|(acc, key)| (acc.clone(), acc.clone(), SessionKeys { aura: key.clone() })) + .map(|acc| { + ( + acc.clone(), + acc.clone(), + get_testnet_session_keys(Into::<[u8; 32]>::into(acc.clone()).unchecked_into()), + ) + }) .collect::>(), }, - polkadot_xcm: PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - }, + polkadot_xcm: PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION) }, treasury: Default::default(), - sudo: SudoConfig { - key: Some(accounts.first().expect("").to_owned()), - }, - council: CouncilConfig { - members: initial_authorities.iter().map(|(acc, _)| acc).cloned().collect(), - phantom: Default::default(), - }, - technical_committee: TechnicalCommitteeConfig { - members: initial_authorities.iter().map(|(acc, _)| acc).cloned().collect(), - phantom: Default::default(), - }, + sudo: SudoConfig { key: Some(sudo_account) }, + council: CouncilConfig { members: accounts.clone(), phantom: Default::default() }, + technical_committee: TechnicalCommitteeConfig { members: accounts.clone(), phantom: Default::default() }, democracy: Default::default(), - did_lookup: Default::default(), vesting: VestingConfig { vesting: vec![] }, } } diff --git a/nodes/parachain/src/cli.rs b/nodes/parachain/src/cli.rs index 8e2d1efa7..4a184008b 100644 --- a/nodes/parachain/src/cli.rs +++ b/nodes/parachain/src/cli.rs @@ -61,11 +61,7 @@ pub enum Subcommand { } #[derive(Debug, clap::Parser)] -#[command( - propagate_version = true, - args_conflicts_with_subcommands = true, - subcommand_negates_reqs = true -)] +#[command(propagate_version = true, args_conflicts_with_subcommands = true, subcommand_negates_reqs = true)] pub struct Cli { #[command(subcommand)] pub subcommand: Option, @@ -103,15 +99,12 @@ pub struct RelayChainCli { impl RelayChainCli { /// Parse the relay chain CLI parameters using the para chain `Configuration`. pub fn new<'a>( - para_config: &sc_service::Configuration, relay_chain_args: impl Iterator, + para_config: &sc_service::Configuration, + relay_chain_args: impl Iterator, ) -> Self { let extension = crate::chain_spec::Extensions::try_get(&*para_config.chain_spec); let chain_id = extension.map(|e| e.relay_chain.clone()); let base_path = para_config.base_path.as_ref().map(|x| x.path().join("polkadot")); - Self { - base_path, - chain_id, - base: clap::Parser::parse_from(relay_chain_args), - } + Self { base_path, chain_id, base: clap::Parser::parse_from(relay_chain_args) } } } diff --git a/nodes/parachain/src/command.rs b/nodes/parachain/src/command.rs index 1451df942..82b0ce4f6 100644 --- a/nodes/parachain/src/command.rs +++ b/nodes/parachain/src/command.rs @@ -92,16 +92,15 @@ fn load_spec(id: &str) -> std::result::Result, String> { Ok(match id { // Base runtime "base-rococo-local" => Box::new(chain_spec::base::get_local_base_chain_spec()?), - "base-polkadot" => Box::new(chain_spec::base::get_live_base_chain_spec()?), + "base-kusama" => Box::new(chain_spec::base::get_kusama_base_chain_spec()?), // Testnet runtime "polimec-rococo-local" => Box::new(chain_spec::testnet::get_chain_spec_dev()?), "polimec-polkadot" => Box::new(chain_spec::testnet::get_prod_chain_spec()?), - "polimec-polkadot-local" => Box::new(chain_spec::testnet::get_local_prod_chain_spec()?), // -- Fallback (generic chainspec) "" => { log::warn!("No ChainSpec.id specified, so using default one, based on polimec-rococo-local"); Box::new(chain_spec::testnet::get_chain_spec_dev()?) - } + }, // A custom chainspec path path => { let path: PathBuf = path.into(); @@ -110,7 +109,7 @@ fn load_spec(id: &str) -> std::result::Result, String> { Runtime::Testnet => Box::new(chain_spec::testnet::ChainSpec::from_json_file(path)?), Runtime::Base => Box::new(chain_spec::base::ChainSpec::from_json_file(path)?), } - } + }, }) } @@ -213,37 +212,35 @@ pub fn run() -> Result<()> { Some(Subcommand::BuildSpec(cmd)) => { let runner = cli.create_runner(cmd)?; runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) - } + }, Some(Subcommand::CheckBlock(cmd)) => { construct_async_run!(|components, cli, cmd, config| { Ok(cmd.run(components.client, components.import_queue)) }) - } + }, Some(Subcommand::ExportBlocks(cmd)) => { construct_async_run!(|components, cli, cmd, config| Ok(cmd.run(components.client, config.database))) - } + }, Some(Subcommand::ExportState(cmd)) => { construct_async_run!(|components, cli, cmd, config| Ok(cmd.run(components.client, config.chain_spec))) - } + }, Some(Subcommand::ImportBlocks(cmd)) => { construct_async_run!(|components, cli, cmd, config| { Ok(cmd.run(components.client, components.import_queue)) }) - } + }, Some(Subcommand::Revert(cmd)) => { construct_async_run!(|components, cli, cmd, config| { Ok(cmd.run(components.client, components.backend, None)) }) - } + }, Some(Subcommand::PurgeChain(cmd)) => { let runner = cli.create_runner(cmd)?; runner.sync_run(|config| { let polkadot_cli = RelayChainCli::new( &config, - [RelayChainCli::executable_name()] - .iter() - .chain(cli.relay_chain_args.iter()), + [RelayChainCli::executable_name()].iter().chain(cli.relay_chain_args.iter()), ); let polkadot_config = @@ -252,7 +249,7 @@ pub fn run() -> Result<()> { cmd.run(config, polkadot_config) }) - } + }, Some(Subcommand::ExportGenesisState(cmd)) => { let runner = cli.create_runner(cmd)?; runner.sync_run(|_config| { @@ -260,40 +257,38 @@ pub fn run() -> Result<()> { let state_version = Cli::native_runtime_version(&spec).state_version(); cmd.run::(&*spec, state_version) }) - } + }, Some(Subcommand::ExportGenesisWasm(cmd)) => { let runner = cli.create_runner(cmd)?; runner.sync_run(|_config| { let spec = cli.load_spec(&cmd.shared_params.chain.clone().unwrap_or_default())?; cmd.run(&*spec) }) - } + }, Some(Subcommand::Benchmark(cmd)) => { let runner = cli.create_runner(cmd)?; // Switch on the concrete benchmark sub-command- match cmd { - BenchmarkCmd::Pallet(cmd) => { + BenchmarkCmd::Pallet(cmd) => if cfg!(feature = "runtime-benchmarks") { runner.sync_run(|config| cmd.run::(config)) } else { Err("Benchmarking wasn't enabled when building the node. \ You can enable it with `--features runtime-benchmarks`." .into()) - } - } + }, BenchmarkCmd::Block(cmd) => runner.sync_run(|config| { let partials = new_partial(&config)?; cmd.run(partials.client) }), #[cfg(not(feature = "runtime-benchmarks"))] - BenchmarkCmd::Storage(_) => { + BenchmarkCmd::Storage(_) => return Err(sc_cli::Error::Input( "Compile with --features=runtime-benchmarks \ to enable storage benchmarks." .into(), ) - .into()) - } + .into()), #[cfg(feature = "runtime-benchmarks")] BenchmarkCmd::Storage(cmd) => runner.sync_run(|config| { let partials = new_partial(&config)?; @@ -301,15 +296,14 @@ pub fn run() -> Result<()> { let storage = partials.backend.expose_storage(); cmd.run(config, partials.client.clone(), db, storage) }), - BenchmarkCmd::Machine(cmd) => { - runner.sync_run(|config| cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone())) - } + BenchmarkCmd::Machine(cmd) => + runner.sync_run(|config| cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone())), // NOTE: this allows the Client to leniently implement // new benchmark commands without requiring a companion MR. #[allow(unreachable_patterns)] _ => Err("Benchmarking sub-command unsupported".into()), } - } + }, #[cfg(feature = "try-runtime")] Some(Subcommand::TryRuntime(cmd)) => { let runner = cli.create_runner(cmd)?; @@ -325,13 +319,8 @@ pub fn run() -> Result<()> { let task_manager = sc_service::TaskManager::new(runner.config().tokio_handle.clone(), *registry) .map_err(|e| format!("Error: {:?}", e))?; - runner.async_run(|_| { - Ok(( - cmd.run::>(), - task_manager, - )) - }) - } + runner.async_run(|_| Ok((cmd.run::>(), task_manager))) + }, #[cfg(not(feature = "try-runtime"))] Some(Subcommand::TryRuntime) => Err("Try-runtime was not enabled when building the node. \ You can enable it with `--features try-runtime`." @@ -362,8 +351,7 @@ pub fn run() -> Result<()> { let id = ParaId::from(para_id); let parachain_account = - AccountIdConversion::::into_account_truncating(&id); - + AccountIdConversion::::into_account_truncating(&id); let state_version = Cli::native_runtime_version(&config.chain_spec).state_version(); let block: Block = generate_genesis_block(&*config.chain_spec, state_version) .map_err(|e| format!("{:?}", e))?; @@ -394,7 +382,7 @@ pub fn run() -> Result<()> { .map(|r| r.0) .map_err(Into::into) }) - } + }, } } @@ -434,10 +422,7 @@ impl CliConfiguration for RelayChainCli { } fn base_path(&self) -> Result> { - Ok(self - .shared_params() - .base_path()? - .or_else(|| self.base_path.clone().map(Into::into))) + Ok(self.shared_params().base_path()?.or_else(|| self.base_path.clone().map(Into::into))) } fn rpc_http(&self, default_listen_port: u16) -> Result> { @@ -453,13 +438,19 @@ impl CliConfiguration for RelayChainCli { } fn prometheus_config( - &self, default_listen_port: u16, chain_spec: &Box, + &self, + default_listen_port: u16, + chain_spec: &Box, ) -> Result> { self.base.base.prometheus_config(default_listen_port, chain_spec) } fn init( - &self, _support_url: &String, _impl_version: &String, _logger_hook: F, _config: &sc_service::Configuration, + &self, + _support_url: &String, + _impl_version: &String, + _logger_hook: F, + _config: &sc_service::Configuration, ) -> Result<()> where F: FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration), @@ -470,11 +461,7 @@ impl CliConfiguration for RelayChainCli { fn chain_id(&self, is_dev: bool) -> Result { let chain_id = self.base.base.chain_id(is_dev)?; - Ok(if chain_id.is_empty() { - self.chain_id.clone().unwrap_or_default() - } else { - chain_id - }) + Ok(if chain_id.is_empty() { self.chain_id.clone().unwrap_or_default() } else { chain_id }) } fn role(&self, is_dev: bool) -> Result { diff --git a/nodes/parachain/src/rpc.rs b/nodes/parachain/src/rpc.rs index ae5a4ed96..44a745abe 100644 --- a/nodes/parachain/src/rpc.rs +++ b/nodes/parachain/src/rpc.rs @@ -61,11 +61,7 @@ where use substrate_frame_rpc_system::{System, SystemApiServer}; let mut module = RpcExtension::new(()); - let FullDeps { - client, - pool, - deny_unsafe, - } = deps; + let FullDeps { client, pool, deny_unsafe } = deps; module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; module.merge(TransactionPayment::new(client).into_rpc())?; diff --git a/nodes/parachain/src/service.rs b/nodes/parachain/src/service.rs index 49dd30d28..ea54c0fa9 100644 --- a/nodes/parachain/src/service.rs +++ b/nodes/parachain/src/service.rs @@ -21,7 +21,7 @@ use std::{sync::Arc, time::Duration}; use cumulus_client_cli::CollatorOptions; // Local Runtime Types -use polimec_parachain_runtime::{opaque::Block, Hash, RuntimeApi}; +use polimec_parachain_runtime::{opaque::Block, RuntimeApi}; // Cumulus Imports use cumulus_client_consensus_aura::{AuraConsensus, BuildAuraConsensusParams, SlotProportion}; @@ -31,17 +31,17 @@ use cumulus_client_service::{ BuildNetworkParams, StartCollatorParams, StartFullNodeParams, }; use cumulus_primitives_core::ParaId; -use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface}; +use cumulus_relay_chain_interface::RelayChainInterface; // Substrate Imports use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE; use sc_consensus::ImportQueue; -use sc_executor::NativeElseWasmExecutor; -use sc_network::NetworkService; -use sc_network_common::service::NetworkBlock; +use sc_executor::{HeapAllocStrategy, NativeElseWasmExecutor, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; +use sc_network::NetworkBlock; +use sc_network_sync::SyncingService; use sc_service::{Configuration, PartialComponents, TFullBackend, TFullClient, TaskManager}; use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle}; -use sp_keystore::SyncCryptoStorePtr; +use sp_keystore::KeystorePtr; use substrate_prometheus_endpoint::Registry; /// Native executor type. @@ -71,6 +71,7 @@ type ParachainBlockImport = TParachainBlockImport, P /// /// Use this macro if you don't actually need the full service, but just the builder in order to /// be able to perform chain operations. +#[allow(clippy::type_complexity)] pub fn new_partial( config: &Configuration, ) -> Result< @@ -95,12 +96,19 @@ pub fn new_partial( }) .transpose()?; - let executor = ParachainExecutor::new( - config.wasm_method, - config.default_heap_pages, - config.max_runtime_instances, - config.runtime_cache_size, - ); + let heap_pages = config + .default_heap_pages + .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { extra_pages: h as _ }); + + let wasm = WasmExecutor::builder() + .with_execution_method(config.wasm_method) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) + .with_max_runtime_instances(config.max_runtime_instances) + .with_runtime_cache_size(config.runtime_cache_size) + .build(); + + let executor = ParachainExecutor::new_with_wasm_executor(wasm); let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::( config, @@ -151,8 +159,11 @@ pub fn new_partial( /// This is the actual implementation that is abstract over the executor and the runtime api. #[sc_tracing::logging::prefix_logs_with("Parachain")] async fn start_node_impl( - parachain_config: Configuration, polkadot_config: Configuration, collator_options: CollatorOptions, - para_id: ParaId, hwbench: Option, + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, ) -> sc_service::error::Result<(TaskManager, Arc)> { let parachain_config = prepare_node_config(parachain_config); @@ -172,10 +183,7 @@ async fn start_node_impl( hwbench.clone(), ) .await - .map_err(|e| match e { - RelayChainError::ServiceError(polkadot_service::Error::Sub(x)) => x, - s => s.to_string().into(), - })?; + .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; let force_authoring = parachain_config.force_authoring; let validator = parachain_config.role.is_authority(); @@ -183,16 +191,17 @@ async fn start_node_impl( let transaction_pool = params.transaction_pool.clone(); let import_queue_service = params.import_queue.service(); - let (network, system_rpc_tx, tx_handler_controller, start_network) = build_network(BuildNetworkParams { - parachain_config: ¶chain_config, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - para_id, - spawn_handle: task_manager.spawn_handle(), - relay_chain_interface: relay_chain_interface.clone(), - import_queue: params.import_queue, - }) - .await?; + let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = + build_network(BuildNetworkParams { + parachain_config: ¶chain_config, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + para_id, + spawn_handle: task_manager.spawn_handle(), + relay_chain_interface: relay_chain_interface.clone(), + import_queue: params.import_queue, + }) + .await?; if parachain_config.offchain_worker.enabled { sc_service::build_offchain_workers( @@ -208,11 +217,7 @@ async fn start_node_impl( let transaction_pool = transaction_pool.clone(); Box::new(move |deny_unsafe, _| { - let deps = crate::rpc::FullDeps { - client: client.clone(), - pool: transaction_pool.clone(), - deny_unsafe, - }; + let deps = crate::rpc::FullDeps { client: client.clone(), pool: transaction_pool.clone(), deny_unsafe }; crate::rpc::create_full(deps).map_err(Into::into) }) @@ -224,9 +229,10 @@ async fn start_node_impl( transaction_pool: transaction_pool.clone(), task_manager: &mut task_manager, config: parachain_config, - keystore: params.keystore_container.sync_keystore(), + keystore: params.keystore_container.keystore(), backend, network: network.clone(), + sync_service: sync_service.clone(), system_rpc_tx, tx_handler_controller, telemetry: telemetry.as_mut(), @@ -252,15 +258,14 @@ async fn start_node_impl( } let announce_block = { - let network = network.clone(); - Arc::new(move |hash, data| network.announce_block(hash, data)) + let sync_service = sync_service.clone(); + Arc::new(move |hash, data| sync_service.announce_block(hash, data)) }; let relay_chain_slot_duration = Duration::from_secs(6); - let overseer_handle = relay_chain_interface - .overseer_handle() - .map_err(|e| sc_service::Error::Application(Box::new(e)))?; + let overseer_handle = + relay_chain_interface.overseer_handle().map_err(|e| sc_service::Error::Application(Box::new(e)))?; if validator { let parachain_consensus = build_consensus( @@ -271,8 +276,8 @@ async fn start_node_impl( &task_manager, relay_chain_interface.clone(), transaction_pool, - network, - params.keystore_container.sync_keystore(), + sync_service.clone(), + params.keystore_container.keystore(), force_authoring, para_id, )?; @@ -291,6 +296,7 @@ async fn start_node_impl( collator_key: collator_key.expect("Command line arguments do not allow this. qed"), relay_chain_slot_duration, recovery_handle: Box::new(overseer_handle), + sync_service, }; start_collator(params).await?; @@ -304,6 +310,7 @@ async fn start_node_impl( relay_chain_slot_duration, import_queue: import_queue_service, recovery_handle: Box::new(overseer_handle), + sync_service, }; start_full_node(params)?; @@ -316,8 +323,11 @@ async fn start_node_impl( /// Build the import queue for the parachain runtime. fn build_import_queue( - client: Arc, block_import: ParachainBlockImport, config: &Configuration, - telemetry: Option, task_manager: &TaskManager, + client: Arc, + block_import: ParachainBlockImport, + config: &Configuration, + telemetry: Option, + task_manager: &TaskManager, ) -> Result, sc_service::Error> { let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; @@ -343,12 +353,18 @@ fn build_import_queue( .map_err(Into::into) } +#[allow(clippy::too_many_arguments)] fn build_consensus( - client: Arc, block_import: ParachainBlockImport, prometheus_registry: Option<&Registry>, - telemetry: Option, task_manager: &TaskManager, + client: Arc, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, relay_chain_interface: Arc, transaction_pool: Arc>, - sync_oracle: Arc>, keystore: SyncCryptoStorePtr, force_authoring: bool, + sync_oracle: Arc>, + keystore: KeystorePtr, + force_authoring: bool, para_id: ParaId, ) -> Result>, sc_service::Error> { let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; @@ -400,21 +416,16 @@ fn build_consensus( telemetry, }; - Ok(AuraConsensus::build::< - sp_consensus_aura::sr25519::AuthorityPair, - _, - _, - _, - _, - _, - _, - >(params)) + Ok(AuraConsensus::build::(params)) } /// Start a parachain node. pub async fn start_parachain_node( - parachain_config: Configuration, polkadot_config: Configuration, collator_options: CollatorOptions, - para_id: ParaId, hwbench: Option, + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, ) -> sc_service::error::Result<(TaskManager, Arc)> { start_node_impl(parachain_config, polkadot_config, collator_options, para_id, hwbench).await } diff --git a/nodes/standalone/Cargo.toml b/nodes/standalone/Cargo.toml index b31ad7d4e..92b409a30 100644 --- a/nodes/standalone/Cargo.toml +++ b/nodes/standalone/Cargo.toml @@ -26,8 +26,6 @@ sc-consensus-aura.workspace = true sp-consensus-aura.workspace = true sp-consensus.workspace = true sc-consensus.workspace = true -sc-finality-grandpa.workspace = true -sp-finality-grandpa.workspace = true sc-client-api.workspace = true sp-runtime.workspace = true sp-timestamp.workspace = true @@ -36,7 +34,8 @@ sp-keyring.workspace = true frame-system.workspace = true pallet-transaction-payment.workspace = true sc-chain-spec.workspace = true - +sc-consensus-grandpa.workspace = true +sp-consensus-grandpa.workspace = true # These dependencies are used for the node's RPCs jsonrpsee = { workspace = true, features = ["server"] } sc-rpc.workspace = true diff --git a/nodes/standalone/src/benchmarking.rs b/nodes/standalone/src/benchmarking.rs index 4b4a86d95..cf1c1c51c 100644 --- a/nodes/standalone/src/benchmarking.rs +++ b/nodes/standalone/src/benchmarking.rs @@ -56,13 +56,9 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for RemarkBuilder { fn build(&self, nonce: u32) -> std::result::Result { let acc = Sr25519Keyring::Bob.pair(); - let extrinsic: OpaqueExtrinsic = create_benchmark_extrinsic( - self.client.as_ref(), - acc, - SystemCall::remark { remark: vec![] }.into(), - nonce, - ) - .into(); + let extrinsic: OpaqueExtrinsic = + create_benchmark_extrinsic(self.client.as_ref(), acc, SystemCall::remark { remark: vec![] }.into(), nonce) + .into(); Ok(extrinsic) } @@ -98,11 +94,7 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder { let extrinsic: OpaqueExtrinsic = create_benchmark_extrinsic( self.client.as_ref(), acc, - BalancesCall::transfer_keep_alive { - dest: self.dest.clone().into(), - value: self.value.into(), - } - .into(), + BalancesCall::transfer_keep_alive { dest: self.dest.clone().into(), value: self.value.into() }.into(), nonce, ) .into(); @@ -115,16 +107,16 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder { /// /// Note: Should only be used for benchmarking. pub fn create_benchmark_extrinsic( - client: &FullClient, sender: sp_core::sr25519::Pair, call: runtime::RuntimeCall, nonce: u32, + client: &FullClient, + sender: sp_core::sr25519::Pair, + call: runtime::RuntimeCall, + nonce: u32, ) -> runtime::UncheckedExtrinsic { let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); let best_hash = client.chain_info().best_hash; let best_block = client.chain_info().best_number; - let period = runtime::BlockHashCount::get() - .checked_next_power_of_two() - .map(|c| c / 2) - .unwrap_or(2) as u64; + let period = runtime::BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64; let extra: runtime::SignedExtra = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), @@ -142,16 +134,7 @@ pub fn create_benchmark_extrinsic( let raw_payload = runtime::SignedPayload::from_raw( call.clone(), extra.clone(), - ( - (), - runtime::VERSION.spec_version, - runtime::VERSION.transaction_version, - genesis_hash, - best_hash, - (), - (), - (), - ), + ((), runtime::VERSION.spec_version, runtime::VERSION.transaction_version, genesis_hash, best_hash, (), (), ()), ); let signature = raw_payload.using_encoded(|e| sender.sign(e)); diff --git a/nodes/standalone/src/chain_spec.rs b/nodes/standalone/src/chain_spec.rs index ebfc0ddee..8d7e956c7 100644 --- a/nodes/standalone/src/chain_spec.rs +++ b/nodes/standalone/src/chain_spec.rs @@ -15,13 +15,12 @@ // along with this program. If not, see . use polimec_standalone_runtime::{ - AccountId, BalancesConfig, CredentialsConfig, GenesisConfig, SessionConfig, Signature, SudoConfig, SystemConfig, - WASM_BINARY, + AccountId, BalancesConfig, GenesisConfig, SessionConfig, Signature, SudoConfig, SystemConfig, WASM_BINARY, }; use sc_service::{ChainType, Properties}; use sp_consensus_aura::sr25519::AuthorityId as AuraId; +use sp_consensus_grandpa::AuthorityId as GrandpaId; use sp_core::{sr25519, Pair, Public}; -use sp_finality_grandpa::AuthorityId as GrandpaId; use sp_runtime::traits::{IdentifyAccount, Verify}; // The URL for the telemetry server. @@ -39,9 +38,7 @@ fn polimec_properties() -> Properties { /// Helper function to generate a crypto pair from seed fn get_from_secret(seed: &str) -> ::Public { - TPublic::Pair::from_string(seed, None) - .unwrap_or_else(|_| panic!("Invalid string '{seed}'")) - .public() + TPublic::Pair::from_string(seed, None).unwrap_or_else(|_| panic!("Invalid string '{seed}'")).public() } /// Helper function to generate an account ID from seed @@ -120,10 +117,7 @@ pub fn local_testnet_config() -> Result { testnet_genesis( wasm_binary, // Initial PoA authorities - vec![ - get_authority_keys_from_secret("//Alice"), - get_authority_keys_from_secret("//Bob"), - ], + vec![get_authority_keys_from_secret("//Alice"), get_authority_keys_from_secret("//Bob")], // Sudo account get_account_id_from_secret::("//Alice"), // Pre-funded accounts @@ -153,7 +147,9 @@ pub fn local_testnet_config() -> Result { /// Configure initial storage state for FRAME modules. fn testnet_genesis( - wasm_binary: &[u8], initial_authorities: Vec<(AccountId, AuraId, GrandpaId)>, root_key: AccountId, + wasm_binary: &[u8], + initial_authorities: Vec<(AccountId, AuraId, GrandpaId)>, + root_key: AccountId, endowed_accounts: Vec, ) -> GenesisConfig { GenesisConfig { @@ -175,12 +171,6 @@ fn testnet_genesis( council: Default::default(), technical_committee: Default::default(), democracy: Default::default(), - credentials: CredentialsConfig { - issuers: endowed_accounts.clone(), - retails: endowed_accounts.clone(), - professionals: endowed_accounts.clone(), - institutionals: endowed_accounts.clone(), - }, session: SessionConfig { keys: initial_authorities .iter() @@ -188,10 +178,7 @@ fn testnet_genesis( ( x.0.clone(), x.0.clone(), - polimec_standalone_runtime::opaque::SessionKeys { - aura: x.1.clone(), - grandpa: x.2.clone(), - }, + polimec_standalone_runtime::opaque::SessionKeys { aura: x.1.clone(), grandpa: x.2.clone() }, ) }) .collect::>(), diff --git a/nodes/standalone/src/command.rs b/nodes/standalone/src/command.rs index d9145c6aa..8f07f6943 100644 --- a/nodes/standalone/src/command.rs +++ b/nodes/standalone/src/command.rs @@ -1,19 +1,3 @@ -// Polimec Blockchain – https://www.polimec.org/ -// Copyright (C) Polimec 2022. All rights reserved. - -// The Polimec Blockchain 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. - -// The Polimec Blockchain 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::{ benchmarking::{inherent_benchmark_data, RemarkBuilder, TransferKeepAliveBuilder}, chain_spec, @@ -26,6 +10,9 @@ use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; use sc_service::PartialComponents; use sp_keyring::Sr25519Keyring; +#[cfg(feature = "try-runtime")] +use try_runtime_cli::block_building_info::timestamp_with_aura_info; + impl SubstrateCli for Cli { fn impl_name() -> String { "Substrate Node".into() @@ -73,69 +60,50 @@ pub fn run() -> sc_cli::Result<()> { Some(Subcommand::BuildSpec(cmd)) => { let runner = cli.create_runner(cmd)?; runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) - } + }, Some(Subcommand::CheckBlock(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { - let PartialComponents { - client, - task_manager, - import_queue, - .. - } = service::new_partial(&config)?; + let PartialComponents { client, task_manager, import_queue, .. } = service::new_partial(&config)?; Ok((cmd.run(client, import_queue), task_manager)) }) - } + }, Some(Subcommand::ExportBlocks(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { - let PartialComponents { - client, task_manager, .. - } = service::new_partial(&config)?; + let PartialComponents { client, task_manager, .. } = service::new_partial(&config)?; Ok((cmd.run(client, config.database), task_manager)) }) - } + }, Some(Subcommand::ExportState(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { - let PartialComponents { - client, task_manager, .. - } = service::new_partial(&config)?; + let PartialComponents { client, task_manager, .. } = service::new_partial(&config)?; Ok((cmd.run(client, config.chain_spec), task_manager)) }) - } + }, Some(Subcommand::ImportBlocks(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { - let PartialComponents { - client, - task_manager, - import_queue, - .. - } = service::new_partial(&config)?; + let PartialComponents { client, task_manager, import_queue, .. } = service::new_partial(&config)?; Ok((cmd.run(client, import_queue), task_manager)) }) - } + }, Some(Subcommand::PurgeChain(cmd)) => { let runner = cli.create_runner(cmd)?; runner.sync_run(|config| cmd.run(config.database)) - } + }, Some(Subcommand::Revert(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { - let PartialComponents { - client, - task_manager, - backend, - .. - } = service::new_partial(&config)?; + let PartialComponents { client, task_manager, backend, .. } = service::new_partial(&config)?; let aux_revert = Box::new(|client, _, blocks| { - sc_finality_grandpa::revert(client, blocks)?; + sc_consensus_grandpa::revert(client, blocks)?; Ok(()) }); Ok((cmd.run(client, backend, Some(aux_revert)), task_manager)) }) - } + }, Some(Subcommand::Benchmark(cmd)) => { let runner = cli.create_runner(cmd)?; @@ -147,19 +115,18 @@ pub fn run() -> sc_cli::Result<()> { if !cfg!(feature = "runtime-benchmarks") { return Err("Runtime benchmarking wasn't enabled when building the node. \ You can enable it with `--features runtime-benchmarks`." - .into()); + .into()) } cmd.run::(config) - } + }, BenchmarkCmd::Block(cmd) => { 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()) - } + 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)?; @@ -167,13 +134,13 @@ pub fn run() -> sc_cli::Result<()> { let storage = backend.expose_storage(); cmd.run(config, client, db, storage) - } + }, BenchmarkCmd::Overhead(cmd) => { let PartialComponents { client, .. } = service::new_partial(&config)?; let ext_builder = RemarkBuilder::new(client.clone()); cmd.run(config, client, inherent_benchmark_data()?, Vec::new(), &ext_builder) - } + }, BenchmarkCmd::Extrinsic(cmd) => { let PartialComponents { client, .. } = service::new_partial(&config)?; // Register the *Remark* and *TKA* builders. @@ -187,13 +154,15 @@ pub fn run() -> sc_cli::Result<()> { ]); cmd.run(client, inherent_benchmark_data()?, Vec::new(), &ext_factory) - } + }, BenchmarkCmd::Machine(cmd) => cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()), } }) - } + }, #[cfg(feature = "try-runtime")] Some(Subcommand::TryRuntime(cmd)) => { + use crate::service::ExecutorDispatch; + use sc_executor::{sp_wasm_interface::ExtendedHostFunctions, NativeExecutionDispatch}; let runner = cli.create_runner(cmd)?; runner.async_run(|config| { // we don't need any of the components of new_partial, just a runtime, or a task @@ -201,9 +170,17 @@ pub fn run() -> sc_cli::Result<()> { let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry); let task_manager = sc_service::TaskManager::new(config.tokio_handle.clone(), registry) .map_err(|e| sc_cli::Error::Service(sc_service::Error::Prometheus(e)))?; - Ok((cmd.run::(config), task_manager)) + let info_provider = timestamp_with_aura_info(6000); + + Ok(( + cmd.run::::ExtendHostFunctions, + >, _>(Some(info_provider)), + task_manager, + )) }) - } + }, #[cfg(not(feature = "try-runtime"))] Some(Subcommand::TryRuntime) => Err("TryRuntime wasn't enabled when building the node. \ You can enable it with `--features try-runtime`." @@ -211,11 +188,11 @@ pub fn run() -> sc_cli::Result<()> { Some(Subcommand::ChainInfo(cmd)) => { let runner = cli.create_runner(cmd)?; runner.sync_run(|config| cmd.run::(&config)) - } + }, None => { let runner = cli.create_runner(&cli.run)?; runner .run_node_until_exit(|config| async move { service::new_full(config).map_err(sc_cli::Error::Service) }) - } + }, } } diff --git a/nodes/standalone/src/rpc.rs b/nodes/standalone/src/rpc.rs index c0051d536..495ce1991 100644 --- a/nodes/standalone/src/rpc.rs +++ b/nodes/standalone/src/rpc.rs @@ -57,11 +57,7 @@ where use substrate_frame_rpc_system::{System, SystemApiServer}; let mut module = RpcModule::new(()); - let FullDeps { - client, - pool, - deny_unsafe, - } = deps; + let FullDeps { client, pool, deny_unsafe } = deps; module.merge(System::new(client.clone(), pool.clone(), deny_unsafe).into_rpc())?; module.merge(TransactionPayment::new(client).into_rpc())?; diff --git a/nodes/standalone/src/service.rs b/nodes/standalone/src/service.rs index e7297d0f7..56ac2c958 100644 --- a/nodes/standalone/src/service.rs +++ b/nodes/standalone/src/service.rs @@ -19,9 +19,8 @@ use polimec_standalone_runtime::{self, opaque::Block, RuntimeApi}; use sc_client_api::BlockBackend; use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams}; +use sc_consensus_grandpa::SharedVoterState; pub use sc_executor::NativeElseWasmExecutor; -use sc_finality_grandpa::SharedVoterState; -use sc_keystore::LocalKeystore; use sc_service::{error::Error as ServiceError, Configuration, TaskManager, WarpSyncParams}; use sc_telemetry::{Telemetry, TelemetryWorker}; use sp_consensus_aura::sr25519::AuthorityPair as AuraPair; @@ -61,17 +60,13 @@ pub fn new_partial( sc_consensus::DefaultImportQueue, sc_transaction_pool::FullPool, ( - sc_finality_grandpa::GrandpaBlockImport, - sc_finality_grandpa::LinkHalf, + sc_consensus_grandpa::GrandpaBlockImport, + sc_consensus_grandpa::LinkHalf, Option, ), >, ServiceError, > { - if config.keystore_remote.is_some() { - return Err(ServiceError::Other("Remote Keystores are not supported.".into())); - } - let telemetry = config .telemetry_endpoints .clone() @@ -83,12 +78,7 @@ pub fn new_partial( }) .transpose()?; - let executor = NativeElseWasmExecutor::::new( - config.wasm_method, - config.default_heap_pages, - config.max_runtime_instances, - config.runtime_cache_size, - ); + let executor = sc_service::new_native_or_wasm_executor(&config); let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::( config, @@ -112,7 +102,7 @@ pub fn new_partial( client.clone(), ); - let (grandpa_block_import, grandpa_link) = sc_finality_grandpa::block_import( + let (grandpa_block_import, grandpa_link) = sc_consensus_grandpa::block_import( client.clone(), &(client.clone() as Arc<_>), select_chain.clone(), @@ -154,13 +144,6 @@ pub fn new_partial( }) } -fn remote_keystore(_url: &String) -> Result, &'static str> { - // FIXME: here would the concrete keystore be built, - // must return a concrete type (NOT `LocalKeystore`) that - // implements `CryptoStore` and `SyncCryptoStore` - Err("Remote Keystore not supported.") -} - /// Builds a new service for a full client. pub fn new_full(mut config: Configuration) -> Result { let sc_service::PartialComponents { @@ -168,41 +151,25 @@ pub fn new_full(mut config: Configuration) -> Result backend, mut task_manager, import_queue, - mut keystore_container, + keystore_container, select_chain, transaction_pool, other: (block_import, grandpa_link, mut telemetry), } = new_partial(&config)?; - if let Some(url) = &config.keystore_remote { - match remote_keystore(url) { - Ok(k) => keystore_container.set_remote_keystore(k), - Err(e) => { - return Err(ServiceError::Other(format!( - "Error hooking up remote keystore for {}: {}", - url, e - ))) - } - }; - } - let grandpa_protocol_name = sc_finality_grandpa::protocol_standard_name( + let grandpa_protocol_name = sc_consensus_grandpa::protocol_standard_name( &client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"), &config.chain_spec, ); - config - .network - .extra_sets - .push(sc_finality_grandpa::grandpa_peers_set_config( - grandpa_protocol_name.clone(), - )); - let warp_sync = Arc::new(sc_finality_grandpa::warp_proof::NetworkProvider::new( + config.network.extra_sets.push(sc_consensus_grandpa::grandpa_peers_set_config(grandpa_protocol_name.clone())); + let warp_sync = Arc::new(sc_consensus_grandpa::warp_proof::NetworkProvider::new( backend.clone(), grandpa_link.shared_authority_set().clone(), Vec::default(), )); - let (network, system_rpc_tx, tx_handler_controller, network_starter) = + let (network, system_rpc_tx, tx_handler_controller, network_starter, sync_service) = sc_service::build_network(sc_service::BuildNetworkParams { config: &config, client: client.clone(), @@ -229,11 +196,7 @@ pub fn new_full(mut config: Configuration) -> Result let pool = transaction_pool.clone(); Box::new(move |deny_unsafe, _| { - let deps = crate::rpc::FullDeps { - client: client.clone(), - pool: pool.clone(), - deny_unsafe, - }; + let deps = crate::rpc::FullDeps { client: client.clone(), pool: pool.clone(), deny_unsafe }; crate::rpc::create_full(deps).map_err(Into::into) }) }; @@ -241,13 +204,14 @@ pub fn new_full(mut config: Configuration) -> Result let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams { network: network.clone(), client: client.clone(), - keystore: keystore_container.sync_keystore(), + keystore: keystore_container.keystore(), task_manager: &mut task_manager, transaction_pool: transaction_pool.clone(), rpc_builder: rpc_extensions_builder, backend, system_rpc_tx, tx_handler_controller, + sync_service: sync_service.clone(), config, telemetry: telemetry.as_mut(), })?; @@ -281,9 +245,9 @@ pub fn new_full(mut config: Configuration) -> Result }, force_authoring, backoff_authoring_blocks, - keystore: keystore_container.sync_keystore(), - sync_oracle: network.clone(), - justification_sync_link: network.clone(), + keystore: keystore_container.keystore(), + sync_oracle: sync_service.clone(), + justification_sync_link: sync_service.clone(), block_proposal_slot_portion: SlotProportion::new(2f32 / 3f32), max_block_proposal_slot_portion: None, telemetry: telemetry.as_ref().map(|x| x.handle()), @@ -292,21 +256,15 @@ pub fn new_full(mut config: Configuration) -> Result // the AURA authoring task is considered essential, i.e. if it // fails we take down the service with it. - task_manager - .spawn_essential_handle() - .spawn_blocking("aura", Some("block-authoring"), aura); + task_manager.spawn_essential_handle().spawn_blocking("aura", Some("block-authoring"), aura); } if enable_grandpa { // if the node isn't actively participating in consensus then it doesn't // need a keystore, regardless of which protocol we use below. - let keystore = if role.is_authority() { - Some(keystore_container.sync_keystore()) - } else { - None - }; + let keystore = if role.is_authority() { Some(keystore_container.keystore()) } else { None }; - let grandpa_config = sc_finality_grandpa::Config { + let grandpa_config = sc_consensus_grandpa::Config { // FIXME #1578 make this available through chainspec gossip_duration: Duration::from_millis(333), justification_period: 512, @@ -324,11 +282,12 @@ pub fn new_full(mut config: Configuration) -> Result // and vote data availability than the observer. The observer has not // been tested extensively yet and having most nodes in a network run it // could lead to finality stalls. - let grandpa_config = sc_finality_grandpa::GrandpaParams { + let grandpa_config = sc_consensus_grandpa::GrandpaParams { config: grandpa_config, link: grandpa_link, network, - voting_rule: sc_finality_grandpa::VotingRulesBuilder::default().build(), + sync: Arc::new(sync_service), + voting_rule: sc_consensus_grandpa::VotingRulesBuilder::default().build(), prometheus_registry, shared_voter_state: SharedVoterState::empty(), telemetry: telemetry.as_ref().map(|x| x.handle()), @@ -339,7 +298,7 @@ pub fn new_full(mut config: Configuration) -> Result task_manager.spawn_essential_handle().spawn_blocking( "grandpa-voter", None, - sc_finality_grandpa::run_grandpa_voter(grandpa_config)?, + sc_consensus_grandpa::run_grandpa_voter(grandpa_config)?, ); } diff --git a/pallets/asset-registry/Cargo.toml b/pallets/asset-registry/Cargo.toml deleted file mode 100644 index bf8db0140..000000000 --- a/pallets/asset-registry/Cargo.toml +++ /dev/null @@ -1,70 +0,0 @@ -[package] -name = "pallet-asset-registry" -version = "0.0.1" -description = "Trappist pallet for XCM Asset Registry." -edition = "2021" -license = "Apache-2.0" -repository = "https://github.com/paritytech/trappist" - - -[dependencies] -scale-info = { workspace = true, features = ["derive", "serde"] } -parity-scale-codec = { workspace = true, features = [ - "derive", -] } -sp-runtime.workspace = true -sp-std.workspace = true -frame-benchmarking.workspace = true -frame-support.workspace = true -frame-system.workspace = true -pallet-assets.workspace = true -pallet-balances.workspace = true -xcm.workspace = true -xcm-primitives.workspace = true - -[dev-dependencies] -sp-core.workspace = true -sp-io.workspace = true -sp-runtime.workspace = true -xcm.workspace = true -xcm-simulator.workspace = true -xcm-executor.workspace = true -xcm-builder.workspace = true -pallet-xcm.workspace = true -polkadot-core-primitives.workspace = true -polkadot-runtime-parachains.workspace = true -polkadot-parachain.workspace = true -parachain-info.workspace = true -parachains-common.workspace = true -cumulus-pallet-dmp-queue.workspace = true -cumulus-pallet-xcmp-queue.workspace = true -cumulus-primitives-core.workspace = true - -[features] -default = ["std"] -std = [ - "parity-scale-codec/std", - "sp-runtime/std", - "sp-std/std", - "pallet-assets/std", - "pallet-balances/std", - "frame-benchmarking/std", - "frame-support/std", - "frame-system/std", - "scale-info/std", - "xcm-primitives/std", - "xcm/std", - "xcm-executor/std", - "xcm-builder/std", - "pallet-xcm/std", - "polkadot-core-primitives/std", - "polkadot-runtime-parachains/std", - "polkadot-parachain/std", - "parachain-info/std", - "parachains-common/std", - "cumulus-pallet-dmp-queue/std", - "cumulus-pallet-xcmp-queue/std", - "cumulus-primitives-core/std", -] -runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] -try-runtime = ["frame-support/try-runtime", "pallet-assets/try-runtime"] diff --git a/pallets/asset-registry/src/benchmarking.rs b/pallets/asset-registry/src/benchmarking.rs deleted file mode 100644 index d2209faa0..000000000 --- a/pallets/asset-registry/src/benchmarking.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Polimec Blockchain – https://www.polimec.org/ -// Copyright (C) Polimec 2022. All rights reserved. - -// The Polimec Blockchain 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. - -// The Polimec Blockchain 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 . - -//! Benchmarking setup for pallet-asset-registry - -use super::*; - -#[allow(unused)] -use crate::Pallet as AssetRegistry; -use frame_benchmarking::benchmarks; -use frame_support::{assert_ok, traits::fungibles::Inspect}; -use frame_system::RawOrigin; -use xcm::opaque::latest::{ - Junction::{GeneralIndex, PalletInstance, Parachain}, - Junctions, MultiLocation, -}; - -pub const LOCAL_ASSET_ID: u32 = 10; - -benchmarks! { - where_clause { - where - T::Assets: Inspect<::AccountId, AssetId = u32>, - } - - register_reserve_asset { - let asset_multi_location = MultiLocation { - parents: 1, - interior: Junctions::X3(Parachain(Default::default()), PalletInstance(Default::default()), GeneralIndex(Default::default())) - }; - - }: _(RawOrigin::Root, LOCAL_ASSET_ID, asset_multi_location.clone()) - verify { - let read_asset_multi_location = AssetRegistry::::asset_id_multilocation(LOCAL_ASSET_ID) - .expect("error reading AssetIdMultiLocation"); - assert_eq!(read_asset_multi_location, asset_multi_location); - } - - unregister_reserve_asset { - let asset_multi_location = MultiLocation { - parents: 1, - interior: Junctions::X3(Parachain(Default::default()), PalletInstance(Default::default()), GeneralIndex(Default::default())) - }; - - assert_ok!(AssetRegistry::::register_reserve_asset(RawOrigin::Root.into(), LOCAL_ASSET_ID, asset_multi_location.clone())); - let read_asset_multi_location = AssetRegistry::::asset_id_multilocation(LOCAL_ASSET_ID) - .expect("error reading AssetIdMultiLocation"); - assert_eq!(read_asset_multi_location, asset_multi_location); - - }: _(RawOrigin::Root, LOCAL_ASSET_ID) - verify { - assert_eq!(AssetRegistry::::asset_id_multilocation(LOCAL_ASSET_ID), None); - } - - impl_benchmark_test_suite!(AssetRegistry, crate::mock::new_test_ext(), crate::mock::Test); -} diff --git a/pallets/asset-registry/src/lib.rs b/pallets/asset-registry/src/lib.rs deleted file mode 100644 index 673e2ed44..000000000 --- a/pallets/asset-registry/src/lib.rs +++ /dev/null @@ -1,171 +0,0 @@ -// Polimec Blockchain – https://www.polimec.org/ -// Copyright (C) Polimec 2022. All rights reserved. - -// The Polimec Blockchain 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. - -// The Polimec Blockchain 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 . - -#![cfg_attr(not(feature = "std"), no_std)] - -/// Edit this file to define custom logic or remove it if it is not needed. -/// Learn more about FRAME and the core library of Substrate FRAME pallets: -/// -pub use pallet::*; - -#[cfg(test)] -mod mock; -#[cfg(test)] -mod tests; - -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking; -pub mod weights; -pub use weights::*; - -#[frame_support::pallet(dev_mode)] -pub mod pallet { - use super::*; - use frame_support::{pallet_prelude::*, sp_runtime::traits::Zero, traits::tokens::fungibles::Inspect}; - use frame_system::pallet_prelude::*; - - use xcm::latest::{ - Junction::{GeneralIndex, PalletInstance, Parachain}, - Junctions, MultiLocation, - }; - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(_); - - type AssetIdOf = <::Assets as Inspect<::AccountId>>::AssetId; - - #[pallet::config] - pub trait Config: frame_system::Config { - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - type ReserveAssetModifierOrigin: EnsureOrigin; - type Assets: Inspect; - type WeightInfo: WeightInfo; - } - - #[pallet::storage] - #[pallet::getter(fn asset_id_multilocation)] - pub type AssetIdMultiLocation = StorageMap<_, Blake2_128Concat, AssetIdOf, MultiLocation>; - - #[pallet::storage] - #[pallet::getter(fn asset_multilocation_id)] - pub type AssetMultiLocationId = StorageMap<_, Blake2_128Concat, MultiLocation, AssetIdOf>; - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - ReserveAssetRegistered { - asset_id: AssetIdOf, - asset_multi_location: MultiLocation, - }, - ReserveAssetUnregistered { - asset_id: AssetIdOf, - asset_multi_location: MultiLocation, - }, - } - - #[pallet::error] - pub enum Error { - /// The Asset ID is already registered - AssetAlreadyRegistered, - /// The Asset ID does not exist - AssetDoesNotExist, - /// The Asset ID is not registered - AssetIsNotRegistered, - /// Invalid MultiLocation - WrongMultiLocation, - } - - #[pallet::call] - impl Pallet { - #[pallet::weight(::WeightInfo::register_reserve_asset())] - pub fn register_reserve_asset( - origin: OriginFor, asset_id: AssetIdOf, asset_multi_location: MultiLocation, - ) -> DispatchResult { - T::ReserveAssetModifierOrigin::ensure_origin(origin)?; - - // verify asset exists on pallet-assets - ensure!(Self::asset_exists(asset_id), Error::::AssetDoesNotExist); - - // verify asset is not yet registered - ensure!( - !AssetIdMultiLocation::::contains_key(asset_id), - Error::::AssetAlreadyRegistered - ); - - // verify MultiLocation is valid - let parents_multi_location_ok = { asset_multi_location.parents == 1 }; - let junctions_multi_location_ok = matches!( - asset_multi_location.interior, - Junctions::X3(Parachain(_), PalletInstance(_), GeneralIndex(_)) - ); - - ensure!( - parents_multi_location_ok && junctions_multi_location_ok, - Error::::WrongMultiLocation - ); - - // register asset - AssetIdMultiLocation::::insert(asset_id, &asset_multi_location); - AssetMultiLocationId::::insert(&asset_multi_location, asset_id); - - Self::deposit_event(Event::ReserveAssetRegistered { - asset_id, - asset_multi_location, - }); - - Ok(()) - } - - #[pallet::weight(::WeightInfo::unregister_reserve_asset())] - pub fn unregister_reserve_asset(origin: OriginFor, asset_id: AssetIdOf) -> DispatchResult { - T::ReserveAssetModifierOrigin::ensure_origin(origin)?; - - // verify asset is registered - let asset_multi_location = - AssetIdMultiLocation::::get(asset_id).ok_or(Error::::AssetIsNotRegistered)?; - - // unregister asset - AssetIdMultiLocation::::remove(asset_id); - AssetMultiLocationId::::remove(&asset_multi_location); - - Self::deposit_event(Event::ReserveAssetUnregistered { - asset_id, - asset_multi_location, - }); - Ok(()) - } - } - - impl xcm_primitives::AssetMultiLocationGetter> for Pallet { - fn get_asset_multi_location(asset_id: AssetIdOf) -> Option { - AssetIdMultiLocation::::get(asset_id) - } - - fn get_asset_id(asset_type: MultiLocation) -> Option> { - AssetMultiLocationId::::get(asset_type) - } - } - - impl Pallet { - // pallet-assets implements the fungibles::Inspect trait - // where minimum_balance(asset_id) always returns non-zero - // for existing assets, and zero for non-existing assets - fn asset_exists(asset_id: AssetIdOf) -> bool { - !T::Assets::minimum_balance(asset_id).is_zero() - } - } -} diff --git a/pallets/asset-registry/src/mock.rs b/pallets/asset-registry/src/mock.rs deleted file mode 100644 index d966bd34c..000000000 --- a/pallets/asset-registry/src/mock.rs +++ /dev/null @@ -1,124 +0,0 @@ -use crate as pallet_asset_registry; -use frame_support::traits::{AsEnsureOriginWithArg, ConstU16, ConstU64, GenesisBuild}; -use frame_system as system; -use sp_core::H256; -use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, ConstU32, IdentityLookup}, -}; - -type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; -type Block = frame_system::mocking::MockBlock; - -frame_support::parameter_types! { - pub const StatemineParaIdInfo: u32 = 1000u32; - pub const StatemineAssetsInstanceInfo: u8 = 50u8; - pub const StatemineAssetIdInfo: u128 = 1u128; -} - -// Configure a mock runtime to test the pallet. -frame_support::construct_runtime!( - pub enum Test where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system, - AssetRegistry: pallet_asset_registry::{Pallet, Call, Storage, Event}, - Assets: pallet_assets::{Pallet, Call, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - } -); - -impl system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Index = u64; - type BlockNumber = u64; - type Hash = H256; - 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 = ConstU16<42>; - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; -} - -impl pallet_asset_registry::Config for Test { - type RuntimeEvent = RuntimeEvent; - type ReserveAssetModifierOrigin = frame_system::EnsureRoot; - type Assets = Assets; - type WeightInfo = pallet_asset_registry::weights::SubstrateWeight; -} - -impl pallet_balances::Config for Test { - type Balance = u64; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ConstU64<1>; - type AccountStore = System; - type WeightInfo = (); - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; -} - -impl pallet_assets::Config for Test { - type RuntimeEvent = RuntimeEvent; - type Balance = u64; - type AssetId = u32; - type Currency = Balances; - type ForceOrigin = frame_system::EnsureRoot; - type AssetDeposit = ConstU64<1>; - type AssetAccountDeposit = ConstU64<10>; - type MetadataDepositBase = ConstU64<1>; - type MetadataDepositPerByte = ConstU64<1>; - type ApprovalDeposit = ConstU64<1>; - type StringLimit = ConstU32<50>; - type Freezer = (); - type WeightInfo = (); - type Extra = (); - type AssetIdParameter = u32; - type CreateOrigin = AsEnsureOriginWithArg>; - type CallbackHandle = (); - type RemoveItemsLimit = frame_support::traits::ConstU32<1000>; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); -} - -pub const LOCAL_ASSET_ID: u32 = 10; - -// Build genesis storage according to the mock runtime. -pub fn new_test_ext() -> sp_io::TestExternalities { - let mut storage = system::GenesisConfig::default().build_storage::().unwrap(); - - let config: pallet_assets::GenesisConfig = pallet_assets::GenesisConfig { - assets: vec![ - // id, owner, is_sufficient, min_balance - (LOCAL_ASSET_ID, 0, true, 1), - ], - metadata: vec![ - // id, name, symbol, decimals - (LOCAL_ASSET_ID, "Token Name".into(), "TOKEN".into(), 10), - ], - accounts: vec![ - // id, account_id, balance - (LOCAL_ASSET_ID, 1, 100), - ], - }; - config.assimilate_storage(&mut storage).unwrap(); - storage.into() -} diff --git a/pallets/asset-registry/src/tests.rs b/pallets/asset-registry/src/tests.rs deleted file mode 100644 index 7b3029e9b..000000000 --- a/pallets/asset-registry/src/tests.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::{mock::*, Error}; -use frame_support::{assert_noop, assert_ok}; -use xcm::latest::prelude::*; - -#[test] -fn register_reserve_asset_works() { - new_test_ext().execute_with(|| { - let statemine_para_id = StatemineParaIdInfo::get(); - let statemine_assets_pallet = StatemineAssetsInstanceInfo::get(); - let statemine_asset_id = StatemineAssetIdInfo::get(); - - let statemine_asset_multi_location = MultiLocation { - parents: 1, - interior: X3( - Parachain(statemine_para_id), - PalletInstance(statemine_assets_pallet), - GeneralIndex(statemine_asset_id), - ), - }; - - assert_ok!(AssetRegistry::register_reserve_asset( - RuntimeOrigin::root(), - LOCAL_ASSET_ID, - statemine_asset_multi_location.clone(), - )); - - let read_asset_multi_location = - AssetRegistry::asset_id_multilocation(LOCAL_ASSET_ID).expect("error reading AssetIdMultiLocation"); - assert_eq!(read_asset_multi_location, statemine_asset_multi_location); - - let read_asset_id = AssetRegistry::asset_multilocation_id(&statemine_asset_multi_location) - .expect("error reading AssetMultiLocationId"); - assert_eq!(read_asset_id, LOCAL_ASSET_ID); - - assert_noop!( - AssetRegistry::register_reserve_asset( - RuntimeOrigin::root(), - LOCAL_ASSET_ID, - statemine_asset_multi_location, - ), - Error::::AssetAlreadyRegistered - ); - }); -} - -#[test] -fn unregister_reserve_asset_works() { - new_test_ext().execute_with(|| { - let statemine_para_id = StatemineParaIdInfo::get(); - let statemine_assets_pallet = StatemineAssetsInstanceInfo::get(); - let statemine_asset_id = StatemineAssetIdInfo::get(); - - let statemine_asset_multi_location = MultiLocation { - parents: 1, - interior: X3( - Parachain(statemine_para_id), - PalletInstance(statemine_assets_pallet), - GeneralIndex(statemine_asset_id), - ), - }; - - assert_ok!(AssetRegistry::register_reserve_asset( - RuntimeOrigin::root(), - LOCAL_ASSET_ID, - statemine_asset_multi_location.clone(), - )); - - assert_ok!(AssetRegistry::unregister_reserve_asset( - RuntimeOrigin::root(), - LOCAL_ASSET_ID - )); - - assert!(AssetRegistry::asset_id_multilocation(LOCAL_ASSET_ID).is_none()); - assert!(AssetRegistry::asset_multilocation_id(statemine_asset_multi_location).is_none()); - }); -} diff --git a/pallets/asset-registry/src/weights.rs b/pallets/asset-registry/src/weights.rs deleted file mode 100644 index 39416c719..000000000 --- a/pallets/asset-registry/src/weights.rs +++ /dev/null @@ -1,76 +0,0 @@ - -//! Autogenerated weights for `pallet_asset_registry` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2022-10-04, STEPS: `20`, REPEAT: 10, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! HOSTNAME: `bernardo-benchmarking`, CPU: `AMD EPYC 7B13` -//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 - -// collected on a c2d-highcpu-8 of Google Cloud Platform - -// Executed Command: -// ./target/release/trappist-collator -// benchmark -// pallet -// --chain -// dev -// --pallet -// pallet_asset_registry -// --extrinsic -// * -// --steps -// 20 -// --repeat -// 10 -// --output -// pallets/asset-registry/src/weights.rs - -#![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; - -pub trait WeightInfo { - fn register_reserve_asset() -> Weight; - fn unregister_reserve_asset() -> Weight; -} - -/// Weight functions for `pallet_asset_registry`. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - // Storage: Assets Asset (r:1 w:0) - // Storage: AssetRegistry AssetIdMultiLocation (r:1 w:1) - // Storage: AssetRegistry AssetMultiLocationId (r:0 w:1) - fn register_reserve_asset() -> Weight { - Weight::from_ref_time(18_710_000) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - // Storage: AssetRegistry AssetIdMultiLocation (r:1 w:1) - // Storage: AssetRegistry AssetMultiLocationId (r:0 w:1) - fn unregister_reserve_asset() -> Weight { - Weight::from_ref_time(16_570_000) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } -} - -impl WeightInfo for () { - // Storage: Assets Asset (r:1 w:0) - // Storage: AssetRegistry AssetIdMultiLocation (r:1 w:1) - // Storage: AssetRegistry AssetMultiLocationId (r:0 w:1) - fn register_reserve_asset() -> Weight { - Weight::from_ref_time(18_710_000) - .saturating_add(RocksDbWeight::get().reads(2)) - .saturating_add(RocksDbWeight::get().writes(2)) - } - // Storage: AssetRegistry AssetIdMultiLocation (r:1 w:1) - // Storage: AssetRegistry AssetMultiLocationId (r:0 w:1) - fn unregister_reserve_asset() -> Weight { - Weight::from_ref_time(16_570_000) - .saturating_add(RocksDbWeight::get().reads(1)) - .saturating_add(RocksDbWeight::get().writes(2)) - } -} diff --git a/pallets/credentials/Cargo.toml b/pallets/credentials/Cargo.toml deleted file mode 100644 index 9fe1014a2..000000000 --- a/pallets/credentials/Cargo.toml +++ /dev/null @@ -1,58 +0,0 @@ -[package] -name = 'pallet-credentials' -description = 'FRAME pallet handle credentials' -authors.workspace = true -documentation.workspace = true -edition.workspace = true -homepage.workspace = true -license-file.workspace = true -readme.workspace = true -repository.workspace = true -version.workspace = true - - -[dependencies] -parity-scale-codec = { workspace = true, features = [ - "derive", -] } -scale-info = { workspace = true, features = ["derive"] } - -# Benchmarking dependencies -frame-benchmarking = { workspace = true, optional = true } -# Substrate dependencies -frame-support.workspace = true -frame-system.workspace = true -sp-std.workspace = true -sp-runtime.workspace = true -polimec-traits.workspace = true - -[dev-dependencies] -sp-core.workspace = true -sp-io.workspace = true -pallet-balances.workspace = true - -[features] -try-runtime = [ - "frame-support/try-runtime", - "frame-system/try-runtime", - "polimec-traits/try-runtime", -] -default = ["std"] -runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "polimec-traits/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", -] -std = [ - "parity-scale-codec/std", - "sp-std/std", - "sp-runtime/std", - "pallet-balances/std", - "polimec-traits/std", - "frame-support/std", - "frame-system/std", - "scale-info/std", - "frame-benchmarking?/std", -] diff --git a/pallets/credentials/src/benchmarking.rs b/pallets/credentials/src/benchmarking.rs deleted file mode 100644 index 8b1378917..000000000 --- a/pallets/credentials/src/benchmarking.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/pallets/credentials/src/lib.rs b/pallets/credentials/src/lib.rs deleted file mode 100644 index 5f3b325af..000000000 --- a/pallets/credentials/src/lib.rs +++ /dev/null @@ -1,279 +0,0 @@ -// Polimec Blockchain – https://www.polimec.org/ -// Copyright (C) Polimec 2022. All rights reserved. - -// The Polimec Blockchain 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. - -// The Polimec Blockchain 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 . - -#![cfg_attr(not(feature = "std"), no_std)] - -pub use pallet::*; - -#[cfg(test)] -mod mock; - -#[cfg(test)] -mod tests; - -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking; - -use frame_support::{ - ensure, - pallet_prelude::DispatchResult, - traits::{ChangeMembers, InitializeMembers}, -}; -use polimec_traits::{Credential, MemberRole, PolimecMembers}; -use sp_runtime::{traits::StaticLookup, DispatchError}; - -type AccountIdLookupOf = <::Lookup as StaticLookup>::Source; - -#[frame_support::pallet(dev_mode)] -pub mod pallet { - use super::*; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - - /// Configure the pallet by specifying the parameters and types on which it depends. - #[pallet::config] - pub trait Config: frame_system::Config { - /// The overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - /// Required origin for adding a member (though can always be Root). - type AddOrigin: EnsureOrigin; - - /// Required origin for removing a member (though can always be Root). - type RemoveOrigin: EnsureOrigin; - - /// Required origin for adding and removing a member in a single action. - /// TODO: Not used ATM - type SwapOrigin: EnsureOrigin; - - /// Required origin for resetting membership. - /// TODO: Not used ATM - type ResetOrigin: EnsureOrigin; - - /// Required origin for setting or resetting the prime member. - /// TODO: Not used ATM - 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 - /// something different on initialization, then you can change this accordingly. - type MembershipInitialized: InitializeMembers; - - /// The receiver of the signal for when the membership has changed. - type MembershipChanged: ChangeMembers; - - // Weight information for extrinsics in this pallet. - // type WeightInfo: WeightInfo; - } - - #[pallet::pallet] - #[pallet::generate_store(pub(super) trait Store)] - pub struct Pallet(_); - - /// Maps member type to members of each type. - #[pallet::storage] - #[pallet::getter(fn members)] - pub type Members = StorageDoubleMap<_, Twox64Concat, MemberRole, Twox64Concat, T::AccountId, ()>; - - #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { - /// The given member was added; see the transaction for who. - MemberAdded, - /// The given member was removed; see the transaction for who. - MemberRemoved, - /// Two members were swapped; see the transaction for who. - MembersSwapped, - /// The membership was reset; see the transaction for who the new set is. - MembersReset, - /// One of the members' keys changed. - KeyChanged, - } - - #[pallet::error] - pub enum Error { - /// Already a member. - AlreadyMember, - /// Not a member. - NotMember, - } - - #[pallet::hooks] - impl Hooks> for Pallet {} - - #[pallet::genesis_config] - pub struct GenesisConfig { - pub issuers: Vec, - pub retails: Vec, - pub professionals: Vec, - pub institutionals: Vec, - } - - #[cfg(feature = "std")] - impl Default for GenesisConfig { - fn default() -> Self { - Self { - issuers: Default::default(), - retails: Default::default(), - professionals: Default::default(), - institutionals: Default::default(), - } - } - } - - #[pallet::genesis_build] - impl GenesisBuild for GenesisConfig { - fn build(&self) { - use sp_std::collections::btree_set::BTreeSet; - - let issuers_set: BTreeSet<_> = self.issuers.iter().collect(); - assert_eq!( - issuers_set.len(), - self.issuers.len(), - "Issuers cannot contain duplicate accounts." - ); - - let retails_set: BTreeSet<_> = self.retails.iter().collect(); - assert_eq!( - retails_set.len(), - self.retails.len(), - "Issuers cannot contain duplicate accounts." - ); - - let professionals_set: BTreeSet<_> = self.professionals.iter().collect(); - assert_eq!( - professionals_set.len(), - self.professionals.len(), - "Issuers cannot contain duplicate accounts." - ); - - let institutionals_set: BTreeSet<_> = self.institutionals.iter().collect(); - assert_eq!( - institutionals_set.len(), - self.institutionals.len(), - "Issuers cannot contain duplicate accounts." - ); - - Pallet::::initialize_members(&MemberRole::Issuer, &self.issuers); - Pallet::::initialize_members(&MemberRole::Retail, &self.retails); - Pallet::::initialize_members(&MemberRole::Professional, &self.professionals); - Pallet::::initialize_members(&MemberRole::Institutional, &self.institutionals); - } - } - - #[pallet::call] - impl Pallet { - /// Add a member `who` to the set. - /// - /// May only be called from `T::AddOrigin`. - // TODO: Set a proper weight - #[pallet::weight(1)] - pub fn add_member(origin: OriginFor, credential: Credential, who: AccountIdLookupOf) -> DispatchResult { - T::AddOrigin::ensure_origin(origin)?; - let who = T::Lookup::lookup(who)?; - - Self::do_add_member(&who, &credential)?; - Ok(()) - } - - /// Remove a member `who` from the set. - /// - /// May only be called from `T::RemoveOrigin`. - // TODO: Set a proper weight - #[pallet::weight(1)] - pub fn remove_member( - origin: OriginFor, credential: Credential, who: AccountIdLookupOf, - ) -> DispatchResult { - T::RemoveOrigin::ensure_origin(origin)?; - let who = T::Lookup::lookup(who)?; - - Self::do_remove_member(&who, &credential)?; - Ok(()) - } - } -} - -impl Pallet { - fn do_add_member(who: &T::AccountId, credential: &Credential) -> Result<(), DispatchError> { - // TODO: This is a placeholder, we still dont't know the actual structure of a `Credential` - let role = credential.role; - ensure!(!Self::is_in(&role, who), Error::::AlreadyMember); - - Self::do_add_member_with_role(&role, who)?; - Ok(()) - } - - fn do_add_member_with_role(role: &MemberRole, who: &T::AccountId) -> Result<(), DispatchError> { - Members::::insert(role, who, ()); - Self::deposit_event(Event::MemberAdded); - Ok(()) - } - - fn do_remove_member(who: &T::AccountId, credential: &Credential) -> Result<(), DispatchError> { - // TODO: This is a placeholder, we still dont't know the actual structure of a `Credential` - let role = credential.role; - ensure!(Self::is_in(&role, who), Error::::NotMember); - - Self::do_remove_member_with_role(&role, who)?; - Ok(()) - } - - fn do_remove_member_with_role(role: &MemberRole, who: &T::AccountId) -> Result<(), DispatchError> { - Members::::remove(role, who); - Self::deposit_event(Event::MemberRemoved); - Ok(()) - } -} - -use sp_std::{vec, vec::Vec}; - -impl PolimecMembers for Pallet { - /// Chech if `who` is in the `role` set - fn is_in(role: &MemberRole, who: &T::AccountId) -> bool { - >::contains_key(role, who) - } - - /// Add `who` to the `role` set - fn add_member(role: &MemberRole, who: &T::AccountId) -> Result<(), DispatchError> { - Self::do_add_member_with_role(role, who) - } - - /// Utility function to set a vector of `member` during the genesis - fn initialize_members(role: &MemberRole, members: &[T::AccountId]) { - if !members.is_empty() { - for member in members { - assert!(!Self::is_in(role, member), "Members are already initialized!"); - } - for member in members { - let _ = Self::do_add_member_with_role(role, member); - } - } - } - - fn get_members_of(role: &MemberRole) -> Vec { - >::iter_key_prefix(role).collect() - } - - fn get_roles_of(who: &T::AccountId) -> Vec { - let mut user_roles = vec![]; - for role in MemberRole::iterator() { - if let Some(()) = Members::::get(role, who) { - user_roles.push(*role) - } - } - user_roles - } -} diff --git a/pallets/credentials/src/mock.rs b/pallets/credentials/src/mock.rs deleted file mode 100644 index a57d581f1..000000000 --- a/pallets/credentials/src/mock.rs +++ /dev/null @@ -1,129 +0,0 @@ -// Polimec Blockchain – https://www.polimec.org/ -// Copyright (C) Polimec 2022. All rights reserved. - -// The Polimec Blockchain 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. - -// The Polimec Blockchain 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 as pallet_credentials; -use frame_support::{parameter_types, traits::ConstU16}; -use frame_system::EnsureRoot; -use sp_core::H256; -use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, -}; - -type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; -type Block = frame_system::mocking::MockBlock; - -pub type AccountId = u64; -pub type Balance = u128; -pub type BlockNumber = u64; - -// Configure a mock runtime to test the pallet. -frame_support::construct_runtime!( - pub enum Test where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system, - Balances: pallet_balances, - Credentials: pallet_credentials, - } -); - -parameter_types! { - pub const BlockHashCount: u32 = 250; -} - -impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Index = u64; - type BlockNumber = BlockNumber; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Header = Header; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = ConstU16<42>; - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -parameter_types! { - pub static ExistentialDeposit: Balance = 1; -} - -impl pallet_balances::Config for Test { - type MaxLocks = frame_support::traits::ConstU32<1024>; - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type Balance = Balance; - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = (); -} - -impl pallet_credentials::Config for Test { - type RuntimeEvent = RuntimeEvent; - type AddOrigin = EnsureRoot; - type RemoveOrigin = EnsureRoot; - type SwapOrigin = EnsureRoot; - type ResetOrigin = EnsureRoot; - type PrimeOrigin = EnsureRoot; - type MembershipInitialized = (); - type MembershipChanged = (); -} - -// Build genesis storage according to the mock runtime. -// TODO: Add some mocks projects at Genesis to simplify the tests -pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - - GenesisConfig { - balances: BalancesConfig { - balances: vec![(1, 512), (2, 512), (3, 512), (4, 512), (5, 512)], - }, - credentials: CredentialsConfig { - issuers: vec![1], - retails: vec![2], - professionals: vec![3, 5], - institutionals: vec![4, 5], - }, - ..Default::default() - } - .assimilate_storage(&mut t) - .unwrap(); - - let mut ext = sp_io::TestExternalities::new(t); - // In order to emit events the block number must be more than 0 - ext.execute_with(|| System::set_block_number(1)); - ext -} diff --git a/pallets/credentials/src/tests.rs b/pallets/credentials/src/tests.rs deleted file mode 100644 index ad6470204..000000000 --- a/pallets/credentials/src/tests.rs +++ /dev/null @@ -1,156 +0,0 @@ -// Polimec Blockchain – https://www.polimec.org/ -// Copyright (C) Polimec 2022. All rights reserved. - -// The Polimec Blockchain 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. - -// The Polimec Blockchain 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::{mock::*, Error}; -use frame_support::{assert_noop, assert_ok, error::BadOrigin, BoundedVec}; -use polimec_traits::{Country, Credential, Issuers, MemberRole, PolimecMembers}; - -pub fn last_event() -> RuntimeEvent { - frame_system::Pallet::::events() - .pop() - .expect("Event expected") - .event -} - -const ALICE: AccountId = 1; -const BOB: AccountId = 2; -const CHARLIE: AccountId = 3; -const DAVE: AccountId = 4; -const EVE: AccountId = 5; - -fn new_test_credential(role: MemberRole) -> Credential { - Credential { - issuer: Issuers::IssuerOne, - role, - domicile: BoundedVec::default(), - country: Country::Switzerland, - date_of_birth: 10, - } -} - -#[test] -fn add_during_genesis_works() { - new_test_ext().execute_with(|| { - assert!(Credentials::members(MemberRole::Issuer, ALICE).is_some()); - assert!(Credentials::is_in(&MemberRole::Issuer, &ALICE)); - - assert!(Credentials::members(MemberRole::Retail, BOB).is_some()); - assert!(Credentials::is_in(&MemberRole::Retail, &BOB)); - - assert!(Credentials::members(MemberRole::Professional, CHARLIE).is_some()); - assert!(Credentials::is_in(&MemberRole::Professional, &CHARLIE)); - - assert!(Credentials::members(MemberRole::Institutional, DAVE).is_some()); - assert!(Credentials::is_in(&MemberRole::Institutional, &DAVE)); - }) -} - -#[test] -fn add_member_works() { - new_test_ext().execute_with(|| { - let cred = new_test_credential(MemberRole::Issuer); - assert_ok!(Credentials::add_member(RuntimeOrigin::root(), cred, BOB)); - assert_eq!(last_event(), RuntimeEvent::Credentials(crate::Event::MemberAdded)); - }) -} - -#[test] -fn only_root_can_add_member() { - new_test_ext().execute_with(|| { - let cred = new_test_credential(MemberRole::Issuer); - assert_noop!( - Credentials::add_member(RuntimeOrigin::signed(ALICE), cred, BOB), - BadOrigin - ); - }) -} - -#[test] -fn cant_add_already_member() { - new_test_ext().execute_with(|| { - let cred = new_test_credential(MemberRole::Issuer); - assert_noop!( - Credentials::add_member(RuntimeOrigin::root(), cred, ALICE), - Error::::AlreadyMember - ); - }) -} - -#[test] -fn remove_member_works() { - new_test_ext().execute_with(|| { - let cred = new_test_credential(MemberRole::Issuer); - assert_ok!(Credentials::remove_member(RuntimeOrigin::root(), cred, ALICE)); - assert_eq!(last_event(), RuntimeEvent::Credentials(crate::Event::MemberRemoved)); - }) -} - -#[test] -fn only_root_can_remove_member() { - new_test_ext().execute_with(|| { - let cred = new_test_credential(MemberRole::Issuer); - assert_noop!( - Credentials::remove_member(RuntimeOrigin::signed(ALICE), cred, ALICE), - BadOrigin - ); - }) -} - -#[test] -fn cant_remove_not_a_member() { - new_test_ext().execute_with(|| { - let cred = new_test_credential(MemberRole::Issuer); - assert_noop!( - Credentials::remove_member(RuntimeOrigin::root(), cred, EVE), - Error::::NotMember - ); - }) -} - -#[test] -fn get_members_of_works() { - new_test_ext().execute_with(|| { - let issuers = Credentials::get_members_of(&MemberRole::Issuer); - assert!(issuers == vec![1]); - let cred = new_test_credential(MemberRole::Issuer); - let _ = Credentials::add_member(RuntimeOrigin::root(), cred.clone(), BOB); - let issuers = Credentials::get_members_of(&MemberRole::Issuer); - assert!(issuers == vec![1, 2]); - let _ = Credentials::remove_member(RuntimeOrigin::root(), cred, ALICE); - let issuers = Credentials::get_members_of(&MemberRole::Issuer); - assert!(issuers == vec![2]); - }) -} - -#[test] -fn get_roles_of_works() { - new_test_ext().execute_with(|| { - let roles = Credentials::get_roles_of(&EVE); - let expected_roles = vec![MemberRole::Professional, MemberRole::Institutional]; - assert!(roles.len() == 2); - assert!(roles == expected_roles); - }) -} - -#[test] -fn get_roles_of_not_user() { - new_test_ext().execute_with(|| { - let roles = Credentials::get_roles_of(&6); - let expected_roles: Vec = vec![]; - assert!(roles.is_empty()); - assert!(roles == expected_roles); - }) -} diff --git a/pallets/funding/Cargo.toml b/pallets/funding/Cargo.toml index 715a43d3d..88731b9bb 100644 --- a/pallets/funding/Cargo.toml +++ b/pallets/funding/Cargo.toml @@ -22,7 +22,6 @@ frame-system.workspace = true sp-std.workspace = true sp-runtime.workspace = true sp-arithmetic.workspace = true -polimec-traits.workspace = true # Benchmarking dependencies frame-benchmarking = { workspace = true, optional = true } @@ -33,7 +32,6 @@ sp-io.workspace = true pallet-balances.workspace = true pallet-insecure-randomness-collective-flip.workspace = true pallet-assets.workspace = true -pallet-credentials.workspace = true [features] default = ["std"] @@ -47,8 +45,6 @@ std = [ "frame-system/std", "pallet-assets/std", "pallet-balances/std", - "pallet-credentials/std", - "polimec-traits/std", "frame-benchmarking?/std", ] runtime-benchmarks = [ diff --git a/pallets/funding/src/benchmarking.rs b/pallets/funding/src/benchmarking.rs index 2e789b8c7..359096b49 100644 --- a/pallets/funding/src/benchmarking.rs +++ b/pallets/funding/src/benchmarking.rs @@ -62,10 +62,7 @@ fn assert_last_event(generic_event: ::RuntimeEvent) { #[allow(unused)] fn get_events() -> frame_benchmarking::Vec<::RuntimeEvent> { - frame_system::Pallet::::events() - .into_iter() - .map(|r| r.event) - .collect::>() + frame_system::Pallet::::events().into_iter().map(|r| r.event).collect::>() } fn create_default_project(id: Option) -> (T::ProjectIdParameter, T::AccountId, ProjectMetadataOf) { diff --git a/pallets/funding/src/functions.rs b/pallets/funding/src/functions.rs index 2e0e44c8d..0a32ddea2 100644 --- a/pallets/funding/src/functions.rs +++ b/pallets/funding/src/functions.rs @@ -65,7 +65,7 @@ impl Pallet { ValidityError::PriceTooLow => Err(Error::::PriceTooLow.into()), ValidityError::ParticipantsSizeError => Err(Error::::ParticipantsSizeError.into()), ValidityError::TicketSizeError => Err(Error::::TicketSizeError.into()), - }; + } } // * Calculate new variables * @@ -126,23 +126,14 @@ impl Pallet { let now = >::block_number(); // * Validity checks * - ensure!( - project_info.project_status == ProjectStatus::Application, - Error::::ProjectNotInApplicationRound - ); + ensure!(project_info.project_status == ProjectStatus::Application, Error::::ProjectNotInApplicationRound); ensure!(!project_info.is_frozen, Error::::ProjectAlreadyFrozen); - ensure!( - project.offchain_information_hash.is_some(), - Error::::MetadataNotProvided - ); + ensure!(project.offchain_information_hash.is_some(), Error::::MetadataNotProvided); // * Calculate new variables * let evaluation_end_block = now + T::EvaluationDuration::get(); project_info.phase_transition_points.application.update(None, Some(now)); - project_info - .phase_transition_points - .evaluation - .update(Some(now + 1u32.into()), Some(evaluation_end_block)); + project_info.phase_transition_points.evaluation.update(Some(now + 1u32.into()), Some(evaluation_end_block)); project_info.is_frozen = true; project_info.project_status = ProjectStatus::EvaluationRound; @@ -150,10 +141,7 @@ impl Pallet { // TODO: Should we make it possible to end an application, and schedule for a later point the evaluation? // Or should we just make it so that the evaluation starts immediately after the application ends? ProjectsDetails::::insert(project_id, project_info); - Self::add_to_update_store( - evaluation_end_block + 1u32.into(), - (&project_id, UpdateType::EvaluationEnd), - ); + Self::add_to_update_store(evaluation_end_block + 1u32.into(), (&project_id, UpdateType::EvaluationEnd)); // * Emit events * Self::deposit_event(Event::::EvaluationStarted { project_id }); @@ -193,18 +181,12 @@ impl Pallet { // * Get variables * let mut project_info = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectInfoNotFound)?; let now = >::block_number(); - let evaluation_end_block = project_info - .phase_transition_points - .evaluation - .end() - .ok_or(Error::::FieldIsNone)?; + let evaluation_end_block = + project_info.phase_transition_points.evaluation.end().ok_or(Error::::FieldIsNone)?; let fundraising_target = project_info.fundraising_target; // * Validity checks * - ensure!( - project_info.project_status == ProjectStatus::EvaluationRound, - Error::::ProjectNotInEvaluationRound - ); + ensure!(project_info.project_status == ProjectStatus::EvaluationRound, Error::::ProjectNotInEvaluationRound); ensure!(now > evaluation_end_block, Error::::EvaluationPeriodNotEnded); // * Calculate new variables * @@ -226,10 +208,10 @@ impl Pallet { // Successful path if is_funded { // * Update storage * - project_info.phase_transition_points.auction_initialize_period.update( - Some(auction_initialize_period_start_block), - Some(auction_initialize_period_end_block), - ); + project_info + .phase_transition_points + .auction_initialize_period + .update(Some(auction_initialize_period_start_block), Some(auction_initialize_period_end_block)); project_info.project_status = ProjectStatus::AuctionInitializePeriod; ProjectsDetails::::insert(project_id, project_info); Self::add_to_update_store( @@ -299,10 +281,7 @@ impl Pallet { .ok_or(Error::::EvaluationPeriodNotEnded)?; // * Validity checks * - ensure!( - now >= auction_initialize_period_start_block, - Error::::TooEarlyForEnglishAuctionStart - ); + ensure!(now >= auction_initialize_period_start_block, Error::::TooEarlyForEnglishAuctionStart); ensure!( project_info.project_status == ProjectStatus::AuctionInitializePeriod, Error::::ProjectNotInAuctionInitializePeriodRound @@ -313,10 +292,7 @@ impl Pallet { let english_end_block = now + T::EnglishAuctionDuration::get(); // * Update Storage * - project_info - .phase_transition_points - .english_auction - .update(Some(english_start_block), Some(english_end_block)); + project_info.phase_transition_points.english_auction.update(Some(english_start_block), Some(english_end_block)); project_info.project_status = ProjectStatus::AuctionRound(AuctionPhase::English); ProjectsDetails::::insert(project_id, project_info); @@ -326,10 +302,7 @@ impl Pallet { Self::remove_from_update_store(&project_id)?; } // Schedule for automatic transition to candle auction round - Self::add_to_update_store( - english_end_block + 1u32.into(), - (&project_id, UpdateType::CandleAuctionStart), - ); + Self::add_to_update_store(english_end_block + 1u32.into(), (&project_id, UpdateType::CandleAuctionStart)); // * Emit events * Self::deposit_event(Event::::EnglishAuctionStarted { project_id, when: now }); @@ -364,11 +337,8 @@ impl Pallet { // * Get variables * let mut project_info = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectInfoNotFound)?; let now = >::block_number(); - let english_end_block = project_info - .phase_transition_points - .english_auction - .end() - .ok_or(Error::::FieldIsNone)?; + let english_end_block = + project_info.phase_transition_points.english_auction.end().ok_or(Error::::FieldIsNone)?; // * Validity checks * ensure!(now > english_end_block, Error::::TooEarlyForCandleAuctionStart); @@ -382,17 +352,11 @@ impl Pallet { let candle_end_block = now + T::CandleAuctionDuration::get(); // * Update Storage * - project_info - .phase_transition_points - .candle_auction - .update(Some(candle_start_block), Some(candle_end_block)); + project_info.phase_transition_points.candle_auction.update(Some(candle_start_block), Some(candle_end_block)); project_info.project_status = ProjectStatus::AuctionRound(AuctionPhase::Candle); ProjectsDetails::::insert(project_id, project_info); // Schedule for automatic check by on_initialize. Success depending on enough funding reached - Self::add_to_update_store( - candle_end_block + 1u32.into(), - (&project_id, UpdateType::CommunityFundingStart), - ); + Self::add_to_update_store(candle_end_block + 1u32.into(), (&project_id, UpdateType::CommunityFundingStart)); // * Emit events * Self::deposit_event(Event::::CandleAuctionStarted { project_id, when: now }); @@ -426,22 +390,13 @@ impl Pallet { // * Get variables * let project_info = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectInfoNotFound)?; let now = >::block_number(); - let auction_candle_start_block = project_info - .phase_transition_points - .candle_auction - .start() - .ok_or(Error::::FieldIsNone)?; - let auction_candle_end_block = project_info - .phase_transition_points - .candle_auction - .end() - .ok_or(Error::::FieldIsNone)?; + let auction_candle_start_block = + project_info.phase_transition_points.candle_auction.start().ok_or(Error::::FieldIsNone)?; + let auction_candle_end_block = + project_info.phase_transition_points.candle_auction.end().ok_or(Error::::FieldIsNone)?; // * Validity checks * - ensure!( - now > auction_candle_end_block, - Error::::TooEarlyForCommunityRoundStart - ); + ensure!(now > auction_candle_end_block, Error::::TooEarlyForCommunityRoundStart); ensure!( project_info.project_status == ProjectStatus::AuctionRound(AuctionPhase::Candle), Error::::ProjectNotInCandleAuctionRound @@ -457,17 +412,11 @@ impl Pallet { // Get info again after updating it with new price. let mut project_info = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectInfoNotFound)?; project_info.phase_transition_points.random_candle_ending = Some(end_block); - project_info - .phase_transition_points - .community - .update(Some(community_start_block), Some(community_end_block)); + project_info.phase_transition_points.community.update(Some(community_start_block), Some(community_end_block)); project_info.project_status = ProjectStatus::CommunityRound; ProjectsDetails::::insert(project_id, project_info); // Schedule for automatic transition by `on_initialize` - Self::add_to_update_store( - community_end_block + 1u32.into(), - (&project_id, UpdateType::RemainderFundingStart), - ); + Self::add_to_update_store(community_end_block + 1u32.into(), (&project_id, UpdateType::RemainderFundingStart)); // * Emit events * Self::deposit_event(Event::::CommunityFundingStarted { project_id }); @@ -499,28 +448,19 @@ impl Pallet { // * Get variables * let mut project_info = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectInfoNotFound)?; let now = >::block_number(); - let community_end_block = project_info - .phase_transition_points - .community - .end() - .ok_or(Error::::FieldIsNone)?; + let community_end_block = + project_info.phase_transition_points.community.end().ok_or(Error::::FieldIsNone)?; // * Validity checks * ensure!(now > community_end_block, Error::::TooEarlyForRemainderRoundStart); - ensure!( - project_info.project_status == ProjectStatus::CommunityRound, - Error::::ProjectNotInCommunityRound - ); + ensure!(project_info.project_status == ProjectStatus::CommunityRound, Error::::ProjectNotInCommunityRound); // * Calculate new variables * let remainder_start_block = now + 1u32.into(); let remainder_end_block = now + T::RemainderFundingDuration::get(); // * Update Storage * - project_info - .phase_transition_points - .remainder - .update(Some(remainder_start_block), Some(remainder_end_block)); + project_info.phase_transition_points.remainder.update(Some(remainder_start_block), Some(remainder_end_block)); project_info.project_status = ProjectStatus::RemainderRound; ProjectsDetails::::insert(project_id, project_info); // Schedule for automatic transition by `on_initialize` @@ -625,10 +565,7 @@ impl Pallet { let mut project_info = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectInfoNotFound)?; // * Validity checks * - ensure!( - project_info.project_status == ProjectStatus::FundingEnded, - Error::::ProjectNotInFundingEndedRound - ); + ensure!(project_info.project_status == ProjectStatus::FundingEnded, Error::::ProjectNotInFundingEndedRound); // Update project Info project_info.project_status = ProjectStatus::ReadyToLaunch; @@ -653,22 +590,18 @@ impl Pallet { /// * [`ProjectsDetails`] - Check that the project is not frozen /// * [`ProjectsMetadata`] - Update the metadata hash pub fn do_edit_metadata( - issuer: T::AccountId, project_id: T::ProjectIdentifier, project_metadata_hash: T::Hash, + issuer: T::AccountId, + project_id: T::ProjectIdentifier, + project_metadata_hash: T::Hash, ) -> Result<(), DispatchError> { // * Get variables * let mut project = ProjectsMetadata::::get(project_id).ok_or(Error::::ProjectNotFound)?; let project_info = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectInfoNotFound)?; // * Validity checks * - ensure!( - ProjectsIssuers::::get(project_id) == Some(issuer), - Error::::NotAllowed - ); + ensure!(ProjectsIssuers::::get(project_id) == Some(issuer), Error::::NotAllowed); ensure!(!project_info.is_frozen, Error::::Frozen); - ensure!( - !Images::::contains_key(project_metadata_hash), - Error::::MetadataAlreadyExists - ); + ensure!(!Images::::contains_key(project_metadata_hash), Error::::MetadataAlreadyExists); // TODO: PLMC-133. Replace this when this PR is merged: https://github.com/KILTprotocol/kilt-node/pull/448 // ensure!( @@ -701,7 +634,9 @@ impl Pallet { /// * [`EvaluationBonds`] - Update the storage with the evaluators bond, by either increasing an existing /// one, or appending a new bond pub fn do_evaluation_bond( - evaluator: T::AccountId, project_id: T::ProjectIdentifier, amount: BalanceOf, + evaluator: T::AccountId, + project_id: T::ProjectIdentifier, + amount: BalanceOf, ) -> Result<(), DispatchError> { // * Get variables * let project_issuer = ProjectsIssuers::::get(project_id).ok_or(Error::::ProjectIssuerNotFound)?; @@ -714,10 +649,7 @@ impl Pallet { // Error::::NotAuthorized // ); ensure!(evaluator != project_issuer, Error::::ContributionToThemselves); - ensure!( - project_info.project_status == ProjectStatus::EvaluationRound, - Error::::EvaluationNotStarted - ); + ensure!(project_info.project_status == ProjectStatus::EvaluationRound, Error::::EvaluationNotStarted); // * Calculate new variables * @@ -730,7 +662,7 @@ impl Pallet { bond.amount += amount; T::NativeCurrency::reserve_named(&BondType::Evaluation, &evaluator, amount) .map_err(|_| Error::::InsufficientBalance)?; - } + }, None => { // If the user has not bonded yet, create a new bond *maybe_bond = Some(EvaluationBond { @@ -743,22 +675,14 @@ impl Pallet { // Reserve the required PLMC T::NativeCurrency::reserve_named(&BondType::Evaluation, &evaluator, amount) .map_err(|_| Error::::InsufficientBalance)?; - } + }, } - Self::deposit_event(Event::::FundsBonded { - project_id, - amount, - bonder: evaluator.clone(), - }); + Self::deposit_event(Event::::FundsBonded { project_id, amount, bonder: evaluator.clone() }); Result::<(), Error>::Ok(()) })?; // * Emit events * - Self::deposit_event(Event::::FundsBonded { - project_id, - amount, - bonder: evaluator, - }); + Self::deposit_event(Event::::FundsBonded { project_id, amount, bonder: evaluator }); Ok(()) } @@ -772,16 +696,14 @@ impl Pallet { /// * [`ProjectsDetails`] - Check that the project is in the evaluation failed stage /// * [`EvaluationBonds`] - Remove the bond from storage pub fn do_failed_evaluation_unbond_for( - bond: EvaluationBond, releaser: T::AccountId, + bond: EvaluationBond, + releaser: T::AccountId, ) -> Result<(), DispatchError> { // * Get variables * let project_info = ProjectsDetails::::get(bond.project).ok_or(Error::::ProjectInfoNotFound)?; // * Validity checks * - ensure!( - project_info.project_status == ProjectStatus::EvaluationFailed, - Error::::EvaluationNotFailed - ); + ensure!(project_info.project_status == ProjectStatus::EvaluationFailed, Error::::EvaluationNotFailed); // * Calculate new variables * @@ -815,7 +737,10 @@ impl Pallet { /// * [`BiddingBonds`] - Update the storage with the bidder's PLMC bond for that bid /// * [`AuctionsInfo`] - Check previous bids by that user, and update the storage with the new bid pub fn do_bid( - bidder: T::AccountId, project_id: T::ProjectIdentifier, amount: BalanceOf, price: BalanceOf, + bidder: T::AccountId, + project_id: T::ProjectIdentifier, + amount: BalanceOf, + price: BalanceOf, multiplier: Option>, ) -> Result<(), DispatchError> { // * Get variables * @@ -829,10 +754,7 @@ impl Pallet { // * Validity checks * ensure!(bidder != project_issuer, Error::::ContributionToThemselves); - ensure!( - matches!(project_info.project_status, ProjectStatus::AuctionRound(_)), - Error::::AuctionNotStarted - ); + ensure!(matches!(project_info.project_status, ProjectStatus::AuctionRound(_)), Error::::AuctionNotStarted); ensure!(price >= project.minimum_price, Error::::BidTooLow); if let Some(minimum_ticket_size) = project.ticket_size.minimum { // Make sure the bid amount is greater than the minimum specified by the issuer @@ -886,18 +808,12 @@ impl Pallet { // Alternative TODO: PLMC-159. The user should have the specified currency (e.g: USDC) already on Polimec user_bids.sort_by_key(|bid| Reverse(bid.price)); AuctionsInfo::::set(project_id, bidder, Some(user_bids)); - Self::deposit_event(Event::::Bid { - project_id, - amount, - price, - multiplier, - }); - } + Self::deposit_event(Event::::Bid { project_id, amount, price, multiplier }); + }, Err(_) => { // Since the bids are sorted by price, and in this branch the Vec is full, the last element is the lowest bid - let lowest_bid_index: usize = (T::MaximumBidsPerUser::get() - 1) - .try_into() - .map_err(|_| Error::::BadMath)?; + let lowest_bid_index: usize = + (T::MaximumBidsPerUser::get() - 1).try_into().map_err(|_| Error::::BadMath)?; let lowest_bid = user_bids.swap_remove(lowest_bid_index); ensure!(bid > lowest_bid, Error::::BidTooLow); // Unreserve the lowest bid first @@ -905,19 +821,12 @@ impl Pallet { // Reserve the new bid T::FundingCurrency::reserve(&bidder, bid.ticket_size)?; // Add the new bid to the AuctionsInfo, this should never fail since we just removed an element - user_bids - .try_push(bid) - .expect("We removed an element, so there is always space"); + user_bids.try_push(bid).expect("We removed an element, so there is always space"); user_bids.sort_by_key(|bid| Reverse(bid.price)); AuctionsInfo::::set(project_id, bidder, Some(user_bids)); // TODO: PLMC-159. Send an XCM message to Statemine to transfer amount * multiplier USDT to the PalletId Account - Self::deposit_event(Event::::Bid { - project_id, - amount, - price, - multiplier, - }); - } + Self::deposit_event(Event::::Bid { project_id, amount, price, multiplier }); + }, }; NextBidId::::set(bid_id.saturating_add(One::one())); @@ -940,7 +849,9 @@ impl Pallet { /// * [`Contributions`] - Update storage with the new contribution /// * [`T::NativeCurrency`] - Update the balance of the contributor and the project pot pub fn do_contribute( - contributor: T::AccountId, project_id: T::ProjectIdentifier, token_amount: BalanceOf, + contributor: T::AccountId, + project_id: T::ProjectIdentifier, + token_amount: BalanceOf, multiplier: Option>, ) -> Result<(), DispatchError> { // * Get variables * @@ -949,17 +860,15 @@ impl Pallet { let project = ProjectsMetadata::::get(project_id).ok_or(Error::::ProjectNotFound)?; // Default should normally be multiplier of 1 let multiplier = multiplier.unwrap_or_default(); - let weighted_average_price = project_info - .weighted_average_price - .ok_or(Error::::AuctionNotStarted)?; + let weighted_average_price = project_info.weighted_average_price.ok_or(Error::::AuctionNotStarted)?; let decimals = project.token_information.decimals; let fund_account = Self::fund_account_id(project_id); // * Validity checks * ensure!(contributor != project_issuer, Error::::ContributionToThemselves); ensure!( - project_info.project_status == ProjectStatus::CommunityRound - || project_info.project_status == ProjectStatus::RemainderRound, + project_info.project_status == ProjectStatus::CommunityRound || + project_info.project_status == ProjectStatus::RemainderRound, Error::::AuctionNotStarted ); @@ -988,11 +897,8 @@ impl Pallet { decimals, ) .map_err(|_| Error::::BadMath)?; - let contribution = ContributionInfo { - contribution_amount: ticket_size, - plmc_vesting: plmc_vesting.clone(), - ct_vesting, - }; + let contribution = + ContributionInfo { contribution_amount: ticket_size, plmc_vesting: plmc_vesting.clone(), ct_vesting }; // Calculate how much plmc is required to be bonded for this contribution, // based on existing unused PLMC bonds for the project @@ -1006,9 +912,7 @@ impl Pallet { } required_plmc_bond.saturating_sub(bonded_plmc); - let remaining_cts_after_purchase = project_info - .remaining_contribution_tokens - .saturating_sub(buyable_tokens); + let remaining_cts_after_purchase = project_info.remaining_contribution_tokens.saturating_sub(buyable_tokens); let now = >::block_number(); // * Update storage * @@ -1022,12 +926,11 @@ impl Pallet { // Alternative TODO: PLMC-159. The user should have the specified currency (e.g: USDC) already on Polimec user_contributions.sort_by_key(|contribution| Reverse(contribution.plmc_vesting.amount)); Contributions::::set(project_id, contributor.clone(), Some(user_contributions)); - } + }, Err(_) => { // The contributions are sorted by highest PLMC bond. If the contribution vector for the user is full, we drop the lowest/last item - let lowest_contribution_index: usize = (T::MaxContributionsPerUser::get() - 1) - .try_into() - .map_err(|_| Error::::BadMath)?; + let lowest_contribution_index: usize = + (T::MaxContributionsPerUser::get() - 1).try_into().map_err(|_| Error::::BadMath)?; let lowest_contribution = user_contributions.swap_remove(lowest_contribution_index); ensure!( contribution.plmc_vesting.amount > lowest_contribution.plmc_vesting.amount, @@ -1062,7 +965,7 @@ impl Pallet { user_contributions.sort_by_key(|contribution| Reverse(contribution.plmc_vesting.amount)); Contributions::::set(project_id, contributor.clone(), Some(user_contributions)); // TODO: PLMC-159. Send an XCM message to Statemine to transfer amount * multiplier USDT to the PalletId Account - } + }, }; // Transfer funds from contributor to fund account @@ -1087,12 +990,7 @@ impl Pallet { } // * Emit events * - Self::deposit_event(Event::::Contribution { - project_id, - contributor, - amount: token_amount, - multiplier, - }); + Self::deposit_event(Event::::Contribution { project_id, contributor, amount: token_amount, multiplier }); Ok(()) } @@ -1107,7 +1005,9 @@ impl Pallet { /// * [`BiddingBonds`] - Update the bid with the new vesting period struct, reflecting this withdrawal /// * [`T::NativeCurrency`] - Unreserve the unbonded amount pub fn do_vested_plmc_bid_unbond_for( - releaser: T::AccountId, project_id: T::ProjectIdentifier, bidder: T::AccountId, + releaser: T::AccountId, + project_id: T::ProjectIdentifier, + bidder: T::AccountId, ) -> Result<(), DispatchError> { // * Get variables * let bids = AuctionsInfo::::get(project_id, &bidder).ok_or(Error::::BidNotFound)?; @@ -1120,7 +1020,7 @@ impl Pallet { // * Validity checks * // check that it is not too early to withdraw the next amount if plmc_vesting.next_withdrawal > now { - continue; + continue } // * Calculate variables * @@ -1129,7 +1029,7 @@ impl Pallet { while let Ok(amount) = plmc_vesting.calculate_next_withdrawal() { unbond_amount = unbond_amount.saturating_add(amount); if plmc_vesting.next_withdrawal > now { - break; + break } } bid.plmc_vesting_period = plmc_vesting; @@ -1175,7 +1075,9 @@ impl Pallet { /// * `AuctionsInfo` - Check if its time to mint some tokens based on the bid vesting period, and update the bid after minting. /// * `T::ContributionTokenCurrency` - Mint the tokens to the bidder pub fn do_vested_contribution_token_bid_mint_for( - releaser: T::AccountId, project_id: T::ProjectIdentifier, bidder: T::AccountId, + releaser: T::AccountId, + project_id: T::ProjectIdentifier, + bidder: T::AccountId, ) -> Result<(), DispatchError> { // * Get variables * let bids = AuctionsInfo::::get(project_id, &bidder).ok_or(Error::::BidNotFound)?; @@ -1188,7 +1090,7 @@ impl Pallet { // * Validity checks * // check that it is not too early to withdraw the next amount if ct_vesting.next_withdrawal > now { - continue; + continue } // * Calculate variables * @@ -1196,7 +1098,7 @@ impl Pallet { while let Ok(amount) = ct_vesting.calculate_next_withdrawal() { mint_amount = mint_amount.saturating_add(amount); if ct_vesting.next_withdrawal > now { - break; + break } } bid.ct_vesting_period = ct_vesting; @@ -1233,7 +1135,9 @@ impl Pallet { /// * [`BiddingBonds`] - Update the bid with the new vesting period struct, reflecting this withdrawal /// * [`T::NativeCurrency`] - Unreserve the unbonded amount pub fn do_vested_plmc_purchase_unbond_for( - releaser: T::AccountId, project_id: T::ProjectIdentifier, claimer: T::AccountId, + releaser: T::AccountId, + project_id: T::ProjectIdentifier, + claimer: T::AccountId, ) -> Result<(), DispatchError> { // * Get variables * let project_info = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectNotFound)?; @@ -1247,10 +1151,7 @@ impl Pallet { // T::HandleMembers::is_in(&MemberRole::Issuer, &issuer), // Error::::NotAuthorized // ); - ensure!( - project_info.project_status == ProjectStatus::FundingEnded, - Error::::CannotClaimYet - ); + ensure!(project_info.project_status == ProjectStatus::FundingEnded, Error::::CannotClaimYet); // TODO: PLMC-160. Check the flow of the final_price if the final price discovery during the Auction Round fails for mut contribution in contributions { @@ -1260,7 +1161,7 @@ impl Pallet { // * Validity checks * // check that it is not too early to withdraw the next amount if plmc_vesting.next_withdrawal > now { - continue; + continue } // * Calculate variables * @@ -1268,7 +1169,7 @@ impl Pallet { while let Ok(amount) = plmc_vesting.calculate_next_withdrawal() { unbond_amount = unbond_amount.saturating_add(amount); if plmc_vesting.next_withdrawal > now { - break; + break } } contribution.plmc_vesting = plmc_vesting; @@ -1293,9 +1194,7 @@ impl Pallet { // Obviously also the participants of the Auction Round should be able to claim their tokens // In theory this should never fail, since we insert the same number of contributions as before let updated_contributions: BoundedVec, T::MaxContributionsPerUser> = - updated_contributions - .try_into() - .map_err(|_| Error::::TooManyContributions)?; + updated_contributions.try_into().map_err(|_| Error::::TooManyContributions)?; Contributions::::insert(project_id, &claimer, updated_contributions); Ok(()) @@ -1312,7 +1211,9 @@ impl Pallet { /// * [`Contributions`] - Check if its time to mint some tokens based on the contributions vesting periods, and update the contribution after minting. /// * [`T::ContributionTokenCurrency`] - Mint the tokens to the claimer pub fn do_vested_contribution_token_purchase_mint_for( - releaser: T::AccountId, project_id: T::ProjectIdentifier, claimer: T::AccountId, + releaser: T::AccountId, + project_id: T::ProjectIdentifier, + claimer: T::AccountId, ) -> Result<(), DispatchError> { // * Get variables * let project_info = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectNotFound)?; @@ -1326,10 +1227,7 @@ impl Pallet { // T::HandleMembers::is_in(&MemberRole::Issuer, &issuer), // Error::::NotAuthorized // ); - ensure!( - project_info.project_status == ProjectStatus::FundingEnded, - Error::::CannotClaimYet - ); + ensure!(project_info.project_status == ProjectStatus::FundingEnded, Error::::CannotClaimYet); // TODO: PLMC-160. Check the flow of the final_price if the final price discovery during the Auction Round fails for mut contribution in contributions { @@ -1339,7 +1237,7 @@ impl Pallet { // * Validity checks * // check that it is not too early to withdraw the next amount if ct_vesting.next_withdrawal > now { - continue; + continue } // * Calculate variables * @@ -1347,7 +1245,7 @@ impl Pallet { while let Ok(amount) = ct_vesting.calculate_next_withdrawal() { mint_amount = mint_amount.saturating_add(amount); if ct_vesting.next_withdrawal > now { - break; + break } } contribution.ct_vesting = ct_vesting; @@ -1372,9 +1270,7 @@ impl Pallet { // Obviously also the participants of the Auction Round should be able to claim their tokens // In theory this should never fail, since we insert the same number of contributions as before let updated_contributions: BoundedVec, T::MaxContributionsPerUser> = - updated_contributions - .try_into() - .map_err(|_| Error::::TooManyContributions)?; + updated_contributions.try_into().map_err(|_| Error::::TooManyContributions)?; Contributions::::insert(project_id, &claimer, updated_contributions); Ok(()) @@ -1393,12 +1289,12 @@ impl Pallet { } pub fn bond_bidding( - caller: T::AccountId, project_id: T::ProjectIdentifier, amount: BalanceOf, + caller: T::AccountId, + project_id: T::ProjectIdentifier, + amount: BalanceOf, ) -> Result<(), DispatchError> { let now = >::block_number(); - let project_info = ProjectsDetails::::get(project_id) - .ok_or(Error::::ProjectInfoNotFound) - .unwrap(); + let project_info = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectInfoNotFound).unwrap(); if let Some(bidding_end_block) = project_info.phase_transition_points.candle_auction.end() { ensure!(now < bidding_end_block, Error::::TooLateForBidBonding); @@ -1411,7 +1307,7 @@ impl Pallet { bond.amount += amount; T::NativeCurrency::reserve_named(&BondType::Bidding, &caller, amount) .map_err(|_| Error::::InsufficientBalance)?; - } + }, None => { // If the user has not bonded yet, create a new bond *maybe_bond = Some(BiddingBond { @@ -1424,13 +1320,9 @@ impl Pallet { // Reserve the required PLMC T::NativeCurrency::reserve_named(&BondType::Bidding, &caller, amount) .map_err(|_| Error::::InsufficientBalance)?; - } + }, } - Self::deposit_event(Event::::FundsBonded { - project_id, - amount, - bonder: caller.clone(), - }); + Self::deposit_event(Event::::FundsBonded { project_id, amount, bonder: caller.clone() }); Result::<(), Error>::Ok(()) })?; @@ -1438,12 +1330,12 @@ impl Pallet { } pub fn bond_contributing( - caller: T::AccountId, project_id: T::ProjectIdentifier, amount: BalanceOf, + caller: T::AccountId, + project_id: T::ProjectIdentifier, + amount: BalanceOf, ) -> Result<(), DispatchError> { let now = >::block_number(); - let project_info = ProjectsDetails::::get(project_id) - .ok_or(Error::::ProjectInfoNotFound) - .unwrap(); + let project_info = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectInfoNotFound).unwrap(); if let Some(remainder_end_block) = project_info.phase_transition_points.remainder.end() { ensure!(now < remainder_end_block, Error::::TooLateForContributingBonding); @@ -1456,25 +1348,17 @@ impl Pallet { bond.amount += amount; T::NativeCurrency::reserve_named(&BondType::Contributing, &caller, amount) .map_err(|_| Error::::InsufficientBalance)?; - } + }, None => { // If the user has not bonded yet, create a new bond - *maybe_bond = Some(ContributingBond { - project: project_id, - account: caller.clone(), - amount, - }); + *maybe_bond = Some(ContributingBond { project: project_id, account: caller.clone(), amount }); // Reserve the required PLMC T::NativeCurrency::reserve_named(&BondType::Contributing, &caller, amount) .map_err(|_| Error::::InsufficientBalance)?; - } + }, } - Self::deposit_event(Event::::FundsBonded { - project_id, - amount, - bonder: caller.clone(), - }); + Self::deposit_event(Event::::FundsBonded { project_id, amount, bonder: caller.clone() }); Result::<(), Error>::Ok(()) })?; @@ -1510,15 +1394,12 @@ impl Pallet { /// Based on the amount of tokens and price to buy, a desired multiplier, and the type of investor the caller is, /// calculate the amount and vesting periods of bonded PLMC and reward CT tokens. pub fn calculate_vesting_periods( - _caller: T::AccountId, multiplier: MultiplierOf, token_amount: BalanceOf, token_price: BalanceOf, + _caller: T::AccountId, + multiplier: MultiplierOf, + token_amount: BalanceOf, + token_price: BalanceOf, decimals: u8, - ) -> Result< - ( - Vesting>, - Vesting>, - ), - (), - > { + ) -> Result<(Vesting>, Vesting>), ()> { let plmc_start: T::BlockNumber = 0u32.into(); let ct_start: T::BlockNumber = (T::MaxProjectsToUpdatePerBlock::get() * 7).into(); // TODO: Calculate real vesting periods based on multiplier and caller type @@ -1546,7 +1427,9 @@ impl Pallet { /// Calculates the price of contribution tokens for the Community and Remainder Rounds pub fn calculate_weighted_average_price( - project_id: T::ProjectIdentifier, end_block: T::BlockNumber, total_allocation_size: BalanceOf, + project_id: T::ProjectIdentifier, + end_block: T::BlockNumber, + total_allocation_size: BalanceOf, ) -> Result<(), DispatchError> { // Get all the bids that were made before the end of the candle let mut bids = AuctionsInfo::::iter_values().flatten().collect::>(); @@ -1564,7 +1447,7 @@ impl Pallet { if bid.when > end_block { bid.status = BidStatus::Rejected(RejectionReason::AfterCandleEnd); // TODO: PLMC-147. Unlock funds. We can do this inside the "on_idle" hook, and change the `status` of the `Bid` to "Unreserved" - return bid; + return bid } let buyable_amount = total_allocation_size.saturating_sub(bid_amount_sum); if buyable_amount == 0_u32.into() { @@ -1586,20 +1469,13 @@ impl Pallet { // Update the bid in the storage for bid in bids.iter() { - AuctionsInfo::::mutate( - project_id, - bid.bidder.clone(), - |maybe_bids| -> Result<(), DispatchError> { - let mut bids = maybe_bids.clone().ok_or(Error::::ImpossibleState)?; - let bid_index = bids - .iter() - .position(|b| b.bid_id == bid.bid_id) - .ok_or(Error::::ImpossibleState)?; - bids[bid_index] = bid.clone(); - *maybe_bids = Some(bids); - Ok(()) - }, - )?; + AuctionsInfo::::mutate(project_id, bid.bidder.clone(), |maybe_bids| -> Result<(), DispatchError> { + let mut bids = maybe_bids.clone().ok_or(Error::::ImpossibleState)?; + let bid_index = bids.iter().position(|b| b.bid_id == bid.bid_id).ok_or(Error::::ImpossibleState)?; + bids[bid_index] = bid.clone(); + *maybe_bids = Some(bids); + Ok(()) + })?; } // Calculate the weighted price of the token for the next funding rounds, using winning bids. @@ -1624,12 +1500,9 @@ impl Pallet { // TODO: PLMC-150. collecting due to previous mut borrow, find a way to not collect and borrow bid on filter_map .into_iter() .filter_map(|bid| match bid.status { - BidStatus::Accepted => { - Some(Perbill::from_rational(bid.amount * bid.price, bid_value_sum) * bid.price) - }, - BidStatus::PartiallyAccepted(amount, _) => { - Some(Perbill::from_rational(amount * bid.price, bid_value_sum) * bid.price) - }, + BidStatus::Accepted => Some(Perbill::from_rational(bid.amount * bid.price, bid_value_sum) * bid.price), + BidStatus::PartiallyAccepted(amount, _) => + Some(Perbill::from_rational(amount * bid.price, bid_value_sum) * bid.price), _ => None, }) .reduce(|a, b| a.saturating_add(b)) @@ -1650,7 +1523,8 @@ impl Pallet { } pub fn select_random_block( - candle_starting_block: T::BlockNumber, candle_ending_block: T::BlockNumber, + candle_starting_block: T::BlockNumber, + candle_ending_block: T::BlockNumber, ) -> T::BlockNumber { let nonce = Self::get_and_increment_nonce(); let (random_value, _known_since) = T::Randomness::random(&nonce); @@ -1671,7 +1545,8 @@ impl Pallet { // This function is kept separate from the `do_claim_contribution_tokens` for easier testing the logic #[inline(always)] pub fn calculate_claimable_tokens( - contribution_amount: BalanceOf, weighted_average_price: BalanceOf, + contribution_amount: BalanceOf, + weighted_average_price: BalanceOf, ) -> FixedU128 { FixedU128::saturating_from_rational(contribution_amount, weighted_average_price) } diff --git a/pallets/funding/src/lib.rs b/pallets/funding/src/lib.rs index 5e78af3bb..3f5d77c30 100644 --- a/pallets/funding/src/lib.rs +++ b/pallets/funding/src/lib.rs @@ -197,15 +197,12 @@ pub mod tests; mod benchmarking; pub mod traits; -#[allow(unused_imports)] -use polimec_traits::{MemberRole, PolimecMembers}; - pub use crate::weights::WeightInfo; use frame_support::{ pallet_prelude::ValueQuery, traits::{ tokens::{ - fungibles::{metadata::Mutate as MetadataMutate, Create, InspectMetadata, Mutate}, + fungibles::{metadata::Mutate as MetadataMutate, Create, Mutate}, Balance, }, Currency as CurrencyT, Get, NamedReservableCurrency, Randomness, ReservableCurrency, @@ -298,8 +295,7 @@ pub mod pallet { /// The currency used for minting contribution tokens as fungible assets (i.e pallet-assets) type ContributionTokenCurrency: Create> + Mutate - + MetadataMutate - + InspectMetadata; + + MetadataMutate; /// Unique identifier for any bid in the system. type BidId: Parameter + Copy + Saturating + One + Default; @@ -307,9 +303,6 @@ pub mod pallet { /// Something that provides randomness in the runtime. type Randomness: Randomness; - /// Something that provides the members of Polimec - type HandleMembers: PolimecMembers; - /// The maximum length of data stored on-chain. #[pallet::constant] type StringLimit: Get; @@ -500,23 +493,13 @@ pub mod pallet { end_block: T::BlockNumber, }, /// The auction round of a project started. - EnglishAuctionStarted { - project_id: T::ProjectIdentifier, - when: T::BlockNumber, - }, + EnglishAuctionStarted { project_id: T::ProjectIdentifier, when: T::BlockNumber }, /// The candle auction part of the auction started for a project - CandleAuctionStarted { - project_id: T::ProjectIdentifier, - when: T::BlockNumber, - }, + CandleAuctionStarted { project_id: T::ProjectIdentifier, when: T::BlockNumber }, /// The auction round of a project ended. AuctionEnded { project_id: T::ProjectIdentifier }, /// A `bonder` bonded an `amount` of PLMC for `project_id`. - FundsBonded { - project_id: T::ProjectIdentifier, - amount: BalanceOf, - bonder: T::AccountId, - }, + FundsBonded { project_id: T::ProjectIdentifier, amount: BalanceOf, bonder: T::AccountId }, /// Someone paid for the release of a user's PLMC bond for a project. BondReleased { project_id: T::ProjectIdentifier, @@ -525,12 +508,7 @@ pub mod pallet { releaser: T::AccountId, }, /// A bid was made for a project - Bid { - project_id: T::ProjectIdentifier, - amount: BalanceOf, - price: BalanceOf, - multiplier: MultiplierOf, - }, + Bid { project_id: T::ProjectIdentifier, amount: BalanceOf, price: BalanceOf, multiplier: MultiplierOf }, /// A contribution was made for a project. i.e token purchase Contribution { project_id: T::ProjectIdentifier, @@ -545,10 +523,7 @@ pub mod pallet { /// A project has now finished funding FundingEnded { project_id: T::ProjectIdentifier }, /// Something was not properly initialized. Most likely due to dev error manually calling do_* functions or updating storage - TransitionError { - project_id: T::ProjectIdentifier, - error: DispatchError, - }, + TransitionError { project_id: T::ProjectIdentifier, error: DispatchError }, /// Something terribly wrong happened where the bond could not be unbonded. Most likely a programming error FailedEvaluationUnbondFailed { error: DispatchError }, /// Contribution tokens were minted to a user @@ -681,7 +656,9 @@ pub mod pallet { /// Change the metadata hash of a project #[pallet::weight(T::WeightInfo::edit_metadata())] pub fn edit_metadata( - origin: OriginFor, project_id: T::ProjectIdParameter, project_metadata_hash: T::Hash, + origin: OriginFor, + project_id: T::ProjectIdParameter, + project_metadata_hash: T::Hash, ) -> DispatchResult { let issuer = ensure_signed(origin)?; let project_id = project_id.into(); @@ -701,10 +678,7 @@ pub mod pallet { // Error::::NotAuthorized // ); - ensure!( - ProjectsIssuers::::get(project_id) == Some(issuer), - Error::::NotAllowed - ); + ensure!(ProjectsIssuers::::get(project_id) == Some(issuer), Error::::NotAllowed); Self::do_evaluation_start(project_id) } @@ -723,10 +697,7 @@ pub mod pallet { // Error::::NotAuthorized // ); - ensure!( - ProjectsIssuers::::get(project_id) == Some(issuer), - Error::::NotAllowed - ); + ensure!(ProjectsIssuers::::get(project_id) == Some(issuer), Error::::NotAllowed); Self::do_english_auction(project_id) } @@ -734,7 +705,9 @@ pub mod pallet { /// Bond PLMC for a project in the evaluation stage #[pallet::weight(T::WeightInfo::bond())] pub fn bond_evaluation( - origin: OriginFor, project_id: T::ProjectIdParameter, #[pallet::compact] amount: BalanceOf, + origin: OriginFor, + project_id: T::ProjectIdParameter, + #[pallet::compact] amount: BalanceOf, ) -> DispatchResult { let from = ensure_signed(origin)?; let project_id = project_id.into(); @@ -744,7 +717,9 @@ pub mod pallet { /// Release the bonded PLMC for an evaluator if the project assigned to it is in the EvaluationFailed phase #[pallet::weight(T::WeightInfo::failed_evaluation_unbond_for())] pub fn failed_evaluation_unbond_for( - origin: OriginFor, project_id: T::ProjectIdParameter, bonder: T::AccountId, + origin: OriginFor, + project_id: T::ProjectIdParameter, + bonder: T::AccountId, ) -> DispatchResult { let releaser = ensure_signed(origin)?; let bond = EvaluationBonds::::get(project_id.into(), bonder).ok_or(Error::::BondNotFound)?; @@ -776,7 +751,9 @@ pub mod pallet { /// Buy tokens in the Community or Remainder round at the price set in the Auction Round #[pallet::weight(T::WeightInfo::contribute())] pub fn contribute( - origin: OriginFor, project_id: T::ProjectIdParameter, #[pallet::compact] amount: BalanceOf, + origin: OriginFor, + project_id: T::ProjectIdParameter, + #[pallet::compact] amount: BalanceOf, multiplier: Option>, ) -> DispatchResult { let contributor = ensure_signed(origin)?; @@ -787,7 +764,9 @@ pub mod pallet { /// Unbond some plmc from a contribution, after a step in the vesting period has passed. pub fn vested_plmc_bid_unbond_for( - origin: OriginFor, project_id: T::ProjectIdParameter, bidder: T::AccountId, + origin: OriginFor, + project_id: T::ProjectIdParameter, + bidder: T::AccountId, ) -> DispatchResult { // TODO: PLMC-157. Manage the fact that the CTs may not be claimed by those entitled let claimer = ensure_signed(origin)?; @@ -799,7 +778,9 @@ pub mod pallet { // TODO: PLMC-157. Manage the fact that the CTs may not be claimed by those entitled /// Mint contribution tokens after a step in the vesting period for a successful bid. pub fn vested_contribution_token_bid_mint_for( - origin: OriginFor, project_id: T::ProjectIdParameter, bidder: T::AccountId, + origin: OriginFor, + project_id: T::ProjectIdParameter, + bidder: T::AccountId, ) -> DispatchResult { let claimer = ensure_signed(origin)?; let project_id = project_id.into(); @@ -810,7 +791,9 @@ pub mod pallet { // TODO: PLMC-157. Manage the fact that the CTs may not be claimed by those entitled /// Unbond some plmc from a contribution, after a step in the vesting period has passed. pub fn vested_plmc_purchase_unbond_for( - origin: OriginFor, project_id: T::ProjectIdParameter, purchaser: T::AccountId, + origin: OriginFor, + project_id: T::ProjectIdParameter, + purchaser: T::AccountId, ) -> DispatchResult { let claimer = ensure_signed(origin)?; let project_id = project_id.into(); @@ -821,7 +804,9 @@ pub mod pallet { // TODO: PLMC-157. Manage the fact that the CTs may not be claimed by those entitled /// Mint contribution tokens after a step in the vesting period for a contribution. pub fn vested_contribution_token_purchase_mint_for( - origin: OriginFor, project_id: T::ProjectIdParameter, purchaser: T::AccountId, + origin: OriginFor, + project_id: T::ProjectIdParameter, + purchaser: T::AccountId, ) -> DispatchResult { let claimer = ensure_signed(origin)?; let project_id = project_id.into(); @@ -839,33 +824,33 @@ pub mod pallet { // EvaluationRound -> AuctionInitializePeriod | EvaluationFailed UpdateType::EvaluationEnd => { unwrap_result_or_skip!(Self::do_evaluation_end(project_id), project_id); - } + }, // AuctionInitializePeriod -> AuctionRound(AuctionPhase::English) // Only if it wasn't first handled by user extrinsic UpdateType::EnglishAuctionStart => { unwrap_result_or_skip!(Self::do_english_auction(project_id), project_id); - } + }, // AuctionRound(AuctionPhase::English) -> AuctionRound(AuctionPhase::Candle) UpdateType::CandleAuctionStart => { unwrap_result_or_skip!(Self::do_candle_auction(project_id), project_id); - } + }, // AuctionRound(AuctionPhase::Candle) -> CommunityRound UpdateType::CommunityFundingStart => { unwrap_result_or_skip!(Self::do_community_funding(project_id), project_id); - } + }, // CommunityRound -> RemainderRound UpdateType::RemainderFundingStart => { unwrap_result_or_skip!(Self::do_remainder_funding(project_id), project_id) - } + }, // CommunityRound || RemainderRound -> FundingEnded UpdateType::FundingEnd => { unwrap_result_or_skip!(Self::do_end_funding(project_id), project_id) - } + }, } } // TODO: PLMC-127. Set a proper weight @@ -890,9 +875,7 @@ pub mod pallet { // Get a flat list of bonds .flat_map(|project_id| { // get all the bonds for projects with a failed evaluation phase - EvaluationBonds::::iter_prefix(project_id) - .map(|(_bonder, bond)| bond) - .collect::>() + EvaluationBonds::::iter_prefix(project_id).map(|(_bonder, bond)| bond).collect::>() }) // Retrieve as many as possible for the given weight .take_while(|_| { @@ -932,18 +915,13 @@ pub mod pallet { fn create_project_id_parameter(id: u32) -> T::ProjectIdParameter { id.into() } + fn create_dummy_project(metadata_hash: T::Hash) -> ProjectMetadataOf { let project: ProjectMetadataOf = ProjectMetadata { total_allocation_size: 1_000_000u64.into(), minimum_price: 1__0_000_000_000_u64.into(), - ticket_size: TicketSize { - minimum: Some(1u8.into()), - maximum: None, - }, - participants_size: ParticipantsSize { - minimum: Some(2), - maximum: None, - }, + ticket_size: TicketSize { minimum: Some(1u8.into()), maximum: None }, + participants_size: ParticipantsSize { minimum: Some(2), maximum: None }, offchain_information_hash: Some(metadata_hash), ..Default::default() }; @@ -965,8 +943,8 @@ pub mod local_macros { project_id: $project_id, error: Error::::FieldIsNone.into(), }); - continue; - } + continue + }, } }; } @@ -978,12 +956,9 @@ pub mod local_macros { match $option { Ok(val) => val, Err(err) => { - Self::deposit_event(Event::::TransitionError { - project_id: $project_id, - error: err, - }); - continue; - } + Self::deposit_event(Event::::TransitionError { project_id: $project_id, error: err }); + continue + }, } }; } diff --git a/pallets/funding/src/mock.rs b/pallets/funding/src/mock.rs index ebf310623..9814c651e 100644 --- a/pallets/funding/src/mock.rs +++ b/pallets/funding/src/mock.rs @@ -55,7 +55,6 @@ frame_support::construct_runtime!( Assets: pallet_assets, Balances: pallet_balances, FundingModule: pallet_funding, - Credentials: pallet_credentials, } ); @@ -64,30 +63,30 @@ parameter_types! { } impl system::Config for TestRuntime { + type AccountData = pallet_balances::AccountData; + type AccountId = AccountId; type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); + type BlockHashCount = BlockHashCount; type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Index = u64; type BlockNumber = BlockNumber; + type BlockWeights = (); + type DbWeight = (); type Hash = H256; type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; type Header = Header; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); + type Index = u64; + type Lookup = IdentityLookup; + type MaxConsumers = frame_support::traits::ConstU32<16>; type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = ConstU16<42>; + type OnNewAccount = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type PalletInfo = PalletInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type SS58Prefix = ConstU16<42>; + type SystemWeightInfo = (); + type Version = (); } parameter_types! { @@ -95,51 +94,44 @@ parameter_types! { } impl pallet_balances::Config for TestRuntime { + type AccountStore = System; + type Balance = Balance; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type FreezeIdentifier = (); + type HoldIdentifier = BondType; + type MaxFreezes = (); + type MaxHolds = ConstU32<1024>; type MaxLocks = frame_support::traits::ConstU32<1024>; type MaxReserves = frame_support::traits::ConstU32<1024>; type ReserveIdentifier = BondType; - type Balance = Balance; type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; type WeightInfo = (); } impl pallet_insecure_randomness_collective_flip::Config for TestRuntime {} -impl pallet_credentials::Config for TestRuntime { - type RuntimeEvent = RuntimeEvent; - type AddOrigin = EnsureSigned; - type RemoveOrigin = EnsureSigned; - type SwapOrigin = EnsureSigned; - type ResetOrigin = EnsureSigned; - type PrimeOrigin = EnsureSigned; - type MembershipInitialized = (); - type MembershipChanged = (); -} - impl pallet_assets::Config for TestRuntime { - type RuntimeEvent = RuntimeEvent; - type Balance = Balance; + type ApprovalDeposit = ConstU128<1>; + type AssetAccountDeposit = ConstU128<10>; + type AssetDeposit = ConstU128<1>; type AssetId = Identifier; + type AssetIdParameter = Identifier; + type Balance = Balance; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); + type CallbackHandle = (); + type CreateOrigin = AsEnsureOriginWithArg>; type Currency = Balances; + type Extra = (); type ForceOrigin = frame_system::EnsureRoot; - type AssetDeposit = ConstU128<1>; - type AssetAccountDeposit = ConstU128<10>; + type Freezer = (); type MetadataDepositBase = ConstU128<1>; type MetadataDepositPerByte = ConstU128<1>; - type ApprovalDeposit = ConstU128<1>; + type RemoveItemsLimit = frame_support::traits::ConstU32<1000>; + type RuntimeEvent = RuntimeEvent; type StringLimit = ConstU32<50>; - type Freezer = (); type WeightInfo = (); - type Extra = (); - type AssetIdParameter = Identifier; - type CreateOrigin = AsEnsureOriginWithArg>; - type CallbackHandle = (); - type RemoveItemsLimit = frame_support::traits::ConstU32<1000>; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); } pub const HOURS: BlockNumber = 300u64; @@ -156,55 +148,43 @@ parameter_types! { } impl pallet_funding::Config for TestRuntime { - type RuntimeEvent = RuntimeEvent; - type StringLimit = ConstU32<64>; - type ProjectIdentifier = Identifier; - type ProjectIdParameter = Identifier; + type AuctionInitializePeriodDuration = AuctionInitializePeriodDuration; + type Balance = Balance; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); type BidId = u128; + type CandleAuctionDuration = CandleAuctionDuration; + type CommunityFundingDuration = CommunityRoundDuration; type ContributionTokenCurrency = Assets; - type EvaluationDuration = EvaluationDuration; - type AuctionInitializePeriodDuration = AuctionInitializePeriodDuration; + type ContributionVesting = ConstU32<4>; type EnglishAuctionDuration = EnglishAuctionDuration; - type CandleAuctionDuration = CandleAuctionDuration; - type RemainderFundingDuration = RemainderFundingDuration; - type PalletId = FundingPalletId; + type EvaluationDuration = EvaluationDuration; + type FundingCurrency = Balances; + type MaxContributionsPerUser = ConstU32<4>; type MaxProjectsToUpdatePerBlock = ConstU32<100>; - type CommunityFundingDuration = CommunityRoundDuration; - type Randomness = RandomnessCollectiveFlip; - type HandleMembers = Credentials; - type PreImageLimit = ConstU32<1024>; // Low value to simplify the tests type MaximumBidsPerUser = ConstU32<4>; - type MaxContributionsPerUser = ConstU32<4>; - type ContributionVesting = ConstU32<4>; - type WeightInfo = (); - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); type Multiplier = types::Multiplier; - type Balance = Balance; type NativeCurrency = Balances; - type FundingCurrency = Balances; + type PalletId = FundingPalletId; + type PreImageLimit = ConstU32<1024>; + type ProjectIdParameter = Identifier; + type ProjectIdentifier = Identifier; + type Randomness = RandomnessCollectiveFlip; + type RemainderFundingDuration = RemainderFundingDuration; + type RuntimeEvent = RuntimeEvent; + type StringLimit = ConstU32<64>; + type WeightInfo = (); } // Build genesis storage according to the mock runtime. // TODO: PLMC-161. Add some mocks projects at Genesis to simplify the tests pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - GenesisConfig { - balances: BalancesConfig { balances: vec![] }, - credentials: CredentialsConfig { - issuers: vec![1, 16558220937623665250], - retails: vec![2], - professionals: vec![2, 3], - institutionals: vec![4], - }, - ..Default::default() - } - .assimilate_storage(&mut t) - .unwrap(); + GenesisConfig { balances: BalancesConfig { balances: vec![] }, ..Default::default() } + .assimilate_storage(&mut t) + .unwrap(); let mut ext = sp_io::TestExternalities::new(t); // In order to emit events the block number must be more than 0 diff --git a/pallets/funding/src/tests.rs b/pallets/funding/src/tests.rs index e9567709d..2f1f3f87e 100644 --- a/pallets/funding/src/tests.rs +++ b/pallets/funding/src/tests.rs @@ -36,14 +36,7 @@ use std::cell::RefCell; type ProjectIdOf = ::ProjectIdentifier; type UserToBalance = Vec<(mock::AccountId, BalanceOf)>; // User -> token_amount, price_per_token, multiplier -type UserToBid = Vec<( - AccountId, - ( - BalanceOf, - BalanceOf, - Option>, - ), -)>; +type UserToBid = Vec<(AccountId, (BalanceOf, BalanceOf, Option>))>; type UserToContribution = Vec<(AccountId, (BalanceOf, Option>))>; const ISSUER: AccountId = 1; @@ -79,10 +72,7 @@ fn remove_missing_accounts_from_fundings(fundings_1: UserToBalance, fundings_2: let mut fundings_1 = fundings_1; let fundings_2 = fundings_2; fundings_1.retain(|(account, _)| { - fundings_2 - .iter() - .find_map(|(account_2, _)| if account == account_2 { Some(()) } else { None }) - .is_some() + fundings_2.iter().find_map(|(account_2, _)| if account == account_2 { Some(()) } else { None }).is_some() }); fundings_1 } @@ -119,18 +109,16 @@ pub struct TestEnvironment { } impl TestEnvironment { pub fn new() -> Self { - Self { - ext_env: RefCell::new(new_test_ext()), - nonce: RefCell::new(0u64), - } + Self { ext_env: RefCell::new(new_test_ext()), nonce: RefCell::new(0u64) } } + fn create_project( - &self, creator: mock::AccountId, project: ProjectMetadataOf, + &self, + creator: mock::AccountId, + project: ProjectMetadataOf, ) -> Result { // Create project in the externalities environment of this struct instance - self.ext_env - .borrow_mut() - .execute_with(|| FundingModule::create(RuntimeOrigin::signed(creator), project))?; + self.ext_env.borrow_mut().execute_with(|| FundingModule::create(RuntimeOrigin::signed(creator), project))?; // Retrieve the project_id from the events let project_id = self.ext_env.borrow_mut().execute_with(|| { @@ -145,12 +133,9 @@ impl TestEnvironment { .clone() }); - Ok(CreatedProject { - test_env: self, - creator, - project_id, - }) + Ok(CreatedProject { test_env: self, creator, project_id }) } + /// Returns the *free* fundings of the Users. #[allow(dead_code)] fn get_free_fundings(&self) -> UserToBalance { @@ -164,6 +149,7 @@ impl TestEnvironment { fundings }) } + /// Returns the *reserved* fundings of the Users. #[allow(dead_code)] fn get_reserved_fundings(&self, reserve_type: BondType) -> UserToBalance { @@ -177,6 +163,7 @@ impl TestEnvironment { fundings }) } + fn fund_accounts(&self, fundings: UserToBalance) { self.ext_env.borrow_mut().execute_with(|| { for (account, amount) in fundings { @@ -184,9 +171,11 @@ impl TestEnvironment { } }); } + fn current_block(&self) -> BlockNumber { self.ext_env.borrow_mut().execute_with(|| System::block_number()) } + fn advance_time(&self, amount: BlockNumber) { self.ext_env.borrow_mut().execute_with(|| { for _block in 0..amount { @@ -197,6 +186,7 @@ impl TestEnvironment { } }); } + fn do_free_funds_assertions(&self, correct_funds: UserToBalance) { for (user, balance) in correct_funds { self.ext_env.borrow_mut().execute_with(|| { @@ -205,6 +195,7 @@ impl TestEnvironment { }); } } + fn do_reserved_funds_assertions(&self, correct_funds: UserToBalance, reserve_type: BondType) { for (user, balance) in correct_funds { self.ext_env.borrow_mut().execute_with(|| { @@ -225,9 +216,11 @@ impl<'a> ProjectInstance for CreatedProject<'a> { fn get_test_environment(&self) -> &TestEnvironment { self.test_env } + fn get_creator(&self) -> AccountId { self.creator.clone() } + fn get_project_id(&self) -> ProjectIdOf { self.project_id.clone() } @@ -236,9 +229,7 @@ impl<'a> CreatedProject<'a> { fn new_default(test_env: &'a TestEnvironment) -> Self { test_env.fund_accounts(default_fundings()); let creator = default_fundings()[0].0; - let project = test_env - .create_project(creator, default_project(test_env.nonce.borrow().clone())) - .unwrap(); + let project = test_env.create_project(creator, default_project(test_env.nonce.borrow().clone())).unwrap(); project.do_project_assertions(default_creation_assertions); *test_env.nonce.borrow_mut() += 1; project @@ -251,11 +242,7 @@ impl<'a> CreatedProject<'a> { .borrow_mut() .execute_with(|| FundingModule::start_evaluation(RuntimeOrigin::signed(caller), self.project_id))?; - Ok(EvaluatingProject { - test_env: self.test_env, - creator: self.creator, - project_id: self.project_id, - }) + Ok(EvaluatingProject { test_env: self.test_env, creator: self.creator, project_id: self.project_id }) } } @@ -269,9 +256,11 @@ impl<'a> ProjectInstance for EvaluatingProject<'a> { fn get_test_environment(&self) -> &TestEnvironment { self.test_env } + fn get_creator(&self) -> AccountId { self.creator.clone() } + fn get_project_id(&self) -> ProjectIdOf { self.project_id.clone() } @@ -300,11 +289,7 @@ impl<'a> EvaluatingProject<'a> { fn start_auction(self, caller: AccountId) -> Result, DispatchError> { self.test_env.ext_env.borrow_mut().execute_with(|| { FundingModule::start_auction(RuntimeOrigin::signed(caller), self.project_id)?; - Ok(AuctioningProject { - test_env: self.test_env, - creator: self.creator, - project_id: self.project_id, - }) + Ok(AuctioningProject { test_env: self.test_env, creator: self.creator, project_id: self.project_id }) }) } } @@ -319,9 +304,11 @@ impl<'a> ProjectInstance for AuctioningProject<'a> { fn get_test_environment(&self) -> &TestEnvironment { self.test_env } + fn get_creator(&self) -> AccountId { self.creator.clone() } + fn get_project_id(&self) -> ProjectIdOf { self.project_id.clone() } @@ -332,9 +319,7 @@ impl<'a> AuctioningProject<'a> { let creator = evaluating_project.get_creator(); // Do Evaluation bonding - evaluating_project - .bond_for_users(default_evaluation_bonds()) - .expect("Bonding should work"); + evaluating_project.bond_for_users(default_evaluation_bonds()).expect("Bonding should work"); // Check that enough funds are reserved test_env.do_reserved_funds_assertions(default_evaluation_bonds(), BondType::Evaluation); @@ -390,22 +375,16 @@ impl<'a> AuctioningProject<'a> { .english_auction .end() .expect("English end point should exist"); - self.test_env - .advance_time(english_end - self.test_env.current_block() + 1); + self.test_env.advance_time(english_end - self.test_env.current_block() + 1); let candle_end = self .get_project_info() .phase_transition_points .candle_auction .end() .expect("Candle end point should exist"); - self.test_env - .advance_time(candle_end - self.test_env.current_block() + 1); + self.test_env.advance_time(candle_end - self.test_env.current_block() + 1); assert_eq!(self.get_project_info().project_status, ProjectStatus::CommunityRound); - CommunityFundingProject { - test_env: self.test_env, - creator: self.creator, - project_id: self.project_id, - } + CommunityFundingProject { test_env: self.test_env, creator: self.creator, project_id: self.project_id } } } @@ -419,9 +398,11 @@ impl<'a> ProjectInstance for CommunityFundingProject<'a> { fn get_test_environment(&self) -> &TestEnvironment { self.test_env } + fn get_creator(&self) -> AccountId { self.creator.clone() } + fn get_project_id(&self) -> ProjectIdOf { self.project_id.clone() } @@ -431,9 +412,7 @@ impl<'a> CommunityFundingProject<'a> { let auctioning_project = AuctioningProject::new_default(test_env); // Do Auction bidding - auctioning_project - .bid_for_users(default_auction_bids()) - .expect("Bidding should work"); + auctioning_project.bid_for_users(default_auction_bids()).expect("Bidding should work"); // Check our auction was properly interpreted test_env.advance_time(1); @@ -465,14 +444,9 @@ impl<'a> CommunityFundingProject<'a> { .community .end() .expect("Community funding end point should exist"); - self.test_env - .advance_time(community_funding_end - self.test_env.current_block() + 1); + self.test_env.advance_time(community_funding_end - self.test_env.current_block() + 1); assert_eq!(self.get_project_info().project_status, ProjectStatus::RemainderRound); - RemainderFundingProject { - test_env: self.test_env, - creator: self.creator, - project_id: self.project_id, - } + RemainderFundingProject { test_env: self.test_env, creator: self.creator, project_id: self.project_id } } } @@ -486,9 +460,11 @@ impl<'a> ProjectInstance for RemainderFundingProject<'a> { fn get_test_environment(&self) -> &TestEnvironment { self.test_env } + fn get_creator(&self) -> AccountId { self.creator.clone() } + fn get_project_id(&self) -> ProjectIdOf { self.project_id.clone() } @@ -508,9 +484,7 @@ impl<'a> RemainderFundingProject<'a> { let community_funding_project = CommunityFundingProject::new_default(test_env); // Do community buying - community_funding_project - .buy_for_retail_users(default_community_buys()) - .expect("Community buying should work"); + community_funding_project.buy_for_retail_users(default_community_buys()).expect("Community buying should work"); // Check our buys were properly interpreted test_env.advance_time(1); @@ -532,14 +506,9 @@ impl<'a> RemainderFundingProject<'a> { .remainder .end() .expect("Remainder funding end point should exist"); - self.test_env - .advance_time(remainder_funding_end - self.test_env.current_block() + 1); + self.test_env.advance_time(remainder_funding_end - self.test_env.current_block() + 1); assert_eq!(self.get_project_info().project_status, ProjectStatus::FundingEnded); - FinishedProject { - test_env: self.test_env, - creator: self.creator, - project_id: self.project_id, - } + FinishedProject { test_env: self.test_env, creator: self.creator, project_id: self.project_id } } } @@ -553,9 +522,11 @@ impl<'a> ProjectInstance for FinishedProject<'a> { fn get_test_environment(&self) -> &TestEnvironment { self.test_env } + fn get_creator(&self) -> AccountId { self.creator.clone() } + fn get_project_id(&self) -> ProjectIdOf { self.project_id.clone() } @@ -563,9 +534,7 @@ impl<'a> ProjectInstance for FinishedProject<'a> { impl<'a> FinishedProject<'a> { fn new_default(test_env: &'a TestEnvironment) -> Self { let remainder_funding_project = RemainderFundingProject::new_default(test_env); - remainder_funding_project - .buy_for_any_user(default_remainder_buys()) - .expect("Buying should work"); + remainder_funding_project.buy_for_any_user(default_remainder_buys()).expect("Buying should work"); // End project funding by moving block to after the end of remainder round let finished_project = remainder_funding_project.finish_project(); @@ -588,14 +557,8 @@ mod defaults { ProjectMetadata { total_allocation_size: 1_000_000, minimum_price: 1 * PLMC, - ticket_size: TicketSize { - minimum: Some(1), - maximum: None, - }, - participants_size: ParticipantsSize { - minimum: Some(2), - maximum: None, - }, + ticket_size: TicketSize { minimum: Some(1), maximum: None }, + participants_size: ParticipantsSize { minimum: Some(2), maximum: None }, funding_thresholds: Default::default(), conversion_rate: 0, participation_currencies: Default::default(), @@ -627,18 +590,11 @@ mod defaults { pub fn default_evaluation_bonds() -> UserToBalance { // currently the default project needs 100_000 PLMC to be successful in the evaluation round // we assume we will use this bond twice - vec![ - (EVALUATOR_1, 20_000 * PLMC), - (EVALUATOR_2, 30_000 * PLMC), - (EVALUATOR_3, 60_000 * PLMC), - ] + vec![(EVALUATOR_1, 20_000 * PLMC), (EVALUATOR_2, 30_000 * PLMC), (EVALUATOR_3, 60_000 * PLMC)] } pub fn default_failing_evaluation_bonds() -> UserToBalance { - default_evaluation_bonds() - .into_iter() - .map(|(user, balance)| (user, balance / 2)) - .collect::() + default_evaluation_bonds().into_iter().map(|(user, balance)| (user, balance / 2)).collect::() } pub fn default_auction_bids() -> UserToBid { @@ -654,44 +610,26 @@ mod defaults { default_auction_bids() .into_iter() .map(|(user, (amount, price, mult))| { - ( - user, - (mult - .unwrap_or_default() - .calculate_bonding_requirement(amount * price) - .unwrap()), - ) + (user, (mult.unwrap_or_default().calculate_bonding_requirement(amount * price).unwrap())) }) .collect() } pub fn default_auction_bids_currency_reserved() -> UserToBalance { - default_auction_bids() - .into_iter() - .map(|(user, (amount, price, _mult))| (user, (amount * price))) - .collect() + default_auction_bids().into_iter().map(|(user, (amount, price, _mult))| (user, (amount * price))).collect() } pub fn default_community_plmc_bondings(price: BalanceOf) -> UserToBalance { default_community_buys() .into_iter() .map(|(user, (amount, multiplier))| { - ( - user, - (multiplier - .unwrap_or_default() - .calculate_bonding_requirement(amount * price) - .unwrap()), - ) + (user, (multiplier.unwrap_or_default().calculate_bonding_requirement(amount * price).unwrap())) }) .collect() } pub fn default_community_buys_currency_reserved(price: BalanceOf) -> UserToBalance { - default_community_buys() - .into_iter() - .map(|(user, (amount, _multiplier))| (user, (amount * price))) - .collect() + default_community_buys().into_iter().map(|(user, (amount, _multiplier))| (user, (amount * price))).collect() } pub fn default_community_buys() -> UserToContribution { @@ -732,10 +670,7 @@ mod defaults { pub fn default_auction_start_assertions(project_id: ProjectIdOf, test_env: &TestEnvironment) { test_env.ext_env.borrow_mut().execute_with(|| { let project_info = FundingModule::project_info(project_id).expect("Project info should exist"); - assert_eq!( - project_info.project_status, - ProjectStatus::AuctionRound(AuctionPhase::English) - ); + assert_eq!(project_info.project_status, ProjectStatus::AuctionRound(AuctionPhase::English)); }); } @@ -786,7 +721,8 @@ mod defaults { } pub fn default_community_funding_start_assertions( - project_id: ProjectIdOf, test_env: &TestEnvironment, + project_id: ProjectIdOf, + test_env: &TestEnvironment, ) { // Bids that reserved bidding currency, should have that drained from their account on community round, and transfered to the pallet account test_env.ext_env.borrow_mut().execute_with(|| { @@ -808,18 +744,12 @@ mod defaults { // Check correct weighted_average_price let token_price = project_info.weighted_average_price.expect("Token price should exist"); - assert_eq!( - token_price, - default_token_average_price(), - "Weighted average token price is incorrect" - ); + assert_eq!(token_price, default_token_average_price(), "Weighted average token price is incorrect"); // Check that remaining CTs are updated let project = FundingModule::project_info(project_id).expect("Project should exist"); - let bought_tokens: u128 = default_auction_bids() - .iter() - .map(|(_account, (amount, _price, _multiplier))| amount) - .sum(); + let bought_tokens: u128 = + default_auction_bids().iter().map(|(_account, (amount, _price, _multiplier))| amount).sum(); assert_eq!( project.remaining_contribution_tokens, default_project(0).total_allocation_size - bought_tokens, @@ -831,10 +761,7 @@ mod defaults { test_env.ext_env.borrow_mut().execute_with(|| { let project_bids = crate::pallet::AuctionsInfo::::iter_prefix(project_id).collect::>(); let project_info = FundingModule::project_info(project_id).unwrap(); - assert!( - matches!(project_info.weighted_average_price, Some(_)), - "Weighted average price should exist" - ); + assert!(matches!(project_info.weighted_average_price, Some(_)), "Weighted average price should exist"); assert!(project_bids .into_iter() .find(|(_bidder, bids)| { !bids.iter().all(|bid| bid.status == BidStatus::Accepted) }) @@ -881,14 +808,10 @@ mod defaults { // Check that remaining CTs are updated test_env.ext_env.borrow_mut().execute_with(|| { let project = FundingModule::project_info(project_id).expect("Project should exist"); - let auction_bought_tokens: u128 = default_auction_bids() - .iter() - .map(|(_account, (amount, _price, _multiplier))| amount) - .sum(); - let community_bought_tokens: u128 = default_community_buys() - .iter() - .map(|(_account, (amount, _multiplier))| amount) - .sum(); + let auction_bought_tokens: u128 = + default_auction_bids().iter().map(|(_account, (amount, _price, _multiplier))| amount).sum(); + let community_bought_tokens: u128 = + default_community_buys().iter().map(|(_account, (amount, _multiplier))| amount).sum(); assert_eq!( project.remaining_contribution_tokens, default_project(0).total_allocation_size - auction_bought_tokens - community_bought_tokens, @@ -898,7 +821,8 @@ mod defaults { } pub fn default_remainder_funding_start_assertions( - project_id: ProjectIdOf, test_env: &TestEnvironment, + project_id: ProjectIdOf, + test_env: &TestEnvironment, ) { test_env.ext_env.borrow_mut().execute_with(|| { let project_info = FundingModule::project_info(project_id).expect("Project info should exist"); @@ -916,24 +840,18 @@ mod defaults { // Check that remaining CTs are updated test_env.ext_env.borrow_mut().execute_with(|| { let project = FundingModule::project_info(project_id).expect("Project should exist"); - let auction_bought_tokens: u128 = default_auction_bids() - .iter() - .map(|(_account, (amount, _price, _multiplier))| amount) - .sum(); - let community_bought_tokens: u128 = default_community_buys() - .iter() - .map(|(_account, (amount, _multiplier))| amount) - .sum(); - let remainder_bought_tokens: u128 = default_remainder_buys() - .iter() - .map(|(_account, (amount, _multiplier))| amount) - .sum(); + let auction_bought_tokens: u128 = + default_auction_bids().iter().map(|(_account, (amount, _price, _multiplier))| amount).sum(); + let community_bought_tokens: u128 = + default_community_buys().iter().map(|(_account, (amount, _multiplier))| amount).sum(); + let remainder_bought_tokens: u128 = + default_remainder_buys().iter().map(|(_account, (amount, _multiplier))| amount).sum(); assert_eq!( project.remaining_contribution_tokens, - default_project(0).total_allocation_size - - auction_bought_tokens - - community_bought_tokens - - remainder_bought_tokens, + default_project(0).total_allocation_size - + auction_bought_tokens - + community_bought_tokens - + remainder_bought_tokens, "Remaining CTs are incorrect" ); }); @@ -961,11 +879,7 @@ mod helper_functions { FundingModule::remove_from_update_store(&69u32).unwrap(); let stored = crate::ProjectsToUpdate::::iter_values().collect::>(); - assert_eq!( - stored[2], - vec![], - "Vector should be empty for that block after deletion" - ); + assert_eq!(stored[2], vec![], "Vector should be empty for that block after deletion"); }); } } @@ -979,11 +893,7 @@ mod creation_round_success { let test_env = TestEnvironment::new(); test_env.fund_accounts(default_fundings()); test_env.ext_env.borrow_mut().execute_with(|| { - assert_ok!(Balances::transfer( - RuntimeOrigin::signed(EVALUATOR_1), - EVALUATOR_2, - 1 * PLMC - )); + assert_ok!(Balances::transfer(RuntimeOrigin::signed(EVALUATOR_1), EVALUATOR_2, 1 * PLMC)); }); } @@ -1027,14 +937,8 @@ mod creation_round_failure { fn price_too_low() { let wrong_project: ProjectMetadataOf = ProjectMetadata { minimum_price: 0, - ticket_size: TicketSize { - minimum: Some(1), - maximum: None, - }, - participants_size: ParticipantsSize { - minimum: Some(2), - maximum: None, - }, + ticket_size: TicketSize { minimum: Some(1), maximum: None }, + participants_size: ParticipantsSize { minimum: Some(2), maximum: None }, offchain_information_hash: Some(hashed(METADATA)), ..Default::default() }; @@ -1050,14 +954,8 @@ mod creation_round_failure { fn participants_size_error() { let wrong_project: ProjectMetadataOf = ProjectMetadata { minimum_price: 1, - ticket_size: TicketSize { - minimum: Some(1), - maximum: None, - }, - participants_size: ParticipantsSize { - minimum: None, - maximum: None, - }, + ticket_size: TicketSize { minimum: Some(1), maximum: None }, + participants_size: ParticipantsSize { minimum: None, maximum: None }, offchain_information_hash: Some(hashed(METADATA)), ..Default::default() }; @@ -1073,14 +971,8 @@ mod creation_round_failure { fn ticket_size_error() { let wrong_project: ProjectMetadataOf = ProjectMetadata { minimum_price: 1, - ticket_size: TicketSize { - minimum: None, - maximum: None, - }, - participants_size: ParticipantsSize { - minimum: Some(1), - maximum: None, - }, + ticket_size: TicketSize { minimum: None, maximum: None }, + participants_size: ParticipantsSize { minimum: Some(1), maximum: None }, offchain_information_hash: Some(hashed(METADATA)), ..Default::default() }; @@ -1097,14 +989,8 @@ mod creation_round_failure { fn multiple_field_error() { let wrong_project: ProjectMetadataOf = ProjectMetadata { minimum_price: 0, - ticket_size: TicketSize { - minimum: None, - maximum: None, - }, - participants_size: ParticipantsSize { - minimum: None, - maximum: None, - }, + ticket_size: TicketSize { minimum: None, maximum: None }, + participants_size: ParticipantsSize { minimum: None, maximum: None }, ..Default::default() }; let test_env = TestEnvironment::new(); @@ -1138,17 +1024,10 @@ mod evaluation_round_success { evaluating_project.bond_for_users(default_evaluation_bonds()).unwrap(); let project_info = evaluating_project.get_project_info(); test_env.advance_time(project_info.phase_transition_points.evaluation.end().unwrap() + 1u64); - let end_block = evaluating_project - .get_project_info() - .phase_transition_points - .auction_initialize_period - .end() - .unwrap(); + let end_block = + evaluating_project.get_project_info().phase_transition_points.auction_initialize_period.end().unwrap(); test_env.advance_time(end_block - test_env.current_block() + 1); - assert_eq!( - evaluating_project.get_project_info().project_status, - ProjectStatus::AuctionRound(English) - ); + assert_eq!(evaluating_project.get_project_info().project_status, ProjectStatus::AuctionRound(English)); } } @@ -1162,9 +1041,7 @@ mod evaluation_round_failure { let evaluating_project = EvaluatingProject::new_default(&test_env); // Partially bond for evaluation - evaluating_project - .bond_for_users(default_failing_evaluation_bonds()) - .expect("Bonding should work"); + evaluating_project.bond_for_users(default_failing_evaluation_bonds()).expect("Bonding should work"); // Check that enough funds are reserved test_env.do_reserved_funds_assertions(default_failing_evaluation_bonds(), BondType::Evaluation); @@ -1251,12 +1128,8 @@ mod auction_round_success { // do one candle bid for each block until the end of candle auction with a new user let mut bidding_account = 1000; let bid_info = default_auction_bids()[0].1; - let necessary_funding = (bid_info.0 * bid_info.1) - + (bid_info - .2 - .unwrap_or_default() - .calculate_bonding_requirement(bid_info.0 * bid_info.1) - .unwrap()); + let necessary_funding = (bid_info.0 * bid_info.1) + + (bid_info.2.unwrap_or_default().calculate_bonding_requirement(bid_info.0 * bid_info.1).unwrap()); let mut bids_made: UserToBid = vec![]; let starting_bid_block = test_env.current_block(); assert_eq!(test_env.current_block(), starting_bid_block); @@ -1268,9 +1141,7 @@ mod auction_round_success { ); test_env.fund_accounts(vec![(bidding_account, necessary_funding)]); let bids: UserToBid = vec![(bidding_account, bid_info)]; - auctioning_project - .bid_for_users(bids.clone()) - .expect("Candle Bidding should not fail"); + auctioning_project.bid_for_users(bids.clone()).expect("Candle Bidding should not fail"); bids_made.push(bids[0]); bidding_account += 1; test_env.advance_time(1); @@ -1286,10 +1157,8 @@ mod auction_round_success { let split = (random_end - starting_bid_block + 1) as usize; let excluded_bids = bids_made.split_off(split); let included_bids = bids_made; - let _weighted_price = auctioning_project - .get_project_info() - .weighted_average_price - .expect("Weighted price should exist"); + let _weighted_price = + auctioning_project.get_project_info().weighted_average_price.expect("Weighted price should exist"); // let all_bids = test_env.ext_env.borrow_mut().execute_with(|| { // AuctionsInfo::::iter_prefix_values(auctioning_project.project_id) // .map(|bids| bids[0].clone()) @@ -1302,14 +1171,7 @@ mod auction_round_success { assert!( matches!( stored_bid[0], - BidInfo { - project: _pid, - amount: _, - price: _, - ticket_size: _, - bidder: _, - .. - } + BidInfo { project: _pid, amount: _, price: _, ticket_size: _, bidder: _, .. } ), "Stored bid does not match the bid that was made" ); @@ -1324,14 +1186,7 @@ mod auction_round_success { assert!( matches!( stored_bid[0], - BidInfo { - project: _pid, - amount: _, - price: _, - ticket_size: _, - bidder: _, - .. - } + BidInfo { project: _pid, amount: _, price: _, ticket_size: _, bidder: _, .. } ), "Stored bid does not match the bid that was made" ); @@ -1402,10 +1257,8 @@ mod auction_round_failure { (DAVE, (20_000, 8 * PLMC, None)), ]; - let mut fundings: UserToBalance = bids - .iter() - .map(|(user, (amount, price, _))| (*user, *amount * *price)) - .collect::>(); + let mut fundings: UserToBalance = + bids.iter().map(|(user, (amount, price, _))| (*user, *amount * *price)).collect::>(); // Existential deposit on DAVE fundings.push((DAVE, 100 * PLMC)); @@ -1484,13 +1337,9 @@ mod community_round_success { let bob_balance = ::NativeCurrency::reserved_balance(&BOB); let stop = "here"; }); - let remaining_ct = community_funding_project - .get_project_info() - .remaining_contribution_tokens; - let ct_price = community_funding_project - .get_project_info() - .weighted_average_price - .expect("CT Price should exist"); + let remaining_ct = community_funding_project.get_project_info().remaining_contribution_tokens; + let ct_price = + community_funding_project.get_project_info().weighted_average_price.expect("CT Price should exist"); // Necessary funds to buy remaining CTs, plus some extra for keeping it account alive let buyers: UserToBalance = vec![(BOB, remaining_ct * ct_price), (BOB, 50 * PLMC)]; @@ -1512,18 +1361,10 @@ mod community_round_success { .expect("The Buyer should be able to buy the exact amount of remaining CTs"); test_env.advance_time(2u64); // Check remaining CTs is 0 - assert_eq!( - community_funding_project - .get_project_info() - .remaining_contribution_tokens, - 0 - ); + assert_eq!(community_funding_project.get_project_info().remaining_contribution_tokens, 0); // Check project is in FundingEnded state - assert_eq!( - community_funding_project.get_project_info().project_status, - ProjectStatus::FundingEnded - ); + assert_eq!(community_funding_project.get_project_info().project_status, ProjectStatus::FundingEnded); test_env.do_free_funds_assertions(vec![(BOB, (50 * PLMC) * 2)]); } @@ -1534,14 +1375,9 @@ mod community_round_success { let community_funding_project = CommunityFundingProject::new_default(&test_env); const BOB: AccountId = 808; - let remaining_ct = community_funding_project - .get_project_info() - .remaining_contribution_tokens - + 40; // Overbuy - let ct_price = community_funding_project - .get_project_info() - .weighted_average_price - .expect("CT Price should exist"); + let remaining_ct = community_funding_project.get_project_info().remaining_contribution_tokens + 40; // Overbuy + let ct_price = + community_funding_project.get_project_info().weighted_average_price.expect("CT Price should exist"); // Necessary funds to buy remaining CTs, plus some extra for keeping it account alive let buyers: UserToBalance = vec![(BOB, remaining_ct * ct_price), (BOB, 50 * PLMC)]; @@ -1556,18 +1392,10 @@ mod community_round_success { test_env.advance_time(2u64); // Check remaining CTs is 0 - assert_eq!( - community_funding_project - .get_project_info() - .remaining_contribution_tokens, - 0 - ); + assert_eq!(community_funding_project.get_project_info().remaining_contribution_tokens, 0); // Check project is in FundingEnded state - assert_eq!( - community_funding_project.get_project_info().project_status, - ProjectStatus::FundingEnded - ); + assert_eq!(community_funding_project.get_project_info().project_status, ProjectStatus::FundingEnded); test_env.do_free_funds_assertions(vec![(BOB, (40 * ct_price) * 2 + (50 * PLMC) * 2)]); } @@ -1590,10 +1418,7 @@ mod community_round_success { // Calculate currencies being transferred and bonded let contribution_ticket_size = token_amount * project_details.weighted_average_price.unwrap(); - let plmc_bond = multiplier - .unwrap_or_default() - .calculate_bonding_requirement(contribution_ticket_size) - .unwrap(); + let plmc_bond = multiplier.unwrap_or_default().calculate_bonding_requirement(contribution_ticket_size).unwrap(); // Reach the limit of contributions for a user-project project.buy_for_retail_users(contributions.clone()).unwrap(); @@ -1618,10 +1443,7 @@ mod community_round_success { let new_token_amount: BalanceOf = 2; let new_contribution: UserToContribution = vec![(BUYER_2, (new_token_amount, new_multiplier))]; let new_ticket_size = new_token_amount * project_details.weighted_average_price.unwrap(); - let new_plmc_bond = new_multiplier - .unwrap_or_default() - .calculate_bonding_requirement(new_ticket_size) - .unwrap(); + let new_plmc_bond = new_multiplier.unwrap_or_default().calculate_bonding_requirement(new_ticket_size).unwrap(); project.buy_for_retail_users(new_contribution.clone()).unwrap(); @@ -1638,10 +1460,7 @@ mod community_round_success { .ext_env .borrow_mut() .execute_with(|| crate::ContributingBonds::::get(project.project_id, BUYER_2).unwrap()); - assert_eq!( - new_plmc_bond_stored.amount, - plmc_bond_stored.amount - plmc_bond + new_plmc_bond - ); + assert_eq!(new_plmc_bond_stored.amount, plmc_bond_stored.amount - plmc_bond + new_plmc_bond); } #[test] @@ -1662,10 +1481,7 @@ mod community_round_success { // Calculate currencies being transferred and bonded let contribution_ticket_size = token_amount * project_details.weighted_average_price.unwrap(); - let plmc_bond = multiplier - .unwrap_or_default() - .calculate_bonding_requirement(contribution_ticket_size) - .unwrap(); + let plmc_bond = multiplier.unwrap_or_default().calculate_bonding_requirement(contribution_ticket_size).unwrap(); // Reach the limit of contributions for a user-project project.buy_for_retail_users(contributions.clone()).unwrap(); @@ -1690,10 +1506,7 @@ mod community_round_success { let new_token_amount: BalanceOf = 1; let new_contribution: UserToContribution = vec![(BUYER_2, (new_token_amount, new_multiplier))]; let new_ticket_size = new_token_amount * project_details.weighted_average_price.unwrap(); - let new_plmc_bond = new_multiplier - .unwrap_or_default() - .calculate_bonding_requirement(new_ticket_size) - .unwrap(); + let new_plmc_bond = new_multiplier.unwrap_or_default().calculate_bonding_requirement(new_ticket_size).unwrap(); project.buy_for_retail_users(new_contribution.clone()).unwrap(); @@ -1710,10 +1523,7 @@ mod community_round_success { .ext_env .borrow_mut() .execute_with(|| crate::ContributingBonds::::get(project.project_id, BUYER_2).unwrap()); - assert_eq!( - new_plmc_bond_stored.amount, - plmc_bond_stored.amount - plmc_bond + new_plmc_bond - ); + assert_eq!(new_plmc_bond_stored.amount, plmc_bond_stored.amount - plmc_bond + new_plmc_bond); } } @@ -1733,10 +1543,8 @@ mod purchased_vesting { let test_env = TestEnvironment::new(); let finished_project = FinishedProject::new_default(&test_env); let project_id = finished_project.project_id; - let token_price = finished_project - .get_project_info() - .weighted_average_price - .expect("CT price should exist at this point"); + let token_price = + finished_project.get_project_info().weighted_average_price.expect("CT price should exist at this point"); let project = finished_project.get_project(); let decimals = project.token_information.decimals; @@ -1760,16 +1568,12 @@ mod purchased_vesting { let test_env = TestEnvironment::new(); let finished_project = FinishedProject::new_default(&test_env); let project_id = finished_project.project_id; - let price = finished_project - .get_project_info() - .weighted_average_price - .expect("CT price should exist at this point"); + let price = + finished_project.get_project_info().weighted_average_price.expect("CT price should exist at this point"); test_env.ext_env.borrow_mut().execute_with(|| { for (buyer, (token_amount, multiplier)) in default_community_buys() { - let theoretical_bonded_plmc = multiplier - .unwrap_or_default() - .calculate_bonding_requirement(token_amount * price) - .unwrap(); + let theoretical_bonded_plmc = + multiplier.unwrap_or_default().calculate_bonding_requirement(token_amount * price).unwrap(); let actual_bonded_plmc = Balances::reserved_balance_named(&BondType::Contributing, &buyer); assert_eq!(theoretical_bonded_plmc, actual_bonded_plmc); assert_ok!(FundingModule::vested_plmc_purchase_unbond_for( @@ -1822,10 +1626,8 @@ mod bids_vesting { let _decimals = project.token_information.decimals; test_env.ext_env.borrow_mut().execute_with(|| { for (bidder, (amount, price, multiplier)) in bidders { - let theoretical_bonded_plmc = multiplier - .unwrap_or_default() - .calculate_bonding_requirement(amount * price) - .unwrap(); + let theoretical_bonded_plmc = + multiplier.unwrap_or_default().calculate_bonding_requirement(amount * price).unwrap(); let actual_bonded_plmc = Balances::reserved_balance_named(&BondType::Bidding, &bidder); assert_eq!(theoretical_bonded_plmc, actual_bonded_plmc); assert_ok!(FundingModule::vested_plmc_bid_unbond_for( diff --git a/pallets/funding/src/types.rs b/pallets/funding/src/types.rs index a0fe9ab4a..ca82b4770 100644 --- a/pallets/funding/src/types.rs +++ b/pallets/funding/src/types.rs @@ -18,8 +18,7 @@ //! Types for Funding pallet. -use crate::traits::BondingRequirementCalculation; -use crate::BalanceOf; +use crate::{traits::BondingRequirementCalculation, BalanceOf}; use frame_support::{pallet_prelude::*, traits::tokens::Balance as BalanceT}; use sp_arithmetic::traits::Saturating; use sp_runtime::traits::CheckedDiv; @@ -76,7 +75,7 @@ impl ProjectMetadata Result<(), ValidityError> { if self.minimum_price == Balance::zero() { - return Err(ValidityError::PriceTooLow); + return Err(ValidityError::PriceTooLow) } self.ticket_size.is_valid()?; self.participants_size.is_valid()?; @@ -94,13 +93,13 @@ impl TicketSize { fn is_valid(&self) -> Result<(), ValidityError> { if self.minimum.is_some() && self.maximum.is_some() { if self.minimum < self.maximum { - return Ok(()); + return Ok(()) } else { - return Err(ValidityError::TicketSizeError); + return Err(ValidityError::TicketSizeError) } } if self.minimum.is_some() || self.maximum.is_some() { - return Ok(()); + return Ok(()) } Err(ValidityError::TicketSizeError) @@ -116,20 +115,18 @@ pub struct ParticipantsSize { impl ParticipantsSize { fn is_valid(&self) -> Result<(), ValidityError> { match (self.minimum, self.maximum) { - (Some(min), Some(max)) => { + (Some(min), Some(max)) => if min < max && min > 0 && max > 0 { Ok(()) } else { Err(ValidityError::ParticipantsSizeError) - } - } - (Some(elem), None) | (None, Some(elem)) => { + }, + (Some(elem), None) | (None, Some(elem)) => if elem > 0 { Ok(()) } else { Err(ValidityError::ParticipantsSizeError) - } - } + }, (None, None) => Err(ValidityError::ParticipantsSizeError), } } @@ -177,6 +174,7 @@ impl BlockNumberPair { pub fn new(start: Option, end: Option) -> Self { Self { start, end } } + pub fn start(&self) -> Option { self.start } @@ -225,8 +223,14 @@ impl { pub fn new( - bid_id: BidId, project: ProjectId, amount: Balance, price: Balance, when: BlockNumber, bidder: AccountId, - plmc_vesting_period: PlmcVesting, ct_vesting_period: CTVesting, + bid_id: BidId, + project: ProjectId, + amount: Balance, + price: Balance, + when: BlockNumber, + bidder: AccountId, + plmc_vesting_period: PlmcVesting, + ct_vesting_period: CTVesting, ) -> Self { let ticket_size = amount.saturating_mul(price); Self { diff --git a/pallets/parachain-staking/Cargo.toml b/pallets/parachain-staking/Cargo.toml index 569bb1636..7b964271a 100644 --- a/pallets/parachain-staking/Cargo.toml +++ b/pallets/parachain-staking/Cargo.toml @@ -1,70 +1,60 @@ [package] -authors = ["KILT "] -description = "Parachain parachain-staking pallet for collator delegation and selection as well as reward distribution" -edition = "2021" -name = "parachain-staking" -version = "1.9.0-dev" - -[dev-dependencies] -pallet-aura = {workspace = true, features = ["std"]} -pallet-timestamp = {workspace = true, features = ["std"]} -sp-consensus-aura = {workspace = true, features = ["std"]} -sp-core = {workspace = true, features = ["std"]} -sp-io = {workspace = true, features = ["std"]} +name = "pallet-parachain-staking" +description = "prachain staking pallet for collator selection and reward distribution" +authors.workspace = true +documentation.workspace = true +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +readme.workspace = true +repository.workspace = true +version.workspace = true [dependencies] -# External dependencies -parity-scale-codec = {workspace = true, features = ["derive"]} -log.workspace = true -scale-info = {workspace = true, features = ["derive", "serde"]} -serde = {workspace = true, optional = true} +serde = { version = "1", default-features = false, optional = true } +log = "0.4" -# Internal dependencies -kilt-runtime-api-staking.workspace = true +parity-scale-codec = { workspace = true, features = [ + "derive", +] } +scale-info = { workspace = true, features = ["derive"] } -# Substrate dependencies +# FRAME +frame-benchmarking = { workspace = true, optional = true } frame-support.workspace = true frame-system.workspace = true -pallet-authorship.workspace = true -pallet-balances.workspace = true -pallet-session.workspace = true sp-runtime.workspace = true -sp-staking.workspace = true sp-std.workspace = true +substrate-fixed.workspace = true +sp-staking.workspace = true +pallet-authorship.workspace = true +pallet-session.workspace = true -# Benchmarking dependencies -frame-benchmarking = {workspace = true, optional = true} +[dev-dependencies] +pallet-balances.workspace = true +pallet-aura.workspace = true +pallet-timestamp.workspace = true +similar-asserts = "1.1.0" +sp-core.workspace = true +sp-io.workspace = true +sp-consensus-aura.workspace = true [features] default = ["std"] -runtime-benchmarks = [ - "frame-benchmarking", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", - "sp-staking/runtime-benchmarks", -] std = [ - "parity-scale-codec/std", - "frame-benchmarking?/std", - "frame-support/std", - "frame-system/std", - "kilt-runtime-api-staking/std", - "log/std", - "pallet-authorship/std", - "pallet-balances/std", - "pallet-session/std", - "scale-info/std", - "serde", - "sp-runtime/std", - "sp-staking/std", - "sp-std/std", -] -try-runtime = [ - "frame-system/try-runtime", - "frame-support/try-runtime", - "pallet-authorship/try-runtime", - "pallet-balances/try-runtime", - "pallet-session/try-runtime", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "parity-scale-codec/std", + "scale-info/std", + "serde/std", + "sp-runtime/std", + "sp-std/std", + "sp-staking/std", + "pallet-authorship/std", + "pallet-session/std", + "pallet-balances/std", + "sp-consensus-aura/std" ] +runtime-benchmarks = ["frame-benchmarking"] +try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/parachain-staking/README.md b/pallets/parachain-staking/README.md new file mode 100644 index 000000000..78afd35c0 --- /dev/null +++ b/pallets/parachain-staking/README.md @@ -0,0 +1,30 @@ +# DPoS Pallet for Parachain Staking + +## Polimec Changes + + + +## Formatting Rules + +- dependencies in alphabetical order in the `Cargo.toml` and at the top of each file +- prefer explicit imports to glob import syntax i.e. prefer `use::crate::{Ex1, Ex2, ..};` to `use super::*;` + +## Description + +Implements Delegated Proof of Stake to + +1. select the active set of eligible block producers +2. reward block authors +3. enable delegators and collators to participate in inflationary rewards + +Links: + +- [Rust Documentation](https://purestake.github.io/moonbeam/pallet_parachain_staking/index.html) +- [Unofficial Documentation](https://meta5.world/parachain-staking-docs/) +- [(Outdated) Blog Post with Justification](https://meta5.world/posts/parachain-staking) + +## History + +Since January 2021, Moonbeam's team has maintained this Delegated Proof of Stake (DPoS) pallet designed specifically for parachains. + +Since April 2021, the development of this pallet has been supported by [a Web3 Foundation grant](https://github.com/w3f/Grants-Program/pull/389). The [first milestone](https://github.com/w3f/Grant-Milestone-Delivery/pull/218) was approved in June 2021. diff --git a/pallets/parachain-staking/migrations.md b/pallets/parachain-staking/migrations.md new file mode 100644 index 000000000..d2277ffcd --- /dev/null +++ b/pallets/parachain-staking/migrations.md @@ -0,0 +1,42 @@ +# Migration History + +## Calculate outgoing rewards based on pending revoke and decrease changes + +- [Migration PR `#1408`](https://github.com/PureStake/moonbeam/pull/1408) + +## Patch delegations total mismatch + +- [Migration PR `#1291`](https://github.com/PureStake/moonbeam/pull/1291) + +## Split candidate state for PoV optimization + +- [Migration PR `#1117`](https://github.com/PureStake/moonbeam/pull/1117) + +## Increase max delegations per candidate + +- [Migration PR `#1096`](https://github.com/PureStake/moonbeam/pull/1096) +- [Migratio bugfix `#1112`](https://github.com/PureStake/moonbeam/pull/1112) + +## Manual Exits and Patch Lack of Delay for bond\_{more, less} + +- [Migration PR `#810`](https://github.com/PureStake/moonbeam/pull/810) +- [Migration Removal PR `#?`]() + +## Purge Stale Storage + +- [Migration PR `#970`](https://github.com/PureStake/moonbeam/pull/970) + +## Delay nominator exits by changing NominatorState and ExitQueue + +- [Migration PR `#610`](https://github.com/PureStake/moonbeam/pull/610) +- [Migration Removal PR `#662`](https://github.com/PureStake/moonbeam/pull/662) + +## Patch nomination DOS attack vector by changing CollatorState + +- [Migration PR `#505`](https://github.com/PureStake/moonbeam/pull/505) +- [Migration Removal PR `#553`](https://github.com/PureStake/moonbeam/pull/553) + +## Patch underflow bug and correct Total storage item + +- [Migration PR `#502`](https://github.com/PureStake/moonbeam/pull/502) +- [Migration Removal PR `#553`](https://github.com/PureStake/moonbeam/pull/553) diff --git a/pallets/parachain-staking/src/api.rs b/pallets/parachain-staking/src/api.rs deleted file mode 100644 index a7ba6a3a5..000000000 --- a/pallets/parachain-staking/src/api.rs +++ /dev/null @@ -1,90 +0,0 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH - -// The KILT Blockchain 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. - -// The KILT Blockchain 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 . - -// If you feel like getting in touch with us, you can do so at info@botlabs.org - -use frame_support::traits::Currency; -use sp_runtime::{ - traits::{Saturating, Zero}, - Perquintill, -}; - -use crate::{ - types::BalanceOf, BlocksAuthored, BlocksRewarded, CandidatePool, Config, DelegatorState, InflationConfig, Pallet, - Rewards, TotalCollatorStake, -}; - -impl Pallet { - /// Calculates the staking rewards for a given account address. - /// - /// Subtracts the number of rewarded blocks from the number of authored - /// blocks by the collator and multiplies that with the current stake - /// as well as reward rate. - /// - /// At least used in Runtime API. - pub fn get_unclaimed_staking_rewards(acc: &T::AccountId) -> BalanceOf { - let count_rewarded = BlocksRewarded::::get(acc); - let rewards = Rewards::::get(acc); - - // delegators and collators need to be handled differently - if let Some(delegator_state) = DelegatorState::::get(acc) { - // #blocks for unclaimed staking rewards equals - // #blocks_authored_by_collator - #blocks_claimed_by_delegator - let count_unclaimed = BlocksAuthored::::get(&delegator_state.owner).saturating_sub(count_rewarded); - let stake = delegator_state.amount; - // rewards += stake * reward_count * delegator_reward_rate - rewards.saturating_add(Self::calc_block_rewards_delegator(stake, count_unclaimed.into())) - } else if Self::is_active_candidate(acc).is_some() { - // #blocks for unclaimed staking rewards equals - // #blocks_authored_by_collator - #blocks_claimed_by_collator - let count_unclaimed = BlocksAuthored::::get(acc).saturating_sub(count_rewarded); - let stake = CandidatePool::::get(acc) - .map(|state| state.stake) - .unwrap_or_else(BalanceOf::::zero); - // rewards += stake * self_count * collator_reward_rate - rewards.saturating_add(Self::calc_block_rewards_collator(stake, count_unclaimed.into())) - } else { - rewards - } - } - - /// Calculates the current staking and reward rates for collators and - /// delegators. - /// - /// At least used in Runtime API. - pub fn get_staking_rates() -> kilt_runtime_api_staking::StakingRates { - let total_issuance = T::Currency::total_issuance(); - let total_stake = TotalCollatorStake::::get(); - let inflation_config = InflationConfig::::get(); - let collator_staking_rate = Perquintill::from_rational(total_stake.collators, total_issuance); - let delegator_staking_rate = Perquintill::from_rational(total_stake.delegators, total_issuance); - let collator_reward_rate = Perquintill::from_rational( - inflation_config.collator.max_rate.deconstruct(), - collator_staking_rate.deconstruct(), - ) * inflation_config.collator.reward_rate.annual; - let delegator_reward_rate = Perquintill::from_rational( - inflation_config.delegator.max_rate.deconstruct(), - delegator_staking_rate.deconstruct(), - ) * inflation_config.delegator.reward_rate.annual; - - kilt_runtime_api_staking::StakingRates { - collator_staking_rate, - collator_reward_rate, - delegator_staking_rate, - delegator_reward_rate, - } - } -} diff --git a/pallets/parachain-staking/src/auto_compound.rs b/pallets/parachain-staking/src/auto_compound.rs new file mode 100644 index 000000000..214b212c0 --- /dev/null +++ b/pallets/parachain-staking/src/auto_compound.rs @@ -0,0 +1,341 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Auto-compounding functionality for staking rewards + +use crate::{ + pallet::{ + AddGet, AutoCompoundingDelegations as AutoCompoundingDelegationsStorage, BalanceOf, CandidateInfo, Config, + DelegatorState, Error, Event, Pallet, Total, + }, + types::{Bond, BondAdjust, Delegator}, +}; +use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, traits::Get, RuntimeDebug}; +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_runtime::{traits::Saturating, BoundedVec, Percent}; +use sp_std::prelude::*; + +/// Represents the auto-compounding amount for a delegation. +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, PartialOrd, Ord)] +pub struct AutoCompoundConfig { + pub delegator: AccountId, + pub value: Percent, +} + +/// Represents the auto-compounding [Delegations] for `T: Config` +#[derive(Clone, Eq, PartialEq, RuntimeDebug)] +pub struct AutoCompoundDelegations( + BoundedVec< + AutoCompoundConfig, + AddGet, + >, +); + +impl AutoCompoundDelegations +where + T: Config, +{ + /// Creates a new instance of [AutoCompoundingDelegations] from a vector of sorted_delegations. + /// This is used for testing purposes only. + #[cfg(test)] + pub fn new( + sorted_delegations: BoundedVec< + AutoCompoundConfig, + AddGet, + >, + ) -> Self { + Self(sorted_delegations) + } + + /// Retrieves an instance of [AutoCompoundingDelegations] storage as [AutoCompoundDelegations]. + pub fn get_storage(candidate: &T::AccountId) -> Self { + Self(>::get(candidate)) + } + + /// Inserts the current state to [AutoCompoundingDelegations] storage. + pub fn set_storage(self, candidate: &T::AccountId) { + >::insert(candidate, self.0) + } + + /// Retrieves the auto-compounding value for a delegation. The `delegations_config` must be a + /// sorted vector for binary_search to work. + pub fn get_for_delegator(&self, delegator: &T::AccountId) -> Option { + match self.0.binary_search_by(|d| d.delegator.cmp(delegator)) { + Ok(index) => Some(self.0[index].value), + Err(_) => None, + } + } + + /// Sets the auto-compounding value for a delegation. The `delegations_config` must be a sorted + /// vector for binary_search to work. + pub fn set_for_delegator(&mut self, delegator: T::AccountId, value: Percent) -> Result> { + match self.0.binary_search_by(|d| d.delegator.cmp(&delegator)) { + Ok(index) => + if self.0[index].value == value { + Ok(false) + } else { + self.0[index].value = value; + Ok(true) + }, + Err(index) => { + self.0 + .try_insert(index, AutoCompoundConfig { delegator, value }) + .map_err(|_| Error::::ExceedMaxDelegationsPerDelegator)?; + Ok(true) + }, + } + } + + /// Removes the auto-compounding value for a delegation. + /// Returns `true` if the entry was removed, `false` otherwise. The `delegations_config` must be a + /// sorted vector for binary_search to work. + pub fn remove_for_delegator(&mut self, delegator: &T::AccountId) -> bool { + match self.0.binary_search_by(|d| d.delegator.cmp(delegator)) { + Ok(index) => { + self.0.remove(index); + true + }, + Err(_) => false, + } + } + + /// Returns the length of the inner vector. + pub fn len(&self) -> u32 { + self.0.len() as u32 + } + + /// Returns a reference to the inner vector. + #[cfg(test)] + pub fn inner( + &self, + ) -> &BoundedVec< + AutoCompoundConfig, + AddGet, + > { + &self.0 + } + + /// Converts the [AutoCompoundDelegations] into the inner vector. + #[cfg(test)] + pub fn into_inner( + self, + ) -> BoundedVec< + AutoCompoundConfig, + AddGet, + > { + self.0 + } + + // -- pallet functions -- + + /// Delegates and sets the auto-compounding config. The function skips inserting auto-compound + /// storage and validation, if the auto-compound value is 0%. + pub(crate) fn delegate_with_auto_compound( + candidate: T::AccountId, + delegator: T::AccountId, + amount: BalanceOf, + auto_compound: Percent, + candidate_delegation_count_hint: u32, + candidate_auto_compounding_delegation_count_hint: u32, + delegation_count_hint: u32, + ) -> DispatchResultWithPostInfo { + // check that caller can lock the amount before any changes to storage + ensure!( + >::get_delegator_stakable_free_balance(&delegator) >= amount, + Error::::InsufficientBalance + ); + + let mut delegator_state = if let Some(mut state) = >::get(&delegator) { + // delegation after first + ensure!(amount >= T::MinDelegation::get(), Error::::DelegationBelowMin); + ensure!( + delegation_count_hint >= state.delegations.0.len() as u32, + Error::::TooLowDelegationCountToDelegate + ); + ensure!( + (state.delegations.0.len() as u32) < T::MaxDelegationsPerDelegator::get(), + Error::::ExceedMaxDelegationsPerDelegator + ); + ensure!( + state.add_delegation(Bond { owner: candidate.clone(), amount }), + Error::::AlreadyDelegatedCandidate + ); + state + } else { + // first delegation + ensure!(amount >= T::MinDelegatorStk::get(), Error::::DelegatorBondBelowMin); + ensure!(!>::is_candidate(&delegator), Error::::CandidateExists); + Delegator::new(delegator.clone(), candidate.clone(), amount) + }; + let mut candidate_state = >::get(&candidate).ok_or(Error::::CandidateDNE)?; + ensure!( + candidate_delegation_count_hint >= candidate_state.delegation_count, + Error::::TooLowCandidateDelegationCountToDelegate + ); + + let auto_compounding_state = if !auto_compound.is_zero() { + let auto_compounding_state = Self::get_storage(&candidate); + ensure!( + auto_compounding_state.len() <= candidate_auto_compounding_delegation_count_hint, + >::TooLowCandidateAutoCompoundingDelegationCountToDelegate, + ); + Some(auto_compounding_state) + } else { + None + }; + + // add delegation to candidate + let (delegator_position, less_total_staked) = + candidate_state.add_delegation::(&candidate, Bond { owner: delegator.clone(), amount })?; + + // lock delegator amount + delegator_state.adjust_bond_lock::(BondAdjust::Increase(amount))?; + + // adjust total locked, + // only is_some if kicked the lowest bottom as a consequence of this new delegation + let net_total_increase = if let Some(less) = less_total_staked { amount.saturating_sub(less) } else { amount }; + let new_total_locked = >::get().saturating_add(net_total_increase); + + // maybe set auto-compound config, state is Some if the percent is non-zero + if let Some(mut state) = auto_compounding_state { + state.set_for_delegator(delegator.clone(), auto_compound)?; + state.set_storage(&candidate); + } + + >::put(new_total_locked); + >::insert(&candidate, candidate_state); + >::insert(&delegator, delegator_state); + >::deposit_event(Event::Delegation { + delegator, + locked_amount: amount, + candidate, + delegator_position, + auto_compound, + }); + + Ok(().into()) + } + + /// Sets the auto-compounding value for a delegation. The config is removed if value is zero. + pub(crate) fn set_auto_compound( + candidate: T::AccountId, + delegator: T::AccountId, + value: Percent, + candidate_auto_compounding_delegation_count_hint: u32, + delegation_count_hint: u32, + ) -> DispatchResultWithPostInfo { + let delegator_state = >::get(&delegator).ok_or(>::DelegatorDNE)?; + ensure!( + delegator_state.delegations.0.len() <= delegation_count_hint as usize, + >::TooLowDelegationCountToAutoCompound, + ); + ensure!(delegator_state.delegations.0.iter().any(|b| b.owner == candidate), >::DelegationDNE,); + + let mut auto_compounding_state = Self::get_storage(&candidate); + ensure!( + auto_compounding_state.len() <= candidate_auto_compounding_delegation_count_hint, + >::TooLowCandidateAutoCompoundingDelegationCountToAutoCompound, + ); + let state_updated = if value.is_zero() { + auto_compounding_state.remove_for_delegator(&delegator) + } else { + auto_compounding_state.set_for_delegator(delegator.clone(), value)? + }; + if state_updated { + auto_compounding_state.set_storage(&candidate); + } + + >::deposit_event(Event::AutoCompoundSet { candidate, delegator, value }); + + Ok(().into()) + } + + /// Removes the auto-compounding value for a delegation. This should be called when the + /// delegation is revoked to cleanup storage. Storage is only written iff the entry existed. + pub(crate) fn remove_auto_compound(candidate: &T::AccountId, delegator: &T::AccountId) { + let mut auto_compounding_state = Self::get_storage(candidate); + if auto_compounding_state.remove_for_delegator(delegator) { + auto_compounding_state.set_storage(candidate); + } + } + + /// Returns the value of auto-compound, if it exists for a given delegation, zero otherwise. + pub(crate) fn auto_compound(candidate: &T::AccountId, delegator: &T::AccountId) -> Percent { + let delegations_config = Self::get_storage(candidate); + delegations_config.get_for_delegator(delegator).unwrap_or_else(Percent::zero) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::Test; + + #[test] + fn test_set_for_delegator_inserts_config_and_returns_true_if_entry_missing() { + let mut delegations_config = AutoCompoundDelegations::::new(vec![].try_into().expect("must succeed")); + assert_eq!(true, delegations_config.set_for_delegator(1, Percent::from_percent(50)).expect("must succeed")); + assert_eq!( + vec![AutoCompoundConfig { delegator: 1, value: Percent::from_percent(50) }], + delegations_config.into_inner().into_inner(), + ); + } + + #[test] + fn test_set_for_delegator_updates_config_and_returns_true_if_entry_changed() { + let mut delegations_config = AutoCompoundDelegations::::new( + vec![AutoCompoundConfig { delegator: 1, value: Percent::from_percent(10) }] + .try_into() + .expect("must succeed"), + ); + assert_eq!(true, delegations_config.set_for_delegator(1, Percent::from_percent(50)).expect("must succeed")); + assert_eq!( + vec![AutoCompoundConfig { delegator: 1, value: Percent::from_percent(50) }], + delegations_config.into_inner().into_inner(), + ); + } + + #[test] + fn test_set_for_delegator_updates_config_and_returns_false_if_entry_unchanged() { + let mut delegations_config = AutoCompoundDelegations::::new( + vec![AutoCompoundConfig { delegator: 1, value: Percent::from_percent(10) }] + .try_into() + .expect("must succeed"), + ); + assert_eq!(false, delegations_config.set_for_delegator(1, Percent::from_percent(10)).expect("must succeed")); + assert_eq!( + vec![AutoCompoundConfig { delegator: 1, value: Percent::from_percent(10) }], + delegations_config.into_inner().into_inner(), + ); + } + + #[test] + fn test_remove_for_delegator_returns_false_if_entry_was_missing() { + let mut delegations_config = AutoCompoundDelegations::::new(vec![].try_into().expect("must succeed")); + assert_eq!(false, delegations_config.remove_for_delegator(&1),); + } + + #[test] + fn test_remove_delegation_config_returns_true_if_entry_existed() { + let mut delegations_config = AutoCompoundDelegations::::new( + vec![AutoCompoundConfig { delegator: 1, value: Percent::from_percent(10) }] + .try_into() + .expect("must succeed"), + ); + assert_eq!(true, delegations_config.remove_for_delegator(&1)); + } +} diff --git a/pallets/parachain-staking/src/benchmarking.rs b/pallets/parachain-staking/src/benchmarking.rs deleted file mode 100644 index be40ccd41..000000000 --- a/pallets/parachain-staking/src/benchmarking.rs +++ /dev/null @@ -1,638 +0,0 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH - -// The KILT Blockchain 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. - -// The KILT Blockchain 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 . - -// If you feel like getting in touch with us, you can do so at info@botlabs.org -#![cfg(feature = "runtime-benchmarks")] - -//! Benchmarking -use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, Zero}; -use frame_support::{ - assert_ok, - traits::{Currency, Get, OnInitialize}, -}; -use frame_system::{Pallet as System, RawOrigin}; -use pallet_session::Pallet as Session; -use sp_runtime::{ - traits::{One, SaturatedConversion, StaticLookup}, - Perquintill, -}; -use sp_std::{convert::TryInto, vec::Vec}; - -use crate::{types::RoundInfo, *}; - -const COLLATOR_ACCOUNT_SEED: u32 = 0; -const DELEGATOR_ACCOUNT_SEED: u32 = 1; - -/// Fills the candidate pool up to `num_candidates`. -fn setup_collator_candidates( - num_candidates: u32, default_amount: Option, -) -> Vec { - let current_collator_count = TopCandidates::::get().len().saturated_into::(); - let collators: Vec = (current_collator_count..num_candidates) - .map(|i| account("collator", i.saturated_into::(), COLLATOR_ACCOUNT_SEED)) - .collect(); - let amount: T::CurrencyBalance = default_amount.unwrap_or_else(T::MinCollatorCandidateStake::get); - - for acc in collators.iter() { - T::Currency::make_free_balance_be(acc, amount); - assert_ok!(Pallet::::join_candidates( - T::RuntimeOrigin::from(Some(acc.clone()).into()), - amount, - )); - assert_eq!(CandidatePool::::get(acc).unwrap().stake, amount); - } - - TopCandidates::::get() - .into_bounded_vec() - .into_inner() - .drain(..) - .map(|c| c.owner) - .collect() -} - -fn fill_delegators(num_delegators: u32, collator: T::AccountId, collator_seed: u32) -> Vec { - let state = CandidatePool::::get(&collator).unwrap(); - let current_delegators = state.delegators.len().saturated_into::(); - - let delegators: Vec = (current_delegators..num_delegators) - .map(|i| { - account( - "delegator", - i.saturated_into::(), - DELEGATOR_ACCOUNT_SEED * 1000 + collator_seed, - ) - }) - .collect(); - - for acc in delegators.iter() { - T::Currency::make_free_balance_be(acc, T::MinDelegatorStake::get()); - assert_ok!(Pallet::::join_delegators( - T::RuntimeOrigin::from(Some(acc.clone()).into()), - T::Lookup::unlookup(collator.clone()), - T::MinDelegatorStake::get(), - )); - } - - delegators -} - -// fills unstake BTreeMap by unstaked many entries of 1 -fn fill_unstaking(collator: &T::AccountId, delegator: Option<&T::AccountId>, unstaked: u64) -where - u64: Into<::BlockNumber>, -{ - let who = delegator.unwrap_or(collator); - assert_eq!(Unstaking::::get(who).len(), 0); - while System::::block_number() < unstaked.into() { - if let Some(delegator) = delegator { - assert_ok!(Pallet::::delegator_stake_less( - RawOrigin::Signed(delegator.clone()).into(), - T::CurrencyBalance::one() - )); - } else { - assert_ok!(Pallet::::candidate_stake_less( - RawOrigin::Signed(collator.clone()).into(), - T::CurrencyBalance::one() - )); - } - System::::set_block_number(System::::block_number() + T::BlockNumber::one()); - } - assert_eq!(Unstaking::::get(who).len() as u64, unstaked); - assert!(Unstaking::::get(who).len() <= T::MaxUnstakeRequests::get().try_into().unwrap()); -} - -benchmarks! { - where_clause { where u64: Into<::BlockNumber> } - - on_initialize_no_action { - assert_eq!(Round::::get().current, 0u32); - let block = T::BlockNumber::one(); - }: { Pallet::::on_initialize(block) } - verify { - assert_eq!(Round::::get().current, 0u32); - } - - on_initialize_round_update { - let round = Round::::get(); - assert_eq!(round.current, 0u32); - }: { Pallet::::on_initialize(round.length) } - verify { - assert_eq!(Round::::get().current, 1u32); - } - - on_initialize_network_rewards { - let issuance = T::Currency::total_issuance(); - // if we only add by one, we also initialize a new year - let block = T::NetworkRewardStart::get() + T::BlockNumber::one() * 2_u64.into(); - }: { Pallet::::on_initialize(block) } - verify { - let new_issuance = T::Currency::total_issuance(); - let max_col_reward = InflationConfig::::get().collator.reward_rate.per_block * MaxCollatorCandidateStake::::get() * MaxSelectedCandidates::::get().into(); - let network_block_reward = T::NetworkRewardRate::get() * max_col_reward; - assert!(new_issuance > issuance); - assert_eq!(new_issuance - issuance, network_block_reward) - } - - force_new_round { - let round = Round::::get(); - let now = System::::block_number(); - assert_eq!(round.current, 0); - assert_eq!(Session::::current_index(), 0); - assert!(!ForceNewRound::::get()); - }: _(RawOrigin::Root) - verify { - assert!(ForceNewRound::::get()); - assert_eq!(Session::::current_index(), 0); - - // jump to next block to trigger new round - let now = now + T::BlockNumber::one(); - System::::set_block_number(now); - Session::::on_initialize(now); - assert_eq!(Session::::current_index(), 1); - assert_eq!(Round::::get(), RoundInfo { - current: 1, - first: now, - length: round.length, - }); - assert!(!ForceNewRound::::get()); - } - - set_inflation { - let n in 0 .. T::MaxTopCandidates::get(); - let m in 0 .. T::MaxDelegatorsPerCollator::get(); - - let candidates = setup_collator_candidates::(n, None); - for (i, c) in candidates.iter().enumerate() { - fill_delegators::(m, c.clone(), i.saturated_into::()); - Rewards::::insert(c, T::Balance::one()); - } - - let inflation = InflationInfo::new( - T::BLOCKS_PER_YEAR.saturated_into(), - Perquintill::from_percent(10), - Perquintill::from_percent(15), - Perquintill::from_percent(40), - Perquintill::from_percent(10) - ); - }: _(RawOrigin::Root, inflation.collator.max_rate, inflation.collator.reward_rate.annual, inflation.delegator.max_rate, inflation.delegator.reward_rate.annual) - verify { - assert_eq!(InflationConfig::::get(), inflation); - candidates.into_iter().for_each(|candidate| { - assert!(!Rewards::::get(&candidate).is_zero()); - }); - } - - set_max_selected_candidates { - let n in (T::MinCollators::get()) .. T::MaxTopCandidates::get(); - let m in 0 .. T::MaxDelegatorsPerCollator::get(); - - let candidates = setup_collator_candidates::(n, None); - for (i, c) in candidates.iter().enumerate() { - fill_delegators::(m, c.clone(), i.saturated_into::()); - } - let old_candidate = candidates[0].clone(); - }: _(RawOrigin::Root, n) - verify { - assert_eq!(MaxSelectedCandidates::::get(), n); - } - - set_blocks_per_round { - let bpr: T::BlockNumber = T::MinBlocksPerRound::get() + T::BlockNumber::one(); - }: _(RawOrigin::Root, bpr) - verify { - assert_eq!(Round::::get().length, bpr); - } - - force_remove_candidate { - let n in (T::MinCollators::get() + 1) .. T::MaxTopCandidates::get(); - let m in 0 .. T::MaxDelegatorsPerCollator::get(); - - let candidates = setup_collator_candidates::(n, None); - for (i, c) in candidates.iter().enumerate() { - fill_delegators::(m, c.clone(), i.saturated_into::()); - } - let candidate = candidates[0].clone(); - let unlookup_candidate = T::Lookup::unlookup(candidate.clone()); - }: _(RawOrigin::Root, unlookup_candidate) - verify { - let candidates = TopCandidates::::get(); - assert!(!candidates.into_iter().any(|other| other.owner == candidate)); - } - - join_candidates { - let n in 1 .. T::MaxTopCandidates::get() - 1; - let m in 0 .. T::MaxDelegatorsPerCollator::get(); - - let min_candidate_stake = T::MinCollatorCandidateStake::get(); - let candidates = setup_collator_candidates::(n, None); - for (i, c) in candidates.iter().enumerate() { - fill_delegators::(m, c.clone(), i.saturated_into::()); - } - - let new_candidate = account("new_collator", u32::MAX , COLLATOR_ACCOUNT_SEED); - T::Currency::make_free_balance_be(&new_candidate, min_candidate_stake); - - let origin = RawOrigin::Signed(new_candidate.clone()); - }: _(origin, min_candidate_stake) - verify { - let candidates = TopCandidates::::get(); - assert!(candidates.into_iter().any(|other| other.owner == new_candidate)); - } - - init_leave_candidates { - let n in (T::MinCollators::get() + 1) .. T::MaxTopCandidates::get() - 1; - let m in 0 .. T::MaxDelegatorsPerCollator::get(); - - let candidates = setup_collator_candidates::(n, None); - for (i, c) in candidates.iter().enumerate() { - fill_delegators::(m, c.clone(), i.saturated_into::()); - } - - let now = Round::::get().current; - let candidate = candidates[0].clone(); - - let origin = RawOrigin::Signed(candidate.clone()); - }: _(origin) - verify { - let candidates = TopCandidates::::get(); - assert!(!candidates.into_iter().any(|other| other.owner == candidate)); - let unlocking_at = now.saturating_add(T::ExitQueueDelay::get()); - assert!(CandidatePool::::get(candidate).unwrap().can_exit(unlocking_at)); - } - - cancel_leave_candidates { - let n in (T::MinCollators::get() + 1) .. T::MaxTopCandidates::get() - 1; - let m in 0 .. T::MaxDelegatorsPerCollator::get(); - - let candidates = setup_collator_candidates::(n, None); - for (i, c) in candidates.iter().enumerate() { - fill_delegators::(m, c.clone(), i.saturated_into::()); - } - - let candidate = candidates[0].clone(); - assert_ok!(Pallet::::init_leave_candidates(RawOrigin::Signed(candidate.clone()).into())); - - let origin = RawOrigin::Signed(candidate.clone()); - }: _(origin) - verify { - let candidates = TopCandidates::::get(); - assert!(candidates.into_iter().any(|other| other.owner == candidate)); - } - - execute_leave_candidates { - let n in (T::MinCollators::get() + 1) .. T::MaxTopCandidates::get() - 1; - let m in 0 .. T::MaxDelegatorsPerCollator::get(); - - let u = T::MaxUnstakeRequests::get() - 1; - let candidates = setup_collator_candidates::(n, None); - for (i, c) in candidates.iter().enumerate() { - fill_delegators::(m, c.clone(), i.saturated_into::()); - } - let candidate = candidates[0].clone(); - - // increase stake so we can unstake, because current stake is minimum - let more_stake = T::MinCollatorCandidateStake::get(); - T::Currency::make_free_balance_be(&candidate, T::CurrencyBalance::from(u128::MAX)); - assert_ok!(Pallet::::candidate_stake_more(RawOrigin::Signed(candidate.clone()).into(), more_stake)); - - // fill unstake BTreeMap by unstaked many entries of 1 - fill_unstaking::(&candidate, None, u as u64); - - // go to block in which we can exit - assert_ok!(Pallet::::init_leave_candidates(RawOrigin::Signed(candidate.clone()).into())); - - for i in 1..=T::ExitQueueDelay::get() { - let round = Round::::get(); - let now = round.first + round.length; - System::::set_block_number(now); - Pallet::::on_initialize(now); - } - let unlookup_candidate = T::Lookup::unlookup(candidate.clone()); - - let origin = RawOrigin::Signed(candidate.clone()); - }: _(origin, unlookup_candidate) - verify { - // should have one more entry in Unstaking - assert_eq!(Unstaking::::get(&candidate).len().saturated_into::(), u.saturating_add(1u32)); - } - - candidate_stake_more { - let n in 1 .. T::MaxTopCandidates::get() - 1; - let m in 0 .. T::MaxDelegatorsPerCollator::get(); - let u in 0 .. (T::MaxUnstakeRequests::get().saturated_into::() - 1); - - let candidates = setup_collator_candidates::(n, None); - for (i, c) in candidates.iter().enumerate() { - fill_delegators::(m, c.clone(), i.saturated_into::()); - } - let candidate = candidates[0].clone(); - - let old_stake = CandidatePool::::get(&candidate).unwrap().stake; - let more_stake = T::MinCollatorCandidateStake::get(); - - // increase stake so we can unstake, because current stake is minimum - T::Currency::make_free_balance_be(&candidate, T::CurrencyBalance::from(u128::MAX)); - assert_ok!(Pallet::::candidate_stake_more(RawOrigin::Signed(candidate.clone()).into(), more_stake)); - - // fill unstake BTreeMap by unstaked many entries of 1 - fill_unstaking::(&candidate, None, u as u64); - - let origin = RawOrigin::Signed(candidate.clone()); - }: _(origin, more_stake) - verify { - let new_stake = CandidatePool::::get(&candidate).unwrap().stake; - assert!(Unstaking::::get(candidate).is_empty()); - assert_eq!(new_stake, old_stake + more_stake + more_stake - T::CurrencyBalance::from(u as u64)); - } - - candidate_stake_less { - let n in 1 .. T::MaxTopCandidates::get() - 1; - let m in 0 .. T::MaxDelegatorsPerCollator::get(); - - let candidates = setup_collator_candidates::(n, None); - for (i, c) in candidates.iter().enumerate() { - fill_delegators::(m, c.clone(), i.saturated_into::()); - } - let candidate = candidates[0].clone(); - - // increase stake of candidate to later decrease it again - let old_stake = CandidatePool::::get(&candidate).unwrap().stake; - let more_stake = T::MinCollatorCandidateStake::get(); - - T::Currency::make_free_balance_be(&candidate, T::CurrencyBalance::from(u128::MAX)); - Pallet::::candidate_stake_more(RawOrigin::Signed(candidate.clone()).into(), more_stake).expect("should increase stake"); - - let new_stake = CandidatePool::::get(&candidate).unwrap().stake; - assert_eq!(new_stake, old_stake + more_stake); - - let origin = RawOrigin::Signed(candidate.clone()); - }: _(origin, more_stake) - verify { - let new_stake = CandidatePool::::get(&candidate).unwrap().stake; - assert_eq!(new_stake, old_stake); - } - - join_delegators { - let n in 1 .. T::MaxTopCandidates::get(); - let m in 1 .. T::MaxDelegatorsPerCollator::get() - 1; - - let candidates = setup_collator_candidates::(n, None); - for (i, c) in candidates.iter().enumerate() { - fill_delegators::(m, c.clone(), i.saturated_into::()); - } - let collator = candidates[0].clone(); - let delegator = account("new-delegator", 0, DELEGATOR_ACCOUNT_SEED); - let amount = T::MinDelegatorStake::get(); - T::Currency::make_free_balance_be(&delegator, amount + amount + amount + amount); - let unlookup_collator = T::Lookup::unlookup(collator.clone()); - - - let origin = RawOrigin::Signed(delegator.clone()); - }: _(origin, unlookup_collator, amount) - verify { - let state = CandidatePool::::get(&collator).unwrap(); - assert!(state.delegators.into_iter().any(|x| x.owner == delegator)); - } - - delegator_stake_more { - // we need at least 1 collators - let n in 1 .. T::MaxTopCandidates::get(); - // we need at least 1 delegator - let m in 1 .. T::MaxDelegatorsPerCollator::get() - 1; - let u in 1 .. (T::MaxUnstakeRequests::get().saturated_into::() - 1); - - let candidates = setup_collator_candidates::(n, None); - for (i, c) in candidates.iter().enumerate() { - fill_delegators::(m, c.clone(), i.saturated_into::()); - } - let collator = candidates[0].clone(); - let amount = T::MinDelegatorStake::get(); - - // make sure delegator collated to collator - let state = CandidatePool::::get(&collator).unwrap(); - let delegator = state.delegators.into_bounded_vec()[0].owner.clone(); - assert_eq!(DelegatorState::::get(&delegator).unwrap().amount, amount); - - // increase stake so we can unstake, because current stake is minimum - T::Currency::make_free_balance_be(&delegator, T::CurrencyBalance::from(u128::MAX)); - assert_ok!(Pallet::::delegator_stake_more(RawOrigin::Signed(delegator.clone()).into(), T::CurrencyBalance::from(u as u64))); - assert_eq!(DelegatorState::::get(&delegator).unwrap().amount, amount + T::CurrencyBalance::from(u as u64)); - - // fill unstake BTreeMap by unstaked many entries of 1 - fill_unstaking::(&collator, Some(&delegator), u as u64); - assert_eq!(DelegatorState::::get(&delegator).unwrap().amount, amount); - - let origin = RawOrigin::Signed(delegator.clone()); - }: _(origin, amount) - verify { - let state = CandidatePool::::get(&collator).unwrap(); - assert!(state.delegators.into_iter().any(|x| x.owner == delegator)); - assert_eq!(DelegatorState::::get(&delegator).unwrap().amount, amount + amount); - assert!(Unstaking::::get(&delegator).is_empty()); - } - - delegator_stake_less { - // we need at least 1 collators - let n in 1 .. T::MaxTopCandidates::get(); - // we need at least 1 delegator - let m in 1 .. T::MaxDelegatorsPerCollator::get() - 1; - - let candidates = setup_collator_candidates::(n, None); - for (i, c) in candidates.iter().enumerate() { - fill_delegators::(m, c.clone(), i.saturated_into::()); - } - let collator = candidates[0].clone(); - let amount = T::CurrencyBalance::one(); - - // make sure delegator collated to collator - let state = CandidatePool::::get(&collator).unwrap(); - let delegator = state.delegators.into_bounded_vec()[0].owner.clone(); - assert_eq!(DelegatorState::::get(&delegator).unwrap().amount, T::MinDelegatorStake::get()); - - // increase stake so we can unstake, because current stake is minimum - T::Currency::make_free_balance_be(&delegator, T::CurrencyBalance::from(u128::MAX)); - assert_ok!(Pallet::::delegator_stake_more(RawOrigin::Signed(delegator.clone()).into(), amount + amount)); - assert_eq!(DelegatorState::::get(&delegator).unwrap().amount, T::MinDelegatorStake::get() + amount + amount); - - // decrease stake once so we have an unstaking entry for this block - assert_ok!(Pallet::::delegator_stake_less(RawOrigin::Signed(delegator.clone()).into(), amount)); - assert_eq!(DelegatorState::::get(&delegator).unwrap().amount, T::MinDelegatorStake::get() + amount); - assert_eq!(Unstaking::::get(&delegator).len(), 1); - - let origin = RawOrigin::Signed(delegator.clone()); - }: _(origin, amount) - verify { - let state = CandidatePool::::get(&collator).unwrap(); - assert!(state.delegators.into_iter().any(|x| x.owner == delegator)); - assert_eq!(DelegatorState::::get(&delegator).unwrap().amount, T::MinDelegatorStake::get()); - assert_eq!(Unstaking::::get(&delegator).len(), 2); - } - - leave_delegators { - // we need at least 1 collators - let n in 1 .. T::MaxTopCandidates::get(); - // we need at least 1 delegator - let m in 1 .. T::MaxDelegatorsPerCollator::get() - 1; - - let candidates = setup_collator_candidates::(n, None); - for (i, c) in candidates.iter().enumerate() { - fill_delegators::(m, c.clone(), i.saturated_into::()); - } - let collator = candidates[0].clone(); - let amount = T::CurrencyBalance::one(); - - // make sure delegator collated to collator - let state = CandidatePool::::get(&collator).unwrap(); - let delegator = state.delegators.into_bounded_vec()[0].owner.clone(); - assert_eq!(DelegatorState::::get(&delegator).unwrap().amount, T::MinDelegatorStake::get()); - - // increase stake so we can unstake, because current stake is minimum - T::Currency::make_free_balance_be(&delegator, T::CurrencyBalance::from(u128::MAX)); - assert_ok!(Pallet::::delegator_stake_more(RawOrigin::Signed(delegator.clone()).into(), amount + amount)); - assert_eq!(DelegatorState::::get(&delegator).unwrap().amount, T::MinDelegatorStake::get() + amount + amount); - - // decrease stake once so we have an unstaking entry for this block - assert_ok!(Pallet::::delegator_stake_less(RawOrigin::Signed(delegator.clone()).into(), amount)); - assert_eq!(DelegatorState::::get(&delegator).unwrap().amount, T::MinDelegatorStake::get() + amount); - assert_eq!(Unstaking::::get(&delegator).len(), 1); - - let origin = RawOrigin::Signed(delegator.clone()); - }: _(origin) - verify { - let state = CandidatePool::::get(&collator).unwrap(); - assert!(!state.delegators.into_iter().any(|x| x.owner == delegator)); - assert!(DelegatorState::::get(&delegator).is_none()); - assert_eq!(Unstaking::::get(&delegator).len(), 2); - } - - unlock_unstaked { - let u in 1 .. (T::MaxUnstakeRequests::get() - 1); - - let candidate = account("collator", 0u32, COLLATOR_ACCOUNT_SEED); - let free_balance = T::CurrencyBalance::from(u128::MAX); - let stake = T::MinCollatorCandidateStake::get(); - T::Currency::make_free_balance_be(&candidate, free_balance); - assert_ok!(Pallet::::join_candidates( - T::RuntimeOrigin::from(Some(candidate.clone()).into()), - stake, - )); - assert_eq!(pallet_balances::Pallet::::usable_balance(&candidate), (free_balance - T::MinCollatorCandidateStake::get()).into()); - - // increase stake so we can unstake, because current stake is minimum - assert_ok!(Pallet::::candidate_stake_more(RawOrigin::Signed(candidate.clone()).into(), stake)); - - // fill unstake BTreeMap by unstaked many entries of 1 - fill_unstaking::(&candidate, None, u as u64); - assert_eq!(CandidatePool::::get(&candidate).unwrap().stake, stake + stake - T::CurrencyBalance::from(u as u64)); - - // roll to block in which first unstake can be unlocked - System::::set_block_number(T::StakeDuration::get()); - assert_eq!(pallet_balances::Pallet::::usable_balance(&candidate), (free_balance - stake - stake).into()); - let unlookup_candidate = T::Lookup::unlookup(candidate.clone()); - - let origin = RawOrigin::Signed(candidate.clone()); - }: _(origin, unlookup_candidate) - verify { - assert_eq!(Unstaking::::get(&candidate).len().saturated_into::(), u.saturating_sub(1u32)); - assert_eq!(pallet_balances::Pallet::::usable_balance(&candidate), (free_balance - stake - stake + T::CurrencyBalance::one()).into()); - } - - set_max_candidate_stake { - let old = MaxCollatorCandidateStake::::get(); - let new = MaxCollatorCandidateStake::::get() + T::CurrencyBalance::from(10u128); - }: _(RawOrigin::Root, new) - verify { - assert_eq!(MaxCollatorCandidateStake::::get(), new); - } - - increment_delegator_rewards { - let collator = setup_collator_candidates::(1, None)[0].clone(); - let delegator = fill_delegators::(1, collator.clone(), COLLATOR_ACCOUNT_SEED)[0].clone(); - - // mock high values to compensate for tiny values in unit test env - let stake = T::CurrencyBalance::from(1_000_000_000_000_000_000u128); - DelegatorState::::insert(&delegator, crate::types::Delegator { owner: collator.clone(), amount: stake}); - BlocksAuthored::::insert(&collator, u64::MAX.into()); - - assert!(Rewards::::get(&delegator).is_zero()); - let origin = RawOrigin::Signed(delegator.clone()); - }: _(origin) - verify { - assert!(!Rewards::::get(&delegator).is_zero()); - assert_eq!(BlocksRewarded::::get(&delegator), u64::MAX.into()); - } - - increment_collator_rewards { - let collator = setup_collator_candidates::(1, None)[0].clone(); - - // mock high counter to compensate for tiny amounts in unit test env - BlocksAuthored::::insert(&collator, u64::MAX.into()); - assert!(Rewards::::get(&collator).is_zero(), "reward {:?}", Rewards::::get(&collator)); - let origin = RawOrigin::Signed(collator.clone()); - }: _(origin) - verify { - assert!(!Rewards::::get(&collator).is_zero()); - assert_eq!(BlocksRewarded::::get(&collator), u64::MAX.into()); - } - - claim_rewards { - let beneficiary = account("beneficiary", 0, 0); - let amount = T::MinCollatorCandidateStake::get(); - T::Currency::make_free_balance_be(&beneficiary, amount); - Rewards::::insert(&beneficiary, amount); - assert_eq!(pallet_balances::Pallet::::usable_balance(&beneficiary), amount.into()); - let origin = RawOrigin::Signed(beneficiary.clone()); - }: _(origin) - verify { - assert!(Rewards::::get(&beneficiary).is_zero()); - assert_eq!(pallet_balances::Pallet::::usable_balance(&beneficiary), (amount + amount).into()); - } - - execute_scheduled_reward_change { - // we need at least 1 collators - let n in 0 .. T::MaxTopCandidates::get(); - // we need at least 1 delegator - let m in 0 .. T::MaxDelegatorsPerCollator::get(); - - let candidates = setup_collator_candidates::(n, None); - for (i, c) in candidates.iter().enumerate() { - fill_delegators::(m, c.clone(), i.saturated_into::()); - } - let collator = candidates[0].clone(); - - let old = InflationConfig::::get(); - assert_eq!(LastRewardReduction::::get(), T::BlockNumber::zero()); - System::::set_block_number(T::BLOCKS_PER_YEAR + T::BlockNumber::one()); - }: _(RawOrigin::Signed(collator)) - verify { - let new = InflationConfig::::get(); - assert_eq!(LastRewardReduction::::get(), T::BlockNumber::one()); - assert_eq!(new.collator.max_rate, old.collator.max_rate); - assert_eq!(new.delegator.max_rate, old.delegator.max_rate); - assert!(new.collator.reward_rate.annual < old.collator.reward_rate.annual); - assert!(new.delegator.reward_rate.annual < old.delegator.reward_rate.annual); - } - -} - -impl_benchmark_test_suite!( - Pallet, - crate::mock::ExtBuilder::default() - .with_balances(vec![(u64::MAX, 1000 * crate::mock::MILLI_KILT)]) - .with_collators(vec![(u64::MAX, 1000 * crate::mock::MILLI_KILT)]) - .build(), - crate::mock::Test, -); diff --git a/pallets/parachain-staking/src/benchmarks.rs b/pallets/parachain-staking/src/benchmarks.rs new file mode 100644 index 000000000..9380f521c --- /dev/null +++ b/pallets/parachain-staking/src/benchmarks.rs @@ -0,0 +1,1476 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +#![cfg(feature = "runtime-benchmarks")] + +//! Benchmarking +use crate::{ + AwardedPts, BalanceOf, Call, CandidateBondLessRequest, Config, DelegationAction, Pallet, ParachainBondConfig, + ParachainBondInfo, Points, Range, RewardPayment, Round, ScheduledRequest, Staked, TopDelegations, +}; +use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, vec}; +use frame_support::traits::{Currency, Get, OnFinalize, OnInitialize}; +use frame_system::RawOrigin; +use sp_runtime::{Perbill, Percent}; +use sp_std::vec::Vec; + +/// Minimum collator candidate stake +fn min_candidate_stk() -> BalanceOf { + <::MinCandidateStk as Get>>::get() +} + +/// Minimum delegator stake +fn min_delegator_stk() -> BalanceOf { + <::MinDelegatorStk as Get>>::get() +} + +/// Create a funded user. +/// Extra + min_candidate_stk is total minted funds +/// Returns tuple (id, balance) +fn create_funded_user(string: &'static str, n: u32, extra: BalanceOf) -> (T::AccountId, BalanceOf) { + const SEED: u32 = 0; + let user = account(string, n, SEED); + let min_candidate_stk = min_candidate_stk::(); + let total = min_candidate_stk + extra; + T::Currency::make_free_balance_be(&user, total); + T::Currency::issue(total); + (user, total) +} + +/// Create a funded delegator. +fn create_funded_delegator( + string: &'static str, + n: u32, + extra: BalanceOf, + collator: T::AccountId, + min_bond: bool, + collator_delegator_count: u32, +) -> Result { + let (user, total) = create_funded_user::(string, n, extra); + let bond = if min_bond { min_delegator_stk::() } else { total }; + Pallet::::delegate( + RawOrigin::Signed(user.clone()).into(), + collator, + bond, + collator_delegator_count, + 0u32, // first delegation for all calls + )?; + Ok(user) +} + +/// Create a funded collator. +fn create_funded_collator( + string: &'static str, + n: u32, + extra: BalanceOf, + min_bond: bool, + candidate_count: u32, +) -> Result { + let (user, total) = create_funded_user::(string, n, extra); + let bond = if min_bond { min_candidate_stk::() } else { total }; + Pallet::::join_candidates(RawOrigin::Signed(user.clone()).into(), bond, candidate_count)?; + Ok(user) +} + +// Simulate staking on finalize by manually setting points +fn parachain_staking_on_finalize(author: T::AccountId) { + let now = >::get().current; + let score_plus_20 = >::get(now, &author).saturating_add(20); + >::insert(now, author, score_plus_20); + >::mutate(now, |x| *x = x.saturating_add(20)); +} + +/// Run to end block and author +fn roll_to_and_author(round_delay: u32, author: T::AccountId) { + let total_rounds = round_delay + 1u32; + let round_length: T::BlockNumber = Pallet::::round().length.into(); + let mut now = >::block_number() + 1u32.into(); + let end = Pallet::::round().first + (round_length * total_rounds.into()); + while now < end { + parachain_staking_on_finalize::(author.clone()); + >::on_finalize(>::block_number()); + >::set_block_number(>::block_number() + 1u32.into()); + >::on_initialize(>::block_number()); + Pallet::::on_initialize(>::block_number()); + now += 1u32.into(); + } +} + +const USER_SEED: u32 = 999666; +struct Seed { + pub inner: u32, +} +impl Seed { + fn new() -> Self { + Seed { inner: USER_SEED } + } + + pub fn take(&mut self) -> u32 { + let v = self.inner; + self.inner += 1; + v + } +} + +benchmarks! { + // MONETARY ORIGIN DISPATCHABLES + set_staking_expectations { + let stake_range: Range> = Range { + min: 100u32.into(), + ideal: 200u32.into(), + max: 300u32.into(), + }; + }: _(RawOrigin::Root, stake_range) + verify { + assert_eq!(Pallet::::inflation_config().expect, stake_range); + } + + set_inflation { + let inflation_range: Range = Range { + min: Perbill::from_perthousand(1), + ideal: Perbill::from_perthousand(2), + max: Perbill::from_perthousand(3), + }; + + }: _(RawOrigin::Root, inflation_range) + verify { + assert_eq!(Pallet::::inflation_config().annual, inflation_range); + } + + set_parachain_bond_account { + let parachain_bond_account: T::AccountId = account("TEST", 0u32, USER_SEED); + }: _(RawOrigin::Root, parachain_bond_account.clone()) + verify { + assert_eq!(Pallet::::parachain_bond_info().account, parachain_bond_account); + } + + set_parachain_bond_reserve_percent { + }: _(RawOrigin::Root, Percent::from_percent(33)) + verify { + assert_eq!(Pallet::::parachain_bond_info().percent, Percent::from_percent(33)); + } + + // ROOT DISPATCHABLES + + set_total_selected { + Pallet::::set_blocks_per_round(RawOrigin::Root.into(), 101u32)?; + }: _(RawOrigin::Root, 100u32) + verify { + assert_eq!(Pallet::::total_selected(), 100u32); + } + + set_collator_commission {}: _(RawOrigin::Root, Perbill::from_percent(33)) + verify { + assert_eq!(Pallet::::collator_commission(), Perbill::from_percent(33)); + } + + set_blocks_per_round {}: _(RawOrigin::Root, 1200u32) + verify { + assert_eq!(Pallet::::round().length, 1200u32); + } + + // USER DISPATCHABLES + + join_candidates { + let x in 3..1_000; + // Worst Case Complexity is insertion into an ordered list so \exists full list before call + let mut candidate_count = 1u32; + for i in 2..x { + let seed = USER_SEED - i; + let collator = create_funded_collator::( + "collator", + seed, + 0u32.into(), + true, + candidate_count + )?; + candidate_count += 1u32; + } + let (caller, min_candidate_stk) = create_funded_user::("caller", USER_SEED, 0u32.into()); + }: _(RawOrigin::Signed(caller.clone()), min_candidate_stk, candidate_count) + verify { + assert!(Pallet::::is_candidate(&caller)); + } + + // This call schedules the collator's exit and removes them from the candidate pool + // -> it retains the self-bond and delegator bonds + schedule_leave_candidates { + let x in 3..1_000; + // Worst Case Complexity is removal from an ordered list so \exists full list before call + let mut candidate_count = 1u32; + for i in 2..x { + let seed = USER_SEED - i; + let collator = create_funded_collator::( + "collator", + seed, + 0u32.into(), + true, + candidate_count + )?; + candidate_count += 1u32; + } + let caller: T::AccountId = create_funded_collator::( + "caller", + USER_SEED, + 0u32.into(), + true, + candidate_count, + )?; + candidate_count += 1u32; + }: _(RawOrigin::Signed(caller.clone()), candidate_count) + verify { + assert!(Pallet::::candidate_info(&caller).expect("must exist").is_leaving()); + } + + execute_leave_candidates { + // x is total number of delegations for the candidate + let x in 2..(<::MaxTopDelegationsPerCandidate as Get>::get() + + <::MaxBottomDelegationsPerCandidate as Get>::get()); + let candidate: T::AccountId = create_funded_collator::( + "unique_caller", + USER_SEED - 100, + 0u32.into(), + true, + 1u32, + )?; + // 2nd delegation required for all delegators to ensure DelegatorState updated not removed + let second_candidate: T::AccountId = create_funded_collator::( + "unique__caller", + USER_SEED - 99, + 0u32.into(), + true, + 2u32, + )?; + let mut delegators: Vec = Vec::new(); + let mut col_del_count = 0u32; + for i in 1..x { + let seed = USER_SEED + i; + let delegator = create_funded_delegator::( + "delegator", + seed, + min_delegator_stk::(), + candidate.clone(), + true, + col_del_count, + )?; + Pallet::::delegate( + RawOrigin::Signed(delegator.clone()).into(), + second_candidate.clone(), + min_delegator_stk::(), + col_del_count, + 1u32, + )?; + Pallet::::schedule_revoke_delegation( + RawOrigin::Signed(delegator.clone()).into(), + candidate.clone() + )?; + delegators.push(delegator); + col_del_count += 1u32; + } + Pallet::::schedule_leave_candidates( + RawOrigin::Signed(candidate.clone()).into(), + 3u32 + )?; + roll_to_and_author::(2, candidate.clone()); + }: _(RawOrigin::Signed(candidate.clone()), candidate.clone(), col_del_count) + verify { + assert!(Pallet::::candidate_info(&candidate).is_none()); + assert!(Pallet::::candidate_info(&second_candidate).is_some()); + for delegator in delegators { + assert!(Pallet::::is_delegator(&delegator)); + } + } + + cancel_leave_candidates { + let x in 3..1_000; + // Worst Case Complexity is removal from an ordered list so \exists full list before call + let mut candidate_count = 1u32; + for i in 2..x { + let seed = USER_SEED - i; + let collator = create_funded_collator::( + "collator", + seed, + 0u32.into(), + true, + candidate_count + )?; + candidate_count += 1u32; + } + let caller: T::AccountId = create_funded_collator::( + "caller", + USER_SEED, + 0u32.into(), + true, + candidate_count, + )?; + candidate_count += 1u32; + Pallet::::schedule_leave_candidates( + RawOrigin::Signed(caller.clone()).into(), + candidate_count + )?; + candidate_count -= 1u32; + }: _(RawOrigin::Signed(caller.clone()), candidate_count) + verify { + assert!(Pallet::::candidate_info(&caller).expect("must exist").is_active()); + } + + go_offline { + let caller: T::AccountId = create_funded_collator::( + "collator", + USER_SEED, + 0u32.into(), + true, + 1u32 + )?; + }: _(RawOrigin::Signed(caller.clone())) + verify { + assert!(!Pallet::::candidate_info(&caller).expect("must exist").is_active()); + } + + go_online { + let caller: T::AccountId = create_funded_collator::( + "collator", + USER_SEED, + 0u32.into(), + true, + 1u32 + )?; + Pallet::::go_offline(RawOrigin::Signed(caller.clone()).into())?; + }: _(RawOrigin::Signed(caller.clone())) + verify { + assert!(Pallet::::candidate_info(&caller).expect("must exist").is_active()); + } + + candidate_bond_more { + let more = min_candidate_stk::(); + let caller: T::AccountId = create_funded_collator::( + "collator", + USER_SEED, + more, + true, + 1u32, + )?; + }: _(RawOrigin::Signed(caller.clone()), more) + verify { + let expected_bond = more * 2u32.into(); + assert_eq!( + Pallet::::candidate_info(&caller).expect("candidate was created, qed").bond, + expected_bond, + ); + } + + schedule_candidate_bond_less { + let min_candidate_stk = min_candidate_stk::(); + let caller: T::AccountId = create_funded_collator::( + "collator", + USER_SEED, + min_candidate_stk, + false, + 1u32, + )?; + }: _(RawOrigin::Signed(caller.clone()), min_candidate_stk) + verify { + let state = Pallet::::candidate_info(&caller).expect("request bonded less so exists"); + assert_eq!( + state.request, + Some(CandidateBondLessRequest { + amount: min_candidate_stk, + when_executable: 3, + }) + ); + } + + execute_candidate_bond_less { + let min_candidate_stk = min_candidate_stk::(); + let caller: T::AccountId = create_funded_collator::( + "collator", + USER_SEED, + min_candidate_stk, + false, + 1u32, + )?; + Pallet::::schedule_candidate_bond_less( + RawOrigin::Signed(caller.clone()).into(), + min_candidate_stk + )?; + roll_to_and_author::(2, caller.clone()); + }: { + Pallet::::execute_candidate_bond_less( + RawOrigin::Signed(caller.clone()).into(), + caller.clone() + )?; + } verify { + assert_eq!( + Pallet::::candidate_info(&caller).expect("candidate was created, qed").bond, + min_candidate_stk, + ); + } + + cancel_candidate_bond_less { + let min_candidate_stk = min_candidate_stk::(); + let caller: T::AccountId = create_funded_collator::( + "collator", + USER_SEED, + min_candidate_stk, + false, + 1u32, + )?; + Pallet::::schedule_candidate_bond_less( + RawOrigin::Signed(caller.clone()).into(), + min_candidate_stk + )?; + }: { + Pallet::::cancel_candidate_bond_less( + RawOrigin::Signed(caller.clone()).into(), + )?; + } verify { + assert!( + Pallet::::candidate_info(&caller).expect("must exist").request.is_none() + ); + } + + delegate { + let x in 3..<::MaxDelegationsPerDelegator as Get>::get(); + let y in 2..<::MaxTopDelegationsPerCandidate as Get>::get(); + // Worst Case is full of delegations before calling `delegate` + let mut collators: Vec = Vec::new(); + // Initialize MaxDelegationsPerDelegator collator candidates + for i in 2..x { + let seed = USER_SEED - i; + let collator = create_funded_collator::( + "collator", + seed, + 0u32.into(), + true, + collators.len() as u32 + 1u32, + )?; + collators.push(collator.clone()); + } + let bond = <::MinDelegatorStk as Get>>::get(); + let extra = if (bond * (collators.len() as u32 + 1u32).into()) > min_candidate_stk::() { + (bond * (collators.len() as u32 + 1u32).into()) - min_candidate_stk::() + } else { + 0u32.into() + }; + let (caller, _) = create_funded_user::("caller", USER_SEED, extra.into()); + // Delegation count + let mut del_del_count = 0u32; + // Nominate MaxDelegationsPerDelegators collator candidates + for col in collators.clone() { + Pallet::::delegate( + RawOrigin::Signed(caller.clone()).into(), col, bond, 0u32, del_del_count + )?; + del_del_count += 1u32; + } + // Last collator to be delegated + let collator: T::AccountId = create_funded_collator::( + "collator", + USER_SEED, + 0u32.into(), + true, + collators.len() as u32 + 1u32, + )?; + // Worst Case Complexity is insertion into an almost full collator + let mut col_del_count = 0u32; + for i in 1..y { + let seed = USER_SEED + i; + let _ = create_funded_delegator::( + "delegator", + seed, + 0u32.into(), + collator.clone(), + true, + col_del_count, + )?; + col_del_count += 1u32; + } + }: _(RawOrigin::Signed(caller.clone()), collator, bond, col_del_count, del_del_count) + verify { + assert!(Pallet::::is_delegator(&caller)); + } + + schedule_leave_delegators { + let collator: T::AccountId = create_funded_collator::( + "collator", + USER_SEED, + 0u32.into(), + true, + 1u32 + )?; + let (caller, _) = create_funded_user::("caller", USER_SEED, 0u32.into()); + let bond = <::MinDelegatorStk as Get>>::get(); + Pallet::::delegate(RawOrigin::Signed( + caller.clone()).into(), + collator.clone(), + bond, + 0u32, + 0u32 + )?; + }: _(RawOrigin::Signed(caller.clone())) + verify { + assert!( + Pallet::::delegation_scheduled_requests(&collator) + .iter() + .any(|r| r.delegator == caller && matches!(r.action, DelegationAction::Revoke(_))) + ); + } + + execute_leave_delegators { + let x in 2..<::MaxDelegationsPerDelegator as Get>::get(); + // Worst Case is full of delegations before execute exit + let mut collators: Vec = Vec::new(); + // Initialize MaxDelegationsPerDelegator collator candidates + for i in 1..x { + let seed = USER_SEED - i; + let collator = create_funded_collator::( + "collator", + seed, + 0u32.into(), + true, + collators.len() as u32 + 1u32 + )?; + collators.push(collator.clone()); + } + let bond = <::MinDelegatorStk as Get>>::get(); + let need = bond * (collators.len() as u32).into(); + let default_minted = min_candidate_stk::(); + let need: BalanceOf = if need > default_minted { + need - default_minted + } else { + 0u32.into() + }; + // Fund the delegator + let (caller, _) = create_funded_user::("caller", USER_SEED, need); + // Delegation count + let mut delegation_count = 0u32; + let author = collators[0].clone(); + // Nominate MaxDelegationsPerDelegators collator candidates + for col in collators { + Pallet::::delegate( + RawOrigin::Signed(caller.clone()).into(), + col, + bond, + 0u32, + delegation_count + )?; + delegation_count += 1u32; + } + Pallet::::schedule_leave_delegators(RawOrigin::Signed(caller.clone()).into())?; + roll_to_and_author::(2, author); + }: _(RawOrigin::Signed(caller.clone()), caller.clone(), delegation_count) + verify { + assert!(Pallet::::delegator_state(&caller).is_none()); + } + + cancel_leave_delegators { + let collator: T::AccountId = create_funded_collator::( + "collator", + USER_SEED, + 0u32.into(), + true, + 1u32 + )?; + let (caller, _) = create_funded_user::("caller", USER_SEED, 0u32.into()); + let bond = <::MinDelegatorStk as Get>>::get(); + Pallet::::delegate(RawOrigin::Signed( + caller.clone()).into(), + collator.clone(), + bond, + 0u32, + 0u32 + )?; + Pallet::::schedule_leave_delegators(RawOrigin::Signed(caller.clone()).into())?; + }: _(RawOrigin::Signed(caller.clone())) + verify { + assert!(Pallet::::delegator_state(&caller).expect("must exist").is_active()); + } + + schedule_revoke_delegation { + let collator: T::AccountId = create_funded_collator::( + "collator", + USER_SEED, + 0u32.into(), + true, + 1u32 + )?; + let (caller, _) = create_funded_user::("caller", USER_SEED, 0u32.into()); + let bond = <::MinDelegatorStk as Get>>::get(); + Pallet::::delegate(RawOrigin::Signed( + caller.clone()).into(), + collator.clone(), + bond, + 0u32, + 0u32 + )?; + }: _(RawOrigin::Signed(caller.clone()), collator.clone()) + verify { + assert_eq!( + Pallet::::delegation_scheduled_requests(&collator), + vec![ScheduledRequest { + delegator: caller, + when_executable: 3, + action: DelegationAction::Revoke(bond), + }], + ); + } + + delegator_bond_more { + let collator: T::AccountId = create_funded_collator::( + "collator", + USER_SEED, + 0u32.into(), + true, + 1u32 + )?; + let (caller, _) = create_funded_user::("caller", USER_SEED, 0u32.into()); + let bond = <::MinDelegatorStk as Get>>::get(); + Pallet::::delegate( + RawOrigin::Signed(caller.clone()).into(), + collator.clone(), + bond, + 0u32, + 0u32 + )?; + }: _(RawOrigin::Signed(caller.clone()), collator.clone(), bond) + verify { + let expected_bond = bond * 2u32.into(); + assert_eq!( + Pallet::::delegator_state(&caller).expect("candidate was created, qed").total, + expected_bond, + ); + } + + schedule_delegator_bond_less { + let collator: T::AccountId = create_funded_collator::( + "collator", + USER_SEED, + 0u32.into(), + true, + 1u32 + )?; + let (caller, total) = create_funded_user::("caller", USER_SEED, 0u32.into()); + Pallet::::delegate(RawOrigin::Signed( + caller.clone()).into(), + collator.clone(), + total, + 0u32, + 0u32 + )?; + let bond_less = <::MinDelegatorStk as Get>>::get(); + }: _(RawOrigin::Signed(caller.clone()), collator.clone(), bond_less) + verify { + let state = Pallet::::delegator_state(&caller) + .expect("just request bonded less so exists"); + assert_eq!( + Pallet::::delegation_scheduled_requests(&collator), + vec![ScheduledRequest { + delegator: caller, + when_executable: 3, + action: DelegationAction::Decrease(bond_less), + }], + ); + } + + execute_revoke_delegation { + let collator: T::AccountId = create_funded_collator::( + "collator", + USER_SEED, + 0u32.into(), + true, + 1u32 + )?; + let (caller, _) = create_funded_user::("caller", USER_SEED, 0u32.into()); + let bond = <::MinDelegatorStk as Get>>::get(); + Pallet::::delegate(RawOrigin::Signed( + caller.clone()).into(), + collator.clone(), + bond, + 0u32, + 0u32 + )?; + Pallet::::schedule_revoke_delegation(RawOrigin::Signed( + caller.clone()).into(), + collator.clone() + )?; + roll_to_and_author::(2, collator.clone()); + }: { + Pallet::::execute_delegation_request( + RawOrigin::Signed(caller.clone()).into(), + caller.clone(), + collator.clone() + )?; + } verify { + assert!( + !Pallet::::is_delegator(&caller) + ); + } + + execute_delegator_bond_less { + let collator: T::AccountId = create_funded_collator::( + "collator", + USER_SEED, + 0u32.into(), + true, + 1u32 + )?; + let (caller, total) = create_funded_user::("caller", USER_SEED, 0u32.into()); + Pallet::::delegate(RawOrigin::Signed( + caller.clone()).into(), + collator.clone(), + total, + 0u32, + 0u32 + )?; + let bond_less = <::MinDelegatorStk as Get>>::get(); + Pallet::::schedule_delegator_bond_less( + RawOrigin::Signed(caller.clone()).into(), + collator.clone(), + bond_less + )?; + roll_to_and_author::(2, collator.clone()); + }: { + Pallet::::execute_delegation_request( + RawOrigin::Signed(caller.clone()).into(), + caller.clone(), + collator.clone() + )?; + } verify { + let expected = total - bond_less; + assert_eq!( + Pallet::::delegator_state(&caller).expect("candidate was created, qed").total, + expected, + ); + } + + cancel_revoke_delegation { + let collator: T::AccountId = create_funded_collator::( + "collator", + USER_SEED, + 0u32.into(), + true, + 1u32 + )?; + let (caller, _) = create_funded_user::("caller", USER_SEED, 0u32.into()); + let bond = <::MinDelegatorStk as Get>>::get(); + Pallet::::delegate(RawOrigin::Signed( + caller.clone()).into(), + collator.clone(), + bond, + 0u32, + 0u32 + )?; + Pallet::::schedule_revoke_delegation( + RawOrigin::Signed(caller.clone()).into(), + collator.clone() + )?; + }: { + Pallet::::cancel_delegation_request( + RawOrigin::Signed(caller.clone()).into(), + collator.clone() + )?; + } verify { + assert!( + !Pallet::::delegation_scheduled_requests(&collator) + .iter() + .any(|x| &x.delegator == &caller) + ); + } + + cancel_delegator_bond_less { + let collator: T::AccountId = create_funded_collator::( + "collator", + USER_SEED, + 0u32.into(), + true, + 1u32 + )?; + let (caller, total) = create_funded_user::("caller", USER_SEED, 0u32.into()); + Pallet::::delegate(RawOrigin::Signed( + caller.clone()).into(), + collator.clone(), + total, + 0u32, + 0u32 + )?; + let bond_less = <::MinDelegatorStk as Get>>::get(); + Pallet::::schedule_delegator_bond_less( + RawOrigin::Signed(caller.clone()).into(), + collator.clone(), + bond_less + )?; + roll_to_and_author::(2, collator.clone()); + }: { + Pallet::::cancel_delegation_request( + RawOrigin::Signed(caller.clone()).into(), + collator.clone() + )?; + } verify { + assert!( + !Pallet::::delegation_scheduled_requests(&collator) + .iter() + .any(|x| &x.delegator == &caller) + ); + } + + // ON_INITIALIZE + + prepare_staking_payouts { + let reward_delay = <::RewardPaymentDelay as Get>::get(); + let round = reward_delay + 2u32; + let payout_round = round - reward_delay; + // may need: + // > + // > + // > + // ensure parachain bond account exists so that deposit_into_existing succeeds + >::insert(payout_round, 100); + >::insert(payout_round, min_candidate_stk::()); + + // set an account in the bond config so that we will measure the payout to it + let account = create_funded_user::( + "parachain_bond", + 0, + min_candidate_stk::(), + ).0; + >::put(ParachainBondConfig { + account, + percent: Percent::from_percent(50), + }); + + }: { Pallet::::prepare_staking_payouts(round); } + verify { + } + + get_rewardable_delegators { + let y in 0..<::MaxDelegationsPerDelegator as Get>::get(); // num delegators + + let high_inflation: Range = Range { + min: Perbill::one(), + ideal: Perbill::one(), + max: Perbill::one(), + }; + Pallet::::set_inflation(RawOrigin::Root.into(), high_inflation.clone())?; + Pallet::::set_blocks_per_round(RawOrigin::Root.into(), 101u32)?; + Pallet::::set_total_selected(RawOrigin::Root.into(), 100u32)?; + + let collator = create_funded_collator::( + "collator", + 0, + min_candidate_stk::() * 1_000_000u32.into(), + true, + 1, + )?; + + // create delegators + for i in 0..y { + let seed = USER_SEED + i + 1; + let delegator = create_funded_delegator::( + "delegator", + seed, + min_candidate_stk::() * 1_000_000u32.into(), + collator.clone(), + true, + i, + )?; + } + + let mut _results = None; + + }: { _results = Some(Pallet::::get_rewardable_delegators(&collator)); } + verify { + let counted_delegations = _results.expect("get_rewardable_delegators returned some results"); + assert!(counted_delegations.uncounted_stake == 0u32.into()); + assert!(counted_delegations.rewardable_delegations.len() as u32 == y); + let top_delegations = >::get(collator.clone()) + .expect("delegations were set for collator through delegate() calls"); + assert!(top_delegations.delegations.len() as u32 == y); + } + + select_top_candidates { + let x in 0..50; // num collators + let y in 0..<::MaxDelegationsPerDelegator as Get>::get(); // num delegators + + let high_inflation: Range = Range { + min: Perbill::one(), + ideal: Perbill::one(), + max: Perbill::one(), + }; + Pallet::::set_inflation(RawOrigin::Root.into(), high_inflation.clone())?; + Pallet::::set_blocks_per_round(RawOrigin::Root.into(), 101u32)?; + Pallet::::set_total_selected(RawOrigin::Root.into(), 100u32)?; + + let mut seed = USER_SEED + 1; + + for _ in 0..x { + let collator = create_funded_collator::( + "collator", + seed, + min_candidate_stk::() * 1_000_000u32.into(), + true, + 999999, + )?; + seed += 1; + + // create delegators + for _ in 0..y { + let delegator = create_funded_delegator::( + "delegator", + seed, + min_candidate_stk::() * 1_000_000u32.into(), + collator.clone(), + true, + 9999999, + )?; + seed += 1; + } + } + + }: { Pallet::::select_top_candidates(1); } + verify { + } + + pay_one_collator_reward { + // y controls number of delegations, its maximum per collator is the max top delegations + let y in 0..<::MaxTopDelegationsPerCandidate as Get>::get(); + + // must come after 'let foo in 0..` statements for macro + use crate::{ + DelayedPayout, DelayedPayouts, AtStake, CollatorSnapshot, BondWithAutoCompound, Points, + AwardedPts, + }; + + let before_running_round_index = Pallet::::round().current; + let initial_stake_amount = min_candidate_stk::() * 1_000_000u32.into(); + + let mut total_staked = 0u32.into(); + + // initialize our single collator + let sole_collator = create_funded_collator::( + "collator", + 0, + initial_stake_amount, + true, + 1u32, + )?; + total_staked += initial_stake_amount; + + // generate funded collator accounts + let mut delegators: Vec = Vec::new(); + for i in 0..y { + let seed = USER_SEED + i; + let delegator = create_funded_delegator::( + "delegator", + seed, + initial_stake_amount, + sole_collator.clone(), + true, + delegators.len() as u32, + )?; + delegators.push(delegator); + total_staked += initial_stake_amount; + } + + // rather than roll through rounds in order to initialize the storage we want, we set it + // directly and then call pay_one_collator_reward directly. + + let round_for_payout = 5; + >::insert(&round_for_payout, DelayedPayout { + // NOTE: round_issuance is not correct here, but it doesn't seem to cause problems + round_issuance: 1000u32.into(), + total_staking_reward: total_staked, + collator_commission: Perbill::from_rational(1u32, 100u32), + }); + + let mut delegations: Vec>> = Vec::new(); + for delegator in &delegators { + delegations.push(BondWithAutoCompound { + owner: delegator.clone(), + amount: 100u32.into(), + auto_compound: Percent::zero(), + }); + } + + >::insert(round_for_payout, &sole_collator, CollatorSnapshot { + bond: 1_000u32.into(), + delegations, + total: 1_000_000u32.into(), + }); + + >::insert(round_for_payout, 100); + >::insert(round_for_payout, &sole_collator, 20); + + }: { + let round_for_payout = 5; + // TODO: this is an extra read right here (we should whitelist it?) + let payout_info = Pallet::::delayed_payouts(round_for_payout).expect("payout expected"); + let result = Pallet::::pay_one_collator_reward(round_for_payout, payout_info); + // TODO: how to keep this in scope so it can be done in verify block? + assert!(matches!(result.0, RewardPayment::Paid)); + } + verify { + // collator should have been paid + assert!( + T::Currency::free_balance(&sole_collator) > initial_stake_amount, + "collator should have been paid in pay_one_collator_reward" + ); + // nominators should have been paid + for delegator in &delegators { + assert!( + T::Currency::free_balance(&delegator) > initial_stake_amount, + "delegator should have been paid in pay_one_collator_reward" + ); + } + } + + base_on_initialize { + let collator: T::AccountId = create_funded_collator::( + "collator", + USER_SEED, + 0u32.into(), + true, + 1u32 + )?; + let start = >::block_number(); + parachain_staking_on_finalize::(collator.clone()); + >::on_finalize(start); + >::set_block_number( + start + 1u32.into() + ); + let end = >::block_number(); + >::on_initialize(end); + }: { Pallet::::on_initialize(end); } + verify { + // Round transitions + assert_eq!(start + 1u32.into(), end); + } + + set_auto_compound { + // x controls number of distinct auto-compounding delegations the prime collator will have + // y controls number of distinct delegations the prime delegator will have + let x in 0..<::MaxTopDelegationsPerCandidate as Get>::get(); + let y in 0..<::MaxDelegationsPerDelegator as Get>::get(); + + use crate::auto_compound::AutoCompoundDelegations; + + let min_candidate_stake = min_candidate_stk::(); + let min_delegator_stake = min_delegator_stk::(); + let mut seed = Seed::new(); + + // initialize the prime collator + let prime_candidate = create_funded_collator::( + "collator", + seed.take(), + min_candidate_stake, + true, + 1, + )?; + + // initialize the prime delegator + let prime_delegator = create_funded_delegator::( + "delegator", + seed.take(), + min_delegator_stake * (y+1).into(), + prime_candidate.clone(), + true, + 0, + )?; + + // have x-1 distinct auto-compounding delegators delegate to prime collator + // we directly set the storage, since benchmarks don't work when the same extrinsic is + // called from within the benchmark. + let mut auto_compounding_state = >::get_storage(&prime_candidate); + for i in 1..x { + let delegator = create_funded_delegator::( + "delegator", + seed.take(), + min_delegator_stake, + prime_candidate.clone(), + true, + i, + )?; + auto_compounding_state.set_for_delegator( + delegator, + Percent::from_percent(100), + ).expect("must succeed"); + } + auto_compounding_state.set_storage(&prime_candidate); + + // delegate to y-1 distinct collators from the prime delegator + for i in 1..y { + let collator = create_funded_collator::( + "collator", + seed.take(), + min_candidate_stake, + true, + i+1, + )?; + Pallet::::delegate( + RawOrigin::Signed(prime_delegator.clone()).into(), + collator, + min_delegator_stake, + 0, + i, + )?; + } + }: { + Pallet::::set_auto_compound( + RawOrigin::Signed(prime_delegator.clone()).into(), + prime_candidate.clone(), + Percent::from_percent(50), + x, + y+1, + )?; + } + verify { + let actual_auto_compound = >::get_storage(&prime_candidate) + .get_for_delegator(&prime_delegator); + let expected_auto_compound = Some(Percent::from_percent(50)); + assert_eq!( + expected_auto_compound, + actual_auto_compound, + "delegation must have an auto-compound entry", + ); + } + + delegate_with_auto_compound { + // x controls number of distinct delegations the prime collator will have + // y controls number of distinct auto-compounding delegations the prime collator will have + // z controls number of distinct delegations the prime delegator will have + let x in 0..(<::MaxTopDelegationsPerCandidate as Get>::get() + + <::MaxBottomDelegationsPerCandidate as Get>::get()); + let y in 0..<::MaxTopDelegationsPerCandidate as Get>::get() + + <::MaxBottomDelegationsPerCandidate as Get>::get(); + let z in 0..<::MaxDelegationsPerDelegator as Get>::get(); + + use crate::auto_compound::AutoCompoundDelegations; + + let min_candidate_stake = min_candidate_stk::(); + let min_delegator_stake = min_delegator_stk::(); + let mut seed = Seed::new(); + + // initialize the prime collator + let prime_candidate = create_funded_collator::( + "collator", + seed.take(), + min_candidate_stake, + true, + 1, + )?; + + // initialize the future delegator + let (prime_delegator, _) = create_funded_user::( + "delegator", + seed.take(), + min_delegator_stake * (z+1).into(), + ); + + // have x-1 distinct delegators delegate to prime collator, of which y are auto-compounding. + // we can directly set the storage here. + let auto_compound_z = x * y / 100; + for i in 1..x { + let delegator = create_funded_delegator::( + "delegator", + seed.take(), + min_delegator_stake, + prime_candidate.clone(), + true, + i, + )?; + if i <= y { + Pallet::::set_auto_compound( + RawOrigin::Signed(delegator.clone()).into(), + prime_candidate.clone(), + Percent::from_percent(100), + i+1, + i, + )?; + } + } + + // delegate to z-1 distinct collators from the prime delegator + for i in 1..z { + let collator = create_funded_collator::( + "collator", + seed.take(), + min_candidate_stake, + true, + i+1, + )?; + Pallet::::delegate( + RawOrigin::Signed(prime_delegator.clone()).into(), + collator, + min_delegator_stake, + 0, + i, + )?; + } + }: { + Pallet::::delegate_with_auto_compound( + RawOrigin::Signed(prime_delegator.clone()).into(), + prime_candidate.clone(), + min_delegator_stake, + Percent::from_percent(50), + x, + y, + z, + )?; + } + verify { + assert!(Pallet::::is_delegator(&prime_delegator)); + let actual_auto_compound = >::get_storage(&prime_candidate) + .get_for_delegator(&prime_delegator); + let expected_auto_compound = Some(Percent::from_percent(50)); + assert_eq!( + expected_auto_compound, + actual_auto_compound, + "delegation must have an auto-compound entry", + ); + } + + mint_collator_reward { + let mut seed = Seed::new(); + let collator = create_funded_collator::( + "collator", + seed.take(), + 0u32.into(), + true, + 1, + )?; + let original_free_balance = T::Currency::free_balance(&collator); + }: { + Pallet::::mint_collator_reward(1u32.into(), collator.clone(), 50u32.into()) + } + verify { + assert_eq!(T::Currency::free_balance(&collator), original_free_balance + 50u32.into()); + } +} + +#[cfg(test)] +mod tests { + use crate::{benchmarks::*, mock::Test}; + use frame_support::assert_ok; + use sp_io::TestExternalities; + + pub fn new_test_ext() -> TestExternalities { + let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + TestExternalities::new(t) + } + + #[test] + fn bench_set_staking_expectations() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_set_staking_expectations()); + }); + } + + #[test] + fn bench_set_inflation() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_set_inflation()); + }); + } + + #[test] + fn bench_set_parachain_bond_account() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_set_parachain_bond_account()); + }); + } + + #[test] + fn bench_set_parachain_bond_reserve_percent() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_set_parachain_bond_reserve_percent()); + }); + } + + #[test] + fn bench_set_total_selected() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_set_total_selected()); + }); + } + + #[test] + fn bench_set_collator_commission() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_set_collator_commission()); + }); + } + + #[test] + fn bench_set_blocks_per_round() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_set_blocks_per_round()); + }); + } + + #[test] + fn bench_join_candidates() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_join_candidates()); + }); + } + + #[test] + fn bench_schedule_leave_candidates() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_schedule_leave_candidates()); + }); + } + + #[test] + fn bench_execute_leave_candidates() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_execute_leave_candidates()); + }); + } + + #[test] + fn bench_cancel_leave_candidates() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_cancel_leave_candidates()); + }); + } + + #[test] + fn bench_go_offline() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_go_offline()); + }); + } + + #[test] + fn bench_go_online() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_go_online()); + }); + } + + #[test] + fn bench_candidate_bond_more() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_candidate_bond_more()); + }); + } + + #[test] + fn bench_schedule_candidate_bond_less() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_schedule_candidate_bond_less()); + }); + } + + #[test] + fn bench_execute_candidate_bond_less() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_execute_candidate_bond_less()); + }); + } + + #[test] + fn bench_cancel_candidate_bond_less() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_cancel_candidate_bond_less()); + }); + } + + #[test] + fn bench_delegate() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_delegate()); + }); + } + + #[test] + fn bench_schedule_leave_delegators() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_schedule_leave_delegators()); + }); + } + + #[test] + fn bench_execute_leave_delegators() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_execute_leave_delegators()); + }); + } + + #[test] + fn bench_cancel_leave_delegators() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_cancel_leave_delegators()); + }); + } + + #[test] + fn bench_schedule_revoke_delegation() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_schedule_revoke_delegation()); + }); + } + + #[test] + fn bench_delegator_bond_more() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_delegator_bond_more()); + }); + } + + #[test] + fn bench_schedule_delegator_bond_less() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_schedule_delegator_bond_less()); + }); + } + + #[test] + fn bench_execute_revoke_delegation() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_execute_revoke_delegation()); + }); + } + + #[test] + fn bench_execute_delegator_bond_less() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_execute_delegator_bond_less()); + }); + } + + #[test] + fn bench_cancel_revoke_delegation() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_cancel_revoke_delegation()); + }); + } + + #[test] + fn bench_cancel_delegator_bond_less() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_cancel_delegator_bond_less()); + }); + } + + #[test] + fn bench_base_on_initialize() { + new_test_ext().execute_with(|| { + assert_ok!(Pallet::::test_benchmark_base_on_initialize()); + }); + } +} + +impl_benchmark_test_suite!(Pallet, crate::benchmarks::tests::new_test_ext(), crate::mock::Test); diff --git a/pallets/parachain-staking/src/default_weights.rs b/pallets/parachain-staking/src/default_weights.rs deleted file mode 100644 index aeb1d1081..000000000 --- a/pallets/parachain-staking/src/default_weights.rs +++ /dev/null @@ -1,843 +0,0 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH - -// The KILT Blockchain 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. - -// The KILT Blockchain 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 . - -// If you feel like getting in touch with us, you can do so at info@botlabs.org - -//! Autogenerated weights for parachain_staking -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-01, STEPS: {{cmd.steps}}\, REPEAT: {{cmd.repeat}}\, LOW RANGE: {{cmd.lowest_range_values}}\, HIGH RANGE: {{cmd.highest_range_values}}\ -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/release/kilt-parachain -// benchmark -// pallet -// --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=parachain-staking -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --output=./pallets/parachain-staking/src/default_weights.rs -// --template=.maintain/weight-template.hbs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(clippy::unnecessary_cast)] - -use frame_support::{traits::Get, weights::{constants::RocksDbWeight, Weight}}; -use sp_std::marker::PhantomData; - -/// Weight functions needed for parachain_staking. -pub trait WeightInfo { - fn on_initialize_no_action() -> Weight; - fn on_initialize_round_update() -> Weight; - fn on_initialize_network_rewards() -> Weight; - fn force_new_round() -> Weight; - fn set_inflation(n: u32, m: u32, ) -> Weight; - fn set_max_selected_candidates(n: u32, m: u32, ) -> Weight; - fn set_blocks_per_round() -> Weight; - fn force_remove_candidate(n: u32, m: u32, ) -> Weight; - fn join_candidates(n: u32, m: u32, ) -> Weight; - fn init_leave_candidates(n: u32, m: u32, ) -> Weight; - fn cancel_leave_candidates(n: u32, m: u32, ) -> Weight; - fn execute_leave_candidates(n: u32, m: u32, ) -> Weight; - fn candidate_stake_more(n: u32, m: u32, u: u32, ) -> Weight; - fn candidate_stake_less(n: u32, m: u32, ) -> Weight; - fn join_delegators(n: u32, m: u32, ) -> Weight; - fn delegator_stake_more(n: u32, m: u32, u: u32, ) -> Weight; - fn delegator_stake_less(n: u32, m: u32, ) -> Weight; - fn leave_delegators(n: u32, m: u32, ) -> Weight; - fn unlock_unstaked(u: u32, ) -> Weight; - fn set_max_candidate_stake() -> Weight; - fn increment_delegator_rewards() -> Weight; - fn increment_collator_rewards() -> Weight; - fn claim_rewards() -> Weight; - fn execute_scheduled_reward_change(n: u32, m: u32, ) -> Weight; -} - -/// Weights for parachain_staking using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - // Storage: ParachainStaking Round (r:1 w:0) - fn on_initialize_no_action() -> Weight { - Weight::from_ref_time(7_295_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - } - // Storage: ParachainStaking Round (r:1 w:1) - fn on_initialize_round_update() -> Weight { - Weight::from_ref_time(20_334_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: ParachainStaking Round (r:1 w:1) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - // Storage: ParachainStaking MaxCollatorCandidateStake (r:1 w:0) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: System Account (r:1 w:1) - fn on_initialize_network_rewards() -> Weight { - Weight::from_ref_time(53_479_000 as u64) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - } - // Storage: ParachainStaking ForceNewRound (r:0 w:1) - fn force_new_round() -> Weight { - Weight::from_ref_time(15_272_000 as u64) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: ParachainStaking CandidatePool (r:3 w:0) - // Storage: ParachainStaking BlocksAuthored (r:2 w:0) - // Storage: ParachainStaking BlocksRewarded (r:72 w:72) - // Storage: ParachainStaking Rewards (r:72 w:72) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:0) - // Storage: ParachainStaking InflationConfig (r:1 w:1) - // Storage: ParachainStaking CounterForCandidatePool (r:1 w:0) - /// The range of component `n` is `[0, 75]`. - /// The range of component `m` is `[0, 35]`. - fn set_inflation(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(880_206_000 as u64) - // Standard Error: 5_316_702 - .saturating_add(Weight::from_ref_time(170_934_184 as u64).saturating_mul(n as u64)) - // Standard Error: 11_414_842 - .saturating_add(Weight::from_ref_time(326_552_012 as u64).saturating_mul(m as u64)) - .saturating_add(T::DbWeight::get().reads(152 as u64)) - .saturating_add(T::DbWeight::get().reads((27 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().reads((51 as u64).saturating_mul(m as u64))) - .saturating_add(T::DbWeight::get().writes(145 as u64)) - .saturating_add(T::DbWeight::get().writes((25 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes((51 as u64).saturating_mul(m as u64))) - } - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking CandidatePool (r:1 w:0) - /// The range of component `n` is `[16, 75]`. - /// The range of component `m` is `[0, 35]`. - fn set_max_selected_candidates(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(71_790_000 as u64) - // Standard Error: 27_483 - .saturating_add(Weight::from_ref_time(3_582_143 as u64).saturating_mul(n as u64)) - // Standard Error: 60_832 - .saturating_add(Weight::from_ref_time(349_083 as u64).saturating_mul(m as u64)) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().reads((1 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - } - // Storage: ParachainStaking Round (r:1 w:1) - fn set_blocks_per_round() -> Weight { - Weight::from_ref_time(56_977_000 as u64) - .saturating_add(T::DbWeight::get().reads(1 as u64)) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: ParachainStaking CandidatePool (r:17 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking BlocksAuthored (r:1 w:1) - // Storage: ParachainStaking BlocksRewarded (r:36 w:36) - // Storage: ParachainStaking Rewards (r:36 w:36) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - // Storage: ParachainStaking Unstaking (r:36 w:36) - // Storage: ParachainStaking DelegatorState (r:35 w:35) - // Storage: Session Validators (r:1 w:0) - // Storage: Session DisabledValidators (r:1 w:1) - // Storage: System Digest (r:1 w:1) - // Storage: ParachainStaking CounterForCandidatePool (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - /// The range of component `n` is `[17, 75]`. - /// The range of component `m` is `[0, 35]`. - fn force_remove_candidate(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(167_630_000 as u64) - // Standard Error: 33_915 - .saturating_add(Weight::from_ref_time(1_267_282 as u64).saturating_mul(n as u64)) - // Standard Error: 75_237 - .saturating_add(Weight::from_ref_time(32_352_601 as u64).saturating_mul(m as u64)) - .saturating_add(T::DbWeight::get().reads(29 as u64)) - .saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(m as u64))) - .saturating_add(T::DbWeight::get().writes(10 as u64)) - .saturating_add(T::DbWeight::get().writes((4 as u64).saturating_mul(m as u64))) - } - // Storage: ParachainStaking CandidatePool (r:1 w:1) - // Storage: ParachainStaking DelegatorState (r:1 w:0) - // Storage: ParachainStaking MaxCollatorCandidateStake (r:1 w:0) - // Storage: ParachainStaking Unstaking (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking CounterForCandidatePool (r:1 w:1) - /// The range of component `n` is `[1, 74]`. - /// The range of component `m` is `[0, 35]`. - fn join_candidates(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(74_868_992 as u64) - // Standard Error: 15_510 - .saturating_add(Weight::from_ref_time(844_907 as u64).saturating_mul(n as u64)) - // Standard Error: 32_208 - .saturating_add(Weight::from_ref_time(1_664_228 as u64).saturating_mul(m as u64)) - .saturating_add(T::DbWeight::get().reads(10 as u64)) - .saturating_add(T::DbWeight::get().writes(7 as u64)) - } - // Storage: ParachainStaking CandidatePool (r:17 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking Round (r:1 w:0) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - /// The range of component `n` is `[17, 74]`. - /// The range of component `m` is `[0, 35]`. - fn init_leave_candidates(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(102_892_381 as u64) - // Standard Error: 15_634 - .saturating_add(Weight::from_ref_time(884_087 as u64).saturating_mul(n as u64)) - // Standard Error: 25_354 - .saturating_add(Weight::from_ref_time(1_951_960 as u64).saturating_mul(m as u64)) - .saturating_add(T::DbWeight::get().reads(21 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - } - // Storage: ParachainStaking CandidatePool (r:2 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - /// The range of component `n` is `[17, 74]`. - /// The range of component `m` is `[0, 35]`. - fn cancel_leave_candidates(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(62_163_088 as u64) - // Standard Error: 11_849 - .saturating_add(Weight::from_ref_time(470_670 as u64).saturating_mul(n as u64)) - // Standard Error: 19_216 - .saturating_add(Weight::from_ref_time(1_150_199 as u64).saturating_mul(m as u64)) - .saturating_add(T::DbWeight::get().reads(5 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - } - // Storage: ParachainStaking CandidatePool (r:1 w:1) - // Storage: ParachainStaking Round (r:1 w:0) - // Storage: ParachainStaking BlocksAuthored (r:1 w:1) - // Storage: ParachainStaking BlocksRewarded (r:36 w:36) - // Storage: ParachainStaking Rewards (r:36 w:36) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:0) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - // Storage: ParachainStaking Unstaking (r:36 w:36) - // Storage: ParachainStaking DelegatorState (r:35 w:35) - // Storage: Session Validators (r:1 w:0) - // Storage: Session DisabledValidators (r:1 w:1) - // Storage: System Digest (r:1 w:1) - // Storage: ParachainStaking CounterForCandidatePool (r:1 w:1) - /// The range of component `n` is `[17, 74]`. - /// The range of component `m` is `[0, 35]`. - fn execute_leave_candidates(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(101_532_000 as u64) - // Standard Error: 33_213 - .saturating_add(Weight::from_ref_time(1_131_850 as u64).saturating_mul(n as u64)) - // Standard Error: 72_738 - .saturating_add(Weight::from_ref_time(32_258_326 as u64).saturating_mul(m as u64)) - .saturating_add(T::DbWeight::get().reads(12 as u64)) - .saturating_add(T::DbWeight::get().reads((4 as u64).saturating_mul(m as u64))) - .saturating_add(T::DbWeight::get().writes(8 as u64)) - .saturating_add(T::DbWeight::get().writes((4 as u64).saturating_mul(m as u64))) - } - // Storage: ParachainStaking CandidatePool (r:1 w:1) - // Storage: ParachainStaking MaxCollatorCandidateStake (r:1 w:0) - // Storage: System Account (r:1 w:1) - // Storage: ParachainStaking Unstaking (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking BlocksAuthored (r:1 w:0) - // Storage: ParachainStaking BlocksRewarded (r:1 w:1) - // Storage: ParachainStaking Rewards (r:1 w:1) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - /// The range of component `n` is `[1, 74]`. - /// The range of component `m` is `[0, 35]`. - /// The range of component `u` is `[0, 9]`. - fn candidate_stake_more(n: u32, m: u32, u: u32) -> Weight { - Weight::from_ref_time(71_965_734 as u64) - // Standard Error: 13_893 - .saturating_add(Weight::from_ref_time(925_357 as u64).saturating_mul(n as u64)) - // Standard Error: 28_840 - .saturating_add(Weight::from_ref_time(1_887_704 as u64).saturating_mul(m as u64)) - // Standard Error: 106_831 - .saturating_add(Weight::from_ref_time(1_865_718 as u64).saturating_mul(u as u64)) - .saturating_add(T::DbWeight::get().reads(12 as u64)) - .saturating_add(T::DbWeight::get().writes(8 as u64)) - } - // Storage: ParachainStaking CandidatePool (r:1 w:1) - // Storage: ParachainStaking Unstaking (r:1 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking BlocksAuthored (r:1 w:0) - // Storage: ParachainStaking BlocksRewarded (r:1 w:1) - // Storage: ParachainStaking Rewards (r:1 w:1) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - /// The range of component `n` is `[1, 74]`. - /// The range of component `m` is `[0, 35]`. - fn candidate_stake_less(n: u32, m: u32) -> Weight { - Weight::from_ref_time(62_739_612 as u64) - // Standard Error: 16_793 - .saturating_add(Weight::from_ref_time(864_759 as u64).saturating_mul(n as u64)) - // Standard Error: 34_871 - .saturating_add(Weight::from_ref_time(1_709_617 as u64).saturating_mul(m as u64)) - .saturating_add(T::DbWeight::get().reads(9 as u64)) - .saturating_add(T::DbWeight::get().writes(6 as u64)) - } - // Storage: System Account (r:1 w:1) - // Storage: ParachainStaking DelegatorState (r:1 w:1) - // Storage: ParachainStaking CandidatePool (r:2 w:1) - // Storage: ParachainStaking Unstaking (r:1 w:1) - // Storage: ParachainStaking LastDelegation (r:1 w:1) - // Storage: ParachainStaking Round (r:1 w:0) - // Storage: Balances Locks (r:1 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking BlocksAuthored (r:1 w:0) - // Storage: ParachainStaking BlocksRewarded (r:0 w:1) - /// The range of component `n` is `[1, 75]`. - /// The range of component `m` is `[1, 34]`. - fn join_delegators(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(77_485_243 as u64) - // Standard Error: 14_703 - .saturating_add(Weight::from_ref_time(1_058_123 as u64).saturating_mul(n as u64)) - // Standard Error: 32_678 - .saturating_add(Weight::from_ref_time(2_182_817 as u64).saturating_mul(m as u64)) - .saturating_add(T::DbWeight::get().reads(12 as u64)) - .saturating_add(T::DbWeight::get().writes(9 as u64)) - } - // Storage: ParachainStaking DelegatorState (r:1 w:1) - // Storage: ParachainStaking CandidatePool (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: ParachainStaking Unstaking (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking BlocksAuthored (r:1 w:0) - // Storage: ParachainStaking BlocksRewarded (r:1 w:1) - // Storage: ParachainStaking Rewards (r:1 w:1) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - /// The range of component `n` is `[1, 75]`. - /// The range of component `m` is `[1, 34]`. - /// The range of component `u` is `[1, 9]`. - fn delegator_stake_more(n: u32, m: u32, u: u32) -> Weight { - Weight::from_ref_time(82_500_737 as u64) - // Standard Error: 12_571 - .saturating_add(Weight::from_ref_time(971_252 as u64).saturating_mul(n as u64)) - // Standard Error: 27_929 - .saturating_add(Weight::from_ref_time(1_947_599 as u64).saturating_mul(m as u64)) - // Standard Error: 108_324 - .saturating_add(Weight::from_ref_time(1_782_476 as u64).saturating_mul(u as u64)) - .saturating_add(T::DbWeight::get().reads(12 as u64)) - .saturating_add(T::DbWeight::get().writes(9 as u64)) - } - // Storage: ParachainStaking DelegatorState (r:1 w:1) - // Storage: ParachainStaking CandidatePool (r:1 w:1) - // Storage: ParachainStaking Unstaking (r:1 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking BlocksAuthored (r:1 w:0) - // Storage: ParachainStaking BlocksRewarded (r:1 w:1) - // Storage: ParachainStaking Rewards (r:1 w:1) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - /// The range of component `n` is `[1, 75]`. - /// The range of component `m` is `[1, 34]`. - fn delegator_stake_less(n: u32, m: u32) -> Weight { - Weight::from_ref_time(72_772_464 as u64) - // Standard Error: 14_214 - .saturating_add(Weight::from_ref_time(909_175 as u64).saturating_mul(n as u64)) - // Standard Error: 31_591 - .saturating_add(Weight::from_ref_time(1_824_513 as u64).saturating_mul(m as u64)) - .saturating_add(T::DbWeight::get().reads(10 as u64)) - .saturating_add(T::DbWeight::get().writes(7 as u64)) - } - // Storage: ParachainStaking DelegatorState (r:1 w:1) - // Storage: ParachainStaking CandidatePool (r:1 w:1) - // Storage: ParachainStaking BlocksAuthored (r:1 w:0) - // Storage: ParachainStaking BlocksRewarded (r:1 w:1) - // Storage: ParachainStaking Rewards (r:1 w:1) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - // Storage: ParachainStaking Unstaking (r:1 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - /// The range of component `n` is `[1, 75]`. - /// The range of component `m` is `[1, 34]`. - fn leave_delegators(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(80_275_828 as u64) - // Standard Error: 14_671 - .saturating_add(Weight::from_ref_time(913_421 as u64).saturating_mul(n as u64)) - // Standard Error: 32_607 - .saturating_add(Weight::from_ref_time(1_764_476 as u64).saturating_mul(m as u64)) - .saturating_add(T::DbWeight::get().reads(10 as u64)) - .saturating_add(T::DbWeight::get().writes(7 as u64)) - } - // Storage: ParachainStaking Unstaking (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) - /// The range of component `u` is `[1, 9]`. - fn unlock_unstaked(u: u32, ) -> Weight { - Weight::from_ref_time(53_730_996 as u64) - // Standard Error: 18_906 - .saturating_add(Weight::from_ref_time(410_777 as u64).saturating_mul(u as u64)) - .saturating_add(T::DbWeight::get().reads(3 as u64)) - .saturating_add(T::DbWeight::get().writes(3 as u64)) - } - // Storage: ParachainStaking MaxCollatorCandidateStake (r:0 w:1) - fn set_max_candidate_stake() -> Weight { - Weight::from_ref_time(43_109_000 as u64) - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - // Storage: ParachainStaking DelegatorState (r:1 w:0) - // Storage: ParachainStaking BlocksAuthored (r:1 w:0) - // Storage: ParachainStaking BlocksRewarded (r:1 w:1) - // Storage: ParachainStaking Rewards (r:1 w:1) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:0) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - fn increment_delegator_rewards() -> Weight { - Weight::from_ref_time(40_000_000 as u64) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - } - // Storage: ParachainStaking CandidatePool (r:1 w:0) - // Storage: ParachainStaking BlocksAuthored (r:1 w:0) - // Storage: ParachainStaking BlocksRewarded (r:1 w:1) - // Storage: ParachainStaking Rewards (r:1 w:1) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:0) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - fn increment_collator_rewards() -> Weight { - Weight::from_ref_time(35_612_000 as u64) - .saturating_add(T::DbWeight::get().reads(6 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - } - // Storage: ParachainStaking Rewards (r:1 w:1) - // Storage: System Account (r:1 w:1) - fn claim_rewards() -> Weight { - Weight::from_ref_time(54_273_000 as u64) - .saturating_add(T::DbWeight::get().reads(2 as u64)) - .saturating_add(T::DbWeight::get().writes(2 as u64)) - } - // Storage: ParachainStaking LastRewardReduction (r:1 w:1) - // Storage: ParachainStaking InflationConfig (r:1 w:1) - // Storage: ParachainStaking CandidatePool (r:3 w:0) - // Storage: ParachainStaking BlocksAuthored (r:2 w:0) - // Storage: ParachainStaking BlocksRewarded (r:72 w:72) - // Storage: ParachainStaking Rewards (r:72 w:72) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:0) - // Storage: ParachainStaking CounterForCandidatePool (r:1 w:0) - /// The range of component `n` is `[0, 75]`. - /// The range of component `m` is `[0, 35]`. - fn execute_scheduled_reward_change(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(869_446_000 as u64) - // Standard Error: 5_211_771 - .saturating_add(Weight::from_ref_time(166_314_407 as u64).saturating_mul(n as u64)) - // Standard Error: 11_189_560 - .saturating_add(Weight::from_ref_time(321_504_163 as u64).saturating_mul(m as u64)) - .saturating_add(T::DbWeight::get().reads(153 as u64)) - .saturating_add(T::DbWeight::get().reads((27 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().reads((51 as u64).saturating_mul(m as u64))) - .saturating_add(T::DbWeight::get().writes(146 as u64)) - .saturating_add(T::DbWeight::get().writes((25 as u64).saturating_mul(n as u64))) - .saturating_add(T::DbWeight::get().writes((51 as u64).saturating_mul(m as u64))) - } -} - -// For backwards compatibility and tests -impl WeightInfo for () { - // Storage: ParachainStaking Round (r:1 w:0) - fn on_initialize_no_action() -> Weight { - Weight::from_ref_time(7_295_000 as u64) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - } - // Storage: ParachainStaking Round (r:1 w:1) - fn on_initialize_round_update() -> Weight { - Weight::from_ref_time(20_334_000 as u64) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: ParachainStaking Round (r:1 w:1) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - // Storage: ParachainStaking MaxCollatorCandidateStake (r:1 w:0) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: System Account (r:1 w:1) - fn on_initialize_network_rewards() -> Weight { - Weight::from_ref_time(53_479_000 as u64) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - } - // Storage: ParachainStaking ForceNewRound (r:0 w:1) - fn force_new_round() -> Weight { - Weight::from_ref_time(15_272_000 as u64) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: ParachainStaking CandidatePool (r:3 w:0) - // Storage: ParachainStaking BlocksAuthored (r:2 w:0) - // Storage: ParachainStaking BlocksRewarded (r:72 w:72) - // Storage: ParachainStaking Rewards (r:72 w:72) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:0) - // Storage: ParachainStaking InflationConfig (r:1 w:1) - // Storage: ParachainStaking CounterForCandidatePool (r:1 w:0) - /// The range of component `n` is `[0, 75]`. - /// The range of component `m` is `[0, 35]`. - fn set_inflation(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(880_206_000 as u64) - // Standard Error: 5_316_702 - .saturating_add(Weight::from_ref_time(170_934_184 as u64).saturating_mul(n as u64)) - // Standard Error: 11_414_842 - .saturating_add(Weight::from_ref_time(326_552_012 as u64).saturating_mul(m as u64)) - .saturating_add(RocksDbWeight::get().reads(152 as u64)) - .saturating_add(RocksDbWeight::get().reads((27 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().reads((51 as u64).saturating_mul(m as u64))) - .saturating_add(RocksDbWeight::get().writes(145 as u64)) - .saturating_add(RocksDbWeight::get().writes((25 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes((51 as u64).saturating_mul(m as u64))) - } - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking CandidatePool (r:1 w:0) - /// The range of component `n` is `[16, 75]`. - /// The range of component `m` is `[0, 35]`. - fn set_max_selected_candidates(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(71_790_000 as u64) - // Standard Error: 27_483 - .saturating_add(Weight::from_ref_time(3_582_143 as u64).saturating_mul(n as u64)) - // Standard Error: 60_832 - .saturating_add(Weight::from_ref_time(349_083 as u64).saturating_mul(m as u64)) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().reads((1 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - } - // Storage: ParachainStaking Round (r:1 w:1) - fn set_blocks_per_round() -> Weight { - Weight::from_ref_time(56_977_000 as u64) - .saturating_add(RocksDbWeight::get().reads(1 as u64)) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: ParachainStaking CandidatePool (r:17 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking BlocksAuthored (r:1 w:1) - // Storage: ParachainStaking BlocksRewarded (r:36 w:36) - // Storage: ParachainStaking Rewards (r:36 w:36) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - // Storage: ParachainStaking Unstaking (r:36 w:36) - // Storage: ParachainStaking DelegatorState (r:35 w:35) - // Storage: Session Validators (r:1 w:0) - // Storage: Session DisabledValidators (r:1 w:1) - // Storage: System Digest (r:1 w:1) - // Storage: ParachainStaking CounterForCandidatePool (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - /// The range of component `n` is `[17, 75]`. - /// The range of component `m` is `[0, 35]`. - fn force_remove_candidate(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(167_630_000 as u64) - // Standard Error: 33_915 - .saturating_add(Weight::from_ref_time(1_267_282 as u64).saturating_mul(n as u64)) - // Standard Error: 75_237 - .saturating_add(Weight::from_ref_time(32_352_601 as u64).saturating_mul(m as u64)) - .saturating_add(RocksDbWeight::get().reads(29 as u64)) - .saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(m as u64))) - .saturating_add(RocksDbWeight::get().writes(10 as u64)) - .saturating_add(RocksDbWeight::get().writes((4 as u64).saturating_mul(m as u64))) - } - // Storage: ParachainStaking CandidatePool (r:1 w:1) - // Storage: ParachainStaking DelegatorState (r:1 w:0) - // Storage: ParachainStaking MaxCollatorCandidateStake (r:1 w:0) - // Storage: ParachainStaking Unstaking (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking CounterForCandidatePool (r:1 w:1) - /// The range of component `n` is `[1, 74]`. - /// The range of component `m` is `[0, 35]`. - fn join_candidates(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(74_868_992 as u64) - // Standard Error: 15_510 - .saturating_add(Weight::from_ref_time(844_907 as u64).saturating_mul(n as u64)) - // Standard Error: 32_208 - .saturating_add(Weight::from_ref_time(1_664_228 as u64).saturating_mul(m as u64)) - .saturating_add(RocksDbWeight::get().reads(10 as u64)) - .saturating_add(RocksDbWeight::get().writes(7 as u64)) - } - // Storage: ParachainStaking CandidatePool (r:17 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking Round (r:1 w:0) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - /// The range of component `n` is `[17, 74]`. - /// The range of component `m` is `[0, 35]`. - fn init_leave_candidates(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(102_892_381 as u64) - // Standard Error: 15_634 - .saturating_add(Weight::from_ref_time(884_087 as u64).saturating_mul(n as u64)) - // Standard Error: 25_354 - .saturating_add(Weight::from_ref_time(1_951_960 as u64).saturating_mul(m as u64)) - .saturating_add(RocksDbWeight::get().reads(21 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - } - // Storage: ParachainStaking CandidatePool (r:2 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - /// The range of component `n` is `[17, 74]`. - /// The range of component `m` is `[0, 35]`. - fn cancel_leave_candidates(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(62_163_088 as u64) - // Standard Error: 11_849 - .saturating_add(Weight::from_ref_time(470_670 as u64).saturating_mul(n as u64)) - // Standard Error: 19_216 - .saturating_add(Weight::from_ref_time(1_150_199 as u64).saturating_mul(m as u64)) - .saturating_add(RocksDbWeight::get().reads(5 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - } - // Storage: ParachainStaking CandidatePool (r:1 w:1) - // Storage: ParachainStaking Round (r:1 w:0) - // Storage: ParachainStaking BlocksAuthored (r:1 w:1) - // Storage: ParachainStaking BlocksRewarded (r:36 w:36) - // Storage: ParachainStaking Rewards (r:36 w:36) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:0) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - // Storage: ParachainStaking Unstaking (r:36 w:36) - // Storage: ParachainStaking DelegatorState (r:35 w:35) - // Storage: Session Validators (r:1 w:0) - // Storage: Session DisabledValidators (r:1 w:1) - // Storage: System Digest (r:1 w:1) - // Storage: ParachainStaking CounterForCandidatePool (r:1 w:1) - /// The range of component `n` is `[17, 74]`. - /// The range of component `m` is `[0, 35]`. - fn execute_leave_candidates(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(101_532_000 as u64) - // Standard Error: 33_213 - .saturating_add(Weight::from_ref_time(1_131_850 as u64).saturating_mul(n as u64)) - // Standard Error: 72_738 - .saturating_add(Weight::from_ref_time(32_258_326 as u64).saturating_mul(m as u64)) - .saturating_add(RocksDbWeight::get().reads(12 as u64)) - .saturating_add(RocksDbWeight::get().reads((4 as u64).saturating_mul(m as u64))) - .saturating_add(RocksDbWeight::get().writes(8 as u64)) - .saturating_add(RocksDbWeight::get().writes((4 as u64).saturating_mul(m as u64))) - } - // Storage: ParachainStaking CandidatePool (r:1 w:1) - // Storage: ParachainStaking MaxCollatorCandidateStake (r:1 w:0) - // Storage: System Account (r:1 w:1) - // Storage: ParachainStaking Unstaking (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking BlocksAuthored (r:1 w:0) - // Storage: ParachainStaking BlocksRewarded (r:1 w:1) - // Storage: ParachainStaking Rewards (r:1 w:1) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - /// The range of component `n` is `[1, 74]`. - /// The range of component `m` is `[0, 35]`. - /// The range of component `u` is `[0, 9]`. - fn candidate_stake_more(n: u32, m: u32, u: u32) -> Weight { - Weight::from_ref_time(71_965_734 as u64) - // Standard Error: 13_893 - .saturating_add(Weight::from_ref_time(925_357 as u64).saturating_mul(n as u64)) - // Standard Error: 28_840 - .saturating_add(Weight::from_ref_time(1_887_704 as u64).saturating_mul(m as u64)) - // Standard Error: 106_831 - .saturating_add(Weight::from_ref_time(1_865_718 as u64).saturating_mul(u as u64)) - .saturating_add(RocksDbWeight::get().reads(12 as u64)) - .saturating_add(RocksDbWeight::get().writes(8 as u64)) - } - // Storage: ParachainStaking CandidatePool (r:1 w:1) - // Storage: ParachainStaking Unstaking (r:1 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking BlocksAuthored (r:1 w:0) - // Storage: ParachainStaking BlocksRewarded (r:1 w:1) - // Storage: ParachainStaking Rewards (r:1 w:1) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - /// The range of component `n` is `[1, 74]`. - /// The range of component `m` is `[0, 35]`. - fn candidate_stake_less(n: u32, m: u32) -> Weight { - Weight::from_ref_time(62_739_612 as u64) - // Standard Error: 16_793 - .saturating_add(Weight::from_ref_time(864_759 as u64).saturating_mul(n as u64)) - // Standard Error: 34_871 - .saturating_add(Weight::from_ref_time(1_709_617 as u64).saturating_mul(m as u64)) - .saturating_add(RocksDbWeight::get().reads(9 as u64)) - .saturating_add(RocksDbWeight::get().writes(6 as u64)) - } - // Storage: System Account (r:1 w:1) - // Storage: ParachainStaking DelegatorState (r:1 w:1) - // Storage: ParachainStaking CandidatePool (r:2 w:1) - // Storage: ParachainStaking Unstaking (r:1 w:1) - // Storage: ParachainStaking LastDelegation (r:1 w:1) - // Storage: ParachainStaking Round (r:1 w:0) - // Storage: Balances Locks (r:1 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking BlocksAuthored (r:1 w:0) - // Storage: ParachainStaking BlocksRewarded (r:0 w:1) - /// The range of component `n` is `[1, 75]`. - /// The range of component `m` is `[1, 34]`. - fn join_delegators(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(77_485_243 as u64) - // Standard Error: 14_703 - .saturating_add(Weight::from_ref_time(1_058_123 as u64).saturating_mul(n as u64)) - // Standard Error: 32_678 - .saturating_add(Weight::from_ref_time(2_182_817 as u64).saturating_mul(m as u64)) - .saturating_add(RocksDbWeight::get().reads(12 as u64)) - .saturating_add(RocksDbWeight::get().writes(9 as u64)) - } - // Storage: ParachainStaking DelegatorState (r:1 w:1) - // Storage: ParachainStaking CandidatePool (r:1 w:1) - // Storage: System Account (r:1 w:1) - // Storage: ParachainStaking Unstaking (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking BlocksAuthored (r:1 w:0) - // Storage: ParachainStaking BlocksRewarded (r:1 w:1) - // Storage: ParachainStaking Rewards (r:1 w:1) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - /// The range of component `n` is `[1, 75]`. - /// The range of component `m` is `[1, 34]`. - /// The range of component `u` is `[1, 9]`. - fn delegator_stake_more(n: u32, m: u32, u: u32) -> Weight { - Weight::from_ref_time(82_500_737 as u64) - // Standard Error: 12_571 - .saturating_add(Weight::from_ref_time(971_252 as u64).saturating_mul(n as u64)) - // Standard Error: 27_929 - .saturating_add(Weight::from_ref_time(1_947_599 as u64).saturating_mul(m as u64)) - // Standard Error: 108_324 - .saturating_add(Weight::from_ref_time(1_782_476 as u64).saturating_mul(u as u64)) - .saturating_add(RocksDbWeight::get().reads(12 as u64)) - .saturating_add(RocksDbWeight::get().writes(9 as u64)) - } - // Storage: ParachainStaking DelegatorState (r:1 w:1) - // Storage: ParachainStaking CandidatePool (r:1 w:1) - // Storage: ParachainStaking Unstaking (r:1 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking BlocksAuthored (r:1 w:0) - // Storage: ParachainStaking BlocksRewarded (r:1 w:1) - // Storage: ParachainStaking Rewards (r:1 w:1) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - /// The range of component `n` is `[1, 75]`. - /// The range of component `m` is `[1, 34]`. - fn delegator_stake_less(n: u32, m: u32) -> Weight { - Weight::from_ref_time(72_772_464 as u64) - // Standard Error: 14_214 - .saturating_add(Weight::from_ref_time(909_175 as u64).saturating_mul(n as u64)) - // Standard Error: 31_591 - .saturating_add(Weight::from_ref_time(1_824_513 as u64).saturating_mul(m as u64)) - .saturating_add(RocksDbWeight::get().reads(10 as u64)) - .saturating_add(RocksDbWeight::get().writes(7 as u64)) - } - // Storage: ParachainStaking DelegatorState (r:1 w:1) - // Storage: ParachainStaking CandidatePool (r:1 w:1) - // Storage: ParachainStaking BlocksAuthored (r:1 w:0) - // Storage: ParachainStaking BlocksRewarded (r:1 w:1) - // Storage: ParachainStaking Rewards (r:1 w:1) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:1) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - // Storage: ParachainStaking Unstaking (r:1 w:1) - // Storage: ParachainStaking TopCandidates (r:1 w:1) - // Storage: ParachainStaking MaxSelectedCandidates (r:1 w:0) - /// The range of component `n` is `[1, 75]`. - /// The range of component `m` is `[1, 34]`. - fn leave_delegators(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(80_275_828 as u64) - // Standard Error: 14_671 - .saturating_add(Weight::from_ref_time(913_421 as u64).saturating_mul(n as u64)) - // Standard Error: 32_607 - .saturating_add(Weight::from_ref_time(1_764_476 as u64).saturating_mul(m as u64)) - .saturating_add(RocksDbWeight::get().reads(10 as u64)) - .saturating_add(RocksDbWeight::get().writes(7 as u64)) - } - // Storage: ParachainStaking Unstaking (r:1 w:1) - // Storage: Balances Locks (r:1 w:1) - // Storage: System Account (r:1 w:1) - /// The range of component `u` is `[1, 9]`. - fn unlock_unstaked(u: u32, ) -> Weight { - Weight::from_ref_time(53_730_996 as u64) - // Standard Error: 18_906 - .saturating_add(Weight::from_ref_time(410_777 as u64).saturating_mul(u as u64)) - .saturating_add(RocksDbWeight::get().reads(3 as u64)) - .saturating_add(RocksDbWeight::get().writes(3 as u64)) - } - // Storage: ParachainStaking MaxCollatorCandidateStake (r:0 w:1) - fn set_max_candidate_stake() -> Weight { - Weight::from_ref_time(43_109_000 as u64) - .saturating_add(RocksDbWeight::get().writes(1 as u64)) - } - // Storage: ParachainStaking DelegatorState (r:1 w:0) - // Storage: ParachainStaking BlocksAuthored (r:1 w:0) - // Storage: ParachainStaking BlocksRewarded (r:1 w:1) - // Storage: ParachainStaking Rewards (r:1 w:1) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:0) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - fn increment_delegator_rewards() -> Weight { - Weight::from_ref_time(40_000_000 as u64) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - } - // Storage: ParachainStaking CandidatePool (r:1 w:0) - // Storage: ParachainStaking BlocksAuthored (r:1 w:0) - // Storage: ParachainStaking BlocksRewarded (r:1 w:1) - // Storage: ParachainStaking Rewards (r:1 w:1) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:0) - // Storage: ParachainStaking InflationConfig (r:1 w:0) - fn increment_collator_rewards() -> Weight { - Weight::from_ref_time(35_612_000 as u64) - .saturating_add(RocksDbWeight::get().reads(6 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - } - // Storage: ParachainStaking Rewards (r:1 w:1) - // Storage: System Account (r:1 w:1) - fn claim_rewards() -> Weight { - Weight::from_ref_time(54_273_000 as u64) - .saturating_add(RocksDbWeight::get().reads(2 as u64)) - .saturating_add(RocksDbWeight::get().writes(2 as u64)) - } - // Storage: ParachainStaking LastRewardReduction (r:1 w:1) - // Storage: ParachainStaking InflationConfig (r:1 w:1) - // Storage: ParachainStaking CandidatePool (r:3 w:0) - // Storage: ParachainStaking BlocksAuthored (r:2 w:0) - // Storage: ParachainStaking BlocksRewarded (r:72 w:72) - // Storage: ParachainStaking Rewards (r:72 w:72) - // Storage: ParachainStaking TotalCollatorStake (r:1 w:0) - // Storage: ParachainStaking CounterForCandidatePool (r:1 w:0) - /// The range of component `n` is `[0, 75]`. - /// The range of component `m` is `[0, 35]`. - fn execute_scheduled_reward_change(n: u32, m: u32, ) -> Weight { - Weight::from_ref_time(869_446_000 as u64) - // Standard Error: 5_211_771 - .saturating_add(Weight::from_ref_time(166_314_407 as u64).saturating_mul(n as u64)) - // Standard Error: 11_189_560 - .saturating_add(Weight::from_ref_time(321_504_163 as u64).saturating_mul(m as u64)) - .saturating_add(RocksDbWeight::get().reads(153 as u64)) - .saturating_add(RocksDbWeight::get().reads((27 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().reads((51 as u64).saturating_mul(m as u64))) - .saturating_add(RocksDbWeight::get().writes(146 as u64)) - .saturating_add(RocksDbWeight::get().writes((25 as u64).saturating_mul(n as u64))) - .saturating_add(RocksDbWeight::get().writes((51 as u64).saturating_mul(m as u64))) - } -} diff --git a/pallets/parachain-staking/src/delegation_requests.rs b/pallets/parachain-staking/src/delegation_requests.rs new file mode 100644 index 000000000..8f5bec1ac --- /dev/null +++ b/pallets/parachain-staking/src/delegation_requests.rs @@ -0,0 +1,579 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! Scheduled requests functionality for delegators + +use crate::{ + auto_compound::AutoCompoundDelegations, + pallet::{ + BalanceOf, CandidateInfo, Config, DelegationScheduledRequests, DelegatorState, Error, Event, Pallet, Round, + RoundIndex, Total, + }, + Delegator, DelegatorStatus, +}; +use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, traits::Get, RuntimeDebug}; +use parity_scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_runtime::traits::Saturating; +use sp_std::{vec, vec::Vec}; + +/// An action that can be performed upon a delegation +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, PartialOrd, Ord)] +pub enum DelegationAction { + Revoke(Balance), + Decrease(Balance), +} + +impl DelegationAction { + /// Returns the wrapped amount value. + pub fn amount(&self) -> Balance { + match self { + DelegationAction::Revoke(amount) => *amount, + DelegationAction::Decrease(amount) => *amount, + } + } +} + +/// Represents a scheduled request that define a [DelegationAction]. The request is executable +/// iff the provided [RoundIndex] is achieved. +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo, PartialOrd, Ord)] +pub struct ScheduledRequest { + pub delegator: AccountId, + pub when_executable: RoundIndex, + pub action: DelegationAction, +} + +/// Represents a cancelled scheduled request for emitting an event. +#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct CancelledScheduledRequest { + pub when_executable: RoundIndex, + pub action: DelegationAction, +} + +impl From> for CancelledScheduledRequest { + fn from(request: ScheduledRequest) -> Self { + CancelledScheduledRequest { when_executable: request.when_executable, action: request.action } + } +} + +impl Pallet { + /// Schedules a [DelegationAction::Revoke] for the delegator, towards a given collator. + pub(crate) fn delegation_schedule_revoke( + collator: T::AccountId, + delegator: T::AccountId, + ) -> DispatchResultWithPostInfo { + let mut state = >::get(&delegator).ok_or(>::DelegatorDNE)?; + let mut scheduled_requests = >::get(&collator); + + ensure!( + !scheduled_requests.iter().any(|req| req.delegator == delegator), + >::PendingDelegationRequestAlreadyExists, + ); + + let bonded_amount = state.get_bond_amount(&collator).ok_or(>::DelegationDNE)?; + let now = >::get().current; + let when = now.saturating_add(T::RevokeDelegationDelay::get()); + scheduled_requests.push(ScheduledRequest { + delegator: delegator.clone(), + action: DelegationAction::Revoke(bonded_amount), + when_executable: when, + }); + state.less_total = state.less_total.saturating_add(bonded_amount); + >::insert(collator.clone(), scheduled_requests); + >::insert(delegator.clone(), state); + + Self::deposit_event(Event::DelegationRevocationScheduled { + round: now, + delegator, + candidate: collator, + scheduled_exit: when, + }); + Ok(().into()) + } + + /// Schedules a [DelegationAction::Decrease] for the delegator, towards a given collator. + pub(crate) fn delegation_schedule_bond_decrease( + collator: T::AccountId, + delegator: T::AccountId, + decrease_amount: BalanceOf, + ) -> DispatchResultWithPostInfo { + let mut state = >::get(&delegator).ok_or(>::DelegatorDNE)?; + let mut scheduled_requests = >::get(&collator); + + ensure!( + !scheduled_requests.iter().any(|req| req.delegator == delegator), + >::PendingDelegationRequestAlreadyExists, + ); + + let bonded_amount = state.get_bond_amount(&collator).ok_or(>::DelegationDNE)?; + ensure!(bonded_amount > decrease_amount, >::DelegatorBondBelowMin); + let new_amount: BalanceOf = bonded_amount - decrease_amount; + ensure!(new_amount >= T::MinDelegation::get(), >::DelegationBelowMin); + + // Net Total is total after pending orders are executed + let net_total = state.total().saturating_sub(state.less_total); + // Net Total is always >= MinDelegatorStk + let max_subtracted_amount = net_total.saturating_sub(T::MinDelegatorStk::get()); + ensure!(decrease_amount <= max_subtracted_amount, >::DelegatorBondBelowMin); + + let now = >::get().current; + let when = now.saturating_add(T::RevokeDelegationDelay::get()); + scheduled_requests.push(ScheduledRequest { + delegator: delegator.clone(), + action: DelegationAction::Decrease(decrease_amount), + when_executable: when, + }); + state.less_total = state.less_total.saturating_add(decrease_amount); + >::insert(collator.clone(), scheduled_requests); + >::insert(delegator.clone(), state); + + Self::deposit_event(Event::DelegationDecreaseScheduled { + delegator, + candidate: collator, + amount_to_decrease: decrease_amount, + execute_round: when, + }); + Ok(().into()) + } + + /// Cancels the delegator's existing [ScheduledRequest] towards a given collator. + pub(crate) fn delegation_cancel_request( + collator: T::AccountId, + delegator: T::AccountId, + ) -> DispatchResultWithPostInfo { + let mut state = >::get(&delegator).ok_or(>::DelegatorDNE)?; + let mut scheduled_requests = >::get(&collator); + + let request = Self::cancel_request_with_state(&delegator, &mut state, &mut scheduled_requests) + .ok_or(>::PendingDelegationRequestDNE)?; + + >::insert(collator.clone(), scheduled_requests); + >::insert(delegator.clone(), state); + + Self::deposit_event(Event::CancelledDelegationRequest { + delegator, + collator, + cancelled_request: request.into(), + }); + Ok(().into()) + } + + fn cancel_request_with_state( + delegator: &T::AccountId, + state: &mut Delegator>, + scheduled_requests: &mut Vec>>, + ) -> Option>> { + let request_idx = scheduled_requests.iter().position(|req| &req.delegator == delegator)?; + + let request = scheduled_requests.remove(request_idx); + let amount = request.action.amount(); + state.less_total = state.less_total.saturating_sub(amount); + Some(request) + } + + /// Executes the delegator's existing [ScheduledRequest] towards a given collator. + pub(crate) fn delegation_execute_scheduled_request( + collator: T::AccountId, + delegator: T::AccountId, + ) -> DispatchResultWithPostInfo { + let mut state = >::get(&delegator).ok_or(>::DelegatorDNE)?; + let mut scheduled_requests = >::get(&collator); + let request_idx = scheduled_requests + .iter() + .position(|req| req.delegator == delegator) + .ok_or(>::PendingDelegationRequestDNE)?; + let request = &scheduled_requests[request_idx]; + + let now = >::get().current; + ensure!(request.when_executable <= now, >::PendingDelegationRequestNotDueYet); + + match request.action { + DelegationAction::Revoke(amount) => { + // revoking last delegation => leaving set of delegators + let leaving = if state.delegations.0.len() == 1usize { + true + } else { + ensure!( + state.total().saturating_sub(T::MinDelegatorStk::get()) >= amount, + >::DelegatorBondBelowMin + ); + false + }; + + // remove from pending requests + let amount = scheduled_requests.remove(request_idx).action.amount(); + state.less_total = state.less_total.saturating_sub(amount); + + // remove delegation from delegator state + state.rm_delegation::(&collator); + + // remove delegation from auto-compounding info + >::remove_auto_compound(&collator, &delegator); + + // remove delegation from collator state delegations + Self::delegator_leaves_candidate(collator.clone(), delegator.clone(), amount)?; + Self::deposit_event(Event::DelegationRevoked { + delegator: delegator.clone(), + candidate: collator.clone(), + unstaked_amount: amount, + }); + + >::insert(collator, scheduled_requests); + if leaving { + >::remove(&delegator); + Self::deposit_event(Event::DelegatorLeft { delegator, unstaked_amount: amount }); + } else { + >::insert(&delegator, state); + } + Ok(().into()) + }, + DelegationAction::Decrease(_) => { + // remove from pending requests + let amount = scheduled_requests.remove(request_idx).action.amount(); + state.less_total = state.less_total.saturating_sub(amount); + + // decrease delegation + for bond in &mut state.delegations.0 { + if bond.owner == collator { + return if bond.amount > amount { + let amount_before: BalanceOf = bond.amount; + bond.amount = bond.amount.saturating_sub(amount); + let mut collator_info = + >::get(&collator).ok_or(>::CandidateDNE)?; + + state.total_sub_if::(amount, |total| { + let new_total: BalanceOf = total; + ensure!(new_total >= T::MinDelegation::get(), >::DelegationBelowMin); + ensure!(new_total >= T::MinDelegatorStk::get(), >::DelegatorBondBelowMin); + + Ok(()) + })?; + + // need to go into decrease_delegation + let in_top = collator_info.decrease_delegation::( + &collator, + delegator.clone(), + amount_before, + amount, + )?; + >::insert(&collator, collator_info); + let new_total_staked = >::get().saturating_sub(amount); + >::put(new_total_staked); + + >::insert(collator.clone(), scheduled_requests); + >::insert(delegator.clone(), state); + Self::deposit_event(Event::DelegationDecreased { + delegator, + candidate: collator.clone(), + amount, + in_top, + }); + Ok(().into()) + } else { + // must rm entire delegation if bond.amount <= less or cancel request + Err(>::DelegationBelowMin.into()) + } + } + } + Err(>::DelegationDNE.into()) + }, + } + } + + /// Schedules [DelegationAction::Revoke] for the delegator, towards all delegated collator. + /// The last fulfilled request causes the delegator to leave the set of delegators. + pub(crate) fn delegator_schedule_revoke_all(delegator: T::AccountId) -> DispatchResultWithPostInfo { + let mut state = >::get(&delegator).ok_or(>::DelegatorDNE)?; + let mut updated_scheduled_requests = vec![]; + let now = >::get().current; + let when = now.saturating_add(T::LeaveDelegatorsDelay::get()); + + // lazy migration for DelegatorStatus::Leaving + #[allow(deprecated)] + if matches!(state.status, DelegatorStatus::Leaving(_)) { + state.status = DelegatorStatus::Active; + >::insert(delegator.clone(), state.clone()); + } + + // it is assumed that a multiple delegations to the same collator does not exist, else this + // will cause a bug - the last duplicate delegation update will be the only one applied. + let mut existing_revoke_count = 0; + for bond in state.delegations.0.clone() { + let collator = bond.owner; + let bonded_amount = bond.amount; + let mut scheduled_requests = >::get(&collator); + + // cancel any existing requests + let request = Self::cancel_request_with_state(&delegator, &mut state, &mut scheduled_requests); + let request = match request { + Some(revoke_req) if matches!(revoke_req.action, DelegationAction::Revoke(_)) => { + existing_revoke_count += 1; + revoke_req // re-insert the same Revoke request + }, + _ => ScheduledRequest { + delegator: delegator.clone(), + action: DelegationAction::Revoke(bonded_amount), + when_executable: when, + }, + }; + + scheduled_requests.push(request); + state.less_total = state.less_total.saturating_add(bonded_amount); + updated_scheduled_requests.push((collator, scheduled_requests)); + } + + if existing_revoke_count == state.delegations.0.len() { + return Err(>::DelegatorAlreadyLeaving.into()) + } + + updated_scheduled_requests.into_iter().for_each(|(collator, scheduled_requests)| { + >::insert(collator, scheduled_requests); + }); + + >::insert(delegator.clone(), state); + Self::deposit_event(Event::DelegatorExitScheduled { round: now, delegator, scheduled_exit: when }); + Ok(().into()) + } + + /// Cancels every [DelegationAction::Revoke] request for a delegator towards a collator. + /// Each delegation must have a [DelegationAction::Revoke] scheduled that must be allowed to be + /// executed in the current round, for this function to succeed. + pub(crate) fn delegator_cancel_scheduled_revoke_all(delegator: T::AccountId) -> DispatchResultWithPostInfo { + let mut state = >::get(&delegator).ok_or(>::DelegatorDNE)?; + let mut updated_scheduled_requests = vec![]; + + // backwards compatible handling for DelegatorStatus::Leaving + #[allow(deprecated)] + if matches!(state.status, DelegatorStatus::Leaving(_)) { + state.status = DelegatorStatus::Active; + >::insert(delegator.clone(), state.clone()); + Self::deposit_event(Event::DelegatorExitCancelled { delegator }); + return Ok(().into()) + } + + // pre-validate that all delegations have a Revoke request. + for bond in &state.delegations.0 { + let collator = bond.owner.clone(); + let scheduled_requests = >::get(&collator); + scheduled_requests + .iter() + .find(|req| req.delegator == delegator && matches!(req.action, DelegationAction::Revoke(_))) + .ok_or(>::DelegatorNotLeaving)?; + } + + // cancel all requests + for bond in state.delegations.0.clone() { + let collator = bond.owner.clone(); + let mut scheduled_requests = >::get(&collator); + Self::cancel_request_with_state(&delegator, &mut state, &mut scheduled_requests); + updated_scheduled_requests.push((collator, scheduled_requests)); + } + + updated_scheduled_requests.into_iter().for_each(|(collator, scheduled_requests)| { + >::insert(collator, scheduled_requests); + }); + + >::insert(delegator.clone(), state); + Self::deposit_event(Event::DelegatorExitCancelled { delegator }); + + Ok(().into()) + } + + /// Executes every [DelegationAction::Revoke] request for a delegator towards a collator. + /// Each delegation must have a [DelegationAction::Revoke] scheduled that must be allowed to be + /// executed in the current round, for this function to succeed. + pub(crate) fn delegator_execute_scheduled_revoke_all( + delegator: T::AccountId, + delegation_count: u32, + ) -> DispatchResultWithPostInfo { + let mut state = >::get(&delegator).ok_or(>::DelegatorDNE)?; + ensure!( + delegation_count >= (state.delegations.0.len() as u32), + Error::::TooLowDelegationCountToLeaveDelegators + ); + let now = >::get().current; + + // backwards compatible handling for DelegatorStatus::Leaving + #[allow(deprecated)] + if let DelegatorStatus::Leaving(when) = state.status { + ensure!(>::get().current >= when, Error::::DelegatorCannotLeaveYet); + + for bond in state.delegations.0.clone() { + if let Err(error) = Self::delegator_leaves_candidate(bond.owner.clone(), delegator.clone(), bond.amount) + { + log::warn!("STORAGE CORRUPTED \nDelegator leaving collator failed with error: {:?}", error); + } + + Self::delegation_remove_request_with_state(&bond.owner, &delegator, &mut state); + >::remove_auto_compound(&bond.owner, &delegator); + } + >::remove(&delegator); + Self::deposit_event(Event::DelegatorLeft { delegator, unstaked_amount: state.total }); + return Ok(().into()) + } + + let mut validated_scheduled_requests = vec![]; + // pre-validate that all delegations have a Revoke request that can be executed now. + for bond in &state.delegations.0 { + let scheduled_requests = >::get(&bond.owner); + let request_idx = scheduled_requests + .iter() + .position(|req| req.delegator == delegator && matches!(req.action, DelegationAction::Revoke(_))) + .ok_or(>::DelegatorNotLeaving)?; + let request = &scheduled_requests[request_idx]; + + ensure!(request.when_executable <= now, >::DelegatorCannotLeaveYet); + + validated_scheduled_requests.push((bond.clone(), scheduled_requests, request_idx)) + } + + let mut updated_scheduled_requests = vec![]; + // we do not update the delegator state, since the it will be completely removed + for (bond, mut scheduled_requests, request_idx) in validated_scheduled_requests { + let collator = bond.owner; + + if let Err(error) = Self::delegator_leaves_candidate(collator.clone(), delegator.clone(), bond.amount) { + log::warn!( + "STORAGE CORRUPTED \nDelegator {:?} leaving collator failed with error: {:?}", + delegator, + error + ); + } + + // remove the scheduled request, since it is fulfilled + scheduled_requests.remove(request_idx).action.amount(); + updated_scheduled_requests.push((collator.clone(), scheduled_requests)); + + // remove the auto-compounding entry for the delegation + >::remove_auto_compound(&collator, &delegator); + } + + // set state.total so that state.adjust_bond_lock will remove lock + let unstaked_amount = state.total(); + state.total_sub::(unstaked_amount)?; + + updated_scheduled_requests.into_iter().for_each(|(collator, scheduled_requests)| { + >::insert(collator, scheduled_requests); + }); + + Self::deposit_event(Event::DelegatorLeft { delegator: delegator.clone(), unstaked_amount }); + >::remove(&delegator); + + Ok(().into()) + } + + /// Removes the delegator's existing [ScheduledRequest] towards a given collator, if exists. + /// The state needs to be persisted by the caller of this function. + pub(crate) fn delegation_remove_request_with_state( + collator: &T::AccountId, + delegator: &T::AccountId, + state: &mut Delegator>, + ) { + let mut scheduled_requests = >::get(collator); + + let maybe_request_idx = scheduled_requests.iter().position(|req| &req.delegator == delegator); + + if let Some(request_idx) = maybe_request_idx { + let request = scheduled_requests.remove(request_idx); + let amount = request.action.amount(); + state.less_total = state.less_total.saturating_sub(amount); + >::insert(collator, scheduled_requests); + } + } + + /// Returns true if a [ScheduledRequest] exists for a given delegation + pub fn delegation_request_exists(collator: &T::AccountId, delegator: &T::AccountId) -> bool { + >::get(collator).iter().any(|req| &req.delegator == delegator) + } + + /// Returns true if a [DelegationAction::Revoke] [ScheduledRequest] exists for a given delegation + pub fn delegation_request_revoke_exists(collator: &T::AccountId, delegator: &T::AccountId) -> bool { + >::get(collator) + .iter() + .any(|req| &req.delegator == delegator && matches!(req.action, DelegationAction::Revoke(_))) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{mock::Test, set::OrderedSet, Bond}; + + #[test] + fn test_cancel_request_with_state_removes_request_for_correct_delegator_and_updates_state() { + let mut state = Delegator { + id: 1, + delegations: OrderedSet::from(vec![Bond { amount: 100, owner: 2 }]), + total: 100, + less_total: 100, + status: crate::DelegatorStatus::Active, + }; + let mut scheduled_requests = vec![ + ScheduledRequest { delegator: 1, when_executable: 1, action: DelegationAction::Revoke(100) }, + ScheduledRequest { delegator: 2, when_executable: 1, action: DelegationAction::Decrease(50) }, + ]; + let removed_request = >::cancel_request_with_state(&1, &mut state, &mut scheduled_requests); + + assert_eq!( + removed_request, + Some(ScheduledRequest { delegator: 1, when_executable: 1, action: DelegationAction::Revoke(100) }) + ); + assert_eq!( + scheduled_requests, + vec![ScheduledRequest { delegator: 2, when_executable: 1, action: DelegationAction::Decrease(50) },] + ); + assert_eq!( + state, + Delegator { + id: 1, + delegations: OrderedSet::from(vec![Bond { amount: 100, owner: 2 }]), + total: 100, + less_total: 0, + status: crate::DelegatorStatus::Active, + } + ); + } + + #[test] + fn test_cancel_request_with_state_does_nothing_when_request_does_not_exist() { + let mut state = Delegator { + id: 1, + delegations: OrderedSet::from(vec![Bond { amount: 100, owner: 2 }]), + total: 100, + less_total: 100, + status: crate::DelegatorStatus::Active, + }; + let mut scheduled_requests = + vec![ScheduledRequest { delegator: 2, when_executable: 1, action: DelegationAction::Decrease(50) }]; + let removed_request = >::cancel_request_with_state(&1, &mut state, &mut scheduled_requests); + + assert_eq!(removed_request, None,); + assert_eq!( + scheduled_requests, + vec![ScheduledRequest { delegator: 2, when_executable: 1, action: DelegationAction::Decrease(50) },] + ); + assert_eq!( + state, + Delegator { + id: 1, + delegations: OrderedSet::from(vec![Bond { amount: 100, owner: 2 }]), + total: 100, + less_total: 100, + status: crate::DelegatorStatus::Active, + } + ); + } +} diff --git a/pallets/parachain-staking/src/inflation.rs b/pallets/parachain-staking/src/inflation.rs index 170e4d89c..b2b6aacd2 100644 --- a/pallets/parachain-staking/src/inflation.rs +++ b/pallets/parachain-staking/src/inflation.rs @@ -1,384 +1,176 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. -// The KILT Blockchain is free software: you can redistribute it and/or modify +// Moonbeam 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. -// The KILT Blockchain is distributed in the hope that it will be useful, +// Moonbeam 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 . - -// If you feel like getting in touch with us, you can do so at info@botlabs.org +// along with Moonbeam. If not, see . //! Helper methods for computing issuance based on inflation +use crate::pallet::{BalanceOf, Config, Pallet}; +use frame_support::traits::Currency; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; -use sp_runtime::{traits::Saturating, Perquintill, RuntimeDebug}; +use sp_runtime::{PerThing, Perbill, RuntimeDebug}; +use substrate_fixed::{transcendental::pow as floatpow, types::I64F64}; + +const SECONDS_PER_YEAR: u32 = 31557600; +const SECONDS_PER_BLOCK: u32 = 12; +pub const BLOCKS_PER_YEAR: u32 = SECONDS_PER_YEAR / SECONDS_PER_BLOCK; -use crate::{pallet::Config, types::BalanceOf}; +fn rounds_per_year() -> u32 { + let blocks_per_round = >::round().length; + BLOCKS_PER_YEAR / blocks_per_round +} #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[derive(Eq, PartialEq, Clone, Encode, Decode, Default, RuntimeDebug, TypeInfo)] -pub struct RewardRate { - pub annual: Perquintill, - pub per_block: Perquintill, +#[derive(Eq, PartialEq, Clone, Copy, Encode, Decode, Default, RuntimeDebug, MaxEncodedLen, TypeInfo)] +pub struct Range { + pub min: T, + pub ideal: T, + pub max: T, } -impl MaxEncodedLen for RewardRate { - fn max_encoded_len() -> usize { - // Perquintill is at most u128 - u128::max_encoded_len().saturating_add(u128::max_encoded_len()) +impl Range { + pub fn is_valid(&self) -> bool { + self.max >= self.ideal && self.ideal >= self.min } } -/// Convert annual reward rate to per_block. -fn annual_to_per_block(blocks_per_year: u64, rate: Perquintill) -> Perquintill { - rate / blocks_per_year.max(1) +impl From for Range { + fn from(other: T) -> Range { + Range { min: other, ideal: other, max: other } + } +} +/// Convert an annual inflation to a round inflation +/// round = (1+annual)^(1/rounds_per_year) - 1 +pub fn perbill_annual_to_perbill_round(annual: Range, rounds_per_year: u32) -> Range { + let exponent = I64F64::from_num(1) / I64F64::from_num(rounds_per_year); + let annual_to_round = |annual: Perbill| -> Perbill { + let x = I64F64::from_num(annual.deconstruct()) / I64F64::from_num(Perbill::ACCURACY); + let y: I64F64 = floatpow(I64F64::from_num(1) + x, exponent) + .expect("Cannot overflow since rounds_per_year is u32 so worst case 0; QED"); + Perbill::from_parts(((y - I64F64::from_num(1)) * I64F64::from_num(Perbill::ACCURACY)).ceil().to_num::()) + }; + Range { min: annual_to_round(annual.min), ideal: annual_to_round(annual.ideal), max: annual_to_round(annual.max) } +} +/// Convert annual inflation rate range to round inflation range +pub fn annual_to_round(annual: Range) -> Range { + let periods = rounds_per_year::(); + perbill_annual_to_perbill_round(annual, periods) } -impl RewardRate { - pub fn new(blocks_per_year: u64, rate: Perquintill) -> Self { - RewardRate { - annual: rate, - per_block: annual_to_per_block(blocks_per_year, rate), - } - } +/// Compute round issuance range from round inflation range and current total issuance +pub fn round_issuance_range(round: Range) -> Range> { + let circulating = T::Currency::total_issuance(); + Range { min: round.min * circulating, ideal: round.ideal * circulating, max: round.max * circulating } } -/// Staking info (staking rate and reward rate) for collators and delegators. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] #[derive(Eq, PartialEq, Clone, Encode, Decode, Default, RuntimeDebug, TypeInfo)] -pub struct StakingInfo { - /// Maximum staking rate. - pub max_rate: Perquintill, - /// Reward rate annually and per_block. - pub reward_rate: RewardRate, +pub struct InflationInfo { + /// Staking expectations + pub expect: Range, + /// Annual inflation range + pub annual: Range, + /// Round inflation range + pub round: Range, } -impl MaxEncodedLen for StakingInfo { - fn max_encoded_len() -> usize { - // Perquintill is at most u128 - RewardRate::max_encoded_len().saturating_add(u128::max_encoded_len()) - } -} - -impl StakingInfo { - pub fn new(blocks_per_year: u64, max_rate: Perquintill, annual_reward_rate: Perquintill) -> Self { - StakingInfo { - max_rate, - reward_rate: RewardRate::new(blocks_per_year, annual_reward_rate), - } +impl InflationInfo { + pub fn new(annual: Range, expect: Range) -> InflationInfo { + InflationInfo { expect, annual, round: annual_to_round::(annual) } } - /// Calculate newly minted rewards on coinbase, e.g., - /// reward = rewards_per_block * staking_rate. - /// - /// NOTE: If we exceed the max staking rate, the reward will be reduced by - /// max_rate / current_rate. - pub fn compute_reward( - &self, stake: BalanceOf, current_staking_rate: Perquintill, authors_per_round: BalanceOf, - ) -> BalanceOf { - // Perquintill automatically bounds to [0, 100]% in case staking_rate is greater - // than self.max_rate - let reduction = Perquintill::from_rational(self.max_rate.deconstruct(), current_staking_rate.deconstruct()); - // multiplication with perbill cannot overflow - let reward = (self.reward_rate.per_block * stake).saturating_mul(authors_per_round); - reduction * reward + /// Set round inflation range according to input annual inflation range + pub fn set_round_from_annual(&mut self, new: Range) { + self.round = annual_to_round::(new); } -} -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -#[derive(Eq, PartialEq, Clone, Encode, Decode, Default, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct InflationInfo { - pub collator: StakingInfo, - pub delegator: StakingInfo, -} - -impl InflationInfo { - /// Create a new inflation info from the max staking rates and annual reward - /// rates for collators and delegators. - /// - /// Example: InflationInfo::new(Perquintill_from_percent(10), ...) - pub fn new( - blocks_per_year: u64, collator_max_rate_percentage: Perquintill, - collator_annual_reward_rate_percentage: Perquintill, delegator_max_rate_percentage: Perquintill, - delegator_annual_reward_rate_percentage: Perquintill, - ) -> Self { - Self { - collator: StakingInfo::new( - blocks_per_year, - collator_max_rate_percentage, - collator_annual_reward_rate_percentage, - ), - delegator: StakingInfo::new( - blocks_per_year, - delegator_max_rate_percentage, - delegator_annual_reward_rate_percentage, - ), - } + /// Reset round inflation rate based on changes to round length + pub fn reset_round(&mut self, new_length: u32) { + let periods = BLOCKS_PER_YEAR / new_length; + self.round = perbill_annual_to_perbill_round(self.annual, periods); } - /// Check whether the annual reward rate is approx. the per_block reward - /// rate multiplied with the number of blocks per year - pub fn is_valid(&self, blocks_per_year: u64) -> bool { - self.collator.reward_rate.annual - >= Perquintill::from_parts( - self.collator - .reward_rate - .per_block - .deconstruct() - .saturating_mul(blocks_per_year), - ) && self.delegator.reward_rate.annual - >= Perquintill::from_parts( - self.delegator - .reward_rate - .per_block - .deconstruct() - .saturating_mul(blocks_per_year), - ) + /// Set staking expectations + pub fn set_expectations(&mut self, expect: Range) { + self.expect = expect; } } #[cfg(test)] mod tests { - use sp_runtime::Perbill; - - use crate::mock::{almost_equal, ExtBuilder, Test, DECIMALS, MAX_COLLATOR_STAKE}; - use super::*; - + fn mock_annual_to_round(annual: Range, rounds_per_year: u32) -> Range { + perbill_annual_to_perbill_round(annual, rounds_per_year) + } + fn mock_round_issuance_range( + // Total circulating before minting + circulating: u128, + // Round inflation range + round: Range, + ) -> Range { + Range { min: round.min * circulating, ideal: round.ideal * circulating, max: round.max * circulating } + } #[test] - fn perquintill() { + fn simple_issuance_conversion() { + // 5% inflation for 10_000_0000 = 500,000 minted over the year + // let's assume there are 10 periods in a year + // => mint 500_000 over 10 periods => 50_000 minted per period + let expected_round_issuance_range: Range = Range { min: 48_909, ideal: 48_909, max: 48_909 }; + let schedule = + Range { min: Perbill::from_percent(5), ideal: Perbill::from_percent(5), max: Perbill::from_percent(5) }; assert_eq!( - Perquintill::from_percent(100) * Perquintill::from_percent(50), - Perquintill::from_percent(50) + expected_round_issuance_range, + mock_round_issuance_range(10_000_000, mock_annual_to_round(schedule, 10)) ); } - #[test] - fn annual_to_block_rate() { - let rate = Perquintill::one(); - assert!(almost_equal( - rate * 10_000_000_000u128, - Perquintill::from_parts( - annual_to_per_block(::BLOCKS_PER_YEAR, rate).deconstruct() - * ::BLOCKS_PER_YEAR - ) * 10_000_000_000u128, - Perbill::from_perthousand(1) - )); + fn range_issuance_conversion() { + // 3-5% inflation for 10_000_0000 = 300_000-500,000 minted over the year + // let's assume there are 10 periods in a year + // => mint 300_000-500_000 over 10 periods => 30_000-50_000 minted per period + let expected_round_issuance_range: Range = Range { min: 29_603, ideal: 39298, max: 48_909 }; + let schedule = + Range { min: Perbill::from_percent(3), ideal: Perbill::from_percent(4), max: Perbill::from_percent(5) }; + assert_eq!( + expected_round_issuance_range, + mock_round_issuance_range(10_000_000, mock_annual_to_round(schedule, 10)) + ); } - #[test] - fn single_block_reward_collator() { - let inflation = InflationInfo::new( - ::BLOCKS_PER_YEAR, - Perquintill::from_percent(10), - Perquintill::from_percent(10), - Perquintill::from_percent(40), - Perquintill::from_percent(8), - ); - let reward = inflation - .collator - .compute_reward::(MAX_COLLATOR_STAKE, Perquintill::from_percent(9), 2); - let expected = ::CurrencyBalance::from(15210282150733u64); - assert!( - almost_equal(reward, expected, Perbill::from_perthousand(1)), - "left {:?}, right {:?}", - reward, - expected + fn expected_parameterization() { + let expected_round_schedule: Range = Range { min: 45, ideal: 56, max: 56 }; + let schedule = + Range { min: Perbill::from_percent(4), ideal: Perbill::from_percent(5), max: Perbill::from_percent(5) }; + assert_eq!( + expected_round_schedule, + mock_round_issuance_range(10_000_000, mock_annual_to_round(schedule, 8766)) ); } - #[test] - fn simple_block_reward_check() { - let precision = Perbill::from_perthousand(1); - ExtBuilder::default() - .with_inflation(10, 15, 40, 10, 5) - .with_balances(vec![(1, 10)]) - .with_collators(vec![(1, 10)]) - .build() - .execute_with(|| { - let inflation = InflationInfo::new( - ::BLOCKS_PER_YEAR, - Perquintill::from_percent(10), - Perquintill::from_percent(15), - Perquintill::from_percent(40), - Perquintill::from_percent(10), - ); - let years_u128: BalanceOf = ::BLOCKS_PER_YEAR as u128; - - // Dummy checks for correct instantiation - assert!(inflation.is_valid(::BLOCKS_PER_YEAR)); - assert_eq!(inflation.collator.max_rate, Perquintill::from_percent(10)); - assert_eq!(inflation.collator.reward_rate.annual, Perquintill::from_percent(15)); - assert!( - almost_equal( - inflation.collator.reward_rate.per_block * DECIMALS * 10_000, - Perquintill::from_percent(15) * 10_000 * DECIMALS / years_u128, - precision - ), - "left = {:?}, right = {:?}", - inflation.collator.reward_rate.per_block * 10_000 * DECIMALS, - Perquintill::from_percent(15) * 10_000 * DECIMALS / years_u128, - ); - assert_eq!(inflation.delegator.max_rate, Perquintill::from_percent(40)); - assert_eq!(inflation.delegator.reward_rate.annual, Perquintill::from_percent(10)); - assert!( - almost_equal( - inflation.delegator.reward_rate.per_block * DECIMALS * 10_000, - Perquintill::from_percent(10) * 10_000 * DECIMALS / years_u128, - precision - ), - "left = {:?}, right = {:?}", - inflation.delegator.reward_rate.per_block * DECIMALS * 10_000, - Perquintill::from_percent(10) * 10_000 * DECIMALS / years_u128, - ); - - // Check collator reward computation - let authors_per_round = 1u128; - let mut current_staking_rate: Perquintill = inflation.collator.max_rate; - assert_eq!( - inflation - .collator - .compute_reward::(0, current_staking_rate, authors_per_round), - 0 - ); - current_staking_rate = Perquintill::from_rational(5000u64, 100_000u64); - assert!( - almost_equal( - inflation.collator.compute_reward::( - 5000 * DECIMALS, - current_staking_rate, - authors_per_round - ) * years_u128, - Perquintill::from_percent(15) * 5000 * DECIMALS, - Perbill::from_percent(1) - ), - "left = {:?}, right = {:?}", - inflation - .collator - .compute_reward::(5000 * DECIMALS, current_staking_rate, authors_per_round) - * years_u128, - Perquintill::from_percent(15) * 5000 * DECIMALS, - ); - // Check for max_rate which is 10% - current_staking_rate = Perquintill::from_rational(10_000u64, 100_000u64); - assert!( - almost_equal( - inflation.collator.compute_reward::( - 10_000 * DECIMALS, - current_staking_rate, - authors_per_round - ) * years_u128, - Perquintill::from_percent(15) * 10_000 * DECIMALS, - Perbill::from_percent(1) - ), - "left = {:?}, right = {:?}", - inflation.collator.compute_reward::( - 10_000 * DECIMALS, - current_staking_rate, - authors_per_round - ) * years_u128, - Perquintill::from_percent(15) * 10_000 * DECIMALS, - ); - - // Check for exceeding max_rate: 50% instead of 10% - current_staking_rate = Perquintill::from_rational(50_000u64, 100_000u64); - assert!( - almost_equal( - inflation.collator.compute_reward::( - 50_000 * DECIMALS, - current_staking_rate, - authors_per_round - ) * years_u128, - Perquintill::from_percent(15) * 10_000 * DECIMALS, - Perbill::from_percent(1) - ), - "left = {:?}, right = {:?}", - inflation.collator.compute_reward::( - 50_000 * DECIMALS, - current_staking_rate, - authors_per_round - ) * years_u128, - Perquintill::from_percent(15) * 10_000 * DECIMALS, - ); - - // Check delegator reward computation - current_staking_rate = inflation.delegator.max_rate; - assert_eq!( - inflation - .delegator - .compute_reward::(0, current_staking_rate, authors_per_round), - 0 - ); - current_staking_rate = Perquintill::from_rational(5000u64, 100_000u64); - assert!( - almost_equal( - inflation.delegator.compute_reward::( - 5000 * DECIMALS, - current_staking_rate, - authors_per_round - ) * years_u128, - Perquintill::from_percent(10) * 5000 * DECIMALS, - Perbill::from_percent(1) - ), - "left = {:?}, right = {:?}", - inflation.delegator.compute_reward::( - 5000 * DECIMALS, - current_staking_rate, - authors_per_round - ) * years_u128, - Perquintill::from_percent(10) * 5000 * DECIMALS, - ); - // Check for max_rate which is 40% - current_staking_rate = Perquintill::from_rational(40_000u64, 100_000u64); - assert!( - almost_equal( - inflation.delegator.compute_reward::( - 40_000 * DECIMALS, - current_staking_rate, - authors_per_round - ) * years_u128, - Perquintill::from_percent(10) * 40_000 * DECIMALS, - Perbill::from_percent(1) - ), - "left = {:?}, right = {:?}", - inflation.delegator.compute_reward::( - 40_000 * DECIMALS, - current_staking_rate, - authors_per_round - ) * years_u128, - Perquintill::from_percent(10) * 40_000 * DECIMALS, - ); - - // Check for exceeding max_rate: 50% instead of 40% - current_staking_rate = Perquintill::from_rational(50_000u64, 100_000u64); - assert!( - almost_equal( - inflation.delegator.compute_reward::( - 50_000 * DECIMALS, - current_staking_rate, - authors_per_round - ) * years_u128, - Perquintill::from_percent(8) * 50_000 * DECIMALS, - Perbill::from_percent(1) - ), - "left = {:?}, right = {:?}", - inflation.delegator.compute_reward::( - 50_000 * DECIMALS, - current_staking_rate, - authors_per_round - ) * years_u128, - Perquintill::from_percent(8) * 50_000 * DECIMALS, - ); - }); + fn inflation_does_not_panic_at_round_number_limit() { + let schedule = Range { + min: Perbill::from_percent(100), + ideal: Perbill::from_percent(100), + max: Perbill::from_percent(100), + }; + mock_round_issuance_range(u32::MAX.into(), mock_annual_to_round(schedule, u32::MAX)); + mock_round_issuance_range(u64::MAX.into(), mock_annual_to_round(schedule, u32::MAX)); + mock_round_issuance_range(u128::MAX.into(), mock_annual_to_round(schedule, u32::MAX)); + mock_round_issuance_range(u32::MAX.into(), mock_annual_to_round(schedule, 1)); + mock_round_issuance_range(u64::MAX.into(), mock_annual_to_round(schedule, 1)); + mock_round_issuance_range(u128::MAX.into(), mock_annual_to_round(schedule, 1)); } } diff --git a/pallets/parachain-staking/src/lib.rs b/pallets/parachain-staking/src/lib.rs index 6de3c6988..b787a8577 100644 --- a/pallets/parachain-staking/src/lib.rs +++ b/pallets/parachain-staking/src/lib.rs @@ -1,666 +1,655 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. -// The KILT Blockchain is free software: you can redistribute it and/or modify +// Moonbeam 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. -// The KILT Blockchain is distributed in the hope that it will be useful, +// Moonbeam 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 . - -// If you feel like getting in touch with us, you can do so at info@botlabs.org +// along with Moonbeam. If not, see . //! # Parachain Staking +//! Minimal staking pallet that implements collator selection by total backed stake. +//! The main difference between this pallet and `frame/pallet-staking` is that this pallet +//! uses direct delegation. Delegators choose exactly who they delegate and with what stake. +//! This is different from `frame/pallet-staking` where delegators approval vote and run Phragmen. //! -//! A simple staking pallet providing means of selecting a set of collators to -//! become block authors based on their total backed stake. The main difference -//! between this pallet and `frame/pallet-staking` is that this pallet uses -//! direct delegation. Delegators choose exactly who they delegate and with what -//! stake. This is different from `frame/pallet-staking` where you approval vote -//! and then run Phragmen. Moreover, this pallet rewards a collator and their -//! delegators immediately when authoring a block. Rewards are calculated -//! separately between collators and delegators. -//! -//! To join the set of candidates, an account must call `join_candidates` with -//! `MinCollatorCandidateStake` <= stake <= `MaxCollatorCandidateStake`. -//! -//! To leave the set of candidates, the collator calls `leave_candidates`. If -//! the call succeeds, the collator is removed from the pool of candidates so -//! they cannot be selected for future collator sets, but they are not unstaking -//! until executing the exit request by calling the extrinsic -//! `execute_leave_candidates` at least `ExitQueueDelay` rounds later. After -//! doing so, the collator candidate as well as their delegators are unstaked. -//! Both parties then have to wait another `StakeDuration` more blocks to be -//! able to unlock their stake. -//! -//! Candidates which requested to leave can still be in the set of authors for -//! the next round due to the design of the session pallet which at the start of -//! session s(i) chooses a set for the next session s(i+1). Thus, candidates -//! have to keep collating at least until the end of the next session (= round). -//! We extend this by delaying their execute by at least `ExitQueueDelay` many -//! sessions. -//! -//! To join the set of delegators, an account must call `join_delegators` with -//! stake >= `MinDelegatorStake`. There are also runtime methods for delegating -//! additional collators and revoking delegations. -//! -//! -//! - [`Config`] -//! - [`Call`] -//! - [`Pallet`] -//! -//! ## Overview -//! -//! The KILT parachain staking pallet provides functions for: -//! - Joining the set of collator candidates of which the best -//! `MaxSelectedCandidates` are chosen to become active collators for the next -//! session. That makes the set of active collators the set of block authors -//! by handing it over to the session and the authority pallet. -//! - Delegating to a collator candidate by staking for them. -//! - Increasing and reducing your stake as a collator or delegator. -//! - Revoking your delegation entirely. -//! - Requesting to leave the set of collator candidates. -//! - Withdrawing your unstaked balance after waiting for a certain number of -//! blocks. -//! -//! ### Terminology -//! -//! - **Candidate:** A user which locks up tokens to be included into the set of -//! authorities which author blocks and receive rewards for doing so. -//! -//! - **Collator:** A candidate that was chosen to collate this round. -//! -//! - **Delegator:** A user which locks up tokens for collators they trust. When -//! their collator authors a block, the corresponding delegators also receive -//! rewards. -//! -//! - **Total Stake:** A collator’s own stake + the sum of delegated stake to -//! this collator. -//! -//! - **Total collator stake:** The sum of tokens locked for staking from all -//! collator candidates. -//! -//! - **Total delegator stake:** The sum of tokens locked for staking from all -//! delegators. +//! ### Rules +//! There is a new round every `>::get().length` blocks. //! -//! - **To Stake:** Lock tokens for staking. +//! At the start of every round, +//! * issuance is calculated for collators (and their delegators) for block authoring +//! `T::RewardPaymentDelay` rounds ago +//! * a new set of collators is chosen from the candidates //! -//! - **To Unstake:** Unlock tokens from staking. +//! Immediately following a round change, payments are made once-per-block until all payments have +//! been made. In each such block, one collator is chosen for a rewards payment and is paid along +//! with each of its top `T::MaxTopDelegationsPerCandidate` delegators. //! -//! - **Round (= Session):** A fixed number of blocks in which the set of -//! collators does not change. We set the length of a session to the length of -//! a staking round, thus both words are interchangeable in the context of -//! this pallet. +//! To join the set of candidates, call `join_candidates` with `bond >= MinCandidateStk`. +//! To leave the set of candidates, call `schedule_leave_candidates`. If the call succeeds, +//! the collator is removed from the pool of candidates so they cannot be selected for future +//! collator sets, but they are not unbonded until their exit request is executed. Any signed +//! account may trigger the exit `T::LeaveCandidatesDelay` rounds after the round in which the +//! original request was made. //! -//! - **Lock:** A freeze on a specified amount of an account's free balance -//! until a specified block number. Multiple locks always operate over the -//! same funds, so they "overlay" rather than "stack" +//! To join the set of delegators, call `delegate` and pass in an account that is +//! already a collator candidate and `bond >= MinDelegatorStk`. Each delegator can delegate up to +//! `T::MaxDelegationsPerDelegator` collator candidates by calling `delegate`. //! -//! ## Genesis config -//! -//! The ParachainStaking pallet depends on the [`GenesisConfig`]. -//! -//! ## Assumptions -//! -//! - At the start of session s(i), the set of session ids for session s(i+1) -//! are chosen. These equal the set of selected candidates. Thus, we cannot -//! allow collators to leave at least until the start of session s(i+2). +//! To revoke a delegation, call `revoke_delegation` with the collator candidate's account. +//! To leave the set of delegators and revoke all delegations, call `leave_delegators`. #![cfg_attr(not(feature = "std"), no_std)] -#![allow(clippy::unused_unit)] - -use frame_support::pallet; - -pub use crate::{default_weights::WeightInfo, pallet::*}; -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmarking; -pub mod default_weights; +mod auto_compound; +mod delegation_requests; +pub mod inflation; +pub mod migrations; +pub mod traits; +pub mod types; +pub mod weights; -pub mod migration; +#[cfg(any(test, feature = "runtime-benchmarks"))] +mod benchmarks; #[cfg(test)] -pub(crate) mod mock; +mod mock; +mod set; #[cfg(test)] -pub(crate) mod tests; +mod tests; -pub mod api; -mod inflation; -mod set; -mod types; +use frame_support::pallet; +pub use inflation::{InflationInfo, Range}; +use weights::WeightInfo; + +pub use auto_compound::{AutoCompoundConfig, AutoCompoundDelegations}; +pub use delegation_requests::{CancelledScheduledRequest, DelegationAction, ScheduledRequest}; +pub use pallet::*; +pub use traits::*; +pub use types::*; +pub use RoundIndex; #[pallet] pub mod pallet { + use crate::{ + delegation_requests::{CancelledScheduledRequest, DelegationAction, ScheduledRequest}, + set::OrderedSet, + traits::*, + types::*, + AutoCompoundConfig, AutoCompoundDelegations, InflationInfo, Range, WeightInfo, + }; use frame_support::{ - assert_ok, pallet_prelude::*, - storage::bounded_btree_map::BoundedBTreeMap, traits::{ - Currency, EstimateNextSessionRotation, Get, Imbalance, LockIdentifier, LockableCurrency, OnUnbalanced, - ReservableCurrency, StorageVersion, WithdrawReasons, + tokens::WithdrawReasons, Currency, EstimateNextSessionRotation, Get, Imbalance, LockIdentifier, + LockableCurrency, ReservableCurrency, }, - BoundedVec, }; use frame_system::pallet_prelude::*; - use pallet_balances::{BalanceLock, Locks}; - use pallet_session::ShouldEndSession; - use scale_info::TypeInfo; use sp_runtime::{ - traits::{Convert, One, SaturatedConversion, Saturating, StaticLookup, Zero}, - Permill, Perquintill, + traits::{Saturating, Zero}, + Perbill, Percent, Permill, }; use sp_staking::SessionIndex; - use sp_std::{convert::TryInto, fmt::Debug, prelude::*}; - - pub use crate::inflation::{InflationInfo, RewardRate, StakingInfo}; - use crate::{ - set::OrderedSet, - types::{ - BalanceOf, Candidate, CandidateOf, CandidateStatus, DelegationCounter, Delegator, NegativeImbalanceOf, - RoundInfo, Stake, StakeOf, TotalStake, - }, - }; + use sp_std::{collections::btree_map::BTreeMap, prelude::*}; - use super::*; + /// Pallet for parachain staking + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(PhantomData); - /// Kilt-specific lock for staking rewards. - pub(crate) const STAKING_ID: LockIdentifier = *b"kiltpstk"; + pub type RoundIndex = u32; + type RewardPoint = u32; + pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; - /// The current storage version. - const STORAGE_VERSION: StorageVersion = StorageVersion::new(8); + pub type AccountIdOf = ::AccountId; - /// Pallet for parachain staking. - #[pallet::pallet] - #[pallet::generate_store(pub (super) trait Store)] - #[pallet::storage_version(STORAGE_VERSION)] - pub struct Pallet(PhantomData); + pub const COLLATOR_LOCK_ID: LockIdentifier = *b"stkngcol"; + pub const DELEGATOR_LOCK_ID: LockIdentifier = *b"stkngdel"; /// Configuration trait of this pallet. #[pallet::config] - pub trait Config: frame_system::Config + pallet_balances::Config + pallet_session::Config { + pub trait Config: frame_system::Config { /// Overarching event type type RuntimeEvent: From> + IsType<::RuntimeEvent>; - // FIXME: Remove Currency and CurrencyBalance types. Problem: Need to restrict - // pallet_balances::Config::Balance with From for usage with Perquintill - // multiplication /// The currency type - /// Note: Declaration of Balance taken from pallet_gilt - type Currency: Currency - + ReservableCurrency - + LockableCurrency - + Eq; - - /// Just the `Currency::Balance` type; we have this item to allow us to - /// constrain it to `From`. - /// Note: Definition taken from pallet_gilt - type CurrencyBalance: sp_runtime::traits::AtLeast32BitUnsigned - + parity_scale_codec::FullCodec - + Copy - + MaybeSerializeDeserialize - + sp_std::fmt::Debug - + Default - + From - + From - + Into<::Balance> - + From<::Balance> - + From - + TypeInfo - + MaxEncodedLen; - - /// Minimum number of blocks validation rounds can last. - #[pallet::constant] - type MinBlocksPerRound: Get; - - /// Default number of blocks validation rounds last, as set in the - /// genesis configuration. + type Currency: Currency + + ReservableCurrency + + LockableCurrency; + /// The origin for monetary governance + type MonetaryGovernanceOrigin: EnsureOrigin; + /// Minimum number of blocks per round #[pallet::constant] - type DefaultBlocksPerRound: Get; - /// Number of blocks for which unstaked balance will still be locked - /// before it can be unlocked by actively calling the extrinsic - /// `unlock_unstaked`. + type MinBlocksPerRound: Get; + /// Number of rounds that candidates remain bonded before exit request is executable #[pallet::constant] - type StakeDuration: Get; - /// Number of rounds a collator has to stay active after submitting a - /// request to leave the set of collator candidates. + type LeaveCandidatesDelay: Get; + /// Number of rounds candidate requests to decrease self-bond must wait to be executable #[pallet::constant] - type ExitQueueDelay: Get; - - /// Minimum number of collators selected from the set of candidates at - /// every validation round. + type CandidateBondLessDelay: Get; + /// Number of rounds that delegators remain bonded before exit request is executable #[pallet::constant] - type MinCollators: Get; - - /// Minimum number of collators which cannot leave the network if there - /// are no others. + type LeaveDelegatorsDelay: Get; + /// Number of rounds that delegations remain bonded before revocation request is executable #[pallet::constant] - type MinRequiredCollators: Get; - - /// Maximum number of delegations which can be made within the same - /// round. - /// - /// NOTE: To prevent re-delegation-reward attacks, we should keep this - /// to be one. + type RevokeDelegationDelay: Get; + /// Number of rounds that delegation less requests must wait before executable #[pallet::constant] - type MaxDelegationsPerRound: Get; - - /// Maximum number of delegators a single collator can have. + type DelegationBondLessDelay: Get; + /// Number of rounds after which block authors are rewarded #[pallet::constant] - type MaxDelegatorsPerCollator: Get + Debug + PartialEq; - - /// Maximum size of the top candidates set. + type RewardPaymentDelay: Get; + /// Minimum number of selected candidates every round #[pallet::constant] - type MaxTopCandidates: Get + Debug + PartialEq; - - /// Minimum stake required for any account to be elected as validator - /// for a round. + type MinSelectedCandidates: Get; + /// Maximum top delegations counted per candidate #[pallet::constant] - type MinCollatorStake: Get>; - - /// Minimum stake required for any account to be added to the set of - /// candidates. + type MaxTopDelegationsPerCandidate: Get; + /// Maximum bottom delegations (not counted) per candidate #[pallet::constant] - type MinCollatorCandidateStake: Get>; - - /// Minimum stake required for any account to become a delegator. + type MaxBottomDelegationsPerCandidate: Get; + /// Maximum delegations per delegator #[pallet::constant] - type MinDelegatorStake: Get>; - - /// Max number of concurrent active unstaking requests before - /// unlocking. - /// - /// NOTE: To protect against irremovability of a candidate or delegator, - /// we only allow for MaxUnstakeRequests - 1 many manual unstake - /// requests. The last one serves as a placeholder for the cases of - /// calling either `kick_delegator`, force_remove_candidate` or - /// `execute_leave_candidates`. Otherwise, a user could max out their - /// unstake requests and prevent themselves from being kicked from the - /// set of candidates/delegators until they unlock their funds. + type MaxDelegationsPerDelegator: Get; + /// Minimum stake required for any account to be a collator candidate #[pallet::constant] - type MaxUnstakeRequests: Get; - - /// The starting block number for the network rewards. Once the current - /// block number exceeds this start, the beneficiary will receive the - /// configured reward in each block. + type MinCandidateStk: Get>; + /// Minimum stake for any registered on-chain account to delegate #[pallet::constant] - type NetworkRewardStart: Get<::BlockNumber>; - - /// The rate in percent for the network rewards which are based on the - /// maximum number of collators and the maximum amount a collator can - /// stake. + type MinDelegation: Get>; + /// Minimum stake for any registered on-chain account to be a delegator #[pallet::constant] - type NetworkRewardRate: Get; - - /// The beneficiary to receive the network rewards. - type NetworkRewardBeneficiary: OnUnbalanced>; - + type MinDelegatorStk: Get>; + /// Get the current block author + // type BlockAuthor: Get; + /// Handler to notify the runtime when a collator is paid. + /// If you don't need it, you can specify the type `()`. + type OnCollatorPayout: OnCollatorPayout>; + /// Handler to distribute a collator's reward. + /// To use the default implementation of minting rewards, specify the type `()`. + type PayoutCollatorReward: PayoutCollatorReward; + /// Handler to notify the runtime when a new round begin. + /// If you don't need it, you can specify the type `()`. + type OnNewRound: OnNewRound; /// Weight information for extrinsics in this pallet. type WeightInfo: WeightInfo; - - const BLOCKS_PER_YEAR: Self::BlockNumber; } #[pallet::error] pub enum Error { - /// The account is not part of the delegators set. - DelegatorNotFound, - /// The account is not part of the collator candidates set. - CandidateNotFound, - /// The account is already part of the delegators set. + DelegatorDNE, + DelegatorDNEinTopNorBottom, + DelegatorDNEInDelegatorSet, + CandidateDNE, + DelegationDNE, DelegatorExists, - /// The account is already part of the collator candidates set. CandidateExists, - /// The account tried to stake more or less with amount zero. - ValStakeZero, - /// The account has not staked enough funds to be added to the collator - /// candidates set. - ValStakeBelowMin, - /// The account has already staked the maximum amount of funds possible. - ValStakeAboveMax, - /// The account has not staked enough funds to delegate a collator - /// candidate. + CandidateBondBelowMin, + InsufficientBalance, + DelegatorBondBelowMin, DelegationBelowMin, - /// The collator candidate has already trigger the process to leave the - /// set of collator candidates. - AlreadyLeaving, - /// The collator candidate wanted to execute the exit but has not - /// requested to leave before by calling `init_leave_candidates`. - NotLeaving, - /// The collator tried to leave before waiting at least for - /// `ExitQueueDelay` many rounds. - CannotLeaveYet, - /// The account has a full list of unstaking requests and needs to - /// unlock at least one of these before being able to join (again). - /// NOTE: Can only happen if the account was a candidate or - /// delegator before and either got kicked or exited voluntarily. - CannotJoinBeforeUnlocking, - /// The account is already delegating the collator candidate. - AlreadyDelegating, - /// The account has not delegated any collator candidate yet, hence it - /// is not in the set of delegators. - NotYetDelegating, - /// The delegator has exceeded the number of delegations per round which - /// is equal to MaxDelegatorsPerCollator. - /// - /// This protects against attacks in which a delegator can re-delegate - /// from a collator who has already authored a block, to another one - /// which has not in this round. - DelegationsPerRoundExceeded, - /// The collator candidate has already reached the maximum number of - /// delegators. - /// - /// This error is generated in case a new delegation request does not - /// stake enough funds to replace some other existing delegation. - TooManyDelegators, - /// The set of collator candidates would fall below the required minimum - /// if the collator left. - TooFewCollatorCandidates, - /// The collator candidate is in the process of leaving the set of - /// candidates and cannot perform any other actions in the meantime. - CannotStakeIfLeaving, - /// The collator candidate is in the process of leaving the set of - /// candidates and thus cannot be delegated to. + AlreadyOffline, + AlreadyActive, + DelegatorAlreadyLeaving, + DelegatorNotLeaving, + DelegatorCannotLeaveYet, CannotDelegateIfLeaving, - /// The delegator has already delegated the maximum number of candidates - /// allowed. - MaxCollatorsPerDelegatorExceeded, - /// The delegator has already previously delegated the collator - /// candidate. - AlreadyDelegatedCollator, - /// The given delegation does not exist in the set of delegations. - DelegationNotFound, - /// The collator delegate or the delegator is trying to un-stake more - /// funds that are currently staked. - Underflow, - /// The number of selected candidates per staking round is - /// above the maximum value allowed. - CannotSetAboveMax, - /// The number of selected candidates per staking round is - /// below the minimum value allowed. - CannotSetBelowMin, - /// An invalid inflation configuration is trying to be set. + CandidateAlreadyLeaving, + CandidateNotLeaving, + CandidateCannotLeaveYet, + CannotGoOnlineIfLeaving, + ExceedMaxDelegationsPerDelegator, + AlreadyDelegatedCandidate, InvalidSchedule, - /// The staking reward being unlocked does not exist. - /// Max unlocking requests reached. - NoMoreUnstaking, - /// The reward rate cannot be adjusted yet as an entire year has not - /// passed. - TooEarly, - /// Provided staked value is zero. Should never be thrown. - StakeNotFound, - /// Cannot unlock when Unstaked is empty. - UnstakingIsEmpty, - /// Cannot claim rewards if empty. - RewardsNotFound, + CannotSetBelowMin, + RoundLengthMustBeGreaterThanTotalSelectedCollators, + NoWritingSameValue, + TooLowCandidateCountWeightHintJoinCandidates, + TooLowCandidateCountWeightHintCancelLeaveCandidates, + TooLowCandidateCountToLeaveCandidates, + TooLowDelegationCountToDelegate, + TooLowCandidateDelegationCountToDelegate, + TooLowCandidateDelegationCountToLeaveCandidates, + TooLowDelegationCountToLeaveDelegators, + PendingCandidateRequestsDNE, + PendingCandidateRequestAlreadyExists, + PendingCandidateRequestNotDueYet, + PendingDelegationRequestDNE, + PendingDelegationRequestAlreadyExists, + PendingDelegationRequestNotDueYet, + CannotDelegateLessThanOrEqualToLowestBottomWhenFull, + PendingDelegationRevoke, + TooLowDelegationCountToAutoCompound, + TooLowCandidateAutoCompoundingDelegationCountToAutoCompound, + TooLowCandidateAutoCompoundingDelegationCountToDelegate, } #[pallet::event] #[pallet::generate_deposit(pub(crate) fn deposit_event)] pub enum Event { - /// A new staking round has started. - /// \[block number, round number\] - NewRound(T::BlockNumber, SessionIndex), - /// A new account has joined the set of top candidates. - /// \[account\] - EnteredTopCandidates(T::AccountId), - /// An account was removed from the set of top candidates. - /// \[account\] - LeftTopCandidates(T::AccountId), - /// A new account has joined the set of collator candidates. - /// \[account, amount staked by the new candidate\] - JoinedCollatorCandidates(T::AccountId, BalanceOf), - /// A collator candidate has increased the amount of funds at stake. - /// \[collator's account, previous stake, new stake\] - CollatorStakedMore(T::AccountId, BalanceOf, BalanceOf), - /// A collator candidate has decreased the amount of funds at stake. - /// \[collator's account, previous stake, new stake\] - CollatorStakedLess(T::AccountId, BalanceOf, BalanceOf), - /// A collator candidate has started the process to leave the set of - /// candidates. \[round number, collator's account, round number when - /// the collator will be effectively removed from the set of - /// candidates\] - CollatorScheduledExit(SessionIndex, T::AccountId, SessionIndex), - /// A collator candidate has canceled the process to leave the set of - /// candidates and was added back to the candidate pool. \[collator's - /// account\] - CollatorCanceledExit(T::AccountId), - /// An account has left the set of collator candidates. - /// \[account, amount of funds un-staked\] - CandidateLeft(T::AccountId, BalanceOf), - /// An account was forcedly removed from the set of collator - /// candidates. \[account, amount of funds un-staked\] - CollatorRemoved(T::AccountId, BalanceOf), - /// The maximum candidate stake has been changed. - /// \[new max amount\] - MaxCandidateStakeChanged(BalanceOf), - /// A delegator has increased the amount of funds at stake for a - /// collator. \[delegator's account, collator's account, previous - /// delegation stake, new delegation stake\] - DelegatorStakedMore(T::AccountId, T::AccountId, BalanceOf, BalanceOf), - /// A delegator has decreased the amount of funds at stake for a - /// collator. \[delegator's account, collator's account, previous - /// delegation stake, new delegation stake\] - DelegatorStakedLess(T::AccountId, T::AccountId, BalanceOf, BalanceOf), - /// An account has left the set of delegators. - /// \[account, amount of funds un-staked\] - DelegatorLeft(T::AccountId, BalanceOf), - /// An account has delegated a new collator candidate. - /// \[account, amount of funds staked, total amount of delegators' funds - /// staked for the collator candidate\] - Delegation(T::AccountId, BalanceOf, T::AccountId, BalanceOf), - /// A new delegation has replaced an existing one in the set of ongoing - /// delegations for a collator candidate. \[new delegator's account, - /// amount of funds staked in the new delegation, replaced delegator's - /// account, amount of funds staked in the replace delegation, collator - /// candidate's account, new total amount of delegators' funds staked - /// for the collator candidate\] - DelegationReplaced( - T::AccountId, - BalanceOf, - T::AccountId, - BalanceOf, - T::AccountId, - BalanceOf, - ), - /// An account has stopped delegating a collator candidate. - /// \[account, collator candidate's account, old amount of delegators' - /// funds staked, new amount of delegators' funds staked\] - DelegatorLeftCollator(T::AccountId, T::AccountId, BalanceOf, BalanceOf), - /// A collator or a delegator has received a reward. - /// \[account, amount of reward\] - Rewarded(T::AccountId, BalanceOf), - /// Inflation configuration for future validation rounds has changed. - /// \[maximum collator's staking rate, maximum collator's reward rate, - /// maximum delegator's staking rate, maximum delegator's reward rate\] - RoundInflationSet(Perquintill, Perquintill, Perquintill, Perquintill), - /// The maximum number of collator candidates selected in future - /// validation rounds has changed. \[old value, new value\] - MaxSelectedCandidatesSet(u32, u32), - /// The length in blocks for future validation rounds has changed. - /// \[round number, first block in the current round, old value, new - /// value\] - BlocksPerRoundSet(SessionIndex, T::BlockNumber, T::BlockNumber, T::BlockNumber), + /// Started new round. + NewRound { + starting_block: T::BlockNumber, + round: RoundIndex, + selected_collators_number: u32, + total_balance: BalanceOf, + }, + /// Account joined the set of collator candidates. + JoinedCollatorCandidates { + account: T::AccountId, + amount_locked: BalanceOf, + new_total_amt_locked: BalanceOf, + }, + /// Candidate selected for collators. Total Exposed Amount includes all delegations. + CollatorChosen { + round: RoundIndex, + collator_account: T::AccountId, + total_exposed_amount: BalanceOf, + }, + /// Candidate requested to decrease a self bond. + CandidateBondLessRequested { + candidate: T::AccountId, + amount_to_decrease: BalanceOf, + execute_round: RoundIndex, + }, + /// Candidate has increased a self bond. + CandidateBondedMore { + candidate: T::AccountId, + amount: BalanceOf, + new_total_bond: BalanceOf, + }, + /// Candidate has decreased a self bond. + CandidateBondedLess { + candidate: T::AccountId, + amount: BalanceOf, + new_bond: BalanceOf, + }, + /// Candidate temporarily leave the set of collator candidates without unbonding. + CandidateWentOffline { + candidate: T::AccountId, + }, + /// Candidate rejoins the set of collator candidates. + CandidateBackOnline { + candidate: T::AccountId, + }, + /// Candidate has requested to leave the set of candidates. + CandidateScheduledExit { + exit_allowed_round: RoundIndex, + candidate: T::AccountId, + scheduled_exit: RoundIndex, + }, + /// Cancelled request to leave the set of candidates. + CancelledCandidateExit { + candidate: T::AccountId, + }, + /// Cancelled request to decrease candidate's bond. + CancelledCandidateBondLess { + candidate: T::AccountId, + amount: BalanceOf, + execute_round: RoundIndex, + }, + /// Candidate has left the set of candidates. + CandidateLeft { + ex_candidate: T::AccountId, + unlocked_amount: BalanceOf, + new_total_amt_locked: BalanceOf, + }, + /// Delegator requested to decrease a bond for the collator candidate. + DelegationDecreaseScheduled { + delegator: T::AccountId, + candidate: T::AccountId, + amount_to_decrease: BalanceOf, + execute_round: RoundIndex, + }, + // Delegation increased. + DelegationIncreased { + delegator: T::AccountId, + candidate: T::AccountId, + amount: BalanceOf, + in_top: bool, + }, + // Delegation decreased. + DelegationDecreased { + delegator: T::AccountId, + candidate: T::AccountId, + amount: BalanceOf, + in_top: bool, + }, + /// Delegator requested to leave the set of delegators. + DelegatorExitScheduled { + round: RoundIndex, + delegator: T::AccountId, + scheduled_exit: RoundIndex, + }, + /// Delegator requested to revoke delegation. + DelegationRevocationScheduled { + round: RoundIndex, + delegator: T::AccountId, + candidate: T::AccountId, + scheduled_exit: RoundIndex, + }, + /// Delegator has left the set of delegators. + DelegatorLeft { + delegator: T::AccountId, + unstaked_amount: BalanceOf, + }, + /// Delegation revoked. + DelegationRevoked { + delegator: T::AccountId, + candidate: T::AccountId, + unstaked_amount: BalanceOf, + }, + /// Delegation kicked. + DelegationKicked { + delegator: T::AccountId, + candidate: T::AccountId, + unstaked_amount: BalanceOf, + }, + /// Cancelled a pending request to exit the set of delegators. + DelegatorExitCancelled { + delegator: T::AccountId, + }, + /// Cancelled request to change an existing delegation. + CancelledDelegationRequest { + delegator: T::AccountId, + cancelled_request: CancelledScheduledRequest>, + collator: T::AccountId, + }, + /// New delegation (increase of the existing one). + Delegation { + delegator: T::AccountId, + locked_amount: BalanceOf, + candidate: T::AccountId, + delegator_position: DelegatorAdded>, + auto_compound: Percent, + }, + /// Delegation from candidate state has been remove. + DelegatorLeftCandidate { + delegator: T::AccountId, + candidate: T::AccountId, + unstaked_amount: BalanceOf, + total_candidate_staked: BalanceOf, + }, + /// Paid the account (delegator or collator) the balance as liquid rewards. + Rewarded { + account: T::AccountId, + rewards: BalanceOf, + }, + /// Transferred to account which holds funds reserved for parachain bond. + ReservedForParachainBond { + account: T::AccountId, + value: BalanceOf, + }, + /// Account (re)set for parachain bond treasury. + ParachainBondAccountSet { + old: T::AccountId, + new: T::AccountId, + }, + /// Percent of inflation reserved for parachain bond (re)set. + ParachainBondReservePercentSet { + old: Percent, + new: Percent, + }, + /// Annual inflation input (first 3) was used to derive new per-round inflation (last 3) + InflationSet { + annual_min: Perbill, + annual_ideal: Perbill, + annual_max: Perbill, + round_min: Perbill, + round_ideal: Perbill, + round_max: Perbill, + }, + /// Staking expectations set. + StakeExpectationsSet { + expect_min: BalanceOf, + expect_ideal: BalanceOf, + expect_max: BalanceOf, + }, + /// Set total selected candidates to this value. + TotalSelectedSet { + old: u32, + new: u32, + }, + /// Set collator commission to this value. + CollatorCommissionSet { + old: Perbill, + new: Perbill, + }, + /// Set blocks per round + BlocksPerRoundSet { + current_round: RoundIndex, + first_block: T::BlockNumber, + old: u32, + new: u32, + new_per_round_inflation_min: Perbill, + new_per_round_inflation_ideal: Perbill, + new_per_round_inflation_max: Perbill, + }, + /// Auto-compounding reward percent was set for a delegation. + AutoCompoundSet { + candidate: T::AccountId, + delegator: T::AccountId, + value: Percent, + }, + /// Compounded a portion of rewards towards the delegation. + Compounded { + candidate: T::AccountId, + delegator: T::AccountId, + amount: BalanceOf, + }, } #[pallet::hooks] impl Hooks> for Pallet { - fn on_initialize(now: T::BlockNumber) -> frame_support::weights::Weight { - let mut post_weight = ::WeightInfo::on_initialize_no_action(); - let mut round = Round::::get(); + fn on_initialize(n: T::BlockNumber) -> Weight { + let mut weight = T::WeightInfo::base_on_initialize(); + + let mut round = >::get(); - // check for round update - if round.should_update(now) { + if round.should_update(n) { // mutate round - round.update(now); + round.update(n); + // notify that new round begin + weight = weight.saturating_add(T::OnNewRound::on_new_round(round.current)); + // pay all stakers for T::RewardPaymentDelay rounds ago + weight = weight.saturating_add(Self::prepare_staking_payouts(round.current)); + // select top collator candidates for next round + let (extra_weight, collator_count, _delegation_count, total_staked) = + Self::select_top_candidates(round.current); + weight = weight.saturating_add(extra_weight); // start next round - Round::::put(round); - - Self::deposit_event(Event::NewRound(round.first, round.current)); - post_weight = ::WeightInfo::on_initialize_round_update(); - } - // check for network reward and mint - // on success, mint each block - if now > T::NetworkRewardStart::get() { - T::NetworkRewardBeneficiary::on_unbalanced(Self::issue_network_reward()); - post_weight = post_weight.saturating_add(::WeightInfo::on_initialize_network_rewards()); + >::put(round); + // snapshot total stake + >::insert(round.current, >::get()); + Self::deposit_event(Event::NewRound { + starting_block: round.first, + round: round.current, + selected_collators_number: collator_count, + total_balance: total_staked, + }); + // account for Round and Staked writes + weight = weight.saturating_add(T::DbWeight::get().reads_writes(0, 2)); + } else { + weight = weight.saturating_add(Self::handle_delayed_payouts(round.current)); } - post_weight + + // add on_finalize weight + // read: Author, Points, AwardedPts + // write: Points, AwardedPts + weight = weight.saturating_add(T::DbWeight::get().reads_writes(3, 2)); + weight } } - /// The maximum number of collator candidates selected at each round. #[pallet::storage] - #[pallet::getter(fn max_selected_candidates)] - pub(crate) type MaxSelectedCandidates = StorageValue<_, u32, ValueQuery>; + #[pallet::getter(fn collator_commission)] + /// Commission percent taken off of rewards for all collators + type CollatorCommission = StorageValue<_, Perbill, ValueQuery>; - /// Current round number and next round scheduled transition. #[pallet::storage] - #[pallet::getter(fn round)] - pub(crate) type Round = StorageValue<_, RoundInfo, ValueQuery>; + #[pallet::getter(fn total_selected)] + /// The total candidates selected every round + pub(crate) type TotalSelected = StorageValue<_, u32, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn parachain_bond_info)] + /// Parachain bond config info { account, percent_of_inflation } + pub(crate) type ParachainBondInfo = StorageValue<_, ParachainBondConfig, ValueQuery>; - /// Delegation information for the latest session in which a delegator - /// delegated. - /// - /// It maps from an account to the number of delegations in the last - /// session in which they (re-)delegated. #[pallet::storage] - #[pallet::getter(fn last_delegation)] - pub(crate) type LastDelegation = - StorageMap<_, Twox64Concat, T::AccountId, DelegationCounter, ValueQuery>; + #[pallet::getter(fn round)] + /// Current round index and next round scheduled transition + pub(crate) type Round = StorageValue<_, RoundInfo, ValueQuery>; - /// Delegation staking information. - /// - /// It maps from an account to its delegation details. #[pallet::storage] #[pallet::getter(fn delegator_state)] + /// Get delegator state associated with an account if account is delegating else None pub(crate) type DelegatorState = StorageMap<_, Twox64Concat, T::AccountId, Delegator>, OptionQuery>; - /// The staking information for a candidate. - /// - /// It maps from an account to its information. - /// Moreover, it counts the number of candidates. #[pallet::storage] - #[pallet::getter(fn candidate_pool)] - pub(crate) type CandidatePool = CountedStorageMap< + #[pallet::getter(fn candidate_info)] + /// Get collator candidate info associated with an account if account is candidate else None + pub(crate) type CandidateInfo = + StorageMap<_, Twox64Concat, T::AccountId, CandidateMetadata>, OptionQuery>; + + /// Stores outstanding delegation requests per collator. + #[pallet::storage] + #[pallet::getter(fn delegation_scheduled_requests)] + pub(crate) type DelegationScheduledRequests = + StorageMap<_, Blake2_128Concat, T::AccountId, Vec>>, ValueQuery>; + + pub struct AddGet { + _phantom: PhantomData<(T, R)>, + } + impl Get for AddGet + where + T: Get, + R: Get, + { + fn get() -> u32 { + T::get() + R::get() + } + } + + /// Stores auto-compounding configuration per collator. + #[pallet::storage] + #[pallet::getter(fn auto_compounding_delegations)] + pub(crate) type AutoCompoundingDelegations = StorageMap< _, - Twox64Concat, + Blake2_128Concat, T::AccountId, - Candidate, T::MaxDelegatorsPerCollator>, - OptionQuery, + BoundedVec< + AutoCompoundConfig, + AddGet, + >, + ValueQuery, >; - /// Total funds locked to back the currently selected collators. - /// The sum of all collator and their delegator stakes. - /// - /// Note: There are more funds locked by this pallet, since the backing for - /// non collating candidates is not included in [TotalCollatorStake]. #[pallet::storage] - #[pallet::getter(fn total_collator_stake)] - pub(crate) type TotalCollatorStake = StorageValue<_, TotalStake>, ValueQuery>; - - /// The collator candidates with the highest amount of stake. - /// - /// Each time the stake of a collator is increased, it is checked whether - /// this pushes another candidate out of the list. When the stake is - /// reduced however, it is not checked if another candidate has more stake, - /// since this would require iterating over the entire [CandidatePool]. - /// - /// There must always be more candidates than [MaxSelectedCandidates] so - /// that a collator can drop out of the collator set by reducing their - /// stake. + #[pallet::getter(fn top_delegations)] + /// Top delegations for collator candidate + pub(crate) type TopDelegations = + StorageMap<_, Twox64Concat, T::AccountId, Delegations>, OptionQuery>; + #[pallet::storage] - #[pallet::getter(fn top_candidates)] - pub(crate) type TopCandidates = - StorageValue<_, OrderedSet>, T::MaxTopCandidates>, ValueQuery>; + #[pallet::getter(fn bottom_delegations)] + /// Bottom delegations for collator candidate + pub(crate) type BottomDelegations = + StorageMap<_, Twox64Concat, T::AccountId, Delegations>, OptionQuery>; - /// Inflation configuration. #[pallet::storage] - #[pallet::getter(fn inflation_config)] - pub(crate) type InflationConfig = StorageValue<_, InflationInfo, ValueQuery>; + #[pallet::getter(fn selected_candidates)] + /// The collator candidates selected for the current round + type SelectedCandidates = StorageValue<_, Vec, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn total)] + /// Total capital locked by this staking pallet + pub(crate) type Total = StorageValue<_, BalanceOf, ValueQuery>; - /// The funds waiting to be unstaked. - /// - /// It maps from accounts to all the funds addressed to them in the future - /// blocks. #[pallet::storage] - #[pallet::getter(fn unstaking)] - pub(crate) type Unstaking = StorageMap< + #[pallet::getter(fn candidate_pool)] + /// The pool of collator candidates, each with their total backing stake + pub(crate) type CandidatePool = + StorageValue<_, OrderedSet>>, ValueQuery>; + + #[pallet::storage] + #[pallet::getter(fn at_stake)] + /// Snapshot of collator delegation stake at the start of the round + pub type AtStake = StorageDoubleMap< _, Twox64Concat, + RoundIndex, + Twox64Concat, T::AccountId, - BoundedBTreeMap, T::MaxUnstakeRequests>, + CollatorSnapshot>, ValueQuery, >; - /// The maximum amount a collator candidate can stake. #[pallet::storage] - #[pallet::getter(fn max_candidate_stake)] - pub(crate) type MaxCollatorCandidateStake = StorageValue<_, BalanceOf, ValueQuery>; - - /// The year in which the last automatic reduction of the reward rates - /// occurred. - /// - /// It starts at zero at genesis and increments by one every BLOCKS_PER_YEAR - /// many blocks. - #[pallet::storage] - #[pallet::getter(fn last_reward_reduction)] - pub(crate) type LastRewardReduction = StorageValue<_, T::BlockNumber, ValueQuery>; + #[pallet::getter(fn delayed_payouts)] + /// Delayed payouts + pub type DelayedPayouts = + StorageMap<_, Twox64Concat, RoundIndex, DelayedPayout>, OptionQuery>; - /// The number of authored blocks for collators. It is updated via the - /// `note_author` hook when authoring a block . - #[pallet::storage] - #[pallet::getter(fn blocks_authored)] - pub(crate) type BlocksAuthored = StorageMap<_, Twox64Concat, T::AccountId, T::BlockNumber, ValueQuery>; - - /// The number of blocks for which rewards have been claimed by an address. - /// - /// For collators, this can be at most BlocksAuthored. It is updated when - /// incrementing collator rewards, either when calling - /// `inc_collator_rewards` or updating the `InflationInfo`. - /// - /// For delegators, this can be at most BlocksAuthored of the collator.It is - /// updated when incrementing delegator rewards, either when calling - /// `inc_delegator_rewards` or updating the `InflationInfo`. #[pallet::storage] - #[pallet::getter(fn blocks_rewarded)] - pub(crate) type BlocksRewarded = StorageMap<_, Twox64Concat, T::AccountId, T::BlockNumber, ValueQuery>; + #[pallet::getter(fn staked)] + /// Total counted stake for selected candidates in the round + pub type Staked = StorageMap<_, Twox64Concat, RoundIndex, BalanceOf, ValueQuery>; - /// The accumulated rewards for collator candidates and delegators. - /// - /// It maps from accounts to their total rewards since the last payout. #[pallet::storage] - #[pallet::getter(fn rewards)] - pub(crate) type Rewards = StorageMap<_, Twox64Concat, T::AccountId, BalanceOf, ValueQuery>; + #[pallet::getter(fn inflation_config)] + /// Inflation configuration + pub type InflationConfig = StorageValue<_, InflationInfo>, ValueQuery>; - pub type GenesisStaker = Vec<( - ::AccountId, - Option<::AccountId>, - BalanceOf, - )>; + #[pallet::storage] + #[pallet::getter(fn points)] + /// Total points awarded to collators for block production in the round + pub type Points = StorageMap<_, Twox64Concat, RoundIndex, RewardPoint, ValueQuery>; #[pallet::storage] - #[pallet::getter(fn new_round_forced)] - pub(crate) type ForceNewRound = StorageValue<_, bool, ValueQuery>; + #[pallet::getter(fn awarded_pts)] + /// Points for each collator per round + pub type AwardedPts = + StorageDoubleMap<_, Twox64Concat, RoundIndex, Twox64Concat, T::AccountId, RewardPoint, ValueQuery>; #[pallet::genesis_config] pub struct GenesisConfig { - pub stakers: GenesisStaker, - pub inflation_config: InflationInfo, - pub max_candidate_stake: BalanceOf, + /// Initialize balance and register all as collators: `(collator AccountId, balance Amount)` + pub candidates: Vec<(T::AccountId, BalanceOf)>, + /// Initialize balance and make delegations: + /// `(delegator AccountId, collator AccountId, delegation Amount, auto-compounding Percent)` + pub delegations: Vec<(T::AccountId, T::AccountId, BalanceOf, Percent)>, + /// Inflation configuration + pub inflation_config: InflationInfo>, + /// Default fixed percent a collator takes off the top of due rewards + pub collator_commission: Perbill, + /// Default percent of inflation set aside for parachain bond every round + pub parachain_bond_reserve_percent: Percent, + /// Default number of blocks in a round + pub blocks_per_round: u32, + /// Number of selected candidates every round. Cannot be lower than MinSelectedCandidates + pub num_selected_candidates: u32, } #[cfg(feature = "std")] impl Default for GenesisConfig { fn default() -> Self { Self { - stakers: Default::default(), + candidates: vec![], + delegations: vec![], inflation_config: Default::default(), - max_candidate_stake: Default::default(), + collator_commission: Default::default(), + parachain_bond_reserve_percent: Default::default(), + blocks_per_round: 1u32, + num_selected_candidates: T::MinSelectedCandidates::get(), } } } @@ -668,1816 +657,1197 @@ pub mod pallet { #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { - assert!( - self.inflation_config.is_valid(T::BLOCKS_PER_YEAR.saturated_into()), - "Invalid inflation configuration" - ); - - InflationConfig::::put(self.inflation_config.clone()); - MaxCollatorCandidateStake::::put(self.max_candidate_stake); - - // Setup delegate & collators - for &(ref actor, ref opt_val, balance) in &self.stakers { + assert!(self.blocks_per_round > 0, "Blocks per round must be > 0"); + >::put(self.inflation_config.clone()); + let mut candidate_count = 0u32; + // Initialize the candidates + for &(ref candidate, balance) in &self.candidates { assert!( - T::Currency::free_balance(actor) >= balance, - "Account does not have enough balance to stake." + >::get_collator_stakable_free_balance(candidate) >= balance, + "Account does not have enough balance to bond as a candidate." ); - if let Some(delegated_val) = opt_val { - assert_ok!(Pallet::::join_delegators( - T::RuntimeOrigin::from(Some(actor.clone()).into()), - T::Lookup::unlookup(delegated_val.clone()), - balance, - )); + if let Err(error) = >::join_candidates( + T::RuntimeOrigin::from(Some(candidate.clone()).into()), + balance, + candidate_count, + ) { + log::warn!("Join candidates failed in genesis with error {:?}", error); } else { - assert_ok!(Pallet::::join_candidates( - T::RuntimeOrigin::from(Some(actor.clone()).into()), - balance - )); + candidate_count = candidate_count.saturating_add(1u32); } } - // Set total selected candidates to minimum config - MaxSelectedCandidates::::put(T::MinCollators::get()); - Pallet::::update_total_stake(); - - // Start Round 0 at Block 0 - let round: RoundInfo = RoundInfo::new(0u32, 0u32.into(), T::DefaultBlocksPerRound::get()); - Round::::put(round); + let mut col_delegator_count: BTreeMap = BTreeMap::new(); + let mut col_auto_compound_delegator_count: BTreeMap = BTreeMap::new(); + let mut del_delegation_count: BTreeMap = BTreeMap::new(); + // Initialize the delegations + for &(ref delegator, ref target, balance, auto_compound) in &self.delegations { + assert!( + >::get_delegator_stakable_free_balance(delegator) >= balance, + "Account does not have enough balance to place delegation." + ); + let cd_count = if let Some(x) = col_delegator_count.get(target) { *x } else { 0u32 }; + let dd_count = if let Some(x) = del_delegation_count.get(delegator) { *x } else { 0u32 }; + let cd_auto_compound_count = col_auto_compound_delegator_count.get(target).cloned().unwrap_or_default(); + if let Err(error) = >::delegate_with_auto_compound( + T::RuntimeOrigin::from(Some(delegator.clone()).into()), + target.clone(), + balance, + auto_compound, + cd_count, + cd_auto_compound_count, + dd_count, + ) { + log::warn!("Delegate failed in genesis with error {:?}", error); + } else { + if let Some(x) = col_delegator_count.get_mut(target) { + *x = x.saturating_add(1u32); + } else { + col_delegator_count.insert(target.clone(), 1u32); + }; + if let Some(x) = del_delegation_count.get_mut(delegator) { + *x = x.saturating_add(1u32); + } else { + del_delegation_count.insert(delegator.clone(), 1u32); + }; + if !auto_compound.is_zero() { + col_auto_compound_delegator_count + .entry(target.clone()) + .and_modify(|x| *x = x.saturating_add(1)) + .or_insert(1); + } + } + } + // Set collator commission to default config + >::put(self.collator_commission); + // Set parachain bond config to default config + >::put(ParachainBondConfig { + // must be set soon; if not => due inflation will be sent to collators/delegators + account: T::AccountId::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) + .expect("infinite length input; no invalid inputs for type; qed"), + percent: self.parachain_bond_reserve_percent, + }); + // Set total selected candidates to value from config + assert!( + self.num_selected_candidates >= T::MinSelectedCandidates::get(), + "{:?}", + Error::::CannotSetBelowMin + ); + >::put(self.num_selected_candidates); + // Choose top TotalSelected collator candidates + let (_, v_count, _, total_staked) = >::select_top_candidates(1u32); + // Start Round 1 at Block 0 + let round: RoundInfo = RoundInfo::new(1u32, 0u32.into(), self.blocks_per_round); + >::put(round); + // Snapshot total stake + >::insert(1u32, >::get()); + >::deposit_event(Event::NewRound { + starting_block: T::BlockNumber::zero(), + round: 1u32, + selected_collators_number: v_count, + total_balance: total_staked, + }); } } #[pallet::call] impl Pallet { - /// Forces the start of the new round in the next block. - /// - /// The new round will be enforced via >::should_end_session. - /// - /// The dispatch origin must be Root. + /// Set the expectations for total staked. These expectations determine the issuance for + /// the round according to logic in `fn compute_issuance` #[pallet::call_index(0)] - #[pallet::weight(::WeightInfo::force_new_round())] - pub fn force_new_round(origin: OriginFor) -> DispatchResult { - ensure_root(origin)?; - - // set force_new_round handle which, at the start of the next block, will - // trigger `should_end_session` in `Session::on_initialize` and update the - // current round - ForceNewRound::::put(true); - - Ok(()) + #[pallet::weight(::WeightInfo::set_staking_expectations())] + pub fn set_staking_expectations( + origin: OriginFor, + expectations: Range>, + ) -> DispatchResultWithPostInfo { + T::MonetaryGovernanceOrigin::ensure_origin(origin)?; + ensure!(expectations.is_valid(), Error::::InvalidSchedule); + let mut config = >::get(); + ensure!(config.expect != expectations, Error::::NoWritingSameValue); + config.set_expectations(expectations); + Self::deposit_event(Event::StakeExpectationsSet { + expect_min: config.expect.min, + expect_ideal: config.expect.ideal, + expect_max: config.expect.max, + }); + >::put(config); + Ok(().into()) } - /// Set the annual inflation rate to derive per-round inflation. - /// - /// The inflation details are considered valid if the annual reward rate - /// is approximately the per-block reward rate multiplied by the - /// estimated* total number of blocks per year. - /// - /// The estimated average block time is twelve seconds. - /// - /// NOTE: Iterates over CandidatePool and for each candidate over their - /// delegators to update their rewards before the reward rates change. - /// Needs to be improved when scaling up `MaxTopCandidates`. - /// - /// The dispatch origin must be Root. - /// - /// Emits `RoundInflationSet`. + /// Set the annual inflation rate to derive per-round inflation #[pallet::call_index(1)] - #[pallet::weight(::WeightInfo::set_inflation(T::MaxTopCandidates::get(), T::MaxDelegatorsPerCollator::get()))] - pub fn set_inflation( - origin: OriginFor, collator_max_rate_percentage: Perquintill, - collator_annual_reward_rate_percentage: Perquintill, delegator_max_rate_percentage: Perquintill, - delegator_annual_reward_rate_percentage: Perquintill, - ) -> DispatchResultWithPostInfo { - ensure_root(origin)?; - - // Update inflation and increment rewards - let (num_col, num_del) = Self::do_set_inflation( - T::BLOCKS_PER_YEAR, - collator_max_rate_percentage, - collator_annual_reward_rate_percentage, - delegator_max_rate_percentage, - delegator_annual_reward_rate_percentage, - )?; - - Ok(Some(::WeightInfo::set_inflation(num_col, num_del)).into()) + #[pallet::weight(::WeightInfo::set_inflation())] + pub fn set_inflation(origin: OriginFor, schedule: Range) -> DispatchResultWithPostInfo { + T::MonetaryGovernanceOrigin::ensure_origin(origin)?; + ensure!(schedule.is_valid(), Error::::InvalidSchedule); + let mut config = >::get(); + ensure!(config.annual != schedule, Error::::NoWritingSameValue); + config.annual = schedule; + config.set_round_from_annual::(schedule); + Self::deposit_event(Event::InflationSet { + annual_min: config.annual.min, + annual_ideal: config.annual.ideal, + annual_max: config.annual.max, + round_min: config.round.min, + round_ideal: config.round.ideal, + round_max: config.round.max, + }); + >::put(config); + Ok(().into()) } - /// Set the maximum number of collator candidates that can be selected - /// at the beginning of each validation round. - /// - /// Changes are not applied until the start of the next round. - /// - /// The new value must be higher than the minimum allowed as set in the - /// pallet's configuration. - /// - /// The dispatch origin must be Root. - /// - /// Emits `MaxSelectedCandidatesSet`. + /// Set the account that will hold funds set aside for parachain bond #[pallet::call_index(2)] - #[pallet::weight(::WeightInfo::set_max_selected_candidates( - *new, - T::MaxDelegatorsPerCollator::get() - ))] - pub fn set_max_selected_candidates(origin: OriginFor, new: u32) -> DispatchResultWithPostInfo { - ensure_root(origin)?; - ensure!(new >= T::MinCollators::get(), Error::::CannotSetBelowMin); - ensure!(new <= T::MaxTopCandidates::get(), Error::::CannotSetAboveMax); - let old = MaxSelectedCandidates::::get(); - - // *** No Fail beyond this point *** - - MaxSelectedCandidates::::put(new); - - // Update total amount at stake for new top collators and their delegators - let start = old.min(new); - let end = old.max(new); - - // The slice [start, end] contains the added or removed collators. We sum up - // their stake to adjust the total stake. - let (diff_collation, diff_delegation, num_delegators) = TopCandidates::::get() - .into_iter() - .skip(start.saturated_into()) - // SAFETY: we ensured that end > start further above. - .take((end - start).saturated_into()) - .filter_map(|candidate| CandidatePool::::get(&candidate.owner)) - .map(|state| { - ( - state.stake, - // SAFETY: the total is always more than the stake - state.total - state.stake, - state.delegators.len().saturated_into::(), - ) - }) - .reduce(|a, b| (a.0.saturating_add(b.0), a.1.saturating_add(b.1), a.2.max(b.2))) - .unwrap_or((BalanceOf::::zero(), BalanceOf::::zero(), 0u32)); - - TotalCollatorStake::::mutate(|total| { - if new > old { - total.collators = total.collators.saturating_add(diff_collation); - total.delegators = total.delegators.saturating_add(diff_delegation); - } else { - total.collators = total.collators.saturating_sub(diff_collation); - total.delegators = total.delegators.saturating_sub(diff_delegation); - } - }); - - Self::deposit_event(Event::MaxSelectedCandidatesSet(old, new)); - - Ok(Some(::WeightInfo::set_max_selected_candidates( - // SAFETY: we ensured that end > start further above. - end - start, - num_delegators, - )) - .into()) + #[pallet::weight(::WeightInfo::set_parachain_bond_account())] + pub fn set_parachain_bond_account(origin: OriginFor, new: T::AccountId) -> DispatchResultWithPostInfo { + T::MonetaryGovernanceOrigin::ensure_origin(origin)?; + let ParachainBondConfig { account: old, percent } = >::get(); + ensure!(old != new, Error::::NoWritingSameValue); + >::put(ParachainBondConfig { account: new.clone(), percent }); + Self::deposit_event(Event::ParachainBondAccountSet { old, new }); + Ok(().into()) } - /// Set the number of blocks each validation round lasts. - /// - /// If the new value is less than the length of the current round, the - /// system will immediately move to the next round in the next block. - /// - /// The new value must be higher than the minimum allowed as set in the - /// pallet's configuration. - /// - /// The dispatch origin must be Root. - /// - /// Emits `BlocksPerRoundSet`. + /// Set the percent of inflation set aside for parachain bond #[pallet::call_index(3)] - #[pallet::weight(::WeightInfo::set_blocks_per_round())] - pub fn set_blocks_per_round(origin: OriginFor, new: T::BlockNumber) -> DispatchResult { - ensure_root(origin)?; - ensure!(new >= T::MinBlocksPerRound::get(), Error::::CannotSetBelowMin); - - let old_round = Round::::get(); + #[pallet::weight(::WeightInfo::set_parachain_bond_reserve_percent())] + pub fn set_parachain_bond_reserve_percent(origin: OriginFor, new: Percent) -> DispatchResultWithPostInfo { + T::MonetaryGovernanceOrigin::ensure_origin(origin)?; + let ParachainBondConfig { account, percent: old } = >::get(); + ensure!(old != new, Error::::NoWritingSameValue); + >::put(ParachainBondConfig { account, percent: new }); + Self::deposit_event(Event::ParachainBondReservePercentSet { old, new }); + Ok(().into()) + } - // *** No Fail beyond this point *** + /// Set the total number of collator candidates selected per round + /// - changes are not applied until the start of the next round + #[pallet::call_index(4)] + #[pallet::weight(::WeightInfo::set_total_selected())] + pub fn set_total_selected(origin: OriginFor, new: u32) -> DispatchResultWithPostInfo { + frame_system::ensure_root(origin)?; + ensure!(new >= T::MinSelectedCandidates::get(), Error::::CannotSetBelowMin); + let old = >::get(); + ensure!(old != new, Error::::NoWritingSameValue); + ensure!(new < >::get().length, Error::::RoundLengthMustBeGreaterThanTotalSelectedCollators,); + >::put(new); + Self::deposit_event(Event::TotalSelectedSet { old, new }); + Ok(().into()) + } - Round::::put(RoundInfo { - length: new, - ..old_round - }); + /// Set the commission for all collators + #[pallet::call_index(5)] + #[pallet::weight(::WeightInfo::set_collator_commission())] + pub fn set_collator_commission(origin: OriginFor, new: Perbill) -> DispatchResultWithPostInfo { + frame_system::ensure_root(origin)?; + let old = >::get(); + ensure!(old != new, Error::::NoWritingSameValue); + >::put(new); + Self::deposit_event(Event::CollatorCommissionSet { old, new }); + Ok(().into()) + } - Self::deposit_event(Event::BlocksPerRoundSet( - old_round.current, - old_round.first, - old_round.length, + /// Set blocks per round + /// - if called with `new` less than length of current round, will transition immediately + /// in the next block + /// - also updates per-round inflation config + #[pallet::call_index(6)] + #[pallet::weight(::WeightInfo::set_blocks_per_round())] + pub fn set_blocks_per_round(origin: OriginFor, new: u32) -> DispatchResultWithPostInfo { + frame_system::ensure_root(origin)?; + ensure!(new >= T::MinBlocksPerRound::get(), Error::::CannotSetBelowMin); + let mut round = >::get(); + let (now, first, old) = (round.current, round.first, round.length); + ensure!(old != new, Error::::NoWritingSameValue); + ensure!(new > >::get(), Error::::RoundLengthMustBeGreaterThanTotalSelectedCollators,); + round.length = new; + // update per-round inflation given new rounds per year + let mut inflation_config = >::get(); + inflation_config.reset_round(new); + >::put(round); + Self::deposit_event(Event::BlocksPerRoundSet { + current_round: now, + first_block: first, + old, new, - )); - Ok(()) + new_per_round_inflation_min: inflation_config.round.min, + new_per_round_inflation_ideal: inflation_config.round.ideal, + new_per_round_inflation_max: inflation_config.round.max, + }); + >::put(inflation_config); + Ok(().into()) } - /// Set the maximal amount a collator can stake. Existing stakes are not - /// changed. - /// - /// The dispatch origin must be Root. - /// - /// Emits `MaxCandidateStakeChanged`. - #[pallet::call_index(4)] - #[pallet::weight(::WeightInfo::set_max_candidate_stake())] - pub fn set_max_candidate_stake(origin: OriginFor, new: BalanceOf) -> DispatchResult { - ensure_root(origin)?; - ensure!( - new >= T::MinCollatorCandidateStake::get(), - Error::::CannotSetBelowMin - ); - - // *** No Fail beyond this point *** - - MaxCollatorCandidateStake::::put(new); + /// Join the set of collator candidates + #[pallet::call_index(7)] + #[pallet::weight(::WeightInfo::join_candidates(*candidate_count))] + pub fn join_candidates( + origin: OriginFor, + bond: BalanceOf, + candidate_count: u32, + ) -> DispatchResultWithPostInfo { + let acc = ensure_signed(origin)?; + ensure!(!Self::is_candidate(&acc), Error::::CandidateExists); + ensure!(!Self::is_delegator(&acc), Error::::DelegatorExists); + ensure!(bond >= T::MinCandidateStk::get(), Error::::CandidateBondBelowMin); + let mut candidates = >::get(); + let old_count = candidates.0.len() as u32; + ensure!(candidate_count >= old_count, Error::::TooLowCandidateCountWeightHintJoinCandidates); + ensure!(candidates.insert(Bond { owner: acc.clone(), amount: bond }), Error::::CandidateExists); + ensure!(Self::get_collator_stakable_free_balance(&acc) >= bond, Error::::InsufficientBalance,); + T::Currency::set_lock(COLLATOR_LOCK_ID, &acc, bond, WithdrawReasons::all()); + let candidate = CandidateMetadata::new(bond); + >::insert(&acc, candidate); + let empty_delegations: Delegations> = Default::default(); + // insert empty top delegations + >::insert(&acc, empty_delegations.clone()); + // insert empty bottom delegations + >::insert(&acc, empty_delegations); + >::put(candidates); + let new_total = >::get().saturating_add(bond); + >::put(new_total); + Self::deposit_event(Event::JoinedCollatorCandidates { + account: acc, + amount_locked: bond, + new_total_amt_locked: new_total, + }); + Ok(().into()) + } - Self::deposit_event(Event::MaxCandidateStakeChanged(new)); - Ok(()) + /// Request to leave the set of candidates. If successful, the account is immediately + /// removed from the candidate pool to prevent selection as a collator. + #[pallet::call_index(8)] + #[pallet::weight(::WeightInfo::schedule_leave_candidates(*candidate_count))] + pub fn schedule_leave_candidates(origin: OriginFor, candidate_count: u32) -> DispatchResultWithPostInfo { + let collator = ensure_signed(origin)?; + let mut state = >::get(&collator).ok_or(Error::::CandidateDNE)?; + let (now, when) = state.schedule_leave::()?; + let mut candidates = >::get(); + ensure!(candidate_count >= candidates.0.len() as u32, Error::::TooLowCandidateCountToLeaveCandidates); + if candidates.remove(&Bond::from_owner(collator.clone())) { + >::put(candidates); + } + >::insert(&collator, state); + Self::deposit_event(Event::CandidateScheduledExit { + exit_allowed_round: now, + candidate: collator, + scheduled_exit: when, + }); + Ok(().into()) } - /// Forcedly removes a collator candidate from the TopCandidates and - /// clears all associated storage for the candidate and their - /// delegators. - /// - /// Prepares unstaking of the candidates and their delegators stake - /// which can be unlocked via `unlock_unstaked` after waiting at - /// least `StakeDuration` many blocks. Also increments rewards for the - /// collator and their delegators. - /// - /// Increments rewards of candidate and their delegators. - /// - /// Emits `CandidateRemoved`. - #[pallet::call_index(5)] - #[pallet::weight(::WeightInfo::force_remove_candidate( - T::MaxTopCandidates::get(), - T::MaxDelegatorsPerCollator::get() - ))] - pub fn force_remove_candidate( - origin: OriginFor, collator: ::Source, + /// Execute leave candidates request + #[pallet::call_index(9)] + #[pallet::weight( + ::WeightInfo::execute_leave_candidates(*candidate_delegation_count) + )] + pub fn execute_leave_candidates( + origin: OriginFor, + candidate: T::AccountId, + candidate_delegation_count: u32, ) -> DispatchResultWithPostInfo { - ensure_root(origin)?; - let collator = T::Lookup::lookup(collator)?; - let state = CandidatePool::::get(&collator).ok_or(Error::::CandidateNotFound)?; - let total_amount = state.total; - - let mut candidates = TopCandidates::::get(); + ensure_signed(origin)?; + let state = >::get(&candidate).ok_or(Error::::CandidateDNE)?; ensure!( - candidates.len().saturated_into::() > T::MinRequiredCollators::get(), - Error::::TooFewCollatorCandidates + state.delegation_count <= candidate_delegation_count, + Error::::TooLowCandidateDelegationCountToLeaveCandidates ); + state.can_leave::()?; + let return_stake = |bond: Bond>| -> DispatchResult { + // remove delegation from delegator state + let mut delegator = DelegatorState::::get(&bond.owner).expect( + "Collator state and delegator state are consistent. + Collator state has a record of this delegation. Therefore, + Delegator state also has a record. qed.", + ); - // *** No Fail except during remove_candidate beyond this point *** - - // remove candidate storage and increment rewards - Self::remove_candidate(&collator, &state)?; + if let Some(remaining) = delegator.rm_delegation::(&candidate) { + Self::delegation_remove_request_with_state(&candidate, &bond.owner, &mut delegator); + >::remove_auto_compound(&candidate, &bond.owner); - let (num_collators, num_delegators) = if candidates - .remove(&Stake { - owner: collator.clone(), - amount: state.total, - }) - .is_some() - { - // update top candidates - TopCandidates::::put(candidates); - // update total amount at stake from scratch - Self::update_total_stake() - } else { - (0u32, 0u32) + if remaining.is_zero() { + // we do not remove the scheduled delegation requests from other collators + // since it is assumed that they were removed incrementally before only the + // last delegation was left. + >::remove(&bond.owner); + T::Currency::remove_lock(DELEGATOR_LOCK_ID, &bond.owner); + } else { + >::insert(&bond.owner, delegator); + } + } else { + // TODO: review. we assume here that this delegator has no remaining staked + // balance, so we ensure the lock is cleared + T::Currency::remove_lock(DELEGATOR_LOCK_ID, &bond.owner); + } + Ok(()) }; - - Self::deposit_event(Event::CollatorRemoved(collator, total_amount)); - - Ok(Some(::WeightInfo::force_remove_candidate( - num_collators, - num_delegators, - )) - .into()) + // total backing stake is at least the candidate self bond + let mut total_backing = state.bond; + // return all top delegations + let top_delegations = >::take(&candidate).expect("CandidateInfo existence checked"); + for bond in top_delegations.delegations { + return_stake(bond)?; + } + total_backing = total_backing.saturating_add(top_delegations.total); + // return all bottom delegations + let bottom_delegations = >::take(&candidate).expect("CandidateInfo existence checked"); + for bond in bottom_delegations.delegations { + return_stake(bond)?; + } + total_backing = total_backing.saturating_add(bottom_delegations.total); + // return stake to collator + T::Currency::remove_lock(COLLATOR_LOCK_ID, &candidate); + >::remove(&candidate); + >::remove(&candidate); + >::remove(&candidate); + >::remove(&candidate); + >::remove(&candidate); + let new_total_staked = >::get().saturating_sub(total_backing); + >::put(new_total_staked); + Self::deposit_event(Event::CandidateLeft { + ex_candidate: candidate, + unlocked_amount: total_backing, + new_total_amt_locked: new_total_staked, + }); + Ok(().into()) } - /// Join the set of collator candidates. - /// - /// In the next blocks, if the collator candidate has enough funds - /// staked to be included in any of the top `MaxSelectedCandidates` - /// positions, it will be included in the set of potential authors that - /// will be selected by the stake-weighted random selection function. - /// - /// The staked funds of the new collator candidate are added to the - /// total stake of the system. - /// - /// The total amount of funds staked must be within the allowed range as - /// set in the pallet's configuration. - /// - /// The dispatch origin must not be already part of the collator - /// candidates nor of the delegators set. - /// - /// Emits `JoinedCollatorCandidates`. - #[pallet::call_index(6)] - #[pallet::weight(::WeightInfo::join_candidates( - T::MaxTopCandidates::get(), - T::MaxDelegatorsPerCollator::get() - ))] - pub fn join_candidates(origin: OriginFor, stake: BalanceOf) -> DispatchResultWithPostInfo { - let sender = ensure_signed(origin)?; - if let Some(is_active_candidate) = Self::is_active_candidate(&sender) { - ensure!(is_active_candidate, Error::::AlreadyLeaving); - ensure!(!is_active_candidate, Error::::CandidateExists); - } - ensure!(!Self::is_delegator(&sender), Error::::DelegatorExists); - ensure!( - stake >= T::MinCollatorCandidateStake::get(), - Error::::ValStakeBelowMin - ); + /// Cancel open request to leave candidates + /// - only callable by collator account + /// - result upon successful call is the candidate is active in the candidate pool + #[pallet::call_index(10)] + #[pallet::weight(::WeightInfo::cancel_leave_candidates(*candidate_count))] + pub fn cancel_leave_candidates(origin: OriginFor, candidate_count: u32) -> DispatchResultWithPostInfo { + let collator = ensure_signed(origin)?; + let mut state = >::get(&collator).ok_or(Error::::CandidateDNE)?; + ensure!(state.is_leaving(), Error::::CandidateNotLeaving); + state.go_online(); + let mut candidates = >::get(); ensure!( - stake <= MaxCollatorCandidateStake::::get(), - Error::::ValStakeAboveMax + candidates.0.len() as u32 <= candidate_count, + Error::::TooLowCandidateCountWeightHintCancelLeaveCandidates ); ensure!( - Unstaking::::get(&sender).len().saturated_into::() < T::MaxUnstakeRequests::get(), - Error::::CannotJoinBeforeUnlocking - ); - - // *** No Fail except during increase_lock beyond this point *** - - Self::increase_lock(&sender, stake, BalanceOf::::zero())?; - - let candidate = Candidate::new(sender.clone(), stake); - let n = Self::update_top_candidates( - sender.clone(), - BalanceOf::::zero(), - BalanceOf::::zero(), - stake, - BalanceOf::::zero(), + candidates.insert(Bond { owner: collator.clone(), amount: state.total_counted }), + Error::::AlreadyActive ); - CandidatePool::::insert(&sender, candidate); - - Self::deposit_event(Event::JoinedCollatorCandidates(sender, stake)); - Ok(Some(::WeightInfo::join_candidates( - n, - T::MaxDelegatorsPerCollator::get(), - )) - .into()) + >::put(candidates); + >::insert(&collator, state); + Self::deposit_event(Event::CancelledCandidateExit { candidate: collator }); + Ok(().into()) } - /// Request to leave the set of collator candidates. - /// - /// On success, the account is immediately removed from the candidate - /// pool to prevent selection as a collator in future validation rounds, - /// but unstaking of the funds is executed with a delay of - /// `StakeDuration` blocks. - /// - /// The exit request can be reversed by calling - /// `cancel_leave_candidates`. - /// - /// This operation affects the pallet's total stake amount. It is - /// updated even though the funds of the candidate who signaled to leave - /// are still locked for `ExitDelay` + `StakeDuration` more blocks. - /// - /// NOTE 1: Upon starting a new session_i in `new_session`, the current - /// top candidates are selected to be block authors for session_i+1. Any - /// changes to the top candidates afterwards do not effect the set of - /// authors for session_i+1. - /// Thus, we have to make sure none of these collators can - /// leave before session_i+1 ends by delaying their - /// exit for `ExitDelay` many blocks. - /// - /// NOTE 2: We do not increment rewards in this extrinsic as the - /// candidate could still author blocks, and thus be eligible to receive - /// rewards, until the end of the next session. - /// - /// Emits `CollatorScheduledExit`. - #[pallet::call_index(7)] - #[pallet::weight(::WeightInfo::init_leave_candidates( - T::MaxTopCandidates::get(), - T::MaxTopCandidates::get().saturating_mul(T::MaxDelegatorsPerCollator::get()) - ))] - pub fn init_leave_candidates(origin: OriginFor) -> DispatchResultWithPostInfo { + /// Temporarily leave the set of collator candidates without unbonding + #[pallet::call_index(11)] + #[pallet::weight(::WeightInfo::go_offline())] + pub fn go_offline(origin: OriginFor) -> DispatchResultWithPostInfo { let collator = ensure_signed(origin)?; - let mut state = CandidatePool::::get(&collator).ok_or(Error::::CandidateNotFound)?; - ensure!(!state.is_leaving(), Error::::AlreadyLeaving); - let mut candidates = TopCandidates::::get(); - ensure!( - candidates.len().saturated_into::() > T::MinRequiredCollators::get(), - Error::::TooFewCollatorCandidates - ); - - let now = Round::::get().current; - let when = now.saturating_add(T::ExitQueueDelay::get()); - state.leave_candidates(when); - - // *** No Fail beyond this point *** - - let (num_collators, num_delegators) = if candidates - .remove(&Stake { - owner: collator.clone(), - amount: state.total, - }) - .is_some() - { - // update top candidates - TopCandidates::::put(candidates); - Self::deposit_event(Event::LeftTopCandidates(collator.clone())); - // update total amount at stake from scratch - Self::update_total_stake() - } else { - (0u32, 0u32) - }; - CandidatePool::::insert(&collator, state); - - Self::deposit_event(Event::CollatorScheduledExit(now, collator, when)); - Ok(Some(::WeightInfo::init_leave_candidates( - num_collators, - num_delegators, - )) - .into()) - } - - /// Execute the network exit of a candidate who requested to leave at - /// least `ExitQueueDelay` rounds ago. Prepares unstaking of the - /// candidates and their delegators stake which can be unlocked via - /// `unlock_unstaked` after waiting at least `StakeDuration` many - /// blocks. - /// - /// Requires the candidate to previously have called - /// `init_leave_candidates`. - /// - /// The exit request can be reversed by calling - /// `cancel_leave_candidates`. - /// - /// NOTE: Iterates over CandidatePool for each candidate over their - /// delegators to set rewards. Needs to be improved when scaling up - /// `MaxTopCandidates`. - /// - /// Emits `CollatorLeft`. - #[pallet::call_index(8)] - #[pallet::weight(::WeightInfo::execute_leave_candidates( - T::MaxTopCandidates::get(), - T::MaxDelegatorsPerCollator::get(), - ))] - pub fn execute_leave_candidates( - origin: OriginFor, collator: ::Source, - ) -> DispatchResultWithPostInfo { - ensure_signed(origin)?; - let collator = T::Lookup::lookup(collator)?; - let state = CandidatePool::::get(&collator).ok_or(Error::::CandidateNotFound)?; - ensure!(state.is_leaving(), Error::::NotLeaving); - ensure!(state.can_exit(Round::::get().current), Error::::CannotLeaveYet); - - let num_delegators = state.delegators.len().saturated_into::(); - let total_amount = state.total; - - // *** No Fail except during remove_candidate beyond this point *** - - // remove candidate storage and increment rewards - Self::remove_candidate(&collator, &state)?; - - Self::deposit_event(Event::CandidateLeft(collator, total_amount)); - - Ok(Some(::WeightInfo::execute_leave_candidates( - T::MaxTopCandidates::get(), - num_delegators, - )) - .into()) - } - - /// Revert the previously requested exit of the network of a collator - /// candidate. On success, adds back the candidate to the TopCandidates - /// and updates the collators. - /// - /// Requires the candidate to previously have called - /// `init_leave_candidates`. - /// - /// Emits `CollatorCanceledExit`. - #[pallet::call_index(9)] - #[pallet::weight(::WeightInfo::cancel_leave_candidates( - T::MaxTopCandidates::get(), - T::MaxDelegatorsPerCollator::get(), - ))] - pub fn cancel_leave_candidates(origin: OriginFor) -> DispatchResultWithPostInfo { - let candidate = ensure_signed(origin)?; - let mut state = CandidatePool::::get(&candidate).ok_or(Error::::CandidateNotFound)?; - ensure!(state.is_leaving(), Error::::NotLeaving); - - // revert leaving state - state.revert_leaving(); - - // *** No Fail beyond this point *** - - let n = Self::update_top_candidates( - candidate.clone(), - state.stake, - // safe because total >= stake - state.total - state.stake, - state.stake, - state.total - state.stake, - ); - - // update candidates for next round - CandidatePool::::insert(&candidate, state); - - Self::deposit_event(Event::CollatorCanceledExit(candidate)); - - Ok(Some(::WeightInfo::cancel_leave_candidates( - n, - T::MaxDelegatorsPerCollator::get(), - )) - .into()) + let mut state = >::get(&collator).ok_or(Error::::CandidateDNE)?; + ensure!(state.is_active(), Error::::AlreadyOffline); + state.go_offline(); + let mut candidates = >::get(); + if candidates.remove(&Bond::from_owner(collator.clone())) { + >::put(candidates); + } + >::insert(&collator, state); + Self::deposit_event(Event::CandidateWentOffline { candidate: collator }); + Ok(().into()) } - /// Stake more funds for a collator candidate. - /// - /// If not in the set of candidates, staking enough funds allows the - /// account to be added to it. The larger amount of funds, the higher - /// chances to be selected as the author of the next block. - /// - /// This operation affects the pallet's total stake amount. - /// - /// The resulting total amount of funds staked must be within the - /// allowed range as set in the pallet's configuration. - /// - /// Emits `CollatorStakedMore`. - #[pallet::call_index(10)] - #[pallet::weight(::WeightInfo::candidate_stake_more( - T::MaxTopCandidates::get(), - T::MaxDelegatorsPerCollator::get(), - T::MaxUnstakeRequests::get().saturated_into::() - ))] - pub fn candidate_stake_more(origin: OriginFor, more: BalanceOf) -> DispatchResultWithPostInfo { + /// Rejoin the set of collator candidates if previously had called `go_offline` + #[pallet::call_index(12)] + #[pallet::weight(::WeightInfo::go_online())] + pub fn go_online(origin: OriginFor) -> DispatchResultWithPostInfo { let collator = ensure_signed(origin)?; - - ensure!(!more.is_zero(), Error::::ValStakeZero); - let mut state = CandidatePool::::get(&collator).ok_or(Error::::CandidateNotFound)?; - ensure!(!state.is_leaving(), Error::::CannotStakeIfLeaving); - - let CandidateOf:: { - stake: before_stake, - total: before_total, - .. - } = state; - state.stake_more(more); - let after_stake = state.stake; + let mut state = >::get(&collator).ok_or(Error::::CandidateDNE)?; + ensure!(!state.is_active(), Error::::AlreadyActive); + ensure!(!state.is_leaving(), Error::::CannotGoOnlineIfLeaving); + state.go_online(); + let mut candidates = >::get(); ensure!( - state.stake <= MaxCollatorCandidateStake::::get(), - Error::::ValStakeAboveMax + candidates.insert(Bond { owner: collator.clone(), amount: state.total_counted }), + Error::::AlreadyActive ); - - // *** No Fail except during increase_lock beyond this point *** - - let unstaking_len = Self::increase_lock(&collator, state.stake, more)?; - - let n = if state.is_active() { - Self::update_top_candidates( - collator.clone(), - before_stake, - // safe because total >= stake - before_total - before_stake, - state.stake, - state.total - state.stake, - ) - } else { - 0u32 - }; - CandidatePool::::insert(&collator, state); - - // increment rewards for collator and update number of rewarded blocks - Self::do_inc_collator_reward(&collator, before_stake); - - Self::deposit_event(Event::CollatorStakedMore(collator, before_stake, after_stake)); - Ok(Some(::WeightInfo::candidate_stake_more( - n, - T::MaxDelegatorsPerCollator::get(), - unstaking_len, - )) - .into()) + >::put(candidates); + >::insert(&collator, state); + Self::deposit_event(Event::CandidateBackOnline { candidate: collator }); + Ok(().into()) } - /// Stake less funds for a collator candidate. - /// - /// If the new amount of staked fund is not large enough, the account - /// could be removed from the set of collator candidates and not be - /// considered for authoring the next blocks. - /// - /// This operation affects the pallet's total stake amount. - /// - /// The unstaked funds are not released immediately to the account, but - /// they will be available after `StakeDuration` blocks. - /// - /// The resulting total amount of funds staked must be within the - /// allowed range as set in the pallet's configuration. - /// - /// Emits `CollatorStakedLess`. - #[pallet::call_index(11)] - #[pallet::weight(::WeightInfo::candidate_stake_less( - T::MaxTopCandidates::get(), - T::MaxDelegatorsPerCollator::get() - ))] - pub fn candidate_stake_less(origin: OriginFor, less: BalanceOf) -> DispatchResultWithPostInfo { + /// Increase collator candidate self bond by `more` + #[pallet::call_index(13)] + #[pallet::weight(::WeightInfo::candidate_bond_more())] + pub fn candidate_bond_more(origin: OriginFor, more: BalanceOf) -> DispatchResultWithPostInfo { let collator = ensure_signed(origin)?; - ensure!(!less.is_zero(), Error::::ValStakeZero); - - let mut state = CandidatePool::::get(&collator).ok_or(Error::::CandidateNotFound)?; - ensure!(!state.is_leaving(), Error::::CannotStakeIfLeaving); - - let CandidateOf:: { - stake: before_stake, - total: before_total, - .. - } = state; - let after = state.stake_less(less).ok_or(Error::::Underflow)?; - ensure!( - after >= T::MinCollatorCandidateStake::get(), - Error::::ValStakeBelowMin - ); - - // *** No Fail except during prep_unstake beyond this point *** - - // we don't unlock immediately - Self::prep_unstake(&collator, less, false)?; - - let n = if state.is_active() { - Self::update_top_candidates( - collator.clone(), - before_stake, - // safe because total >= stake - before_total - before_stake, - state.stake, - state.total - state.stake, - ) - } else { - 0u32 - }; - CandidatePool::::insert(&collator, state); - - // increment rewards and update number of rewarded blocks - Self::do_inc_collator_reward(&collator, before_stake); + let mut state = >::get(&collator).ok_or(Error::::CandidateDNE)?; + state.bond_more::(collator.clone(), more)?; + let (is_active, total_counted) = (state.is_active(), state.total_counted); + >::insert(&collator, state); + if is_active { + Self::update_active(collator, total_counted); + } + Ok(().into()) + } - Self::deposit_event(Event::CollatorStakedLess(collator, before_stake, after)); - Ok(Some(::WeightInfo::candidate_stake_less( - n, - T::MaxDelegatorsPerCollator::get(), - )) - .into()) + /// Request by collator candidate to decrease self bond by `less` + #[pallet::call_index(14)] + #[pallet::weight(::WeightInfo::schedule_candidate_bond_less())] + pub fn schedule_candidate_bond_less(origin: OriginFor, less: BalanceOf) -> DispatchResultWithPostInfo { + let collator = ensure_signed(origin)?; + let mut state = >::get(&collator).ok_or(Error::::CandidateDNE)?; + let when = state.schedule_bond_less::(less)?; + >::insert(&collator, state); + Self::deposit_event(Event::CandidateBondLessRequested { + candidate: collator, + amount_to_decrease: less, + execute_round: when, + }); + Ok(().into()) } - /// Join the set of delegators by delegating to a collator candidate. - /// - /// The account that wants to delegate cannot be part of the collator - /// candidates set as well. - /// - /// The caller must _not_ have a delegation. If that is the case, they - /// are required to first remove the delegation. - /// - /// The amount staked must be larger than the minimum required to become - /// a delegator as set in the pallet's configuration. - /// - /// As only `MaxDelegatorsPerCollator` are allowed to delegate a given - /// collator, the amount staked must be larger than the lowest one in - /// the current set of delegator for the operation to be meaningful. - /// - /// The collator's total stake as well as the pallet's total stake are - /// increased accordingly. - /// - /// Emits `Delegation`. - /// Emits `DelegationReplaced` if the candidate has - /// `MaxDelegatorsPerCollator` many delegations but this delegator - /// staked more than one of the other delegators of this candidate. - #[pallet::call_index(12)] - #[pallet::weight(::WeightInfo::join_delegators( - T::MaxTopCandidates::get(), - T::MaxDelegatorsPerCollator::get() - ))] - pub fn join_delegators( - origin: OriginFor, collator: ::Source, amount: BalanceOf, + /// Execute pending request to adjust the collator candidate self bond + #[pallet::call_index(15)] + #[pallet::weight(::WeightInfo::execute_candidate_bond_less())] + pub fn execute_candidate_bond_less( + origin: OriginFor, + candidate: T::AccountId, ) -> DispatchResultWithPostInfo { - let acc = ensure_signed(origin)?; - let collator = T::Lookup::lookup(collator)?; - - // check balance - ensure!( - pallet_balances::Pallet::::free_balance(acc.clone()) >= amount.into(), - pallet_balances::Error::::InsufficientBalance - ); - - // first delegation - ensure!(DelegatorState::::get(&acc).is_none(), Error::::AlreadyDelegating); - ensure!(amount >= T::MinDelegatorStake::get(), Error::::DelegationBelowMin); - - // cannot be a collator candidate and delegator with same AccountId - ensure!(Self::is_active_candidate(&acc).is_none(), Error::::CandidateExists); - ensure!( - Unstaking::::get(&acc).len().saturated_into::() < T::MaxUnstakeRequests::get(), - Error::::CannotJoinBeforeUnlocking - ); - // cannot delegate if number of delegations in this round exceeds - // MaxDelegationsPerRound - let delegation_counter = Self::get_delegation_counter(&acc)?; - - // prepare update of collator state - let mut state = CandidatePool::::get(&collator).ok_or(Error::::CandidateNotFound)?; - let num_delegations_pre_insertion: u32 = state.delegators.len().saturated_into(); - - ensure!(!state.is_leaving(), Error::::CannotDelegateIfLeaving); - let delegation = Stake { - owner: acc.clone(), - amount, - }; - - // attempt to insert delegator and check for uniqueness - // NOTE: excess is handled below because we support replacing a delegator with - // fewer stake - let insert_delegator = state - .delegators - // we handle TooManyDelegators error below in do_update_delegator - .try_insert(delegation.clone()) - .unwrap_or(true); - // should never fail but let's be safe - ensure!(insert_delegator, Error::::DelegatorExists); - - let delegator_state = Delegator { - amount, - owner: collator.clone(), - }; - let CandidateOf:: { - stake: old_stake, - total: old_total, - .. - } = state; - - // update state and potentially prepare kicking a delegator with less staked - // amount (includes setting rewards for kicked delegator) - let state = if num_delegations_pre_insertion == T::MaxDelegatorsPerCollator::get() { - Self::do_update_delegator(delegation, state)? - } else { - state.total = state.total.saturating_add(amount); - state - }; - let new_total = state.total; - - // *** No Fail except during increase_lock beyond this point *** - - // lock stake - Self::increase_lock(&acc, amount, BalanceOf::::zero())?; - - // update top candidates and total amount at stake - let n = if state.is_active() { - Self::update_top_candidates( - collator.clone(), - old_stake, - // safe because total >= stake - old_total - old_stake, - state.stake, - state.total - state.stake, - ) - } else { - 0u32 - }; - - // update states - CandidatePool::::insert(&collator, state); - DelegatorState::::insert(&acc, delegator_state); - LastDelegation::::insert(&acc, delegation_counter); - - // initiate rewarded counter to match the current authored counter of the - // candidate - BlocksRewarded::::insert(&acc, BlocksAuthored::::get(&collator)); - - Self::deposit_event(Event::Delegation(acc, amount, collator, new_total)); - Ok(Some(::WeightInfo::join_delegators( - n, - T::MaxDelegatorsPerCollator::get(), - )) - .into()) + ensure_signed(origin)?; // we may want to reward this if caller != candidate + let mut state = >::get(&candidate).ok_or(Error::::CandidateDNE)?; + state.execute_bond_less::(candidate.clone())?; + >::insert(&candidate, state); + Ok(().into()) } - /// Leave the set of delegators and, by implication, revoke the ongoing - /// delegation. - /// - /// All staked funds are not unlocked immediately, but they are added to - /// the queue of pending unstaking, and will effectively be released - /// after `StakeDuration` blocks from the moment the delegator leaves. - /// - /// This operation reduces the total stake of the pallet as well as the - /// stakes of all collators that were delegated, potentially affecting - /// their chances to be included in the set of candidates in the next - /// rounds. - /// - /// Automatically increments the accumulated rewards of the origin of - /// the current delegation. - /// - /// Emits `DelegatorLeft`. - #[pallet::call_index(13)] - #[pallet::weight(::WeightInfo::leave_delegators( - T::MaxTopCandidates::get(), - T::MaxDelegatorsPerCollator::get() - ))] - pub fn leave_delegators(origin: OriginFor) -> DispatchResultWithPostInfo { - let acc = ensure_signed(origin)?; - let delegator = DelegatorState::::get(&acc).ok_or(Error::::DelegatorNotFound)?; - let collator = delegator.owner; - Self::delegator_leaves_collator(acc.clone(), collator)?; - - // *** No Fail beyond this point *** - - DelegatorState::::remove(&acc); - - Self::deposit_event(Event::DelegatorLeft(acc, delegator.amount)); - Ok(Some(::WeightInfo::leave_delegators( - 1, - T::MaxDelegatorsPerCollator::get(), - )) - .into()) + /// Cancel pending request to adjust the collator candidate self bond + #[pallet::call_index(16)] + #[pallet::weight(::WeightInfo::cancel_candidate_bond_less())] + pub fn cancel_candidate_bond_less(origin: OriginFor) -> DispatchResultWithPostInfo { + let collator = ensure_signed(origin)?; + let mut state = >::get(&collator).ok_or(Error::::CandidateDNE)?; + state.cancel_bond_less::(collator.clone())?; + >::insert(&collator, state); + Ok(().into()) } - /// Increase the stake for delegating a collator candidate. - /// - /// If not in the set of candidates, staking enough funds allows the - /// collator candidate to be added to it. - /// - /// Emits `DelegatorStakedMore`. - #[pallet::call_index(14)] - #[pallet::weight(::WeightInfo::delegator_stake_more( - T::MaxTopCandidates::get(), - T::MaxDelegatorsPerCollator::get(), - T::MaxUnstakeRequests::get().saturated_into::()) + /// If caller is not a delegator and not a collator, then join the set of delegators + /// If caller is a delegator, then makes delegation to change their delegation state + #[pallet::call_index(17)] + #[pallet::weight( + ::WeightInfo::delegate( + *candidate_delegation_count, + *delegation_count + ) )] - pub fn delegator_stake_more(origin: OriginFor, more: BalanceOf) -> DispatchResultWithPostInfo { + pub fn delegate( + origin: OriginFor, + candidate: T::AccountId, + amount: BalanceOf, + candidate_delegation_count: u32, + delegation_count: u32, + ) -> DispatchResultWithPostInfo { let delegator = ensure_signed(origin)?; - ensure!(!more.is_zero(), Error::::ValStakeZero); - - let mut delegation = DelegatorState::::get(&delegator).ok_or(Error::::DelegatorNotFound)?; - let candidate = delegation.owner.clone(); - let mut collator = CandidatePool::::get(&candidate).ok_or(Error::::CandidateNotFound)?; - ensure!(!collator.is_leaving(), Error::::CannotDelegateIfLeaving); - let stake_after = delegation - .try_increment(candidate.clone(), more) - .map_err(|_| Error::::DelegationNotFound)?; - - // *** No Fail except during increase_lock beyond this point *** - - // update lock - let unstaking_len = Self::increase_lock(&delegator, stake_after, more)?; - - let CandidateOf:: { - stake: before_stake, - total: before_total, - .. - } = collator; - collator.inc_delegator(delegator.clone(), more); - let after = collator.total; - - // update top candidates and total amount at stake - let n = if collator.is_active() { - Self::update_top_candidates( - candidate.clone(), - before_stake, - // safe because total >= stake - before_total - before_stake, - collator.stake, - collator.total - collator.stake, - ) - } else { - 0u32 - }; - - // increment rewards and update number of rewarded blocks - Self::do_inc_delegator_reward(&delegator, stake_after.saturating_sub(more), &candidate); - - CandidatePool::::insert(&candidate, collator); - DelegatorState::::insert(&delegator, delegation); - - Self::deposit_event(Event::DelegatorStakedMore(delegator, candidate, before_total, after)); - Ok(Some(::WeightInfo::delegator_stake_more( - n, - T::MaxDelegatorsPerCollator::get(), - unstaking_len, - )) - .into()) + >::delegate_with_auto_compound( + candidate, + delegator, + amount, + Percent::zero(), + candidate_delegation_count, + 0, + delegation_count, + ) } - /// Reduce the stake for delegating a collator candidate. - /// - /// If the new amount of staked fund is not large enough, the collator - /// could be removed from the set of collator candidates and not be - /// considered for authoring the next blocks. - /// - /// The unstaked funds are not release immediately to the account, but - /// they will be available after `StakeDuration` blocks. - /// - /// The remaining staked funds must still be larger than the minimum - /// required by this pallet to maintain the status of delegator. - /// - /// The resulting total amount of funds staked must be within the - /// allowed range as set in the pallet's configuration. - /// - /// Emits `DelegatorStakedLess`. - #[pallet::call_index(15)] - #[pallet::weight(::WeightInfo::delegator_stake_less( - T::MaxTopCandidates::get(), - T::MaxDelegatorsPerCollator::get() - ))] - pub fn delegator_stake_less(origin: OriginFor, less: BalanceOf) -> DispatchResultWithPostInfo { + /// If caller is not a delegator and not a collator, then join the set of delegators + /// If caller is a delegator, then makes delegation to change their delegation state + /// Sets the auto-compound config for the delegation + #[pallet::call_index(18)] + #[pallet::weight( + ::WeightInfo::delegate_with_auto_compound( + *candidate_delegation_count, + *candidate_auto_compounding_delegation_count, + *delegation_count, + ) + )] + pub fn delegate_with_auto_compound( + origin: OriginFor, + candidate: T::AccountId, + amount: BalanceOf, + auto_compound: Percent, + candidate_delegation_count: u32, + candidate_auto_compounding_delegation_count: u32, + delegation_count: u32, + ) -> DispatchResultWithPostInfo { let delegator = ensure_signed(origin)?; - ensure!(!less.is_zero(), Error::::ValStakeZero); - - let mut delegation = DelegatorState::::get(&delegator).ok_or(Error::::DelegatorNotFound)?; - let candidate = delegation.owner.clone(); - let mut collator = CandidatePool::::get(&candidate).ok_or(Error::::CandidateNotFound)?; - ensure!(!collator.is_leaving(), Error::::CannotDelegateIfLeaving); - let stake_after = delegation - .try_decrement(candidate.clone(), less) - .map_err(|_| Error::::DelegationNotFound)? - .ok_or(Error::::Underflow)?; - - ensure!( - stake_after >= T::MinDelegatorStake::get(), - Error::::DelegationBelowMin - ); - - // *** No Fail except during prep_unstake beyond this point *** - - Self::prep_unstake(&delegator, less, false)?; - - let CandidateOf:: { - stake: before_stake, - total: before_total, - .. - } = collator; - collator.dec_delegator(delegator.clone(), less); - let after = collator.total; - - // update top candidates and total amount at stake - let n = if collator.is_active() { - Self::update_top_candidates( - candidate.clone(), - before_stake, - // safe because total >= stake - before_total - before_stake, - collator.stake, - collator.total - collator.stake, - ) - } else { - 0u32 - }; - - // increment rewards and update number of rewarded blocks - Self::do_inc_delegator_reward(&delegator, stake_after.saturating_add(less), &candidate); - - CandidatePool::::insert(&candidate, collator); - DelegatorState::::insert(&delegator, delegation); + >::delegate_with_auto_compound( + candidate, + delegator, + amount, + auto_compound, + candidate_delegation_count, + candidate_auto_compounding_delegation_count, + delegation_count, + ) + } - Self::deposit_event(Event::DelegatorStakedLess(delegator, candidate, before_total, after)); - Ok(Some(::WeightInfo::delegator_stake_less( - n, - T::MaxDelegatorsPerCollator::get(), - )) - .into()) + /// DEPRECATED use batch util with schedule_revoke_delegation for all delegations + /// Request to leave the set of delegators. If successful, the caller is scheduled to be + /// allowed to exit via a [DelegationAction::Revoke] towards all existing delegations. + /// Success forbids future delegation requests until the request is invoked or cancelled. + #[pallet::call_index(19)] + #[pallet::weight(::WeightInfo::schedule_leave_delegators())] + pub fn schedule_leave_delegators(origin: OriginFor) -> DispatchResultWithPostInfo { + let delegator = ensure_signed(origin)?; + Self::delegator_schedule_revoke_all(delegator) } - /// Unlock all previously staked funds that are now available for - /// unlocking by the origin account after `StakeDuration` blocks have - /// elapsed. - /// - /// Weight: O(U) where U is the number of locked unstaking requests - /// bounded by `MaxUnstakeRequests`. - /// - Reads: [Origin Account], Unstaking, Locks - /// - Writes: Unstaking, Locks - /// - Kills: Unstaking & Locks if no balance is locked anymore - /// # - #[pallet::call_index(16)] - #[pallet::weight(::WeightInfo::unlock_unstaked( - T::MaxUnstakeRequests::get().saturated_into::() - ))] - pub fn unlock_unstaked( - origin: OriginFor, target: ::Source, + /// DEPRECATED use batch util with execute_delegation_request for all delegations + /// Execute the right to exit the set of delegators and revoke all ongoing delegations. + #[pallet::call_index(20)] + #[pallet::weight(::WeightInfo::execute_leave_delegators(*delegation_count))] + pub fn execute_leave_delegators( + origin: OriginFor, + delegator: T::AccountId, + delegation_count: u32, ) -> DispatchResultWithPostInfo { ensure_signed(origin)?; - let target = T::Lookup::lookup(target)?; - - let unstaking_len = Self::do_unlock(&target)?; - - Ok(Some(::WeightInfo::unlock_unstaked(unstaking_len)).into()) + Self::delegator_execute_scheduled_revoke_all(delegator, delegation_count) } - /// Claim block authoring rewards for the target address. - /// - /// Requires `Rewards` to be set beforehand, which can by triggered by - /// any of the following options - /// * Calling increment_{collator, delegator}_rewards (active) - /// * Altering your stake (active) - /// * Leaving the network as a collator (active) - /// * Revoking a delegation as a delegator (active) - /// * Being a delegator whose collator left the network, altered their - /// stake or incremented rewards (passive) - /// - /// The dispatch origin can be any signed one, e.g., anyone can claim - /// for anyone. - /// - /// Emits `Rewarded`. - #[pallet::call_index(17)] - #[pallet::weight(::WeightInfo::claim_rewards())] - pub fn claim_rewards(origin: OriginFor) -> DispatchResult { - let target = ensure_signed(origin)?; - - // reset rewards - let rewards = Rewards::::take(&target); - ensure!(!rewards.is_zero(), Error::::RewardsNotFound); + /// DEPRECATED use batch util with cancel_delegation_request for all delegations + /// Cancel a pending request to exit the set of delegators. Success clears the pending exit + /// request (thereby resetting the delay upon another `leave_delegators` call). + #[pallet::call_index(21)] + #[pallet::weight(::WeightInfo::cancel_leave_delegators())] + pub fn cancel_leave_delegators(origin: OriginFor) -> DispatchResultWithPostInfo { + let delegator = ensure_signed(origin)?; + Self::delegator_cancel_scheduled_revoke_all(delegator) + } - // mint into target - let rewards = T::Currency::deposit_into_existing(&target, rewards)?; + /// Request to revoke an existing delegation. If successful, the delegation is scheduled + /// to be allowed to be revoked via the `execute_delegation_request` extrinsic. + /// The delegation receives no rewards for the rounds while a revoke is pending. + /// A revoke may not be performed if any other scheduled request is pending. + #[pallet::call_index(22)] + #[pallet::weight(::WeightInfo::schedule_revoke_delegation())] + pub fn schedule_revoke_delegation(origin: OriginFor, collator: T::AccountId) -> DispatchResultWithPostInfo { + let delegator = ensure_signed(origin)?; + Self::delegation_schedule_revoke(collator, delegator) + } - Self::deposit_event(Event::Rewarded(target, rewards.peek())); + /// Bond more for delegators wrt a specific collator candidate. + #[pallet::call_index(23)] + #[pallet::weight(::WeightInfo::delegator_bond_more())] + pub fn delegator_bond_more( + origin: OriginFor, + candidate: T::AccountId, + more: BalanceOf, + ) -> DispatchResultWithPostInfo { + let delegator = ensure_signed(origin)?; + let in_top = Self::delegation_bond_more_without_event(delegator.clone(), candidate.clone(), more)?; + Pallet::::deposit_event(Event::DelegationIncreased { delegator, candidate, amount: more, in_top }); - Ok(()) + Ok(().into()) } - /// Actively increment the rewards of a collator. - /// - /// The same effect is triggered by changing the stake or leaving the - /// network. - /// - /// The dispatch origin must be a collator. - #[pallet::call_index(18)] - #[pallet::weight(::WeightInfo::increment_collator_rewards())] - pub fn increment_collator_rewards(origin: OriginFor) -> DispatchResult { - let collator = ensure_signed(origin)?; - let state = CandidatePool::::get(&collator).ok_or(Error::::CandidateNotFound)?; - - // increment rewards and update number of rewarded blocks - Self::do_inc_collator_reward(&collator, state.stake); + /// Request bond less for delegators wrt a specific collator candidate. The delegation's + /// rewards for rounds while the request is pending use the reduced bonded amount. + /// A bond less may not be performed if any other scheduled request is pending. + #[pallet::call_index(24)] + #[pallet::weight(::WeightInfo::schedule_delegator_bond_less())] + pub fn schedule_delegator_bond_less( + origin: OriginFor, + candidate: T::AccountId, + less: BalanceOf, + ) -> DispatchResultWithPostInfo { + let delegator = ensure_signed(origin)?; + Self::delegation_schedule_bond_decrease(candidate, delegator, less) + } - Ok(()) + /// Execute pending request to change an existing delegation + #[pallet::call_index(25)] + #[pallet::weight(::WeightInfo::execute_delegator_bond_less())] + pub fn execute_delegation_request( + origin: OriginFor, + delegator: T::AccountId, + candidate: T::AccountId, + ) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; // we may want to reward caller if caller != delegator + Self::delegation_execute_scheduled_request(candidate, delegator) } - /// Actively increment the rewards of a delegator. - /// - /// The same effect is triggered by changing the stake or revoking - /// delegations. - /// - /// The dispatch origin must be a delegator. - #[pallet::call_index(19)] - #[pallet::weight(::WeightInfo::increment_delegator_rewards())] - pub fn increment_delegator_rewards(origin: OriginFor) -> DispatchResult { + /// Cancel request to change an existing delegation. + #[pallet::call_index(26)] + #[pallet::weight(::WeightInfo::cancel_delegator_bond_less())] + pub fn cancel_delegation_request(origin: OriginFor, candidate: T::AccountId) -> DispatchResultWithPostInfo { let delegator = ensure_signed(origin)?; - let delegation = DelegatorState::::get(&delegator).ok_or(Error::::DelegatorNotFound)?; - let collator = delegation.owner; - - // increment rewards and update number of rewarded blocks - Self::do_inc_delegator_reward(&delegator, delegation.amount, &collator); + Self::delegation_cancel_request(candidate, delegator) + } - Ok(()) + /// Sets the auto-compounding reward percentage for a delegation. + #[pallet::call_index(27)] + #[pallet::weight(::WeightInfo::set_auto_compound( + *candidate_auto_compounding_delegation_count_hint, + *delegation_count_hint, + ))] + pub fn set_auto_compound( + origin: OriginFor, + candidate: T::AccountId, + value: Percent, + candidate_auto_compounding_delegation_count_hint: u32, + delegation_count_hint: u32, + ) -> DispatchResultWithPostInfo { + let delegator = ensure_signed(origin)?; + >::set_auto_compound( + candidate, + delegator, + value, + candidate_auto_compounding_delegation_count_hint, + delegation_count_hint, + ) } - /// Executes the annual reduction of the reward rates for collators and - /// delegators. - /// - /// Moreover, sets rewards for all collators and delegators - /// before adjusting the inflation. - /// - /// The dispatch origin can be any signed one because we bail if called - /// too early. - /// - /// Emits `RoundInflationSet`. - #[pallet::call_index(20)] - #[pallet::weight(::WeightInfo::execute_scheduled_reward_change(T::MaxTopCandidates::get(), T::MaxDelegatorsPerCollator::get()))] - pub fn execute_scheduled_reward_change(origin: OriginFor) -> DispatchResultWithPostInfo { + /// Hotfix to remove existing empty entries for candidates that have left. + #[pallet::call_index(28)] + #[pallet::weight( + T::DbWeight::get().reads_writes(2 * candidates.len() as u64, candidates.len() as u64) + )] + pub fn hotfix_remove_delegation_requests_exited_candidates( + origin: OriginFor, + candidates: Vec, + ) -> DispatchResult { ensure_signed(origin)?; + ensure!(candidates.len() < 100, >::InsufficientBalance); + for candidate in &candidates { + ensure!(>::get(candidate).is_none(), >::CandidateNotLeaving); + ensure!(>::get(candidate).is_empty(), >::CandidateNotLeaving); + } - let now = frame_system::Pallet::::block_number(); - let year = now / T::BLOCKS_PER_YEAR; - - // We can already mutate thanks to extrinsics being transactional - let last_update = LastRewardReduction::::mutate(|last_year| { - let old = *last_year; - *last_year = old.saturating_add(T::BlockNumber::one()); - old - }); - // Bail if less than a year (in terms of number of blocks) has passed since the - // last update - ensure!(year > last_update, Error::::TooEarly); - - // Calculate new inflation based on last year - let inflation = InflationConfig::::get(); - - // collator reward rate decreases by 2% p.a. of the previous one - let c_reward_rate = inflation.collator.reward_rate.annual * Perquintill::from_percent(98); - - // delegator reward rate should be 6% in 2nd year and 0% afterwards - let d_reward_rate = if year == T::BlockNumber::one() { - Perquintill::from_percent(6) - } else { - Perquintill::zero() - }; - - // Update inflation and increment rewards - let (num_col, num_del) = Self::do_set_inflation( - T::BLOCKS_PER_YEAR, - inflation.collator.max_rate, - c_reward_rate, - inflation.delegator.max_rate, - d_reward_rate, - )?; + for candidate in candidates { + >::remove(candidate); + } - Ok(Some(::WeightInfo::set_inflation(num_col, num_del)).into()) + Ok(()) } } + /// Represents a payout made via `pay_one_collator_reward`. + pub(crate) enum RewardPayment { + /// A collator was paid + Paid, + /// A collator was skipped for payment. This can happen if they haven't been awarded any + /// points, that is, they did not produce any blocks. + Skipped, + /// All collator payments have been processed. + Finished, + } + impl Pallet { - /// Check whether an account is currently delegating. pub fn is_delegator(acc: &T::AccountId) -> bool { - DelegatorState::::get(acc).is_some() + >::get(acc).is_some() } - /// Check whether an account is currently a collator candidate and - /// whether their state is CollatorStatus::Active. - /// - /// Returns Some(is_active) if the account is a candidate, else None. - pub fn is_active_candidate(acc: &T::AccountId) -> Option { - if let Some(state) = CandidatePool::::get(acc) { - Some(state.status == CandidateStatus::Active) - } else { - None - } + pub fn is_candidate(acc: &T::AccountId) -> bool { + >::get(acc).is_some() } - /// Set the annual inflation rate to derive per-round inflation. - /// - /// The inflation details are considered valid if the annual reward rate - /// is approximately the per-block reward rate multiplied by the - /// estimated* total number of blocks per year. - /// - /// The estimated average block time is twelve seconds. - /// - /// NOTE: Iterates over CandidatePool and for each candidate over their - /// delegators to update their rewards before the reward rates change. - /// Needs to be improved when scaling up `MaxTopCandidates`. - /// - /// Emits `RoundInflationSet`. - fn do_set_inflation( - blocks_per_year: T::BlockNumber, col_max_rate: Perquintill, col_reward_rate: Perquintill, - del_max_rate: Perquintill, del_reward_rate: Perquintill, - ) -> Result<(u32, u32), DispatchError> { - // Check validity of new inflation - let inflation = InflationInfo::new( - blocks_per_year.saturated_into(), - col_max_rate, - col_reward_rate, - del_max_rate, - del_reward_rate, - ); - ensure!( - inflation.is_valid(T::BLOCKS_PER_YEAR.saturated_into()), - Error::::InvalidSchedule - ); - - // Increment rewards for all collators and delegators due to change of reward - // rates - let mut num_delegators = 0u32; - CandidatePool::::iter().for_each(|(id, state)| { - // increment collator rewards - Self::do_inc_collator_reward(&id, state.stake); - // increment delegator rewards - state.delegators.into_iter().for_each(|delegator_state| { - Self::do_inc_delegator_reward(&delegator_state.owner, delegator_state.amount, &id); - num_delegators = num_delegators.saturating_add(1u32); - }); - }); - - // Update inflation - InflationConfig::::put(inflation); - Self::deposit_event(Event::RoundInflationSet( - col_max_rate, - col_reward_rate, - del_max_rate, - del_reward_rate, - )); - Ok((CandidatePool::::count(), num_delegators)) + pub fn is_selected_candidate(acc: &T::AccountId) -> bool { + >::get().binary_search(acc).is_ok() } - /// Update the top candidates and total amount at stake after mutating - /// an active candidate's stake. - /// - /// NOTE: It is assumed that the calling context checks whether the - /// collator candidate is currently active before calling this function. - fn update_top_candidates( - candidate: T::AccountId, old_self: BalanceOf, old_delegators: BalanceOf, new_self: BalanceOf, - new_delegators: BalanceOf, - ) -> u32 { - let mut top_candidates = TopCandidates::::get(); - let num_top_candidates: u32 = top_candidates.len().saturated_into(); - let old_stake = Stake { - owner: candidate.clone(), - amount: old_self.saturating_add(old_delegators), - }; - let new_stake = Stake { - owner: candidate.clone(), - amount: new_self.saturating_add(new_delegators), - }; - - // update TopCandidates set - let maybe_top_candidate_update = if let Ok(i) = top_candidates.linear_search(&old_stake) { - // case 1: candidate is member of TopCandidates with old stake - top_candidates.mutate(|vec| { - if let Some(stake) = vec.get_mut(i) { - stake.amount = new_stake.amount; - } - }); - Some((Some(i), top_candidates)) - } else if top_candidates.try_insert_replace(new_stake.clone()).is_ok() { - // case 2: candidate ascends into TopCandidates with new stake - // and might replace another candidate if TopCandidates is full - Self::deposit_event(Event::EnteredTopCandidates(candidate)); - Some((None, top_candidates)) - } else { - // case 3: candidate neither was nor will be member of TopCandidates - None - }; - - // update storage for TotalCollatorStake and TopCandidates - if let Some((maybe_old_idx, top_candidates)) = maybe_top_candidate_update { - let max_selected_candidates = MaxSelectedCandidates::::get().saturated_into::(); - let was_collating = maybe_old_idx.map(|i| i < max_selected_candidates).unwrap_or(false); - let is_collating = top_candidates - .linear_search(&new_stake) - .map(|i| i < max_selected_candidates) - .unwrap_or(false); - - // update TopCollatorStake storage iff candidate was or will be a collator - match (was_collating, is_collating) { - (true, true) => { - Self::update_total_stake_by(new_self, new_delegators, old_self, old_delegators); - } - (true, false) => { - // candidate left the collator set because they staked less and have been - // replaced by the next candidate in the queue at position - // min(max_selected_candidates, top_candidates) - 1 in TopCandidates - let new_col_idx = max_selected_candidates.min(top_candidates.len()).saturating_sub(1); - - // get displacer - let (add_collators, add_delegators) = Self::get_top_candidate_stake_at(&top_candidates, new_col_idx) - // shouldn't be possible to fail, but we handle it gracefully - .unwrap_or((new_self, new_delegators)); - Self::update_total_stake_by(add_collators, add_delegators, old_self, old_delegators); - } - (false, true) => { - // candidate pushed out the least staked collator which is now at position - // min(max_selected_top_candidates, top_candidates - 1) in TopCandidates - let old_col_idx = max_selected_candidates.min(top_candidates.len().saturating_sub(1)); - - // get amount to subtract from TotalCollatorStake - let (drop_self, drop_delegators) = Self::get_top_candidate_stake_at(&top_candidates, old_col_idx) - // default to zero if candidate DNE, e.g. TopCandidates is not full - .unwrap_or((BalanceOf::::zero(), BalanceOf::::zero())); - Self::update_total_stake_by(new_self, new_delegators, drop_self, drop_delegators); - } - _ => {} - } - - // update TopCandidates storage - TopCandidates::::put(top_candidates); + /// Returns an account's free balance which is not locked in delegation staking + pub fn get_delegator_stakable_free_balance(acc: &T::AccountId) -> BalanceOf { + let mut balance = T::Currency::free_balance(acc); + if let Some(state) = >::get(acc) { + balance = balance.saturating_sub(state.total()); } + balance + } - num_top_candidates + /// Returns an account's free balance which is not locked in collator staking + pub fn get_collator_stakable_free_balance(acc: &T::AccountId) -> BalanceOf { + let mut balance = T::Currency::free_balance(acc); + if let Some(info) = >::get(acc) { + balance = balance.saturating_sub(info.bond); + } + balance } - /// Retrieve the staked amounts (self, sum of delegators) of member of - /// [TopCandidates] at the given index, if it exists. - fn get_top_candidate_stake_at( - top_candidates: &OrderedSet, T::MaxTopCandidates>, index: usize, - ) -> Option<(BalanceOf, BalanceOf)> { - top_candidates - .get(index) - .and_then(|stake| CandidatePool::::get(&stake.owner)) - // SAFETY: the total is always more than the stake - .map(|state| (state.stake, state.total - state.stake)) + /// Returns a delegations auto-compound value. + pub fn delegation_auto_compound(candidate: &T::AccountId, delegator: &T::AccountId) -> Percent { + >::auto_compound(candidate, delegator) } - /// Mutate the [TotalCollatorStake] by both incrementing and decreasing - /// it by the provided values. - fn update_total_stake_by( - add_collators: BalanceOf, add_delegators: BalanceOf, sub_collators: BalanceOf, - sub_delegators: BalanceOf, - ) { - TotalCollatorStake::::mutate(|total| { - total.collators = total - .collators - .saturating_sub(sub_collators) - .saturating_add(add_collators); - total.delegators = total - .delegators - .saturating_sub(sub_delegators) - .saturating_add(add_delegators); - }); + /// Caller must ensure candidate is active before calling + pub(crate) fn update_active(candidate: T::AccountId, total: BalanceOf) { + let mut candidates = >::get(); + candidates.remove(&Bond::from_owner(candidate.clone())); + candidates.insert(Bond { owner: candidate, amount: total }); + >::put(candidates); } - /// Iterate over the top `MaxSelectedCandidates` many collators in terms - /// of cumulated stake (self + from delegators) from the [TopCandidates] - /// and recalculate the [TotalCollatorStake] from scratch. - /// - /// NOTE: Should only be called in rare circumstances in which we cannot - /// guarantee a single candidate's stake has changed, e.g. on genesis or - /// when a collator leaves. Otherwise, please use - /// [update_total_stake_by]. - fn update_total_stake() -> (u32, u32) { - let mut num_of_delegators = 0u32; - let mut collator_stake = BalanceOf::::zero(); - let mut delegator_stake = BalanceOf::::zero(); - - let collators = Self::selected_candidates(); - - // Snapshot exposure for round for weighting reward distribution - for account in collators.iter() { - let state = - CandidatePool::::get(account).expect("all members of TopCandidates must be candidates q.e.d"); - num_of_delegators = num_of_delegators.max(state.delegators.len().saturated_into::()); - - // sum up total stake and amount of collators, delegators - let amount_collator = state.stake; - collator_stake = collator_stake.saturating_add(state.stake); - // safe to subtract because total >= stake - let amount_delegators = state.total - amount_collator; - delegator_stake = delegator_stake.saturating_add(amount_delegators); + /// Compute round issuance based on total staked for the given round + fn compute_issuance(staked: BalanceOf) -> BalanceOf { + let config = >::get(); + let round_issuance = crate::inflation::round_issuance_range::(config.round); + // TODO: consider interpolation instead of bounded range + if staked < config.expect.min { + round_issuance.min + } else if staked > config.expect.max { + round_issuance.max + } else { + round_issuance.ideal } + } - TotalCollatorStake::::mutate(|total| { - total.collators = collator_stake; - total.delegators = delegator_stake; + /// Remove delegation from candidate state + /// Amount input should be retrieved from delegator and it informs the storage lookups + pub(crate) fn delegator_leaves_candidate( + candidate: T::AccountId, + delegator: T::AccountId, + amount: BalanceOf, + ) -> DispatchResult { + let mut state = >::get(&candidate).ok_or(Error::::CandidateDNE)?; + state.rm_delegation_if_exists::(&candidate, delegator.clone(), amount)?; + let new_total_locked = >::get().saturating_sub(amount); + >::put(new_total_locked); + let new_total = state.total_counted; + >::insert(&candidate, state); + Self::deposit_event(Event::DelegatorLeftCandidate { + delegator, + candidate, + unstaked_amount: amount, + total_candidate_staked: new_total, }); - - // return number of selected candidates and the corresponding number of their - // delegators for post-weight correction - (collators.len().saturated_into(), num_of_delegators) + Ok(()) } - /// Update the collator's state by removing the delegator's stake and - /// starting the process to unlock the delegator's staked funds as well - /// as incrementing their accumulated rewards. - /// - /// This operation affects the pallet's total stake. - fn delegator_leaves_collator(delegator: T::AccountId, collator: T::AccountId) -> DispatchResult { - let mut state = CandidatePool::::get(&collator).ok_or(Error::::CandidateNotFound)?; - - let delegator_stake = state - .delegators - .remove(&Stake { - owner: delegator.clone(), - // amount is irrelevant for removal - amount: BalanceOf::::one(), - }) - .map(|nom| nom.amount) - .ok_or(Error::::DelegatorNotFound)?; - - let CandidateOf:: { - stake: old_stake, - total: old_total, - .. - } = state; - state.total = state.total.saturating_sub(delegator_stake); - let new_total = state.total; - - // increment rewards and kill storage for number of rewarded blocks - Self::do_inc_delegator_reward(&delegator, delegator_stake, &collator); - BlocksRewarded::::remove(&delegator); - - // we don't unlock immediately - Self::prep_unstake(&delegator, delegator_stake, false)?; - - // update top candidates and total amount at stake - if state.is_active() { - Self::update_top_candidates( - collator.clone(), - old_stake, - // safe because total >= stake - old_total - old_stake, - state.stake, - state.total - state.stake, - ); + pub(crate) fn prepare_staking_payouts(now: RoundIndex) -> Weight { + // payout is now - delay rounds ago => now - delay > 0 else return early + let delay = T::RewardPaymentDelay::get(); + if now <= delay { + return Weight::zero() + } + let round_to_payout = now.saturating_sub(delay); + let total_points = >::get(round_to_payout); + if total_points.is_zero() { + return Weight::zero() + } + let total_staked = >::take(round_to_payout); + let total_issuance = Self::compute_issuance(total_staked); + let mut left_issuance = total_issuance; + // reserve portion of issuance for parachain bond account + let bond_config = >::get(); + let parachain_bond_reserve = bond_config.percent * total_issuance; + if let Ok(imb) = T::Currency::deposit_into_existing(&bond_config.account, parachain_bond_reserve) { + // update round issuance iff transfer succeeds + left_issuance = left_issuance.saturating_sub(imb.peek()); + Self::deposit_event(Event::ReservedForParachainBond { + account: bond_config.account, + value: imb.peek(), + }); } - CandidatePool::::insert(&collator, state); - Self::deposit_event(Event::DelegatorLeftCollator( - delegator, - collator, - delegator_stake, - new_total, - )); - Ok(()) + let payout = DelayedPayout { + round_issuance: total_issuance, + total_staking_reward: left_issuance, + collator_commission: >::get(), + }; + + >::insert(round_to_payout, payout); + T::WeightInfo::prepare_staking_payouts() } - /// Return the best `MaxSelectedCandidates` many candidates. - /// - /// In case a collator from last round was replaced by a candidate with - /// the same total stake during sorting, we revert this swap to - /// prioritize collators over candidates. - pub fn selected_candidates() -> BoundedVec { - let candidates = TopCandidates::::get(); + /// Wrapper around pay_one_collator_reward which handles the following logic: + /// * whether or not a payout needs to be made + /// * cleaning up when payouts are done + /// * returns the weight consumed by pay_one_collator_reward if applicable + fn handle_delayed_payouts(now: RoundIndex) -> Weight { + let delay = T::RewardPaymentDelay::get(); - // Should never fail since WASM usize are 32bits and native are either 32 or 64 - let top_n = MaxSelectedCandidates::::get().saturated_into::(); + // don't underflow uint + if now < delay { + return Weight::from_parts(0u64, 0) + } - log::trace!("{} Candidates for {} Collator seats", candidates.len(), top_n); + let paid_for_round = now.saturating_sub(delay); - // Choose the top MaxSelectedCandidates qualified candidates - let collators = candidates - .into_iter() - .take(top_n) - .filter(|x| x.amount >= T::MinCollatorStake::get()) - .map(|x| x.owner) - .collect::>(); + if let Some(payout_info) = >::get(paid_for_round) { + let result = Self::pay_one_collator_reward(paid_for_round, payout_info); - collators.try_into().expect("Did not extend Collators q.e.d.") + // clean up storage items that we no longer need + if matches!(result.0, RewardPayment::Finished) { + >::remove(paid_for_round); + >::remove(paid_for_round); + } + result.1 // weight consumed by pay_one_collator_reward + } else { + Weight::from_parts(0u64, 0) + } } - /// Attempts to add the stake to the set of delegators of a collator - /// which already reached its maximum size by removing an already - /// existing delegator with less staked value. If the given staked - /// amount is at most the minimum staked value of the original delegator - /// set, an error is returned. - /// - /// Sets rewards for the removed delegator. - /// - /// Returns a tuple which contains the updated candidate state as well - /// as the potentially replaced delegation which will be used later when - /// updating the storage of the replaced delegator. - /// - /// Emits `DelegationReplaced` if the stake exceeds one of the current - /// delegations. - #[allow(clippy::type_complexity)] - fn do_update_delegator( - stake: Stake>, - mut state: Candidate, T::MaxDelegatorsPerCollator>, - ) -> Result, DispatchError> { - // attempt to replace the last element of the set - let stake_to_remove = state - .delegators - .try_insert_replace(stake.clone()) - .map_err(|err_too_many| { - if err_too_many { - Error::::TooManyDelegators - } else { - // should never occur because we previously check this case, but let's be sure - Error::::AlreadyDelegating - } - })?; - - state.total = state.total.saturating_add(stake.amount); - - if let Some(stake_to_remove) = stake_to_remove { - // update total stake - state.total = state.total.saturating_sub(stake_to_remove.amount); - - // update rewards for kicked delegator - Self::do_inc_delegator_reward(&stake_to_remove.owner, stake_to_remove.amount, &state.id); - // prepare unstaking for kicked delegator - Self::prep_unstake(&stake_to_remove.owner, stake_to_remove.amount, true)?; - // remove Delegator state for kicked delegator - DelegatorState::::remove(&stake_to_remove.owner); - - Self::deposit_event(Event::DelegationReplaced( - stake.owner, - stake.amount, - stake_to_remove.owner, - stake_to_remove.amount, - state.id.clone(), - state.total, - )); + /// Payout a single collator from the given round. + /// + /// Returns an optional tuple of (Collator's AccountId, total paid) + /// or None if there were no more payouts to be made for the round. + pub(crate) fn pay_one_collator_reward( + paid_for_round: RoundIndex, + payout_info: DelayedPayout>, + ) -> (RewardPayment, Weight) { + // 'early_weight' tracks weight used for reads/writes done early in this fn before its + // early-exit codepaths. + let mut early_weight = Weight::zero(); + + // TODO: it would probably be optimal to roll Points into the DelayedPayouts storage + // item so that we do fewer reads each block + let total_points = >::get(paid_for_round); + early_weight = early_weight.saturating_add(T::DbWeight::get().reads_writes(1, 0)); + + if total_points.is_zero() { + // TODO: this case is obnoxious... it's a value query, so it could mean one of two + // different logic errors: + // 1. we removed it before we should have + // 2. we called pay_one_collator_reward when we were actually done with deferred + // payouts + log::warn!("pay_one_collator_reward called with no > for the round!"); + return (RewardPayment::Finished, early_weight) } - Ok(state) - } + let collator_fee = payout_info.collator_commission; + let collator_issuance = collator_fee * payout_info.round_issuance; - /// Either set or increase the BalanceLock of target account to - /// amount. - /// - /// Consumes unstaked balance which can be unlocked in the future up to - /// amount and updates `Unstaking` storage accordingly. - fn increase_lock(who: &T::AccountId, amount: BalanceOf, more: BalanceOf) -> Result { - ensure!( - pallet_balances::Pallet::::free_balance(who) >= amount.into(), - pallet_balances::Error::::InsufficientBalance - ); + if let Some((collator, state)) = >::iter_prefix(paid_for_round).drain().next() { + // read and kill AtStake + early_weight = early_weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); - let mut unstaking_len = 0u32; - - // *** No Fail except during Unstaking mutation beyond this point *** - - // update Unstaking by consuming up to {amount | more} - Unstaking::::try_mutate(who, |unstaking| -> DispatchResult { - // reduce {amount | more} by unstaking until either {amount | more} is zero or - // no unstaking is left - // if more is set, we only want to reduce by more to achieve 100 - 40 + 30 = 90 - // locked - let mut amt_consuming_unstaking = if more.is_zero() { amount } else { more }; - unstaking_len = unstaking.len().saturated_into(); - for (block_number, locked_balance) in unstaking.clone() { - if amt_consuming_unstaking.is_zero() { - break; - } else if locked_balance > amt_consuming_unstaking { - // amount is only reducible by locked_balance - amt_consuming_unstaking - let delta = locked_balance.saturating_sub(amt_consuming_unstaking); - // replace old entry with delta - unstaking - .try_insert(block_number, delta) - .map_err(|_| Error::::NoMoreUnstaking)?; - amt_consuming_unstaking = Zero::zero(); - } else { - // amount is either still reducible or reached - amt_consuming_unstaking = amt_consuming_unstaking.saturating_sub(locked_balance); - unstaking.remove(&block_number); - } + // Take the awarded points for the collator + let pts = >::take(paid_for_round, &collator); + // read and kill AwardedPts + early_weight = early_weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); + if pts == 0 { + return (RewardPayment::Skipped, early_weight) } - Ok(()) - })?; - - // Either set a new lock or potentially extend the existing one if amount - // exceeds the currently locked amount - T::Currency::extend_lock(STAKING_ID, who, amount, WithdrawReasons::all()); - Ok(unstaking_len) - } + // 'extra_weight' tracks weight returned from fns that we delegate to which can't be + // known ahead of time. + let mut extra_weight = Weight::zero(); + let pct_due = Perbill::from_rational(pts, total_points); + let total_paid = pct_due * payout_info.total_staking_reward; + let mut amt_due = total_paid; + + let num_delegators = state.delegations.len(); + if state.delegations.is_empty() { + // solo collator with no delegators + extra_weight = extra_weight + .saturating_add(T::PayoutCollatorReward::payout_collator_reward( + paid_for_round, + collator.clone(), + amt_due, + )) + .saturating_add(T::OnCollatorPayout::on_collator_payout(paid_for_round, collator, amt_due)); + log::warn!("💵 Solo collator reward: {:?}", amt_due); + } else { + // pay collator first; commission + due_portion + let collator_pct = Perbill::from_rational(state.bond, state.total); + let commission = pct_due * collator_issuance; + amt_due = amt_due.saturating_sub(commission); + let collator_reward = (collator_pct * amt_due).saturating_add(commission); + extra_weight = extra_weight + .saturating_add(T::PayoutCollatorReward::payout_collator_reward( + paid_for_round, + collator.clone(), + collator_reward, + )) + .saturating_add(T::OnCollatorPayout::on_collator_payout( + paid_for_round, + collator.clone(), + collator_reward, + )); + + // pay delegators due portion + for BondWithAutoCompound { owner, amount, auto_compound } in state.delegations { + let percent = Perbill::from_rational(amount, state.total); + let due = percent * amt_due; + if !due.is_zero() { + extra_weight = extra_weight.saturating_add(Self::mint_and_compound( + due, + auto_compound, + collator.clone(), + owner.clone(), + )); + } + } + } - /// Set the unlocking block for the account and corresponding amount - /// which can be unlocked via `unlock_unstaked` after waiting at - /// least for `StakeDuration` many blocks. - /// - /// Throws if the amount is zero (unlikely) or if active unlocking - /// requests exceed limit. The latter defends against stake reduction - /// spamming. - fn prep_unstake(who: &T::AccountId, amount: BalanceOf, is_removal: bool) -> DispatchResult { - // should never occur but let's be safe - ensure!(!amount.is_zero(), Error::::StakeNotFound); - - let now = frame_system::Pallet::::block_number(); - let unlock_block = now.saturating_add(T::StakeDuration::get()); - let mut unstaking = Unstaking::::get(who); - - let allowed_unstakings = if is_removal { - // the account was forcedly removed and we allow to fill all unstake requests - T::MaxUnstakeRequests::get() + ( + RewardPayment::Paid, + T::WeightInfo::pay_one_collator_reward(num_delegators as u32).saturating_add(extra_weight), + ) } else { - // we need to reserve a free slot for a forced removal of the account - T::MaxUnstakeRequests::get().saturating_sub(1) - }; - ensure!( - unstaking.len().saturated_into::() < allowed_unstakings, - Error::::NoMoreUnstaking, - ); - - // if existent, we have to add the current amount of same unlock_block, because - // insert overwrites the current value - let amount = amount.saturating_add(*unstaking.get(&unlock_block).unwrap_or(&BalanceOf::::zero())); - unstaking - .try_insert(unlock_block, amount) - .map_err(|_| Error::::NoMoreUnstaking)?; - Unstaking::::insert(who, unstaking); - Ok(()) + // Note that we don't clean up storage here; it is cleaned up in + // handle_delayed_payouts() + (RewardPayment::Finished, Weight::from_parts(0u64, 0)) + } } - /// Clear the CandidatePool of the candidate and remove all delegations - /// to the candidate. Moreover, prepare unstaking for the candidate and - /// their former delegations. - fn remove_candidate( - collator: &T::AccountId, state: &CandidateOf, - ) -> DispatchResult { - // iterate over delegators - for stake in &state.delegators[..] { - // increment rewards - Self::do_inc_delegator_reward(&stake.owner, stake.amount, collator); - // prepare unstaking of delegator - Self::prep_unstake(&stake.owner, stake.amount, true)?; - // remove delegation from delegator state - if let Some(mut delegator) = DelegatorState::::get(&stake.owner) { - delegator - .try_clear(collator.clone()) - .map_err(|_| Error::::DelegationNotFound)?; - DelegatorState::::remove(&stake.owner); - } + /// Compute the top `TotalSelected` candidates in the CandidatePool and return + /// a vec of their AccountIds (sorted by AccountId). + /// + /// If the returned vec is empty, the previous candidates should be used. + pub fn compute_top_candidates() -> Vec { + let top_n = >::get() as usize; + if top_n == 0 { + return vec![] } - // prepare unstaking of collator candidate - Self::prep_unstake(&state.id, state.stake, true)?; - // *** No Fail beyond this point *** + let mut candidates = >::get().0; + + // If the number of candidates is greater than top_n, select the candidates with higher + // amount. Otherwise, return all the candidates. + if candidates.len() > top_n { + // Partially sort candidates such that element at index `top_n - 1` is sorted, and + // all the elements in the range 0..top_n are the top n elements. + candidates.select_nth_unstable_by(top_n - 1, |a, b| { + // Order by amount, then owner. The owner is needed to ensure a stable order + // when two accounts have the same amount. + a.amount.cmp(&b.amount).then_with(|| a.owner.cmp(&b.owner)).reverse() + }); - // increment rewards of collator - Self::do_inc_collator_reward(collator, state.stake); + let mut collators = candidates.into_iter().take(top_n).map(|x| x.owner).collect::>(); - // disable validator for next session if they were in the set of validators - pallet_session::Pallet::::validators() - .into_iter() - .enumerate() - .find_map(|(i, id)| { - if ::ValidatorIdOf::convert(collator.clone()) - == Some(id) - { - Some(i) - } else { - None - } - }) - .map(u32::saturated_from::) - // FIXME: Does not prevent the collator from being able to author a block in this (or potentially the next) session. See https://github.com/paritytech/substrate/issues/8004 - .map(pallet_session::Pallet::::disable_index); - - // Kill storage - BlocksAuthored::::remove(collator); - BlocksRewarded::::remove(collator); - CandidatePool::::remove(collator); - Ok(()) + // Sort collators by AccountId + collators.sort(); + + collators + } else { + // Return all candidates + // The candidates are already sorted by AccountId, so no need to sort again + candidates.into_iter().map(|x| x.owner).collect::>() + } } - /// Withdraw all staked currency which was unstaked at least - /// `StakeDuration` blocks ago. - fn do_unlock(who: &T::AccountId) -> Result { - let now = frame_system::Pallet::::block_number(); - let mut unstaking = Unstaking::::get(who); - let unstaking_len = unstaking.len().saturated_into::(); - ensure!(!unstaking.is_empty(), Error::::UnstakingIsEmpty); - - let mut total_unlocked: BalanceOf = Zero::zero(); - let mut total_locked: BalanceOf = Zero::zero(); - let mut expired = Vec::new(); - - // check potential unlocks - for (block_number, locked_balance) in unstaking.clone().into_iter() { - if block_number <= now { - expired.push(block_number); - total_unlocked = total_unlocked.saturating_add(locked_balance); - } else { - total_locked = total_locked.saturating_add(locked_balance); + /// Best as in most cumulatively supported in terms of stake + /// Returns [collator_count, delegation_count, total staked] + pub(crate) fn select_top_candidates(now: RoundIndex) -> (Weight, u32, u32, BalanceOf) { + let (mut collator_count, mut delegation_count, mut total) = (0u32, 0u32, BalanceOf::::zero()); + // choose the top TotalSelected qualified candidates, ordered by stake + let collators = Self::compute_top_candidates(); + if collators.is_empty() { + // SELECTION FAILED TO SELECT >=1 COLLATOR => select collators from previous round + let last_round = now.saturating_sub(1u32); + let mut total_per_candidate: BTreeMap> = BTreeMap::new(); + // set this round AtStake to last round AtStake + for (account, snapshot) in >::iter_prefix(last_round) { + collator_count = collator_count.saturating_add(1u32); + delegation_count = delegation_count.saturating_add(snapshot.delegations.len() as u32); + total = total.saturating_add(snapshot.total); + total_per_candidate.insert(account.clone(), snapshot.total); + >::insert(now, account, snapshot); } + // `SelectedCandidates` remains unchanged from last round + // emit CollatorChosen event for tools that use this event + for candidate in >::get() { + let snapshot_total = + total_per_candidate.get(&candidate).expect("all selected candidates have snapshots"); + Self::deposit_event(Event::CollatorChosen { + round: now, + collator_account: candidate, + total_exposed_amount: *snapshot_total, + }) + } + let weight = T::WeightInfo::select_top_candidates(0, 0); + return (weight, collator_count, delegation_count, total) } - for block_number in expired { - unstaking.remove(&block_number); - } - - // iterate balance locks to retrieve amount of locked balance - let locks = Locks::::get(who); - total_locked = if let Some(BalanceLock { amount, .. }) = locks.iter().find(|l| l.id == STAKING_ID) { - amount.saturating_sub(total_unlocked.into()).into() - } else { - // should never fail to find the lock since we checked whether unstaking is not - // empty but let's be safe - Zero::zero() - }; - if total_locked.is_zero() { - T::Currency::remove_lock(STAKING_ID, who); - Unstaking::::remove(who); - } else { - T::Currency::set_lock(STAKING_ID, who, total_locked, WithdrawReasons::all()); - Unstaking::::insert(who, unstaking); + // snapshot exposure for round for weighting reward distribution + for account in collators.iter() { + let state = >::get(account).expect("all members of CandidateQ must be candidates"); + + collator_count = collator_count.saturating_add(1u32); + delegation_count = delegation_count.saturating_add(state.delegation_count); + total = total.saturating_add(state.total_counted); + let CountedDelegations { uncounted_stake, rewardable_delegations } = + Self::get_rewardable_delegators(account); + let total_counted = state.total_counted.saturating_sub(uncounted_stake); + + let auto_compounding_delegations = >::get(account) + .into_iter() + .map(|x| (x.delegator, x.value)) + .collect::>(); + let rewardable_delegations = rewardable_delegations + .into_iter() + .map(|d| BondWithAutoCompound { + owner: d.owner.clone(), + amount: d.amount, + auto_compound: auto_compounding_delegations + .get(&d.owner) + .cloned() + .unwrap_or_else(Percent::zero), + }) + .collect(); + + let snapshot = + CollatorSnapshot { bond: state.bond, delegations: rewardable_delegations, total: total_counted }; + >::insert(now, account, snapshot); + Self::deposit_event(Event::CollatorChosen { + round: now, + collator_account: account.clone(), + total_exposed_amount: state.total_counted, + }); } + // insert canonical collator set + >::put(collators); - Ok(unstaking_len) + let avg_delegator_count = delegation_count.checked_div(collator_count).unwrap_or(0); + let weight = T::WeightInfo::select_top_candidates(collator_count, avg_delegator_count); + (weight, collator_count, delegation_count, total) } - /// Checks whether a delegator can still delegate in this round, e.g., - /// if they have not delegated MaxDelegationsPerRound many times - /// already in this round. - fn get_delegation_counter(delegator: &T::AccountId) -> Result { - let last_delegation = LastDelegation::::get(delegator); - let round = Round::::get(); - - // reset counter if the round advanced since last delegation - let counter = if last_delegation.round < round.current { - 0u32 - } else { - last_delegation.counter - }; + /// Apply the delegator intent for revoke and decrease in order to build the + /// effective list of delegators with their intended bond amount. + /// + /// This will: + /// - if [DelegationChange::Revoke] is outstanding, set the bond amount to 0. + /// - if [DelegationChange::Decrease] is outstanding, subtract the bond by specified amount. + /// - else, do nothing + /// + /// The intended bond amounts will be used while calculating rewards. + pub(crate) fn get_rewardable_delegators(collator: &T::AccountId) -> CountedDelegations { + let requests = >::get(collator) + .into_iter() + .map(|x| (x.delegator, x.action)) + .collect::>(); + let mut uncounted_stake = BalanceOf::::zero(); + let rewardable_delegations = >::get(collator) + .expect("all members of CandidateQ must be candidates") + .delegations + .into_iter() + .map(|mut bond| { + bond.amount = match requests.get(&bond.owner) { + None => bond.amount, + Some(DelegationAction::Revoke(_)) => { + uncounted_stake = uncounted_stake.saturating_add(bond.amount); + BalanceOf::::zero() + }, + Some(DelegationAction::Decrease(amount)) => { + uncounted_stake = uncounted_stake.saturating_add(*amount); + bond.amount.saturating_sub(*amount) + }, + }; + + bond + }) + .collect(); + CountedDelegations { uncounted_stake, rewardable_delegations } + } + /// This function exists as a helper to delegator_bond_more & auto_compound functionality. + /// Any changes to this function must align with both user-initiated bond increases and + /// auto-compounding bond increases. + /// Any feature-specific preconditions should be validated before this function is invoked. + /// Any feature-specific events must be emitted after this function is invoked. + pub fn delegation_bond_more_without_event( + delegator: T::AccountId, + candidate: T::AccountId, + more: BalanceOf, + ) -> Result { ensure!( - counter < T::MaxDelegationsPerRound::get(), - Error::::DelegationsPerRoundExceeded + !Self::delegation_request_revoke_exists(&candidate, &delegator), + Error::::PendingDelegationRevoke ); - - Ok(DelegationCounter { - round: round.current, - counter: counter.saturating_add(1), - }) + let mut state = >::get(&delegator).ok_or(Error::::DelegatorDNE)?; + state.increase_delegation::(candidate, more) } - /// Calculates the network rewards per block with the current data and - /// issues these rewards to the network. The imbalance will be handled - /// in `on_initialize` by adding it to the free balance of - /// `NetworkRewardBeneficiary`. - /// - /// Over the course of an entire year, the network rewards equal the - /// maximum annual collator staking rewards multiplied with the - /// NetworkRewardRate. E.g., assuming 10% annual collator reward rate, - /// 10% max staking rate, 200k KILT max collator stake and 30 collators: - /// NetworkRewards = NetworkRewardRate * 10% * 10% * 200_000 KILT * 30 - /// - /// The expected rewards are the product of - /// * the current total maximum collator rewards - /// * and the configured NetworkRewardRate - /// - /// `col_reward_rate_per_block * col_max_stake * max_num_of_collators * - /// NetworkRewardRate` - fn issue_network_reward() -> NegativeImbalanceOf { - // Multiplication with Perquintill cannot overflow - let max_col_rewards = InflationConfig::::get().collator.reward_rate.per_block - * MaxCollatorCandidateStake::::get() - * MaxSelectedCandidates::::get().into(); - let network_reward = T::NetworkRewardRate::get() * max_col_rewards; - - T::Currency::issue(network_reward) + /// Mint a specified reward amount to the beneficiary account. Emits the [Rewarded] event. + pub fn mint(amt: BalanceOf, to: T::AccountId) { + if let Ok(amount_transferred) = T::Currency::deposit_into_existing(&to, amt) { + Self::deposit_event(Event::Rewarded { account: to.clone(), rewards: amount_transferred.peek() }); + } } - /// Calculates the collator staking rewards for authoring `multiplier` - /// many blocks based on the given stake. - /// - /// Depends on the current total issuance and staking reward - /// configuration for collators. - pub(crate) fn calc_block_rewards_collator(stake: BalanceOf, multiplier: BalanceOf) -> BalanceOf { - let total_issuance = T::Currency::total_issuance(); - let TotalStake { - collators: total_collators, - .. - } = TotalCollatorStake::::get(); - let staking_rate = Perquintill::from_rational(total_collators, total_issuance); - - InflationConfig::::get() - .collator - .compute_reward::(stake, staking_rate, multiplier) + /// Mint a specified reward amount to the collator's account. Emits the [Rewarded] event. + pub fn mint_collator_reward( + _paid_for_round: RoundIndex, + collator_id: T::AccountId, + amt: BalanceOf, + ) -> Weight { + if let Ok(amount_transferred) = T::Currency::deposit_into_existing(&collator_id, amt) { + Self::deposit_event(Event::Rewarded { + account: collator_id.clone(), + rewards: amount_transferred.peek(), + }); + } + T::WeightInfo::mint_collator_reward() } - /// Calculates the delegator staking rewards for `multiplier` many - /// blocks based on the given stake. - /// - /// Depends on the current total issuance and staking reward - /// configuration for delegators. - pub(crate) fn calc_block_rewards_delegator(stake: BalanceOf, multiplier: BalanceOf) -> BalanceOf { - let total_issuance = T::Currency::total_issuance(); - let TotalStake { - delegators: total_delegators, - .. - } = TotalCollatorStake::::get(); - let staking_rate = Perquintill::from_rational(total_delegators, total_issuance); - - InflationConfig::::get() - .delegator - .compute_reward::(stake, staking_rate, multiplier) - } + /// Mint and compound delegation rewards. The function mints the amount towards the + /// delegator and tries to compound a specified percent of it back towards the delegation. + /// If a scheduled delegation revoke exists, then the amount is only minted, and nothing is + /// compounded. Emits the [Compounded] event. + pub fn mint_and_compound( + amt: BalanceOf, + compound_percent: Percent, + candidate: T::AccountId, + delegator: T::AccountId, + ) -> Weight { + let mut weight = T::WeightInfo::mint_collator_reward(); + if let Ok(amount_transferred) = T::Currency::deposit_into_existing(&delegator, amt) { + Self::deposit_event(Event::Rewarded { account: delegator.clone(), rewards: amount_transferred.peek() }); + + let compound_amount = compound_percent.mul_ceil(amount_transferred.peek()); + if compound_amount.is_zero() { + return weight + } - /// Increment the accumulated rewards of a collator. - /// - /// Updates Rewarded(col) and sets BlocksRewarded(col) to equal - /// BlocksAuthored(col). - fn do_inc_collator_reward(acc: &T::AccountId, stake: BalanceOf) { - let count_authored = BlocksAuthored::::get(acc); - // We can already mutate thanks to extrinsics being transactional - let count_rewarded = BlocksRewarded::::mutate(acc, |rewarded| { - let old = *rewarded; - *rewarded = count_authored; - old - }); - let unclaimed_blocks = count_authored.saturating_sub(count_rewarded); + if let Err(err) = + Self::delegation_bond_more_without_event(delegator.clone(), candidate.clone(), compound_amount) + { + log::warn!( + "skipped compounding staking reward towards candidate '{:?}' for delegator '{:?}': {:?}", + candidate, + delegator, + err + ); + return weight + }; + weight = weight.saturating_add(T::WeightInfo::delegator_bond_more()); + + Pallet::::deposit_event(Event::Compounded { delegator, candidate, amount: compound_amount }); + }; - Rewards::::mutate(acc, |reward| { - *reward = reward.saturating_add(Self::calc_block_rewards_collator(stake, unclaimed_blocks.into())); - }); + weight } + } - /// Increment the accumulated rewards of a delegator by checking the - /// number of authored blocks by the collator. - /// - /// Updates Rewarded(del) and sets BlocksRewarded(del) to equal - /// BlocksAuthored(col). - fn do_inc_delegator_reward(acc: &T::AccountId, stake: BalanceOf, col: &T::AccountId) { - let count_authored = BlocksAuthored::::get(col); - // We can already mutate thanks to extrinsics being transactional - let count_rewarded = BlocksRewarded::::mutate(acc, |rewarded| { - let old = *rewarded; - *rewarded = count_authored; - old - }); - let unclaimed_blocks = count_authored.saturating_sub(count_rewarded); - - Rewards::::mutate(acc, |reward| { - *reward = reward.saturating_add(Self::calc_block_rewards_delegator(stake, unclaimed_blocks.into())) - }); + /// Add reward points to block authors: + /// * 20 points to the block producer for producing a block in the chain + impl Pallet { + fn award_points_to_block_author(author: AccountIdOf) { + let now = >::get().current; + let score_plus_20 = >::get(now, &author).saturating_add(20); + >::insert(now, author, score_plus_20); + >::mutate(now, |x| *x = x.saturating_add(20)); } } - impl pallet_authorship::EventHandler for Pallet + impl Get> for Pallet { + fn get() -> Vec { + Self::selected_candidates() + } + } + impl pallet_authorship::EventHandler, T::BlockNumber> for Pallet where T: Config + pallet_authorship::Config + pallet_session::Config, { - /// Increments the reward counter of the block author by the current - /// number of collators in the session. - fn note_author(author: T::AccountId) { - // should always include state except if the collator has been forcedly removed - // via `force_remove_candidate` in the current or previous round - if CandidatePool::::get(&author).is_some() { - // necessary to compensate for a potentially fluctuating number of collators - let authors = pallet_session::Pallet::::validators(); - BlocksAuthored::::mutate(&author, |count| { - *count = count.saturating_add(authors.len().saturated_into::()); - }); - } - - frame_system::Pallet::::register_extra_weight_unchecked( - T::DbWeight::get().reads_writes(2, 1), - DispatchClass::Mandatory, - ); + /// Add reward points to block authors: + /// * 20 points to the block producer for producing a block in the chain + fn note_author(author: AccountIdOf) { + Pallet::::award_points_to_block_author(author); } } - impl pallet_session::SessionManager for Pallet { + impl pallet_session::SessionManager> for Pallet { /// 1. A new session starts. /// 2. In hook new_session: Read the current top n candidates from the /// TopCandidates and assign this set to author blocks for the next @@ -2485,16 +1855,11 @@ pub mod pallet { /// 3. AuRa queries the authorities from the session pallet for /// this session and picks authors on round-robin-basis from list of /// authorities. - fn new_session(new_index: SessionIndex) -> Option> { - log::debug!( + fn new_session(new_index: SessionIndex) -> Option>> { + log::warn!( "assembling new collators for new session {} at #{:?}", new_index, - frame_system::Pallet::::block_number(), - ); - - frame_system::Pallet::::register_extra_weight_unchecked( - T::DbWeight::get().reads(2), - DispatchClass::Mandatory, + >::block_number(), ); let collators = Pallet::::selected_candidates().to_vec(); @@ -2516,55 +1881,35 @@ pub mod pallet { } } - impl ShouldEndSession for Pallet { + impl pallet_session::ShouldEndSession for Pallet { fn should_end_session(now: T::BlockNumber) -> bool { - frame_system::Pallet::::register_extra_weight_unchecked( - T::DbWeight::get().reads(2), - DispatchClass::Mandatory, - ); - - let mut round = Round::::get(); + let round = >::get(); // always update when a new round should start - if round.should_update(now) { - true - } else if ForceNewRound::::get() { - frame_system::Pallet::::register_extra_weight_unchecked( - T::DbWeight::get().writes(2), - DispatchClass::Mandatory, - ); - // check for forced new round - ForceNewRound::::put(false); - round.update(now); - Round::::put(round); - Self::deposit_event(Event::NewRound(round.first, round.current)); - true - } else { - false - } + round.should_update(now) } } impl EstimateNextSessionRotation for Pallet { fn average_session_length() -> T::BlockNumber { - Round::::get().length + T::BlockNumber::from(>::get().length) } fn estimate_current_session_progress(now: T::BlockNumber) -> (Option, Weight) { - let round = Round::::get(); + let round = >::get(); let passed_blocks = now.saturating_sub(round.first); ( - Some(Permill::from_rational(passed_blocks, round.length)), + Some(Permill::from_rational(passed_blocks, T::BlockNumber::from(round.length))), // One read for the round info, blocknumber is read free T::DbWeight::get().reads(1), ) } fn estimate_next_session_rotation(_now: T::BlockNumber) -> (Option, Weight) { - let round = Round::::get(); + let round = >::get(); ( - Some(round.first + round.length), + Some(round.first + round.length.into()), // One read for the round info, blocknumber is read free T::DbWeight::get().reads(1), ) diff --git a/pallets/parachain-staking/src/migration.rs b/pallets/parachain-staking/src/migrations.rs similarity index 52% rename from pallets/parachain-staking/src/migration.rs rename to pallets/parachain-staking/src/migrations.rs index 79e74681a..de1629368 100644 --- a/pallets/parachain-staking/src/migration.rs +++ b/pallets/parachain-staking/src/migrations.rs @@ -1,17 +1,17 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. -// The KILT Blockchain is free software: you can redistribute it and/or modify +// Moonbeam 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. -// The KILT Blockchain is distributed in the hope that it will be useful, +// Moonbeam 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 . +// along with Moonbeam. If not, see . -// If you feel like getting in touch with us, you can do so at info@botlabs.org +//! # Migrations diff --git a/pallets/parachain-staking/src/mock.rs b/pallets/parachain-staking/src/mock.rs index 838b523ba..563bceb6f 100644 --- a/pallets/parachain-staking/src/mock.rs +++ b/pallets/parachain-staking/src/mock.rs @@ -1,54 +1,43 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. -// The KILT Blockchain is free software: you can redistribute it and/or modify +// Moonbeam 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. -// The KILT Blockchain is distributed in the hope that it will be useful, +// Moonbeam 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 . +// along with Moonbeam. If not, see . -// If you feel like getting in touch with us, you can do so at info@botlabs.org //! Test utilities - -#![allow(clippy::from_over_into)] - +use crate as pallet_parachain_staking; +use crate::{ + pallet, AwardedPts, Config, Event as ParachainStakingEvent, InflationInfo, Points, Range, COLLATOR_LOCK_ID, + DELEGATOR_LOCK_ID, +}; use frame_support::{ - assert_ok, construct_runtime, parameter_types, - traits::{Currency, GenesisBuild, OnFinalize, OnInitialize, OnUnbalanced}, + construct_runtime, parameter_types, + traits::{Everything, GenesisBuild, LockIdentifier, OnFinalize, OnInitialize}, + weights::{constants::RocksDbWeight, Weight}, }; -use pallet_authorship::EventHandler; -use sp_consensus_aura::sr25519::AuthorityId; use sp_core::H256; +use sp_io; use sp_runtime::{ - impl_opaque_keys, - testing::{Header, UintAuthorityId}, - traits::{BlakeTwo256, ConvertInto, IdentityLookup, OpaqueKeys}, - Perbill, Perquintill, + traits::{BlakeTwo256, IdentityLookup}, + Perbill, Percent, }; -use sp_std::fmt::Debug; - -use crate::{self as stake, types::NegativeImbalanceOf}; -use super::*; +pub type AccountId = u64; +pub type Balance = u128; +pub type BlockNumber = u32; -pub(crate) type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; -pub(crate) type Block = frame_system::mocking::MockBlock; -pub(crate) type Balance = u128; -pub(crate) type AccountId = u64; -pub(crate) type BlockNumber = u64; - -pub(crate) const MILLI_KILT: Balance = 10u128.pow(12); -pub(crate) const MAX_COLLATOR_STAKE: Balance = 200_000 * 1000 * MILLI_KILT; -pub(crate) const BLOCKS_PER_ROUND: BlockNumber = 5; -pub(crate) const DECIMALS: Balance = 1000 * MILLI_KILT; -pub(crate) const TREASURY_ACC: AccountId = u64::MAX; +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; // Configure a mock runtime to test the pallet. construct_runtime!( @@ -61,60 +50,67 @@ construct_runtime!( Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, Aura: pallet_aura::{Pallet, Storage}, Session: pallet_session::{Pallet, Call, Storage, Event, Config}, - StakePallet: stake::{Pallet, Call, Storage, Config, Event}, + ParachainStaking: pallet_parachain_staking::{Pallet, Call, Storage, Config, Event}, Authorship: pallet_authorship::{Pallet, Storage}, } ); parameter_types! { - pub const BlockHashCount: u64 = 250; + pub const BlockHashCount: u32 = 250; + pub const MaximumBlockWeight: Weight = Weight::from_parts(1024, 1); pub const MaximumBlockLength: u32 = 2 * 1024; pub const AvailableBlockRatio: Perbill = Perbill::one(); pub const SS58Prefix: u8 = 42; } - impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Index = u64; + type AccountData = pallet_balances::AccountData; + type AccountId = AccountId; + type BaseCallFilter = Everything; + type BlockHashCount = BlockHashCount; + type BlockLength = (); type BlockNumber = BlockNumber; - type RuntimeCall = RuntimeCall; + type BlockWeights = (); + type DbWeight = RocksDbWeight; type Hash = H256; type Hashing = BlakeTwo256; - type AccountId = AccountId; + type Header = sp_runtime::generic::Header; + type Index = u64; type Lookup = IdentityLookup; - type Header = Header; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; type OnKilledAccount = (); - type SystemWeightInfo = (); - type BlockWeights = (); - type BlockLength = (); - type SS58Prefix = SS58Prefix; + type OnNewAccount = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type PalletInfo = PalletInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type SS58Prefix = SS58Prefix; + type SystemWeightInfo = (); + type Version = (); } parameter_types! { - pub const ExistentialDeposit: Balance = 1; + pub const ExistentialDeposit: u128 = 1; } - impl pallet_balances::Config for Test { - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; + type AccountStore = System; type Balance = Balance; - type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; + type FreezeIdentifier = (); + type HoldIdentifier = (); + type MaxFreezes = (); + type MaxHolds = (); + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 4]; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } - +parameter_types! { + #[derive(Debug, Eq, PartialEq)] + pub const MaxCollatorCandidates: u32 = 10; +} +use sp_consensus_aura::sr25519::AuthorityId; impl pallet_aura::Config for Test { type AuthorityId = AuthorityId; type DisabledValidators = (); @@ -122,60 +118,40 @@ impl pallet_aura::Config for Test { } impl pallet_authorship::Config for Test { + type EventHandler = ParachainStaking; type FindAuthor = pallet_session::FindAccountFromAuthorIndex; - type EventHandler = Pallet; } - parameter_types! { - pub const MinBlocksPerRound: BlockNumber = 3; - pub const StakeDuration: u32 = 2; - pub const ExitQueueDelay: u32 = 2; - pub const DefaultBlocksPerRound: BlockNumber = BLOCKS_PER_ROUND; - pub const MinCollators: u32 = 2; - pub const MaxDelegationsPerRound: u32 = 2; - #[derive(Debug, Eq, PartialEq)] - pub const MaxDelegatorsPerCollator: u32 = 4; - pub const MinCollatorStake: Balance = 10; - #[derive(Debug, Eq, PartialEq)] - pub const MaxCollatorCandidates: u32 = 10; - pub const MinDelegatorStake: Balance = 5; - pub const MaxUnstakeRequests: u32 = 6; - pub const NetworkRewardRate: Perquintill = Perquintill::from_percent(10); - pub const NetworkRewardStart: BlockNumber = 5 * 5 * 60 * 24 * 36525 / 100; -} - -pub struct ToBeneficiary(); -impl OnUnbalanced> for ToBeneficiary { - fn on_nonzero_unbalanced(amount: NegativeImbalanceOf) { - // Must resolve into existing but better to be safe. - ::Currency::resolve_creating(&TREASURY_ACC, amount); - } + pub const MinimumPeriod: u64 = 1; } -impl Config for Test { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type CurrencyBalance = ::Balance; - type MinBlocksPerRound = MinBlocksPerRound; - type DefaultBlocksPerRound = DefaultBlocksPerRound; - type StakeDuration = StakeDuration; - type ExitQueueDelay = ExitQueueDelay; - type MinCollators = MinCollators; - type MinRequiredCollators = MinCollators; - type MaxDelegationsPerRound = MaxDelegationsPerRound; - type MaxDelegatorsPerCollator = MaxDelegatorsPerCollator; - type MinCollatorStake = MinCollatorStake; - type MinCollatorCandidateStake = MinCollatorStake; - type MaxTopCandidates = MaxCollatorCandidates; - type MinDelegatorStake = MinDelegatorStake; - type MaxUnstakeRequests = MaxUnstakeRequests; - type NetworkRewardRate = NetworkRewardRate; - type NetworkRewardStart = NetworkRewardStart; - type NetworkRewardBeneficiary = ToBeneficiary; +impl pallet_timestamp::Config for Test { + type MinimumPeriod = MinimumPeriod; + type Moment = u64; + type OnTimestampSet = Aura; type WeightInfo = (); - const BLOCKS_PER_YEAR: Self::BlockNumber = 5 * 60 * 24 * 36525 / 100; } +const GENESIS_BLOCKS_PER_ROUND: u32 = 5; +const GENESIS_COLLATOR_COMMISSION: Perbill = Perbill::from_percent(20); +const GENESIS_PARACHAIN_BOND_RESERVE_PERCENT: Percent = Percent::from_percent(30); +const GENESIS_NUM_SELECTED_CANDIDATES: u32 = 5; +parameter_types! { + pub const MinBlocksPerRound: u32 = 3; + pub const LeaveCandidatesDelay: u32 = 2; + pub const CandidateBondLessDelay: u32 = 2; + pub const LeaveDelegatorsDelay: u32 = 2; + pub const RevokeDelegationDelay: u32 = 2; + pub const DelegationBondLessDelay: u32 = 2; + pub const RewardPaymentDelay: u32 = 2; + pub const MinSelectedCandidates: u32 = GENESIS_NUM_SELECTED_CANDIDATES; + pub const MaxTopDelegationsPerCandidate: u32 = 4; + pub const MaxBottomDelegationsPerCandidate: u32 = 4; + pub const MaxDelegationsPerDelegator: u32 = 4; + pub const MinCandidateStk: u128 = 10; + pub const MinDelegatorStk: u128 = 5; + pub const MinDelegation: u128 = 3; +} impl_opaque_keys! { pub struct MockSessionKeys { pub aura: Aura, @@ -185,27 +161,43 @@ impl_opaque_keys! { parameter_types! { pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17); } +use sp_runtime::{ + impl_opaque_keys, + traits::{ConvertInto, OpaqueKeys}, +}; impl pallet_session::Config for Test { + type Keys = MockSessionKeys; + type NextSessionRotation = ParachainStaking; type RuntimeEvent = RuntimeEvent; + type SessionHandler = ::KeyTypeIdProviders; + type SessionManager = ParachainStaking; + type ShouldEndSession = ParachainStaking; type ValidatorId = AccountId; type ValidatorIdOf = ConvertInto; - type ShouldEndSession = StakePallet; - type NextSessionRotation = StakePallet; - type SessionManager = StakePallet; - type SessionHandler = ::KeyTypeIdProviders; - type Keys = MockSessionKeys; type WeightInfo = (); } - -parameter_types! { - pub const MinimumPeriod: u64 = 1; -} - -impl pallet_timestamp::Config for Test { - type Moment = u64; - type OnTimestampSet = (); - type MinimumPeriod = MinimumPeriod; +impl Config for Test { + type CandidateBondLessDelay = CandidateBondLessDelay; + type Currency = Balances; + type DelegationBondLessDelay = DelegationBondLessDelay; + type LeaveCandidatesDelay = LeaveCandidatesDelay; + type LeaveDelegatorsDelay = LeaveDelegatorsDelay; + type MaxBottomDelegationsPerCandidate = MaxBottomDelegationsPerCandidate; + type MaxDelegationsPerDelegator = MaxDelegationsPerDelegator; + type MaxTopDelegationsPerCandidate = MaxTopDelegationsPerCandidate; + type MinBlocksPerRound = MinBlocksPerRound; + type MinCandidateStk = MinCandidateStk; + type MinDelegation = MinDelegation; + type MinDelegatorStk = MinDelegatorStk; + type MinSelectedCandidates = MinSelectedCandidates; + type MonetaryGovernanceOrigin = frame_system::EnsureRoot; + type OnCollatorPayout = (); + type OnNewRound = (); + type PayoutCollatorReward = (); + type RevokeDelegationDelay = RevokeDelegationDelay; + type RewardPaymentDelay = RewardPaymentDelay; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } @@ -214,70 +206,64 @@ pub(crate) struct ExtBuilder { balances: Vec<(AccountId, Balance)>, // [collator, amount] collators: Vec<(AccountId, Balance)>, - // [delegator, collator, delegation_amount] - delegators: Vec<(AccountId, AccountId, Balance)>, + // [delegator, collator, delegation_amount, auto_compound_percent] + delegations: Vec<(AccountId, AccountId, Balance, Percent)>, // inflation config - inflation_config: InflationInfo, - // blocks per round - blocks_per_round: BlockNumber, + inflation: InflationInfo, } impl Default for ExtBuilder { fn default() -> ExtBuilder { ExtBuilder { balances: vec![], - delegators: vec![], + delegations: vec![], collators: vec![], - blocks_per_round: BLOCKS_PER_ROUND, - inflation_config: InflationInfo::new( - ::BLOCKS_PER_YEAR, - Perquintill::from_percent(10), - Perquintill::from_percent(15), - Perquintill::from_percent(40), - Perquintill::from_percent(10), - ), + inflation: InflationInfo { + expect: Range { min: 700, ideal: 700, max: 700 }, + // not used + annual: Range { + min: Perbill::from_percent(50), + ideal: Perbill::from_percent(50), + max: Perbill::from_percent(50), + }, + // unrealistically high parameterization, only for testing + round: Range { + min: Perbill::from_percent(5), + ideal: Perbill::from_percent(5), + max: Perbill::from_percent(5), + }, + }, } } } impl ExtBuilder { - #[must_use] pub(crate) fn with_balances(mut self, balances: Vec<(AccountId, Balance)>) -> Self { self.balances = balances; self } - #[must_use] - pub(crate) fn with_collators(mut self, collators: Vec<(AccountId, Balance)>) -> Self { + pub(crate) fn with_candidates(mut self, collators: Vec<(AccountId, Balance)>) -> Self { self.collators = collators; self } - #[must_use] - pub(crate) fn with_delegators(mut self, delegators: Vec<(AccountId, AccountId, Balance)>) -> Self { - self.delegators = delegators; + pub(crate) fn with_delegations(mut self, delegations: Vec<(AccountId, AccountId, Balance)>) -> Self { + self.delegations = delegations.into_iter().map(|d| (d.0, d.1, d.2, Percent::zero())).collect(); self } - #[must_use] - pub(crate) fn with_inflation( - mut self, col_max: u64, col_rewards: u64, d_max: u64, d_rewards: u64, blocks_per_round: BlockNumber, + pub(crate) fn with_auto_compounding_delegations( + mut self, + delegations: Vec<(AccountId, AccountId, Balance, Percent)>, ) -> Self { - self.inflation_config = InflationInfo::new( - ::BLOCKS_PER_YEAR, - Perquintill::from_percent(col_max), - Perquintill::from_percent(col_rewards), - Perquintill::from_percent(d_max), - Perquintill::from_percent(d_rewards), - ); - self.blocks_per_round = blocks_per_round; - + self.delegations = delegations; self } - #[must_use] - pub(crate) fn set_blocks_per_round(mut self, blocks_per_round: BlockNumber) -> Self { - self.blocks_per_round = blocks_per_round; + #[allow(dead_code)] + pub(crate) fn with_inflation(mut self, inflation: InflationInfo) -> Self { + self.inflation = inflation; self } @@ -286,136 +272,681 @@ impl ExtBuilder { .build_storage::() .expect("Frame system builds valid default genesis config"); - pallet_balances::GenesisConfig:: { - balances: self.balances.clone(), - } - .assimilate_storage(&mut t) - .expect("Pallet balances storage can be assimilated"); - - let mut stakers: Vec<(AccountId, Option, Balance)> = Vec::new(); - for collator in self.collators.clone() { - stakers.push((collator.0, None, collator.1)); - } - for delegator in self.delegators.clone() { - stakers.push((delegator.0, Some(delegator.1), delegator.2)); - } - stake::GenesisConfig:: { - stakers, - inflation_config: self.inflation_config.clone(), - max_candidate_stake: 160_000_000 * DECIMALS, + pallet_balances::GenesisConfig:: { balances: self.balances } + .assimilate_storage(&mut t) + .expect("Pallet balances storage can be assimilated"); + pallet_parachain_staking::GenesisConfig:: { + candidates: self.collators, + delegations: self.delegations, + inflation_config: self.inflation, + collator_commission: GENESIS_COLLATOR_COMMISSION, + parachain_bond_reserve_percent: GENESIS_PARACHAIN_BOND_RESERVE_PERCENT, + blocks_per_round: GENESIS_BLOCKS_PER_ROUND, + num_selected_candidates: GENESIS_NUM_SELECTED_CANDIDATES, } .assimilate_storage(&mut t) .expect("Parachain Staking's storage can be assimilated"); - // stashes are the AccountId - let session_keys: Vec<_> = self - .collators - .iter() - .map(|(k, _)| { - ( - *k, - *k, - MockSessionKeys { - aura: UintAuthorityId(*k).to_public_key(), - }, - ) - }) - .collect(); - - // NOTE: this will initialize the aura authorities - // through OneSessionHandler::on_genesis_session - pallet_session::GenesisConfig:: { keys: session_keys } - .assimilate_storage(&mut t) - .expect("Session Pallet's storage can be assimilated"); - let mut ext = sp_io::TestExternalities::new(t); - - if self.blocks_per_round != BLOCKS_PER_ROUND { - ext.execute_with(|| { - StakePallet::set_blocks_per_round(RuntimeOrigin::root(), self.blocks_per_round) - .expect("Ran into issues when setting blocks_per_round"); - }); - } - ext.execute_with(|| System::set_block_number(1)); ext } } -/// Compare whether the difference of both sides is at most `precision * left`. -pub(crate) fn almost_equal(left: Balance, right: Balance, precision: Perbill) -> bool { - let err = precision * left; - left.max(right) - left.min(right) <= err +/// Rolls forward one block. Returns the new block number. +fn roll_one_block() -> BlockNumber { + Balances::on_finalize(System::block_number()); + System::on_finalize(System::block_number()); + System::set_block_number(System::block_number() + 1); + System::reset_events(); + System::on_initialize(System::block_number()); + Balances::on_initialize(System::block_number()); + ParachainStaking::on_initialize(System::block_number()); + System::block_number() } -/// Incrementelly traverses from the current block to the provided one and -/// potentially sets block authors. -/// -/// If for a block `i` the corresponding index of the authors input is set, this -/// account is regarded to be the block author and thus gets noted. -/// -/// NOTE: At most, this updates the RewardCount of the block author but does not -/// increment rewards or claim them. Please use `roll_to_claim_rewards` in that -/// case. -pub(crate) fn roll_to(n: BlockNumber, authors: Vec>) { - while System::block_number() < n { - if let Some(Some(author)) = authors.get((System::block_number()) as usize) { - StakePallet::note_author(*author); - } - >::on_finalize(System::block_number()); - System::set_block_number(System::block_number() + 1); - >::on_initialize(System::block_number()); +/// Rolls to the desired block. Returns the number of blocks played. +pub(crate) fn roll_to(n: BlockNumber) -> u32 { + let mut num_blocks = 0; + let mut block = System::block_number(); + while block < n { + block = roll_one_block(); + num_blocks += 1; } + num_blocks } -#[allow(unused_must_use)] -/// Incrementelly traverses from the current block to the provided one and -/// potentially sets block authors. -/// -/// If existent, rewards of the block author and their delegators are -/// incremented and claimed. -/// -/// If for a block `i` the corresponding index of the authors input is set, this -/// account is regarded to be the block author and thus gets noted. -pub(crate) fn roll_to_claim_rewards(n: BlockNumber, authors: Vec>) { - while System::block_number() < n { - if let Some(Some(author)) = authors.get((System::block_number()) as usize) { - StakePallet::note_author(*author); - // author has to increment rewards before claiming - assert_ok!(StakePallet::increment_collator_rewards(RuntimeOrigin::signed(*author))); - // author claims rewards - assert_ok!(StakePallet::claim_rewards(RuntimeOrigin::signed(*author))); - - // claim rewards for delegators - let col_state = StakePallet::candidate_pool(author).expect("Block author must be candidate"); - for delegation in col_state.delegators { - // delegator has to increment rewards before claiming - StakePallet::increment_delegator_rewards(RuntimeOrigin::signed(delegation.owner)); - // NOTE: cannot use assert_ok! as we sometimes expect zero rewards for - // delegators such that the claiming would throw - StakePallet::claim_rewards(RuntimeOrigin::signed(delegation.owner)); - } - } - >::on_finalize(System::block_number()); - System::set_block_number(System::block_number() + 1); - >::on_initialize(System::block_number()); +/// Rolls desired number of blocks. Returns the final block. +pub(crate) fn roll_blocks(num_blocks: u32) -> BlockNumber { + let mut block = System::block_number(); + for _ in 0..num_blocks { + block = roll_one_block(); } + block } -pub(crate) fn last_event() -> pallet::Event { - events().pop().expect("Event expected") +/// Rolls block-by-block to the beginning of the specified round. +/// This will complete the block in which the round change occurs. +/// Returns the number of blocks played. +pub(crate) fn roll_to_round_begin(round: BlockNumber) -> BlockNumber { + let block = (round - 1) * GENESIS_BLOCKS_PER_ROUND; + roll_to(block) +} + +/// Rolls block-by-block to the end of the specified round. +/// The block following will be the one in which the specified round change occurs. +pub(crate) fn roll_to_round_end(round: BlockNumber) -> BlockNumber { + let block = round * GENESIS_BLOCKS_PER_ROUND - 1; + roll_to(block) } pub(crate) fn events() -> Vec> { System::events() .into_iter() .map(|r| r.event) - .filter_map(|e| { - if let RuntimeEvent::StakePallet(inner) = e { - Some(inner) - } else { - None - } - }) + .filter_map(|e| if let RuntimeEvent::ParachainStaking(inner) = e { Some(inner) } else { None }) .collect::>() } + +/// Asserts that some events were never emitted. +/// +/// # Example +/// +/// ``` +/// assert_no_events!(); +/// ``` +#[macro_export] +macro_rules! assert_no_events { + () => { + similar_asserts::assert_eq!(Vec::>::new(), crate::mock::events()) + }; +} + +/// Asserts that emitted events match exactly the given input. +/// +/// # Example +/// +/// ``` +/// assert_events_eq!( +/// Foo { x: 1, y: 2 }, +/// Bar { value: "test" }, +/// Baz { a: 10, b: 20 }, +/// ); +/// ``` +#[macro_export] +macro_rules! assert_events_eq { + ($event:expr) => { + similar_asserts::assert_eq!(vec![$event], crate::mock::events()); + }; + ($($events:expr,)+) => { + similar_asserts::assert_eq!(vec![$($events,)+], crate::mock::events()); + }; +} + +/// Asserts that some emitted events match the given input. +/// +/// # Example +/// +/// ``` +/// assert_events_emitted!( +/// Foo { x: 1, y: 2 }, +/// Baz { a: 10, b: 20 }, +/// ); +/// ``` +#[macro_export] +macro_rules! assert_events_emitted { + ($event:expr) => { + [$event].into_iter().for_each(|e| assert!( + crate::mock::events().into_iter().find(|x| x == &e).is_some(), + "Event {:?} was not found in events: \n{:#?}", + e, + crate::mock::events() + )); + }; + ($($events:expr,)+) => { + [$($events,)+].into_iter().for_each(|e| assert!( + crate::mock::events().into_iter().find(|x| x == &e).is_some(), + "Event {:?} was not found in events: \n{:#?}", + e, + crate::mock::events() + )); + }; +} + +/// Asserts that some events were never emitted. +/// +/// # Example +/// +/// ``` +/// assert_events_not_emitted!( +/// Foo { x: 1, y: 2 }, +/// Bar { value: "test" }, +/// ); +/// ``` +#[macro_export] +macro_rules! assert_events_not_emitted { + ($event:expr) => { + [$event].into_iter().for_each(|e| assert!( + crate::mock::events().into_iter().find(|x| x != &e).is_some(), + "Event {:?} was unexpectedly found in events: \n{:#?}", + e, + crate::mock::events() + )); + }; + ($($events:expr,)+) => { + [$($events,)+].into_iter().for_each(|e| assert!( + crate::mock::events().into_iter().find(|x| x != &e).is_some(), + "Event {:?} was unexpectedly found in events: \n{:#?}", + e, + crate::mock::events() + )); + }; +} + +/// Asserts that the emitted events are exactly equal to the input patterns. +/// +/// # Example +/// +/// ``` +/// assert_events_eq_match!( +/// Foo { x: 1, .. }, +/// Bar { .. }, +/// Baz { a: 10, b: 20 }, +/// ); +/// ``` +#[macro_export] +macro_rules! assert_events_eq_match { + ($index:expr;) => { + assert_eq!( + $index, + crate::mock::events().len(), + "Found {} extra event(s): \n{:#?}", + crate::mock::events().len()-$index, + crate::mock::events() + ); + }; + ($index:expr; $event:pat_param, $($events:pat_param,)*) => { + assert!( + matches!( + crate::mock::events().get($index), + Some($event), + ), + "Event {:#?} was not found at index {}: \n{:#?}", + stringify!($event), + $index, + crate::mock::events() + ); + assert_events_eq_match!($index+1; $($events,)*); + }; + ($event:pat_param) => { + assert_events_eq_match!(0; $event,); + }; + ($($events:pat_param,)+) => { + assert_events_eq_match!(0; $($events,)+); + }; +} + +/// Asserts that some emitted events match the input patterns. +/// +/// # Example +/// +/// ``` +/// assert_events_emitted_match!( +/// Foo { x: 1, .. }, +/// Baz { a: 10, b: 20 }, +/// ); +/// ``` +#[macro_export] +macro_rules! assert_events_emitted_match { + ($event:pat_param) => { + assert!( + crate::mock::events().into_iter().any(|x| matches!(x, $event)), + "Event {:?} was not found in events: \n{:#?}", + stringify!($event), + crate::mock::events() + ); + }; + ($event:pat_param, $($events:pat_param,)+) => { + assert_events_emitted_match!($event); + $( + assert_events_emitted_match!($events); + )+ + }; +} + +/// Asserts that the input patterns match none of the emitted events. +/// +/// # Example +/// +/// ``` +/// assert_events_not_emitted_match!( +/// Foo { x: 1, .. }, +/// Baz { a: 10, b: 20 }, +/// ); +/// ``` +#[macro_export] +macro_rules! assert_events_not_emitted_match { + ($event:pat_param) => { + assert!( + crate::mock::events().into_iter().any(|x| !matches!(x, $event)), + "Event {:?} was unexpectedly found in events: \n{:#?}", + stringify!($event), + crate::mock::events() + ); + }; + ($event:pat_param, $($events:pat_param,)+) => { + assert_events_not_emitted_match!($event); + $( + assert_events_not_emitted_match!($events); + )+ + }; +} + +// Same storage changes as ParachainStaking::on_finalize +pub(crate) fn set_author(round: BlockNumber, acc: u64, pts: u32) { + >::mutate(round, |p| *p += pts); + >::mutate(round, acc, |p| *p += pts); +} + +/// fn to query the lock amount +pub(crate) fn query_lock_amount(account_id: u64, id: LockIdentifier) -> Option { + for lock in Balances::locks(&account_id) { + if lock.id == id { + return Some(lock.amount) + } + } + None +} + +#[test] +fn geneses() { + ExtBuilder::default() + .with_balances(vec![(1, 1000), (2, 300), (3, 100), (4, 100), (5, 100), (6, 100), (7, 100), (8, 9), (9, 4)]) + .with_candidates(vec![(1, 500), (2, 200)]) + .with_delegations(vec![(3, 1, 100), (4, 1, 100), (5, 2, 100), (6, 2, 100)]) + .build() + .execute_with(|| { + assert!(System::events().is_empty()); + // collators + assert_eq!(ParachainStaking::get_collator_stakable_free_balance(&1), 500); + assert_eq!(query_lock_amount(1, COLLATOR_LOCK_ID), Some(500)); + assert!(ParachainStaking::is_candidate(&1)); + assert_eq!(query_lock_amount(2, COLLATOR_LOCK_ID), Some(200)); + assert_eq!(ParachainStaking::get_collator_stakable_free_balance(&2), 100); + assert!(ParachainStaking::is_candidate(&2)); + // delegators + for x in 3..7 { + assert!(ParachainStaking::is_delegator(&x)); + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&x), 0); + assert_eq!(query_lock_amount(x, DELEGATOR_LOCK_ID), Some(100)); + } + // uninvolved + for x in 7..10 { + assert!(!ParachainStaking::is_delegator(&x)); + } + // no delegator staking locks + assert_eq!(query_lock_amount(7, DELEGATOR_LOCK_ID), None); + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&7), 100); + assert_eq!(query_lock_amount(8, DELEGATOR_LOCK_ID), None); + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&8), 9); + assert_eq!(query_lock_amount(9, DELEGATOR_LOCK_ID), None); + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&9), 4); + // no collator staking locks + assert_eq!(ParachainStaking::get_collator_stakable_free_balance(&7), 100); + assert_eq!(ParachainStaking::get_collator_stakable_free_balance(&8), 9); + assert_eq!(ParachainStaking::get_collator_stakable_free_balance(&9), 4); + }); + ExtBuilder::default() + .with_balances(vec![ + (1, 100), + (2, 100), + (3, 100), + (4, 100), + (5, 100), + (6, 100), + (7, 100), + (8, 100), + (9, 100), + (10, 100), + ]) + .with_candidates(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 10)]) + .with_delegations(vec![(6, 1, 10), (7, 1, 10), (8, 2, 10), (9, 2, 10), (10, 1, 10)]) + .build() + .execute_with(|| { + assert!(System::events().is_empty()); + // collators + for x in 1..5 { + assert!(ParachainStaking::is_candidate(&x)); + assert_eq!(query_lock_amount(x, COLLATOR_LOCK_ID), Some(20)); + assert_eq!(ParachainStaking::get_collator_stakable_free_balance(&x), 80); + } + assert!(ParachainStaking::is_candidate(&5)); + assert_eq!(query_lock_amount(5, COLLATOR_LOCK_ID), Some(10)); + assert_eq!(ParachainStaking::get_collator_stakable_free_balance(&5), 90); + // delegators + for x in 6..11 { + assert!(ParachainStaking::is_delegator(&x)); + assert_eq!(query_lock_amount(x, DELEGATOR_LOCK_ID), Some(10)); + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&x), 90); + } + }); +} + +#[test] +fn roll_to_round_begin_works() { + ExtBuilder::default().build().execute_with(|| { + // these tests assume blocks-per-round of 5, as established by GENESIS_BLOCKS_PER_ROUND + assert_eq!(System::block_number(), 1); // we start on block 1 + + let num_blocks = roll_to_round_begin(1); + assert_eq!(System::block_number(), 1); // no-op, we're already on this round + assert_eq!(num_blocks, 0); + + let num_blocks = roll_to_round_begin(2); + assert_eq!(System::block_number(), 5); + assert_eq!(num_blocks, 4); + + let num_blocks = roll_to_round_begin(3); + assert_eq!(System::block_number(), 10); + assert_eq!(num_blocks, 5); + }); +} + +#[test] +fn roll_to_round_end_works() { + ExtBuilder::default().build().execute_with(|| { + // these tests assume blocks-per-round of 5, as established by GENESIS_BLOCKS_PER_ROUND + assert_eq!(System::block_number(), 1); // we start on block 1 + + let num_blocks = roll_to_round_end(1); + assert_eq!(System::block_number(), 4); + assert_eq!(num_blocks, 3); + + let num_blocks = roll_to_round_end(2); + assert_eq!(System::block_number(), 9); + assert_eq!(num_blocks, 5); + + let num_blocks = roll_to_round_end(3); + assert_eq!(System::block_number(), 14); + assert_eq!(num_blocks, 5); + }); +} + +#[test] +#[should_panic] +fn test_assert_events_eq_fails_if_event_missing() { + ExtBuilder::default().build().execute_with(|| { + inject_test_events(); + + assert_events_eq!( + ParachainStakingEvent::CollatorChosen { round: 2, collator_account: 1, total_exposed_amount: 10 }, + ParachainStakingEvent::NewRound { + starting_block: 10, + round: 2, + selected_collators_number: 1, + total_balance: 10, + }, + ); + }); +} + +#[test] +#[should_panic] +fn test_assert_events_eq_fails_if_event_extra() { + ExtBuilder::default().build().execute_with(|| { + inject_test_events(); + + assert_events_eq!( + ParachainStakingEvent::CollatorChosen { round: 2, collator_account: 1, total_exposed_amount: 10 }, + ParachainStakingEvent::NewRound { + starting_block: 10, + round: 2, + selected_collators_number: 1, + total_balance: 10, + }, + ParachainStakingEvent::Rewarded { account: 1, rewards: 100 }, + ParachainStakingEvent::Rewarded { account: 1, rewards: 200 }, + ); + }); +} + +#[test] +#[should_panic] +fn test_assert_events_eq_fails_if_event_wrong_order() { + ExtBuilder::default().build().execute_with(|| { + inject_test_events(); + + assert_events_eq!( + ParachainStakingEvent::Rewarded { account: 1, rewards: 100 }, + ParachainStakingEvent::CollatorChosen { round: 2, collator_account: 1, total_exposed_amount: 10 }, + ParachainStakingEvent::NewRound { + starting_block: 10, + round: 2, + selected_collators_number: 1, + total_balance: 10, + }, + ); + }); +} + +#[test] +#[should_panic] +fn test_assert_events_eq_fails_if_event_wrong_value() { + ExtBuilder::default().build().execute_with(|| { + inject_test_events(); + + assert_events_eq!( + ParachainStakingEvent::CollatorChosen { round: 2, collator_account: 1, total_exposed_amount: 10 }, + ParachainStakingEvent::NewRound { + starting_block: 10, + round: 2, + selected_collators_number: 1, + total_balance: 10, + }, + ParachainStakingEvent::Rewarded { account: 1, rewards: 50 }, + ); + }); +} + +#[test] +fn test_assert_events_eq_passes_if_all_events_present_single() { + ExtBuilder::default().build().execute_with(|| { + System::deposit_event(ParachainStakingEvent::Rewarded { account: 1, rewards: 100 }); + + assert_events_eq!(ParachainStakingEvent::Rewarded { account: 1, rewards: 100 }); + }); +} + +#[test] +fn test_assert_events_eq_passes_if_all_events_present_multiple() { + ExtBuilder::default().build().execute_with(|| { + inject_test_events(); + + assert_events_eq!( + ParachainStakingEvent::CollatorChosen { round: 2, collator_account: 1, total_exposed_amount: 10 }, + ParachainStakingEvent::NewRound { + starting_block: 10, + round: 2, + selected_collators_number: 1, + total_balance: 10, + }, + ParachainStakingEvent::Rewarded { account: 1, rewards: 100 }, + ); + }); +} + +#[test] +#[should_panic] +fn test_assert_events_emitted_fails_if_event_missing() { + ExtBuilder::default().build().execute_with(|| { + inject_test_events(); + + assert_events_emitted!(ParachainStakingEvent::DelegatorExitScheduled { + round: 2, + delegator: 3, + scheduled_exit: 4, + }); + }); +} + +#[test] +#[should_panic] +fn test_assert_events_emitted_fails_if_event_wrong_value() { + ExtBuilder::default().build().execute_with(|| { + inject_test_events(); + + assert_events_emitted!(ParachainStakingEvent::Rewarded { account: 1, rewards: 50 }); + }); +} + +#[test] +fn test_assert_events_emitted_passes_if_all_events_present_single() { + ExtBuilder::default().build().execute_with(|| { + System::deposit_event(ParachainStakingEvent::Rewarded { account: 1, rewards: 100 }); + + assert_events_emitted!(ParachainStakingEvent::Rewarded { account: 1, rewards: 100 }); + }); +} + +#[test] +fn test_assert_events_emitted_passes_if_all_events_present_multiple() { + ExtBuilder::default().build().execute_with(|| { + inject_test_events(); + + assert_events_emitted!( + ParachainStakingEvent::CollatorChosen { round: 2, collator_account: 1, total_exposed_amount: 10 }, + ParachainStakingEvent::Rewarded { account: 1, rewards: 100 }, + ); + }); +} + +#[test] +#[should_panic] +fn test_assert_events_eq_match_fails_if_event_missing() { + ExtBuilder::default().build().execute_with(|| { + inject_test_events(); + + assert_events_eq_match!(ParachainStakingEvent::CollatorChosen { .. }, ParachainStakingEvent::NewRound { .. },); + }); +} + +#[test] +#[should_panic] +fn test_assert_events_eq_match_fails_if_event_extra() { + ExtBuilder::default().build().execute_with(|| { + inject_test_events(); + + assert_events_eq_match!( + ParachainStakingEvent::CollatorChosen { .. }, + ParachainStakingEvent::NewRound { .. }, + ParachainStakingEvent::Rewarded { .. }, + ParachainStakingEvent::Rewarded { .. }, + ); + }); +} + +#[test] +#[should_panic] +fn test_assert_events_eq_match_fails_if_event_wrong_order() { + ExtBuilder::default().build().execute_with(|| { + inject_test_events(); + + assert_events_eq_match!( + ParachainStakingEvent::Rewarded { .. }, + ParachainStakingEvent::CollatorChosen { .. }, + ParachainStakingEvent::NewRound { .. }, + ); + }); +} + +#[test] +#[should_panic] +fn test_assert_events_eq_match_fails_if_event_wrong_value() { + ExtBuilder::default().build().execute_with(|| { + inject_test_events(); + + assert_events_eq_match!( + ParachainStakingEvent::CollatorChosen { .. }, + ParachainStakingEvent::NewRound { .. }, + ParachainStakingEvent::Rewarded { rewards: 50, .. }, + ); + }); +} + +#[test] +fn test_assert_events_eq_match_passes_if_all_events_present_single() { + ExtBuilder::default().build().execute_with(|| { + System::deposit_event(ParachainStakingEvent::Rewarded { account: 1, rewards: 100 }); + + assert_events_eq_match!(ParachainStakingEvent::Rewarded { account: 1, .. }); + }); +} + +#[test] +fn test_assert_events_eq_match_passes_if_all_events_present_multiple() { + ExtBuilder::default().build().execute_with(|| { + inject_test_events(); + + assert_events_eq_match!( + ParachainStakingEvent::CollatorChosen { round: 2, collator_account: 1, .. }, + ParachainStakingEvent::NewRound { starting_block: 10, .. }, + ParachainStakingEvent::Rewarded { account: 1, rewards: 100 }, + ); + }); +} + +#[test] +#[should_panic] +fn test_assert_events_emitted_match_fails_if_event_missing() { + ExtBuilder::default().build().execute_with(|| { + inject_test_events(); + + assert_events_emitted_match!(ParachainStakingEvent::DelegatorExitScheduled { round: 2, .. }); + }); +} + +#[test] +#[should_panic] +fn test_assert_events_emitted_match_fails_if_event_wrong_value() { + ExtBuilder::default().build().execute_with(|| { + inject_test_events(); + + assert_events_emitted_match!(ParachainStakingEvent::Rewarded { rewards: 50, .. }); + }); +} + +#[test] +fn test_assert_events_emitted_match_passes_if_all_events_present_single() { + ExtBuilder::default().build().execute_with(|| { + System::deposit_event(ParachainStakingEvent::Rewarded { account: 1, rewards: 100 }); + + assert_events_emitted_match!(ParachainStakingEvent::Rewarded { rewards: 100, .. }); + }); +} + +#[test] +fn test_assert_events_emitted_match_passes_if_all_events_present_multiple() { + ExtBuilder::default().build().execute_with(|| { + inject_test_events(); + + assert_events_emitted_match!( + ParachainStakingEvent::CollatorChosen { total_exposed_amount: 10, .. }, + ParachainStakingEvent::Rewarded { account: 1, rewards: 100 }, + ); + }); +} + +fn inject_test_events() { + [ + ParachainStakingEvent::CollatorChosen { round: 2, collator_account: 1, total_exposed_amount: 10 }, + ParachainStakingEvent::NewRound { + starting_block: 10, + round: 2, + selected_collators_number: 1, + total_balance: 10, + }, + ParachainStakingEvent::Rewarded { account: 1, rewards: 100 }, + ] + .into_iter() + .for_each(System::deposit_event); +} diff --git a/pallets/parachain-staking/src/set.rs b/pallets/parachain-staking/src/set.rs index d8bf16bae..1f15d68ae 100644 --- a/pallets/parachain-staking/src/set.rs +++ b/pallets/parachain-staking/src/set.rs @@ -1,553 +1,89 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. -// The KILT Blockchain is free software: you can redistribute it and/or modify +// Moonbeam 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. -// The KILT Blockchain is distributed in the hope that it will be useful, +// Moonbeam 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 . +// along with Moonbeam. If not, see . -// If you feel like getting in touch with us, you can do so at info@botlabs.org - -use frame_support::{traits::Get, BoundedVec, DefaultNoBound, RuntimeDebug}; -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; +/* TODO: use orml_utilities::OrderedSet without leaking substrate v2.0 dependencies*/ +use parity_scale_codec::{Decode, Encode}; use scale_info::TypeInfo; -use sp_runtime::{traits::Zero, SaturatedConversion}; #[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; +use sp_runtime::RuntimeDebug; use sp_std::prelude::*; -use sp_std::{ - cmp::Ordering, - convert::TryInto, - ops::{Index, Range, RangeFull}, -}; -/// An ordered set backed by `BoundedVec`. -#[derive(PartialEq, Eq, Encode, Decode, DefaultNoBound, Clone, TypeInfo, MaxEncodedLen, RuntimeDebug)] -#[scale_info(skip_type_params(S))] -#[codec(mel_bound(T: MaxEncodedLen))] -pub struct OrderedSet>(BoundedVec); +/// An ordered set backed by `Vec` +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[derive(RuntimeDebug, PartialEq, Eq, Encode, Decode, Default, Clone, TypeInfo)] +pub struct OrderedSet(pub Vec); -impl> OrderedSet { - /// Create a new empty set. +impl OrderedSet { + /// Create a new empty set pub fn new() -> Self { - Self(BoundedVec::default()) + Self(Vec::new()) } - /// Creates an ordered set from a `BoundedVec`. - /// - /// The vector will be sorted reversily (from greatest to lowest) and - /// deduped first. - pub fn from(bv: BoundedVec) -> Self { - let mut v = bv.into_inner(); - v.sort_by(|a, b| b.cmp(a)); + /// Create a set from a `Vec`. + /// `v` will be sorted and dedup first. + pub fn from(mut v: Vec) -> Self { + v.sort(); v.dedup(); - Self::from_sorted_set(v.try_into().map_err(|_| ()).expect("No values were added")) - } - - /// Create a set from a `BoundedVec`. - /// - /// Assumes that `v` is sorted reversely (from greatest to lowest) and only - /// contains unique elements. - pub fn from_sorted_set(bv: BoundedVec) -> Self { - Self(bv) + Self::from_sorted_set(v) } - /// Mutate the set without restrictions. After the set was mutated it will - /// be resorted and deduplicated. - pub fn mutate)>(&mut self, function: F) { - function(&mut self.0); - (self.0[..]).sort_by(|a, b| b.cmp(a)); - - // TODO: add dedup to BoundedVec - let mut i: usize = 0; - let mut next = i.saturating_add(1); - while next < self.len() { - if self[i] == self[next] { - self.0.remove(next); - } else { - i = next; - next = next.saturating_add(1); - } - } + /// Create a set from a `Vec`. + /// Assume `v` is sorted and contain unique elements. + pub fn from_sorted_set(v: Vec) -> Self { + Self(v) } - /// Inserts an element, if no equal item exist in the set. - /// - /// Returns an error if insertion would exceed the bounded vec's max size. - /// The error contains the index where the element would be inserted, if - /// enough space would be left. - /// - /// Returns true if the item is unique in the set, otherwise returns false. - pub fn try_insert(&mut self, value: T) -> Result { - match self.linear_search(&value) { - Ok(_) => Ok(false), + /// Insert an element. + /// Return true if insertion happened. + pub fn insert(&mut self, value: T) -> bool { + match self.0.binary_search(&value) { + Ok(_) => false, Err(loc) => { - self.0.try_insert(loc, value).map_err(|_| loc)?; - Ok(true) - } - } - } - - /// Inserts an element, if no equal item exist in the set. If the set is - /// full, but an element with a lower rank is in the set, the element with - /// the lowest rank will be removed and the new element will be added. - /// - /// Returns - /// * Ok(Some(old_element)) if the new element was added and an old element - /// had to be removed. - /// * Ok(None) if the element was added without removing an element. - /// * Err(true) if the set is full and the new element has a lower rank than - /// the lowest element in the set. - /// * Err(false) if the element is already in the set. - pub fn try_insert_replace(&mut self, value: T) -> Result, bool> { - // the highest allowed index - let highest_index: usize = S::get().saturating_sub(1).saturated_into(); - if S::get().is_zero() { - return Err(true); - } - match self.try_insert(value.clone()) { - Err(loc) if loc <= highest_index => { - // always replace the last element - let last_idx = self.len().saturating_sub(1); - // accessing by index wont panic since we checked the index, inserting the item - // at the end of the list to ensure last-in-least-priority-rule for collators. - // sorting algorithm must be stable! - let old = sp_std::mem::replace(&mut self.0[last_idx], value); - self.sort_greatest_to_lowest(); - Ok(Some(old)) - } - Err(_) => Err(true), - Ok(false) => Err(false), - Ok(_) => Ok(None), - } - } - - /// Inserts a new element or updates the value of an existing one. - /// - /// Returns an error if the maximum size of the bounded vec would be - /// exceeded upon insertion. - /// - /// Returns the old value if existing or None if the value did not exist - /// before. - pub fn try_upsert(&mut self, value: T) -> Result, ()> { - match self.linear_search(&value) { - Ok(i) => { - let old = sp_std::mem::replace(&mut self.0[i], value); - self.sort_greatest_to_lowest(); - Ok(Some(old)) - } - Err(i) => { - // Delegator - self.0.try_insert(i, value).map_err(|_| ())?; - Ok(None) - } + self.0.insert(loc, value); + true + }, } } - /// Removes an element. - /// - /// Returns true if removal happened. - pub fn remove(&mut self, value: &T) -> Option { - match self.linear_search(value) { - Ok(loc) => Some(self.0.remove(loc)), - Err(_) => None, + /// Remove an element. + /// Return true if removal happened. + pub fn remove(&mut self, value: &T) -> bool { + match self.0.binary_search(value) { + Ok(loc) => { + self.0.remove(loc); + true + }, + Err(_) => false, } } - /// Return whether the set contains `value`. + /// Return if the set contains `value` pub fn contains(&self, value: &T) -> bool { - self.linear_search(value).is_ok() - } - - /// Iteratively searches this (from greatest to lowest) ordered set for a - /// given element. - /// - /// 1. If the value is found, then Result::Ok is returned, containing the - /// index of the matching element. - /// 2. If the value is not found, then Result::Err is returned, containing - /// the index where a matching element could be inserted while maintaining - /// sorted order. - pub fn linear_search(&self, value: &T) -> Result { - let size = self.0.len(); - let mut loc: usize = size; - // keep running until we find a smaller item - self.0 - .iter() - .enumerate() - .find_map(|(i, v)| { - match (v.cmp(value), loc == size) { - // prevent to have same items - (Ordering::Equal, _) => Some(Ok(i)), - // eventually, we want to return this index but we need to keep checking for Ordering::Equal in case - // value is still in the set - (Ordering::Less, true) => { - // insert after current element - loc = i; - None - } - _ => None, - } - }) - .unwrap_or(Err(loc)) + self.0.binary_search(value).is_ok() } - /// Clear the set. + /// Clear the set pub fn clear(&mut self) { - self.0 = BoundedVec::default(); - } - - /// Return the length of the set. - pub fn len(&self) -> usize { - self.0.len() - } - - /// Return whether the set is empty. - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - /// Convert the set to a bounded vector. - pub fn into_bounded_vec(self) -> BoundedVec { - self.0 - } - - /// Returns a reference to an element or None if out of bounds. - pub fn get(&self, index: usize) -> Option<&T> { - self.0.get(index) - } - - /// Sorts from greatest to lowest. - pub fn sort_greatest_to_lowest(&mut self) { - (self.0[..]).sort_by(|a, b| b.cmp(a)); - } -} - -impl> From> for OrderedSet { - fn from(bv: BoundedVec) -> Self { - Self::from(bv) - } -} - -impl> Index for OrderedSet { - type Output = T; - - fn index(&self, index: usize) -> &Self::Output { - &self.0[index] - } -} - -impl> Index> for OrderedSet { - type Output = [T]; - - fn index(&self, range: Range) -> &Self::Output { - &self.0[range] - } -} - -impl> Index for OrderedSet { - type Output = [T]; - - fn index(&self, range: RangeFull) -> &Self::Output { - &self.0[range] + self.0.clear(); } } -impl> IntoIterator for OrderedSet { - type Item = T; - type IntoIter = sp_std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl> From> for BoundedVec { - fn from(s: OrderedSet) -> Self { - s.0 - } -} - -#[cfg(test)] -mod tests { - use frame_support::parameter_types; - use sp_runtime::RuntimeDebug; - - use crate::{mock::Test, types::StakeOf}; - - use super::*; - - parameter_types! { - #[derive(Eq, PartialEq, RuntimeDebug)] - pub const Zero: u32 = 0; - #[derive(Eq, PartialEq, RuntimeDebug)] - pub const One: u32 = 1; - #[derive(Eq, PartialEq, RuntimeDebug)] - pub const Eight: u32 = 8; - #[derive(Clone, Eq, PartialEq, RuntimeDebug)] - pub const Five: u32 = 5; - } - - #[test] - fn from() { - let v: BoundedVec = vec![4, 2, 3, 4, 3, 1].try_into().unwrap(); - let set: OrderedSet = v.into(); - assert_eq!( - set, - OrderedSet::::from(vec![1, 2, 3, 4].try_into().unwrap()) - ); - } - - #[test] - fn insert() { - let mut set: OrderedSet = OrderedSet::new(); - assert_eq!(set, OrderedSet::::from(vec![].try_into().unwrap())); - - assert_eq!(set.try_insert(1), Ok(true)); - assert_eq!(set, OrderedSet::::from(vec![1].try_into().unwrap())); - - assert_eq!(set.try_insert(5), Ok(true)); - assert_eq!(set, OrderedSet::::from(vec![1, 5].try_into().unwrap())); - - assert_eq!(set.try_insert(3), Ok(true)); - assert_eq!(set, OrderedSet::::from(vec![1, 3, 5].try_into().unwrap())); - - assert_eq!(set.try_insert(3), Ok(false)); - assert_eq!(set, OrderedSet::::from(vec![1, 3, 5].try_into().unwrap())); - } - - #[test] - fn remove() { - let mut set: OrderedSet = OrderedSet::from(vec![1, 2, 3, 4].try_into().unwrap()); - - assert_eq!(set.remove(&5), None); - assert_eq!( - set, - OrderedSet::::from(vec![1, 2, 3, 4].try_into().unwrap()) - ); - - assert_eq!(set.remove(&1), Some(1)); - assert_eq!(set, OrderedSet::::from(vec![2, 3, 4].try_into().unwrap())); - - assert_eq!(set.remove(&3), Some(3)); - assert_eq!(set, OrderedSet::::from(vec![2, 4].try_into().unwrap())); - - assert_eq!(set.remove(&3), None); - assert_eq!(set, OrderedSet::::from(vec![2, 4].try_into().unwrap())); - - assert_eq!(set.remove(&4), Some(4)); - assert_eq!(set, OrderedSet::::from(vec![2].try_into().unwrap())); - - assert_eq!(set.remove(&2), Some(2)); - assert_eq!(set, OrderedSet::::from(vec![].try_into().unwrap())); - - assert_eq!(set.remove(&2), None); - assert_eq!(set, OrderedSet::::from(vec![].try_into().unwrap())); - } - - #[test] - fn contains() { - let set: OrderedSet = OrderedSet::from(vec![1, 2, 3, 4].try_into().unwrap()); - assert!(!set.contains(&5)); - assert!(set.contains(&1)); - assert!(set.contains(&3)); - } - - #[test] - fn clear() { - let mut set: OrderedSet = OrderedSet::from(vec![1, 2, 3, 4].try_into().unwrap()); - set.clear(); - assert_eq!(set, OrderedSet::new()); - } - - #[test] - fn try_insert_replace_integer() { - let mut set: OrderedSet = OrderedSet::from(vec![].try_into().unwrap()); - assert_eq!(set.try_insert_replace(10), Err(true)); - - let mut set: OrderedSet = OrderedSet::from(vec![].try_into().unwrap()); - assert_eq!(set.try_insert_replace(10), Ok(None)); - assert_eq!(set.try_insert_replace(9), Err(true)); - assert_eq!(set.try_insert_replace(11), Ok(Some(10))); - - let mut set: OrderedSet = OrderedSet::from(vec![].try_into().unwrap()); - assert_eq!(set.try_insert_replace(10), Ok(None)); - assert_eq!(set.try_insert_replace(7), Ok(None)); - assert_eq!(set.try_insert_replace(9), Ok(None)); - assert_eq!(set.try_insert_replace(8), Ok(None)); - - assert_eq!(set.clone().into_bounded_vec().into_inner(), vec![10, 9, 8, 7]); - assert_eq!(set.try_insert_replace(5), Ok(None)); - assert!(set.try_insert(11).is_err()); - - assert_eq!(set.try_insert_replace(6), Ok(Some(5))); - assert_eq!(set.clone().into_bounded_vec().into_inner(), vec![10, 9, 8, 7, 6]); - - assert_eq!(set.try_insert_replace(6), Err(false)); - assert_eq!(set.try_insert_replace(5), Err(true)); - - assert_eq!(set.try_insert_replace(10), Err(false)); - assert_eq!(set.try_insert_replace(11), Ok(Some(6))); - assert_eq!(set.into_bounded_vec().into_inner(), vec![11, 10, 9, 8, 7]); - } - - #[test] - fn try_insert_replace_stake() { - let mut set: OrderedSet, Eight> = OrderedSet::from( - vec![ - StakeOf:: { owner: 1, amount: 100 }, - StakeOf:: { owner: 3, amount: 90 }, - StakeOf:: { owner: 5, amount: 80 }, - StakeOf:: { owner: 7, amount: 70 }, - StakeOf:: { owner: 8, amount: 70 }, - StakeOf:: { owner: 9, amount: 60 }, - ] - .try_into() - .unwrap(), - ); - assert_eq!( - set.try_insert_replace(StakeOf:: { owner: 1, amount: 0 }), - Err(false) - ); - assert_eq!( - set.try_insert_replace(StakeOf:: { owner: 7, amount: 100 }), - Err(false) - ); - assert_eq!( - set.try_insert_replace(StakeOf:: { owner: 7, amount: 50 }), - Err(false) - ); - assert_eq!( - set.try_insert_replace(StakeOf:: { owner: 8, amount: 50 }), - Err(false) - ); - assert_eq!( - set.try_insert_replace(StakeOf:: { owner: 2, amount: 100 }), - Ok(None) - ); - assert_eq!( - set.try_insert_replace(StakeOf:: { owner: 2, amount: 90 }), - Err(false) - ); - assert_eq!( - set.try_insert_replace(StakeOf:: { owner: 10, amount: 65 }), - Ok(None) - ); - assert_eq!( - set.try_insert_replace(StakeOf:: { owner: 11, amount: 60 }), - Err(true) - ); - assert_eq!( - set.try_insert_replace(StakeOf:: { owner: 11, amount: 100 }), - Ok(Some(StakeOf:: { owner: 9, amount: 60 })) - ); - } - - #[test] - fn exceeding_max_size_should_fail() { - let mut set: OrderedSet = OrderedSet::from(vec![1, 2, 3, 4, 5].try_into().unwrap()); - let inserted = set.try_insert(6); - - assert!(inserted.is_err()); - } - - #[test] - fn linear_search() { - let set: OrderedSet, Eight> = OrderedSet::from( - vec![ - StakeOf:: { owner: 1, amount: 100 }, - StakeOf:: { owner: 3, amount: 90 }, - StakeOf:: { owner: 5, amount: 80 }, - StakeOf:: { owner: 7, amount: 70 }, - StakeOf:: { owner: 8, amount: 70 }, - StakeOf:: { owner: 9, amount: 60 }, - ] - .try_into() - .unwrap(), - ); - assert_eq!(set.linear_search(&StakeOf:: { owner: 1, amount: 0 }), Ok(0)); - assert_eq!(set.linear_search(&StakeOf:: { owner: 7, amount: 100 }), Ok(3)); - assert_eq!(set.linear_search(&StakeOf:: { owner: 7, amount: 50 }), Ok(3)); - assert_eq!(set.linear_search(&StakeOf:: { owner: 8, amount: 50 }), Ok(4)); - assert_eq!(set.linear_search(&StakeOf:: { owner: 2, amount: 100 }), Err(1)); - assert_eq!(set.linear_search(&StakeOf:: { owner: 2, amount: 90 }), Err(2)); - assert_eq!(set.linear_search(&StakeOf:: { owner: 2, amount: 65 }), Err(5)); - assert_eq!(set.linear_search(&StakeOf:: { owner: 2, amount: 60 }), Err(6)); - assert_eq!(set.linear_search(&StakeOf:: { owner: 2, amount: 59 }), Err(6)); - } - - #[test] - fn upsert_set() { - let mut set: OrderedSet, Eight> = OrderedSet::from( - vec![ - StakeOf:: { owner: 1, amount: 100 }, - StakeOf:: { owner: 3, amount: 90 }, - StakeOf:: { owner: 5, amount: 80 }, - StakeOf:: { owner: 7, amount: 70 }, - StakeOf:: { owner: 9, amount: 60 }, - ] - .try_into() - .unwrap(), - ); - assert_eq!(set.try_insert(StakeOf:: { owner: 2, amount: 75 }), Ok(true)); - assert_eq!( - set, - OrderedSet::from( - vec![ - StakeOf:: { owner: 1, amount: 100 }, - StakeOf:: { owner: 3, amount: 90 }, - StakeOf:: { owner: 5, amount: 80 }, - StakeOf:: { owner: 2, amount: 75 }, - StakeOf:: { owner: 7, amount: 70 }, - StakeOf:: { owner: 9, amount: 60 }, - ] - .try_into() - .unwrap() - ) - ); - assert_eq!( - set.try_upsert(StakeOf:: { owner: 2, amount: 90 }), - Ok(Some(StakeOf:: { owner: 2, amount: 75 })) - ); - assert_eq!( - set, - OrderedSet::from( - vec![ - StakeOf:: { owner: 1, amount: 100 }, - StakeOf:: { owner: 3, amount: 90 }, - StakeOf:: { owner: 2, amount: 90 }, - StakeOf:: { owner: 5, amount: 80 }, - StakeOf:: { owner: 7, amount: 70 }, - StakeOf:: { owner: 9, amount: 60 }, - ] - .try_into() - .unwrap() - ) - ); - assert_eq!( - set.try_upsert(StakeOf:: { owner: 2, amount: 60 }), - Ok(Some(StakeOf:: { owner: 2, amount: 90 })) - ); - assert_eq!( - set, - OrderedSet::from( - vec![ - StakeOf:: { owner: 1, amount: 100 }, - StakeOf:: { owner: 3, amount: 90 }, - StakeOf:: { owner: 5, amount: 80 }, - StakeOf:: { owner: 7, amount: 70 }, - StakeOf:: { owner: 2, amount: 60 }, - StakeOf:: { owner: 9, amount: 60 }, - ] - .try_into() - .unwrap() - ) - ); +impl From> for OrderedSet { + fn from(v: Vec) -> Self { + Self::from(v) } } diff --git a/pallets/parachain-staking/src/tests.rs b/pallets/parachain-staking/src/tests.rs index accc93d1a..c6f8bc686 100644 --- a/pallets/parachain-staking/src/tests.rs +++ b/pallets/parachain-staking/src/tests.rs @@ -1,846 +1,2744 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. -// The KILT Blockchain is free software: you can redistribute it and/or modify +// Moonbeam 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. -// The KILT Blockchain is distributed in the hope that it will be useful, +// Moonbeam 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 . +// along with Moonbeam. If not, see . -// If you feel like getting in touch with us, you can do so at info@botlabs.org +//! # Staking Pallet Unit Tests +//! The unit tests are organized by the call they test. The order matches the order +//! of the calls in the `lib.rs`. +//! 1. Root +//! 2. Monetary Governance +//! 3. Public (Collator, Nominator) +//! 4. Miscellaneous Property-Based Tests -//! Unit testing +use crate::{ + assert_events_emitted, assert_events_emitted_match, assert_events_eq, assert_no_events, + auto_compound::{AutoCompoundConfig, AutoCompoundDelegations}, + delegation_requests::{CancelledScheduledRequest, DelegationAction, ScheduledRequest}, + mock::{ + roll_blocks, roll_to, roll_to_round_begin, roll_to_round_end, set_author, Balances, BlockNumber, ExtBuilder, + ParachainStaking, RuntimeOrigin, Test, + }, + AtStake, Bond, CollatorStatus, DelegationScheduledRequests, DelegatorAdded, DelegatorState, DelegatorStatus, Error, + Event, Range, DELEGATOR_LOCK_ID, +}; +use frame_support::{assert_noop, assert_ok}; +use sp_runtime::{traits::Zero, Perbill, Percent}; + +// ~~ ROOT ~~ + +#[test] +fn invalid_root_origin_fails() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + ParachainStaking::set_total_selected(RuntimeOrigin::signed(45), 6u32), + sp_runtime::DispatchError::BadOrigin + ); + assert_noop!( + ParachainStaking::set_collator_commission(RuntimeOrigin::signed(45), Perbill::from_percent(5)), + sp_runtime::DispatchError::BadOrigin + ); + assert_noop!( + ParachainStaking::set_blocks_per_round(RuntimeOrigin::signed(45), 3u32), + sp_runtime::DispatchError::BadOrigin + ); + }); +} + +// SET TOTAL SELECTED + +#[test] +fn set_total_selected_event_emits_correctly() { + ExtBuilder::default().build().execute_with(|| { + // before we can bump total_selected we must bump the blocks per round + assert_ok!(ParachainStaking::set_blocks_per_round(RuntimeOrigin::root(), 7u32)); + roll_blocks(1); + assert_ok!(ParachainStaking::set_total_selected(RuntimeOrigin::root(), 6u32)); + assert_events_eq!(Event::TotalSelectedSet { old: 5u32, new: 6u32 }); + }); +} + +#[test] +fn set_total_selected_fails_if_above_blocks_per_round() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(ParachainStaking::round().length, 5); // test relies on this + assert_noop!( + ParachainStaking::set_total_selected(RuntimeOrigin::root(), 6u32), + Error::::RoundLengthMustBeGreaterThanTotalSelectedCollators, + ); + }); +} + +#[test] +fn set_total_selected_fails_if_equal_to_blocks_per_round() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(ParachainStaking::set_blocks_per_round(RuntimeOrigin::root(), 10u32)); + assert_noop!( + ParachainStaking::set_total_selected(RuntimeOrigin::root(), 10u32), + Error::::RoundLengthMustBeGreaterThanTotalSelectedCollators, + ); + }); +} + +#[test] +fn set_total_selected_passes_if_below_blocks_per_round() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(ParachainStaking::set_blocks_per_round(RuntimeOrigin::root(), 10u32)); + assert_ok!(ParachainStaking::set_total_selected(RuntimeOrigin::root(), 9u32)); + }); +} + +#[test] +fn set_blocks_per_round_fails_if_below_total_selected() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(ParachainStaking::set_blocks_per_round(RuntimeOrigin::root(), 20u32)); + assert_ok!(ParachainStaking::set_total_selected(RuntimeOrigin::root(), 15u32)); + assert_noop!( + ParachainStaking::set_blocks_per_round(RuntimeOrigin::root(), 14u32), + Error::::RoundLengthMustBeGreaterThanTotalSelectedCollators, + ); + }); +} + +#[test] +fn set_blocks_per_round_fails_if_equal_to_total_selected() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(ParachainStaking::set_blocks_per_round(RuntimeOrigin::root(), 10u32)); + assert_ok!(ParachainStaking::set_total_selected(RuntimeOrigin::root(), 9u32)); + assert_noop!( + ParachainStaking::set_blocks_per_round(RuntimeOrigin::root(), 9u32), + Error::::RoundLengthMustBeGreaterThanTotalSelectedCollators, + ); + }); +} + +#[test] +fn set_blocks_per_round_passes_if_above_total_selected() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(ParachainStaking::round().length, 5); // test relies on this + assert_ok!(ParachainStaking::set_blocks_per_round(RuntimeOrigin::root(), 6u32)); + }); +} + +#[test] +fn set_total_selected_storage_updates_correctly() { + ExtBuilder::default().build().execute_with(|| { + // round length must be >= total_selected, so update that first + assert_ok!(ParachainStaking::set_blocks_per_round(RuntimeOrigin::root(), 10u32)); + + assert_eq!(ParachainStaking::total_selected(), 5u32); + assert_ok!(ParachainStaking::set_total_selected(RuntimeOrigin::root(), 6u32)); + assert_eq!(ParachainStaking::total_selected(), 6u32); + }); +} + +#[test] +fn cannot_set_total_selected_to_current_total_selected() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + ParachainStaking::set_total_selected(RuntimeOrigin::root(), 5u32), + Error::::NoWritingSameValue + ); + }); +} + +#[test] +fn cannot_set_total_selected_below_module_min() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + ParachainStaking::set_total_selected(RuntimeOrigin::root(), 4u32), + Error::::CannotSetBelowMin + ); + }); +} + +// SET COLLATOR COMMISSION + +#[test] +fn set_collator_commission_event_emits_correctly() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(ParachainStaking::set_collator_commission(RuntimeOrigin::root(), Perbill::from_percent(5))); + assert_events_eq!(Event::CollatorCommissionSet { + old: Perbill::from_percent(20), + new: Perbill::from_percent(5), + }); + }); +} + +#[test] +fn set_collator_commission_storage_updates_correctly() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(ParachainStaking::collator_commission(), Perbill::from_percent(20)); + assert_ok!(ParachainStaking::set_collator_commission(RuntimeOrigin::root(), Perbill::from_percent(5))); + assert_eq!(ParachainStaking::collator_commission(), Perbill::from_percent(5)); + }); +} + +#[test] +fn cannot_set_collator_commission_to_current_collator_commission() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + ParachainStaking::set_collator_commission(RuntimeOrigin::root(), Perbill::from_percent(20)), + Error::::NoWritingSameValue + ); + }); +} + +// SET BLOCKS PER ROUND + +#[test] +fn set_blocks_per_round_event_emits_correctly() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(ParachainStaking::set_blocks_per_round(RuntimeOrigin::root(), 6u32)); + assert_events_eq!(Event::BlocksPerRoundSet { + current_round: 1, + first_block: 0, + old: 5, + new: 6, + new_per_round_inflation_min: Perbill::from_parts(926), + new_per_round_inflation_ideal: Perbill::from_parts(926), + new_per_round_inflation_max: Perbill::from_parts(926), + }); + }); +} + +#[test] +fn set_blocks_per_round_storage_updates_correctly() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(ParachainStaking::round().length, 5); + assert_ok!(ParachainStaking::set_blocks_per_round(RuntimeOrigin::root(), 6u32)); + assert_eq!(ParachainStaking::round().length, 6); + }); +} + +#[test] +fn cannot_set_blocks_per_round_below_module_min() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + ParachainStaking::set_blocks_per_round(RuntimeOrigin::root(), 2u32), + Error::::CannotSetBelowMin + ); + }); +} + +#[test] +fn cannot_set_blocks_per_round_to_current_blocks_per_round() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + ParachainStaking::set_blocks_per_round(RuntimeOrigin::root(), 5u32), + Error::::NoWritingSameValue + ); + }); +} + +#[test] +fn round_immediately_jumps_if_current_duration_exceeds_new_blocks_per_round() { + ExtBuilder::default().with_balances(vec![(1, 20)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + // we can't lower the blocks per round because it must be above the number of collators, + // and we can't lower the number of collators because it must be above + // MinSelectedCandidates. so we first raise blocks per round, then lower it. + assert_ok!(ParachainStaking::set_blocks_per_round(RuntimeOrigin::root(), 10u32)); + + roll_to(10); + assert_events_emitted!(Event::NewRound { + starting_block: 10, + round: 2, + selected_collators_number: 1, + total_balance: 20 + },); + roll_to(17); + assert_ok!(ParachainStaking::set_blocks_per_round(RuntimeOrigin::root(), 6u32)); + roll_to(18); + assert_events_emitted!(Event::NewRound { + starting_block: 18, + round: 3, + selected_collators_number: 1, + total_balance: 20 + }); + }); +} + +// ~~ MONETARY GOVERNANCE ~~ + +#[test] +fn invalid_monetary_origin_fails() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + ParachainStaking::set_staking_expectations( + RuntimeOrigin::signed(45), + Range { min: 3u32.into(), ideal: 4u32.into(), max: 5u32.into() } + ), + sp_runtime::DispatchError::BadOrigin + ); + assert_noop!( + ParachainStaking::set_inflation( + RuntimeOrigin::signed(45), + Range { min: Perbill::from_percent(3), ideal: Perbill::from_percent(4), max: Perbill::from_percent(5) } + ), + sp_runtime::DispatchError::BadOrigin + ); + assert_noop!( + ParachainStaking::set_inflation( + RuntimeOrigin::signed(45), + Range { min: Perbill::from_percent(3), ideal: Perbill::from_percent(4), max: Perbill::from_percent(5) } + ), + sp_runtime::DispatchError::BadOrigin + ); + assert_noop!( + ParachainStaking::set_parachain_bond_account(RuntimeOrigin::signed(45), 11), + sp_runtime::DispatchError::BadOrigin + ); + assert_noop!( + ParachainStaking::set_parachain_bond_reserve_percent(RuntimeOrigin::signed(45), Percent::from_percent(2)), + sp_runtime::DispatchError::BadOrigin + ); + }); +} + +// SET STAKING EXPECTATIONS + +#[test] +fn set_staking_event_emits_event_correctly() { + ExtBuilder::default().build().execute_with(|| { + // valid call succeeds + assert_ok!(ParachainStaking::set_staking_expectations( + RuntimeOrigin::root(), + Range { min: 3u128, ideal: 4u128, max: 5u128 } + )); + assert_events_eq!(Event::StakeExpectationsSet { expect_min: 3u128, expect_ideal: 4u128, expect_max: 5u128 }); + }); +} + +#[test] +fn set_staking_updates_storage_correctly() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(ParachainStaking::inflation_config().expect, Range { min: 700, ideal: 700, max: 700 }); + assert_ok!(ParachainStaking::set_staking_expectations( + RuntimeOrigin::root(), + Range { min: 3u128, ideal: 4u128, max: 5u128 } + )); + assert_eq!(ParachainStaking::inflation_config().expect, Range { min: 3u128, ideal: 4u128, max: 5u128 }); + }); +} + +#[test] +fn cannot_set_invalid_staking_expectations() { + ExtBuilder::default().build().execute_with(|| { + // invalid call fails + assert_noop!( + ParachainStaking::set_staking_expectations( + RuntimeOrigin::root(), + Range { min: 5u128, ideal: 4u128, max: 3u128 } + ), + Error::::InvalidSchedule + ); + }); +} + +#[test] +fn cannot_set_same_staking_expectations() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(ParachainStaking::set_staking_expectations( + RuntimeOrigin::root(), + Range { min: 3u128, ideal: 4u128, max: 5u128 } + )); + assert_noop!( + ParachainStaking::set_staking_expectations( + RuntimeOrigin::root(), + Range { min: 3u128, ideal: 4u128, max: 5u128 } + ), + Error::::NoWritingSameValue + ); + }); +} + +// SET INFLATION + +#[test] +fn set_inflation_event_emits_correctly() { + ExtBuilder::default().build().execute_with(|| { + let (min, ideal, max): (Perbill, Perbill, Perbill) = + (Perbill::from_percent(3), Perbill::from_percent(4), Perbill::from_percent(5)); + assert_ok!(ParachainStaking::set_inflation(RuntimeOrigin::root(), Range { min, ideal, max })); + assert_events_eq!(Event::InflationSet { + annual_min: min, + annual_ideal: ideal, + annual_max: max, + round_min: Perbill::from_parts(57), + round_ideal: Perbill::from_parts(75), + round_max: Perbill::from_parts(93), + }); + }); +} + +#[test] +fn set_inflation_storage_updates_correctly() { + ExtBuilder::default().build().execute_with(|| { + let (min, ideal, max): (Perbill, Perbill, Perbill) = + (Perbill::from_percent(3), Perbill::from_percent(4), Perbill::from_percent(5)); + assert_eq!( + ParachainStaking::inflation_config().annual, + Range { min: Perbill::from_percent(50), ideal: Perbill::from_percent(50), max: Perbill::from_percent(50) } + ); + assert_eq!( + ParachainStaking::inflation_config().round, + Range { min: Perbill::from_percent(5), ideal: Perbill::from_percent(5), max: Perbill::from_percent(5) } + ); + assert_ok!(ParachainStaking::set_inflation(RuntimeOrigin::root(), Range { min, ideal, max }),); + assert_eq!(ParachainStaking::inflation_config().annual, Range { min, ideal, max }); + assert_eq!( + ParachainStaking::inflation_config().round, + Range { min: Perbill::from_parts(57), ideal: Perbill::from_parts(75), max: Perbill::from_parts(93) } + ); + }); +} + +#[test] +fn cannot_set_invalid_inflation() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + ParachainStaking::set_inflation( + RuntimeOrigin::root(), + Range { min: Perbill::from_percent(5), ideal: Perbill::from_percent(4), max: Perbill::from_percent(3) } + ), + Error::::InvalidSchedule + ); + }); +} + +#[test] +fn cannot_set_same_inflation() { + ExtBuilder::default().build().execute_with(|| { + let (min, ideal, max): (Perbill, Perbill, Perbill) = + (Perbill::from_percent(3), Perbill::from_percent(4), Perbill::from_percent(5)); + assert_ok!(ParachainStaking::set_inflation(RuntimeOrigin::root(), Range { min, ideal, max }),); + assert_noop!( + ParachainStaking::set_inflation(RuntimeOrigin::root(), Range { min, ideal, max }), + Error::::NoWritingSameValue + ); + }); +} + +// SET PARACHAIN BOND ACCOUNT + +#[test] +fn set_parachain_bond_account_event_emits_correctly() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(ParachainStaking::set_parachain_bond_account(RuntimeOrigin::root(), 11)); + assert_events_eq!(Event::ParachainBondAccountSet { old: 0, new: 11 }); + }); +} + +#[test] +fn set_parachain_bond_account_storage_updates_correctly() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(ParachainStaking::parachain_bond_info().account, 0); + assert_ok!(ParachainStaking::set_parachain_bond_account(RuntimeOrigin::root(), 11)); + assert_eq!(ParachainStaking::parachain_bond_info().account, 11); + }); +} + +// SET PARACHAIN BOND RESERVE PERCENT + +#[test] +fn set_parachain_bond_reserve_percent_event_emits_correctly() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(ParachainStaking::set_parachain_bond_reserve_percent( + RuntimeOrigin::root(), + Percent::from_percent(50) + )); + assert_events_eq!(Event::ParachainBondReservePercentSet { + old: Percent::from_percent(30), + new: Percent::from_percent(50), + }); + }); +} + +#[test] +fn set_parachain_bond_reserve_percent_storage_updates_correctly() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(ParachainStaking::parachain_bond_info().percent, Percent::from_percent(30)); + assert_ok!(ParachainStaking::set_parachain_bond_reserve_percent( + RuntimeOrigin::root(), + Percent::from_percent(50) + )); + assert_eq!(ParachainStaking::parachain_bond_info().percent, Percent::from_percent(50)); + }); +} + +#[test] +fn cannot_set_same_parachain_bond_reserve_percent() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + ParachainStaking::set_parachain_bond_reserve_percent(RuntimeOrigin::root(), Percent::from_percent(30)), + Error::::NoWritingSameValue + ); + }); +} + +// ~~ PUBLIC ~~ + +// JOIN CANDIDATES + +#[test] +fn join_candidates_event_emits_correctly() { + ExtBuilder::default().with_balances(vec![(1, 10)]).build().execute_with(|| { + assert_ok!(ParachainStaking::join_candidates(RuntimeOrigin::signed(1), 10u128, 0u32)); + assert_events_eq!(Event::JoinedCollatorCandidates { + account: 1, + amount_locked: 10u128, + new_total_amt_locked: 10u128, + }); + }); +} + +#[test] +fn join_candidates_reserves_balance() { + ExtBuilder::default().with_balances(vec![(1, 10)]).build().execute_with(|| { + assert_eq!(ParachainStaking::get_collator_stakable_free_balance(&1), 10); + assert_ok!(ParachainStaking::join_candidates(RuntimeOrigin::signed(1), 10u128, 0u32)); + assert_eq!(ParachainStaking::get_collator_stakable_free_balance(&1), 0); + }); +} + +#[test] +fn join_candidates_increases_total_staked() { + ExtBuilder::default().with_balances(vec![(1, 10)]).build().execute_with(|| { + assert_eq!(ParachainStaking::total(), 0); + assert_ok!(ParachainStaking::join_candidates(RuntimeOrigin::signed(1), 10u128, 0u32)); + assert_eq!(ParachainStaking::total(), 10); + }); +} + +#[test] +fn join_candidates_creates_candidate_state() { + ExtBuilder::default().with_balances(vec![(1, 10)]).build().execute_with(|| { + assert!(ParachainStaking::candidate_info(1).is_none()); + assert_ok!(ParachainStaking::join_candidates(RuntimeOrigin::signed(1), 10u128, 0u32)); + let candidate_state = ParachainStaking::candidate_info(1).expect("just joined => exists"); + assert_eq!(candidate_state.bond, 10u128); + }); +} + +#[test] +fn join_candidates_adds_to_candidate_pool() { + ExtBuilder::default().with_balances(vec![(1, 10)]).build().execute_with(|| { + assert!(ParachainStaking::candidate_pool().0.is_empty()); + assert_ok!(ParachainStaking::join_candidates(RuntimeOrigin::signed(1), 10u128, 0u32)); + let candidate_pool = ParachainStaking::candidate_pool(); + assert_eq!(candidate_pool.0[0].owner, 1); + assert_eq!(candidate_pool.0[0].amount, 10); + }); +} + +#[test] +fn cannot_join_candidates_if_candidate() { + ExtBuilder::default().with_balances(vec![(1, 1000)]).with_candidates(vec![(1, 500)]).build().execute_with(|| { + assert_noop!( + ParachainStaking::join_candidates(RuntimeOrigin::signed(1), 11u128, 100u32), + Error::::CandidateExists + ); + }); +} + +#[test] +fn cannot_join_candidates_if_delegator() { + ExtBuilder::default() + .with_balances(vec![(1, 50), (2, 20)]) + .with_candidates(vec![(1, 50)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_noop!( + ParachainStaking::join_candidates(RuntimeOrigin::signed(2), 10u128, 1u32), + Error::::DelegatorExists + ); + }); +} + +#[test] +fn cannot_join_candidates_without_min_bond() { + ExtBuilder::default().with_balances(vec![(1, 1000)]).build().execute_with(|| { + assert_noop!( + ParachainStaking::join_candidates(RuntimeOrigin::signed(1), 9u128, 100u32), + Error::::CandidateBondBelowMin + ); + }); +} + +#[test] +fn cannot_join_candidates_with_more_than_available_balance() { + ExtBuilder::default().with_balances(vec![(1, 500)]).build().execute_with(|| { + assert_noop!( + ParachainStaking::join_candidates(RuntimeOrigin::signed(1), 501u128, 100u32), + Error::::InsufficientBalance + ); + }); +} + +#[test] +fn insufficient_join_candidates_weight_hint_fails() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 20), (6, 20)]) + .with_candidates(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 20)]) + .build() + .execute_with(|| { + for i in 0..5 { + assert_noop!( + ParachainStaking::join_candidates(RuntimeOrigin::signed(6), 20, i), + Error::::TooLowCandidateCountWeightHintJoinCandidates + ); + } + }); +} + +#[test] +fn sufficient_join_candidates_weight_hint_succeeds() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 20), (6, 20), (7, 20), (8, 20), (9, 20)]) + .with_candidates(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 20)]) + .build() + .execute_with(|| { + let mut count = 5u32; + for i in 6..10 { + assert_ok!(ParachainStaking::join_candidates(RuntimeOrigin::signed(i), 20, count)); + count += 1u32; + } + }); +} + +// SCHEDULE LEAVE CANDIDATES + +#[test] +fn leave_candidates_event_emits_correctly() { + ExtBuilder::default().with_balances(vec![(1, 10)]).with_candidates(vec![(1, 10)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1u32)); + assert_events_eq!(Event::CandidateScheduledExit { exit_allowed_round: 1, candidate: 1, scheduled_exit: 3 }); + }); +} + +#[test] +fn leave_candidates_removes_candidate_from_candidate_pool() { + ExtBuilder::default().with_balances(vec![(1, 10)]).with_candidates(vec![(1, 10)]).build().execute_with(|| { + assert_eq!(ParachainStaking::candidate_pool().0.len(), 1); + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1u32)); + assert!(ParachainStaking::candidate_pool().0.is_empty()); + }); +} + +#[test] +fn cannot_leave_candidates_if_not_candidate() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1u32), + Error::::CandidateDNE + ); + }); +} + +#[test] +fn cannot_leave_candidates_if_already_leaving_candidates() { + ExtBuilder::default().with_balances(vec![(1, 10)]).with_candidates(vec![(1, 10)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1u32)); + assert_noop!( + ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1u32), + Error::::CandidateAlreadyLeaving + ); + }); +} + +#[test] +fn insufficient_leave_candidates_weight_hint_fails() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 20)]) + .with_candidates(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 20)]) + .build() + .execute_with(|| { + for i in 1..6 { + assert_noop!( + ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(i), 4u32), + Error::::TooLowCandidateCountToLeaveCandidates + ); + } + }); +} + +#[test] +fn sufficient_leave_candidates_weight_hint_succeeds() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 20)]) + .with_candidates(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 20)]) + .build() + .execute_with(|| { + let mut count = 5u32; + for i in 1..6 { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(i), count)); + count -= 1u32; + } + }); +} + +// EXECUTE LEAVE CANDIDATES + +#[test] +fn execute_leave_candidates_emits_event() { + ExtBuilder::default().with_balances(vec![(1, 10)]).with_candidates(vec![(1, 10)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1u32)); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(1), 1, 0)); + assert_events_emitted!(Event::CandidateLeft { ex_candidate: 1, unlocked_amount: 10, new_total_amt_locked: 0 }); + }); +} + +#[test] +fn execute_leave_candidates_callable_by_any_signed() { + ExtBuilder::default().with_balances(vec![(1, 10)]).with_candidates(vec![(1, 10)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1u32)); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(2), 1, 0)); + }); +} + +#[test] +fn execute_leave_candidates_requires_correct_weight_hint() { + ExtBuilder::default() + .with_balances(vec![(1, 10), (2, 10), (3, 10), (4, 10)]) + .with_candidates(vec![(1, 10)]) + .with_delegations(vec![(2, 1, 10), (3, 1, 10), (4, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1u32)); + roll_to(10); + for i in 0..3 { + assert_noop!( + ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(1), 1, i), + Error::::TooLowCandidateDelegationCountToLeaveCandidates + ); + } + assert_ok!(ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(2), 1, 3)); + }); +} + +#[test] +fn execute_leave_candidates_unreserves_balance() { + ExtBuilder::default().with_balances(vec![(1, 10)]).with_candidates(vec![(1, 10)]).build().execute_with(|| { + assert_eq!(ParachainStaking::get_collator_stakable_free_balance(&1), 0); + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1u32)); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(1), 1, 0)); + assert_eq!(ParachainStaking::get_collator_stakable_free_balance(&1), 10); + }); +} + +#[test] +fn execute_leave_candidates_decreases_total_staked() { + ExtBuilder::default().with_balances(vec![(1, 10)]).with_candidates(vec![(1, 10)]).build().execute_with(|| { + assert_eq!(ParachainStaking::total(), 10); + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1u32)); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(1), 1, 0)); + assert_eq!(ParachainStaking::total(), 0); + }); +} + +#[test] +fn execute_leave_candidates_removes_candidate_state() { + ExtBuilder::default().with_balances(vec![(1, 10)]).with_candidates(vec![(1, 10)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1u32)); + // candidate state is not immediately removed + let candidate_state = ParachainStaking::candidate_info(1).expect("just left => still exists"); + assert_eq!(candidate_state.bond, 10u128); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(1), 1, 0)); + assert!(ParachainStaking::candidate_info(1).is_none()); + }); +} + +#[test] +fn execute_leave_candidates_removes_pending_delegation_requests() { + ExtBuilder::default() + .with_balances(vec![(1, 10), (2, 15)]) + .with_candidates(vec![(1, 10)]) + .with_delegations(vec![(2, 1, 15)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 5)); + let state = ParachainStaking::delegation_scheduled_requests(&1); + assert_eq!( + state, + vec![ScheduledRequest { delegator: 2, when_executable: 3, action: DelegationAction::Decrease(5) }], + ); + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1u32)); + // candidate state is not immediately removed + let candidate_state = ParachainStaking::candidate_info(1).expect("just left => still exists"); + assert_eq!(candidate_state.bond, 10u128); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(1), 1, 1)); + assert!(ParachainStaking::candidate_info(1).is_none()); + assert!( + !ParachainStaking::delegation_scheduled_requests(&1).iter().any(|x| x.delegator == 2), + "delegation request not removed" + ); + assert!(!>::contains_key(&1), "the key was not removed from storage"); + }); +} + +#[test] +fn cannot_execute_leave_candidates_before_delay() { + ExtBuilder::default().with_balances(vec![(1, 10)]).with_candidates(vec![(1, 10)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1u32)); + assert_noop!( + ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(3), 1, 0), + Error::::CandidateCannotLeaveYet + ); + roll_to(9); + assert_noop!( + ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(3), 1, 0), + Error::::CandidateCannotLeaveYet + ); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(3), 1, 0)); + }); +} + +// CANCEL LEAVE CANDIDATES + +#[test] +fn cancel_leave_candidates_emits_event() { + ExtBuilder::default().with_balances(vec![(1, 10)]).with_candidates(vec![(1, 10)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1u32)); + assert_ok!(ParachainStaking::cancel_leave_candidates(RuntimeOrigin::signed(1), 1)); + assert_events_emitted!(Event::CancelledCandidateExit { candidate: 1 }); + }); +} + +#[test] +fn cancel_leave_candidates_updates_candidate_state() { + ExtBuilder::default().with_balances(vec![(1, 10)]).with_candidates(vec![(1, 10)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1u32)); + assert_ok!(ParachainStaking::cancel_leave_candidates(RuntimeOrigin::signed(1), 1)); + let candidate = ParachainStaking::candidate_info(&1).expect("just cancelled leave so exists"); + assert!(candidate.is_active()); + }); +} + +#[test] +fn cancel_leave_candidates_adds_to_candidate_pool() { + ExtBuilder::default().with_balances(vec![(1, 10)]).with_candidates(vec![(1, 10)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1u32)); + assert_ok!(ParachainStaking::cancel_leave_candidates(RuntimeOrigin::signed(1), 1)); + assert_eq!(ParachainStaking::candidate_pool().0[0].owner, 1); + assert_eq!(ParachainStaking::candidate_pool().0[0].amount, 10); + }); +} + +// GO OFFLINE + +#[test] +fn go_offline_event_emits_correctly() { + ExtBuilder::default().with_balances(vec![(1, 20)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + assert_ok!(ParachainStaking::go_offline(RuntimeOrigin::signed(1))); + assert_events_eq!(Event::CandidateWentOffline { candidate: 1 }); + }); +} + +#[test] +fn go_offline_removes_candidate_from_candidate_pool() { + ExtBuilder::default().with_balances(vec![(1, 20)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + assert_eq!(ParachainStaking::candidate_pool().0.len(), 1); + assert_ok!(ParachainStaking::go_offline(RuntimeOrigin::signed(1))); + assert!(ParachainStaking::candidate_pool().0.is_empty()); + }); +} + +#[test] +fn go_offline_updates_candidate_state_to_idle() { + ExtBuilder::default().with_balances(vec![(1, 20)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + let candidate_state = ParachainStaking::candidate_info(1).expect("is active candidate"); + assert_eq!(candidate_state.status, CollatorStatus::Active); + assert_ok!(ParachainStaking::go_offline(RuntimeOrigin::signed(1))); + let candidate_state = ParachainStaking::candidate_info(1).expect("is candidate, just offline"); + assert_eq!(candidate_state.status, CollatorStatus::Idle); + }); +} + +#[test] +fn cannot_go_offline_if_not_candidate() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!(ParachainStaking::go_offline(RuntimeOrigin::signed(3)), Error::::CandidateDNE); + }); +} + +#[test] +fn cannot_go_offline_if_already_offline() { + ExtBuilder::default().with_balances(vec![(1, 20)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + assert_ok!(ParachainStaking::go_offline(RuntimeOrigin::signed(1))); + assert_noop!(ParachainStaking::go_offline(RuntimeOrigin::signed(1)), Error::::AlreadyOffline); + }); +} + +// GO ONLINE + +#[test] +fn go_online_event_emits_correctly() { + ExtBuilder::default().with_balances(vec![(1, 20)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + assert_ok!(ParachainStaking::go_offline(RuntimeOrigin::signed(1))); + roll_blocks(1); + assert_ok!(ParachainStaking::go_online(RuntimeOrigin::signed(1))); + assert_events_eq!(Event::CandidateBackOnline { candidate: 1 }); + }); +} + +#[test] +fn go_online_adds_to_candidate_pool() { + ExtBuilder::default().with_balances(vec![(1, 20)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + assert_ok!(ParachainStaking::go_offline(RuntimeOrigin::signed(1))); + assert!(ParachainStaking::candidate_pool().0.is_empty()); + assert_ok!(ParachainStaking::go_online(RuntimeOrigin::signed(1))); + assert_eq!(ParachainStaking::candidate_pool().0[0].owner, 1); + assert_eq!(ParachainStaking::candidate_pool().0[0].amount, 20); + }); +} + +#[test] +fn go_online_storage_updates_candidate_state() { + ExtBuilder::default().with_balances(vec![(1, 20)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + assert_ok!(ParachainStaking::go_offline(RuntimeOrigin::signed(1))); + let candidate_state = ParachainStaking::candidate_info(1).expect("offline still exists"); + assert_eq!(candidate_state.status, CollatorStatus::Idle); + assert_ok!(ParachainStaking::go_online(RuntimeOrigin::signed(1))); + let candidate_state = ParachainStaking::candidate_info(1).expect("online so exists"); + assert_eq!(candidate_state.status, CollatorStatus::Active); + }); +} + +#[test] +fn cannot_go_online_if_not_candidate() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!(ParachainStaking::go_online(RuntimeOrigin::signed(3)), Error::::CandidateDNE); + }); +} + +#[test] +fn cannot_go_online_if_already_online() { + ExtBuilder::default().with_balances(vec![(1, 20)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + assert_noop!(ParachainStaking::go_online(RuntimeOrigin::signed(1)), Error::::AlreadyActive); + }); +} + +#[test] +fn cannot_go_online_if_leaving() { + ExtBuilder::default().with_balances(vec![(1, 20)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1)); + assert_noop!(ParachainStaking::go_online(RuntimeOrigin::signed(1)), Error::::CannotGoOnlineIfLeaving); + }); +} + +// CANDIDATE BOND MORE + +#[test] +fn candidate_bond_more_emits_correct_event() { + ExtBuilder::default().with_balances(vec![(1, 50)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + assert_ok!(ParachainStaking::candidate_bond_more(RuntimeOrigin::signed(1), 30)); + assert_events_eq!(Event::CandidateBondedMore { candidate: 1, amount: 30, new_total_bond: 50 }); + }); +} + +#[test] +fn candidate_bond_more_reserves_balance() { + ExtBuilder::default().with_balances(vec![(1, 50)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + assert_eq!(ParachainStaking::get_collator_stakable_free_balance(&1), 30); + assert_ok!(ParachainStaking::candidate_bond_more(RuntimeOrigin::signed(1), 30)); + assert_eq!(ParachainStaking::get_collator_stakable_free_balance(&1), 0); + }); +} + +#[test] +fn candidate_bond_more_increases_total() { + ExtBuilder::default().with_balances(vec![(1, 50)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + let mut total = ParachainStaking::total(); + assert_ok!(ParachainStaking::candidate_bond_more(RuntimeOrigin::signed(1), 30)); + total += 30; + assert_eq!(ParachainStaking::total(), total); + }); +} + +#[test] +fn candidate_bond_more_updates_candidate_state() { + ExtBuilder::default().with_balances(vec![(1, 50)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + let candidate_state = ParachainStaking::candidate_info(1).expect("updated => exists"); + assert_eq!(candidate_state.bond, 20); + assert_ok!(ParachainStaking::candidate_bond_more(RuntimeOrigin::signed(1), 30)); + let candidate_state = ParachainStaking::candidate_info(1).expect("updated => exists"); + assert_eq!(candidate_state.bond, 50); + }); +} + +#[test] +fn candidate_bond_more_updates_candidate_pool() { + ExtBuilder::default().with_balances(vec![(1, 50)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + assert_eq!(ParachainStaking::candidate_pool().0[0].owner, 1); + assert_eq!(ParachainStaking::candidate_pool().0[0].amount, 20); + assert_ok!(ParachainStaking::candidate_bond_more(RuntimeOrigin::signed(1), 30)); + assert_eq!(ParachainStaking::candidate_pool().0[0].owner, 1); + assert_eq!(ParachainStaking::candidate_pool().0[0].amount, 50); + }); +} + +// SCHEDULE CANDIDATE BOND LESS + +#[test] +fn schedule_candidate_bond_less_event_emits_correctly() { + ExtBuilder::default().with_balances(vec![(1, 30)]).with_candidates(vec![(1, 30)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_candidate_bond_less(RuntimeOrigin::signed(1), 10)); + assert_events_eq!(Event::CandidateBondLessRequested { candidate: 1, amount_to_decrease: 10, execute_round: 3 }); + }); +} + +#[test] +fn cannot_schedule_candidate_bond_less_if_request_exists() { + ExtBuilder::default().with_balances(vec![(1, 30)]).with_candidates(vec![(1, 30)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_candidate_bond_less(RuntimeOrigin::signed(1), 5)); + assert_noop!( + ParachainStaking::schedule_candidate_bond_less(RuntimeOrigin::signed(1), 5), + Error::::PendingCandidateRequestAlreadyExists + ); + }); +} + +#[test] +fn cannot_schedule_candidate_bond_less_if_not_candidate() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + ParachainStaking::schedule_candidate_bond_less(RuntimeOrigin::signed(6), 50), + Error::::CandidateDNE + ); + }); +} + +#[test] +fn cannot_schedule_candidate_bond_less_if_new_total_below_min_candidate_stk() { + ExtBuilder::default().with_balances(vec![(1, 30)]).with_candidates(vec![(1, 30)]).build().execute_with(|| { + assert_noop!( + ParachainStaking::schedule_candidate_bond_less(RuntimeOrigin::signed(1), 21), + Error::::CandidateBondBelowMin + ); + }); +} + +#[test] +fn can_schedule_candidate_bond_less_if_leaving_candidates() { + ExtBuilder::default().with_balances(vec![(1, 30)]).with_candidates(vec![(1, 30)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1)); + assert_ok!(ParachainStaking::schedule_candidate_bond_less(RuntimeOrigin::signed(1), 10)); + }); +} + +#[test] +fn cannot_schedule_candidate_bond_less_if_exited_candidates() { + ExtBuilder::default().with_balances(vec![(1, 30)]).with_candidates(vec![(1, 30)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1)); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(1), 1, 0)); + assert_noop!( + ParachainStaking::schedule_candidate_bond_less(RuntimeOrigin::signed(1), 10), + Error::::CandidateDNE + ); + }); +} + +// 2. EXECUTE BOND LESS REQUEST + +#[test] +fn execute_candidate_bond_less_emits_correct_event() { + ExtBuilder::default().with_balances(vec![(1, 50)]).with_candidates(vec![(1, 50)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_candidate_bond_less(RuntimeOrigin::signed(1), 30)); + roll_to(10); + roll_blocks(1); + assert_ok!(ParachainStaking::execute_candidate_bond_less(RuntimeOrigin::signed(1), 1)); + assert_events_eq!(Event::CandidateBondedLess { candidate: 1, amount: 30, new_bond: 20 }); + }); +} + +#[test] +fn execute_candidate_bond_less_unreserves_balance() { + ExtBuilder::default().with_balances(vec![(1, 30)]).with_candidates(vec![(1, 30)]).build().execute_with(|| { + assert_eq!(ParachainStaking::get_collator_stakable_free_balance(&1), 0); + assert_ok!(ParachainStaking::schedule_candidate_bond_less(RuntimeOrigin::signed(1), 10)); + roll_to(10); + assert_ok!(ParachainStaking::execute_candidate_bond_less(RuntimeOrigin::signed(1), 1)); + assert_eq!(ParachainStaking::get_collator_stakable_free_balance(&1), 10); + }); +} + +#[test] +fn execute_candidate_bond_less_decreases_total() { + ExtBuilder::default().with_balances(vec![(1, 30)]).with_candidates(vec![(1, 30)]).build().execute_with(|| { + let mut total = ParachainStaking::total(); + assert_ok!(ParachainStaking::schedule_candidate_bond_less(RuntimeOrigin::signed(1), 10)); + roll_to(10); + assert_ok!(ParachainStaking::execute_candidate_bond_less(RuntimeOrigin::signed(1), 1)); + total -= 10; + assert_eq!(ParachainStaking::total(), total); + }); +} + +#[test] +fn execute_candidate_bond_less_updates_candidate_state() { + ExtBuilder::default().with_balances(vec![(1, 30)]).with_candidates(vec![(1, 30)]).build().execute_with(|| { + let candidate_state = ParachainStaking::candidate_info(1).expect("updated => exists"); + assert_eq!(candidate_state.bond, 30); + assert_ok!(ParachainStaking::schedule_candidate_bond_less(RuntimeOrigin::signed(1), 10)); + roll_to(10); + assert_ok!(ParachainStaking::execute_candidate_bond_less(RuntimeOrigin::signed(1), 1)); + let candidate_state = ParachainStaking::candidate_info(1).expect("updated => exists"); + assert_eq!(candidate_state.bond, 20); + }); +} + +#[test] +fn execute_candidate_bond_less_updates_candidate_pool() { + ExtBuilder::default().with_balances(vec![(1, 30)]).with_candidates(vec![(1, 30)]).build().execute_with(|| { + assert_eq!(ParachainStaking::candidate_pool().0[0].owner, 1); + assert_eq!(ParachainStaking::candidate_pool().0[0].amount, 30); + assert_ok!(ParachainStaking::schedule_candidate_bond_less(RuntimeOrigin::signed(1), 10)); + roll_to(10); + assert_ok!(ParachainStaking::execute_candidate_bond_less(RuntimeOrigin::signed(1), 1)); + assert_eq!(ParachainStaking::candidate_pool().0[0].owner, 1); + assert_eq!(ParachainStaking::candidate_pool().0[0].amount, 20); + }); +} + +// CANCEL CANDIDATE BOND LESS REQUEST + +#[test] +fn cancel_candidate_bond_less_emits_event() { + ExtBuilder::default().with_balances(vec![(1, 30)]).with_candidates(vec![(1, 30)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_candidate_bond_less(RuntimeOrigin::signed(1), 10)); + assert_ok!(ParachainStaking::cancel_candidate_bond_less(RuntimeOrigin::signed(1))); + assert_events_emitted!(Event::CancelledCandidateBondLess { candidate: 1, amount: 10, execute_round: 3 }); + }); +} + +#[test] +fn cancel_candidate_bond_less_updates_candidate_state() { + ExtBuilder::default().with_balances(vec![(1, 30)]).with_candidates(vec![(1, 30)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_candidate_bond_less(RuntimeOrigin::signed(1), 10)); + assert_ok!(ParachainStaking::cancel_candidate_bond_less(RuntimeOrigin::signed(1))); + assert!(ParachainStaking::candidate_info(&1).unwrap().request.is_none()); + }); +} + +#[test] +fn only_candidate_can_cancel_candidate_bond_less_request() { + ExtBuilder::default().with_balances(vec![(1, 30)]).with_candidates(vec![(1, 30)]).build().execute_with(|| { + assert_ok!(ParachainStaking::schedule_candidate_bond_less(RuntimeOrigin::signed(1), 10)); + assert_noop!( + ParachainStaking::cancel_candidate_bond_less(RuntimeOrigin::signed(2)), + Error::::CandidateDNE + ); + }); +} + +// DELEGATE + +#[test] +fn delegate_event_emits_correctly() { + ExtBuilder::default().with_balances(vec![(1, 30), (2, 10)]).with_candidates(vec![(1, 30)]).build().execute_with( + || { + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(2), 1, 10, 0, 0)); + assert_events_eq!(Event::Delegation { + delegator: 2, + locked_amount: 10, + candidate: 1, + delegator_position: DelegatorAdded::AddedToTop { new_total: 40 }, + auto_compound: Percent::zero(), + }); + }, + ); +} + +#[test] +fn delegate_reserves_balance() { + ExtBuilder::default().with_balances(vec![(1, 30), (2, 10)]).with_candidates(vec![(1, 30)]).build().execute_with( + || { + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&2), 10); + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(2), 1, 10, 0, 0)); + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&2), 0); + }, + ); +} + +#[test] +fn delegate_updates_delegator_state() { + ExtBuilder::default().with_balances(vec![(1, 30), (2, 10)]).with_candidates(vec![(1, 30)]).build().execute_with( + || { + assert!(ParachainStaking::delegator_state(2).is_none()); + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(2), 1, 10, 0, 0)); + let delegator_state = ParachainStaking::delegator_state(2).expect("just delegated => exists"); + assert_eq!(delegator_state.total(), 10); + assert_eq!(delegator_state.delegations.0[0].owner, 1); + assert_eq!(delegator_state.delegations.0[0].amount, 10); + }, + ); +} + +#[test] +fn delegate_updates_collator_state() { + ExtBuilder::default().with_balances(vec![(1, 30), (2, 10)]).with_candidates(vec![(1, 30)]).build().execute_with( + || { + let candidate_state = ParachainStaking::candidate_info(1).expect("registered in genesis"); + assert_eq!(candidate_state.total_counted, 30); + let top_delegations = ParachainStaking::top_delegations(1).expect("registered in genesis"); + assert!(top_delegations.delegations.is_empty()); + assert!(top_delegations.total.is_zero()); + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(2), 1, 10, 0, 0)); + let candidate_state = ParachainStaking::candidate_info(1).expect("just delegated => exists"); + assert_eq!(candidate_state.total_counted, 40); + let top_delegations = ParachainStaking::top_delegations(1).expect("just delegated => exists"); + assert_eq!(top_delegations.delegations[0].owner, 2); + assert_eq!(top_delegations.delegations[0].amount, 10); + assert_eq!(top_delegations.total, 10); + }, + ); +} + +#[test] +fn can_delegate_immediately_after_other_join_candidates() { + ExtBuilder::default().with_balances(vec![(1, 20), (2, 20)]).build().execute_with(|| { + assert_ok!(ParachainStaking::join_candidates(RuntimeOrigin::signed(1), 20, 0)); + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(2), 1, 20, 0, 0)); + }); +} + +#[test] +fn can_delegate_if_revoking() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (2, 30), (3, 20), (4, 20)]) + .with_candidates(vec![(1, 20), (3, 20), (4, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(2), 4, 10, 0, 2)); + }); +} + +#[test] +fn cannot_delegate_if_full_and_new_delegation_less_than_or_equal_lowest_bottom() { + ExtBuilder::default() + .with_balances(vec![ + (1, 20), + (2, 10), + (3, 10), + (4, 10), + (5, 10), + (6, 10), + (7, 10), + (8, 10), + (9, 10), + (10, 10), + (11, 10), + ]) + .with_candidates(vec![(1, 20)]) + .with_delegations(vec![ + (2, 1, 10), + (3, 1, 10), + (4, 1, 10), + (5, 1, 10), + (6, 1, 10), + (8, 1, 10), + (9, 1, 10), + (10, 1, 10), + ]) + .build() + .execute_with(|| { + assert_noop!( + ParachainStaking::delegate(RuntimeOrigin::signed(11), 1, 10, 8, 0), + Error::::CannotDelegateLessThanOrEqualToLowestBottomWhenFull + ); + }); +} + +#[test] +fn can_delegate_if_full_and_new_delegation_greater_than_lowest_bottom() { + ExtBuilder::default() + .with_balances(vec![ + (1, 20), + (2, 10), + (3, 10), + (4, 10), + (5, 10), + (6, 10), + (7, 10), + (8, 10), + (9, 10), + (10, 10), + (11, 11), + ]) + .with_candidates(vec![(1, 20)]) + .with_delegations(vec![ + (2, 1, 10), + (3, 1, 10), + (4, 1, 10), + (5, 1, 10), + (6, 1, 10), + (8, 1, 10), + (9, 1, 10), + (10, 1, 10), + ]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(11), 1, 11, 8, 0)); + assert_events_emitted!(Event::DelegationKicked { delegator: 10, candidate: 1, unstaked_amount: 10 }); + assert_events_emitted!(Event::DelegatorLeft { delegator: 10, unstaked_amount: 10 }); + }); +} + +#[test] +fn can_still_delegate_if_leaving() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (2, 20), (3, 20)]) + .with_candidates(vec![(1, 20), (3, 20)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(2), 3, 10, 0, 1),); + }); +} + +#[test] +fn cannot_delegate_if_candidate() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (2, 30)]) + .with_candidates(vec![(1, 20), (2, 20)]) + .build() + .execute_with(|| { + assert_noop!( + ParachainStaking::delegate(RuntimeOrigin::signed(2), 1, 10, 0, 0), + Error::::CandidateExists + ); + }); +} + +#[test] +fn cannot_delegate_if_already_delegated() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (2, 30)]) + .with_candidates(vec![(1, 20)]) + .with_delegations(vec![(2, 1, 20)]) + .build() + .execute_with(|| { + assert_noop!( + ParachainStaking::delegate(RuntimeOrigin::signed(2), 1, 10, 1, 1), + Error::::AlreadyDelegatedCandidate + ); + }); +} + +#[test] +fn cannot_delegate_more_than_max_delegations() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (2, 50), (3, 20), (4, 20), (5, 20), (6, 20)]) + .with_candidates(vec![(1, 20), (3, 20), (4, 20), (5, 20), (6, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10), (2, 4, 10), (2, 5, 10)]) + .build() + .execute_with(|| { + assert_noop!( + ParachainStaking::delegate(RuntimeOrigin::signed(2), 6, 10, 0, 4), + Error::::ExceedMaxDelegationsPerDelegator, + ); + }); +} + +#[test] +fn sufficient_delegate_weight_hint_succeeds() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 20), (6, 20), (7, 20), (8, 20), (9, 20), (10, 20)]) + .with_candidates(vec![(1, 20), (2, 20)]) + .with_delegations(vec![(3, 1, 10), (4, 1, 10), (5, 1, 10), (6, 1, 10)]) + .build() + .execute_with(|| { + let mut count = 4u32; + for i in 7..11 { + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(i), 1, 10, count, 0u32)); + count += 1u32; + } + let mut count = 0u32; + for i in 3..11 { + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(i), 2, 10, count, 1u32)); + count += 1u32; + } + }); +} + +#[test] +fn insufficient_delegate_weight_hint_fails() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 20), (6, 20), (7, 20), (8, 20), (9, 20), (10, 20)]) + .with_candidates(vec![(1, 20), (2, 20)]) + .with_delegations(vec![(3, 1, 10), (4, 1, 10), (5, 1, 10), (6, 1, 10)]) + .build() + .execute_with(|| { + let mut count = 3u32; + for i in 7..11 { + assert_noop!( + ParachainStaking::delegate(RuntimeOrigin::signed(i), 1, 10, count, 0u32), + Error::::TooLowCandidateDelegationCountToDelegate + ); + } + // to set up for next error test + count = 4u32; + for i in 7..11 { + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(i), 1, 10, count, 0u32)); + count += 1u32; + } + count = 0u32; + for i in 3..11 { + assert_noop!( + ParachainStaking::delegate(RuntimeOrigin::signed(i), 2, 10, count, 0u32), + Error::::TooLowDelegationCountToDelegate + ); + count += 1u32; + } + }); +} + +// SCHEDULE LEAVE DELEGATORS + +#[test] +fn schedule_leave_delegators_event_emits_correctly() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + assert_events_eq!(Event::DelegatorExitScheduled { round: 1, delegator: 2, scheduled_exit: 3 }); + }); +} + +#[test] +fn cannot_schedule_leave_delegators_if_already_leaving() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + assert_noop!( + ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2)), + Error::::DelegatorAlreadyLeaving + ); + }); +} + +#[test] +fn cannot_schedule_leave_delegators_if_not_delegator() { + ExtBuilder::default().with_balances(vec![(1, 30), (2, 10)]).with_candidates(vec![(1, 30)]).build().execute_with( + || { + assert_noop!( + ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2)), + Error::::DelegatorDNE + ); + }, + ); +} + +// EXECUTE LEAVE DELEGATORS + +#[test] +fn execute_leave_delegators_event_emits_correctly() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(2), 2, 1)); + assert_events_emitted!(Event::DelegatorLeft { delegator: 2, unstaked_amount: 10 }); + }); +} + +#[test] +fn execute_leave_delegators_unreserves_balance() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&2), 00); + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(2), 2, 1)); + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&2), 10); + assert_eq!(crate::mock::query_lock_amount(2, DELEGATOR_LOCK_ID), None); + }); +} + +#[test] +fn execute_leave_delegators_decreases_total_staked() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_eq!(ParachainStaking::total(), 40); + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(2), 2, 1)); + assert_eq!(ParachainStaking::total(), 30); + }); +} + +#[test] +fn execute_leave_delegators_removes_delegator_state() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert!(ParachainStaking::delegator_state(2).is_some()); + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(2), 2, 1)); + assert!(ParachainStaking::delegator_state(2).is_none()); + }); +} + +#[test] +fn execute_leave_delegators_removes_pending_delegation_requests() { + ExtBuilder::default() + .with_balances(vec![(1, 10), (2, 15)]) + .with_candidates(vec![(1, 10)]) + .with_delegations(vec![(2, 1, 15)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 5)); + let state = ParachainStaking::delegation_scheduled_requests(&1); + assert_eq!( + state, + vec![ScheduledRequest { delegator: 2, when_executable: 3, action: DelegationAction::Decrease(5) }], + ); + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(2), 2, 1)); + assert!(ParachainStaking::delegator_state(2).is_none()); + assert!( + !ParachainStaking::delegation_scheduled_requests(&1).iter().any(|x| x.delegator == 2), + "delegation request not removed" + ) + }); +} + +#[test] +fn execute_leave_delegators_removes_delegations_from_collator_state() { + ExtBuilder::default() + .with_balances(vec![(1, 100), (2, 20), (3, 20), (4, 20), (5, 20)]) + .with_candidates(vec![(2, 20), (3, 20), (4, 20), (5, 20)]) + .with_delegations(vec![(1, 2, 10), (1, 3, 10), (1, 4, 10), (1, 5, 10)]) + .build() + .execute_with(|| { + for i in 2..6 { + let candidate_state = ParachainStaking::candidate_info(i).expect("initialized in ext builder"); + assert_eq!(candidate_state.total_counted, 30); + let top_delegations = ParachainStaking::top_delegations(i).expect("initialized in ext builder"); + assert_eq!(top_delegations.delegations[0].owner, 1); + assert_eq!(top_delegations.delegations[0].amount, 10); + assert_eq!(top_delegations.total, 10); + } + assert_eq!(ParachainStaking::delegator_state(1).unwrap().delegations.0.len(), 4usize); + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(1))); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(1), 1, 10)); + for i in 2..6 { + let candidate_state = ParachainStaking::candidate_info(i).expect("initialized in ext builder"); + assert_eq!(candidate_state.total_counted, 20); + let top_delegations = ParachainStaking::top_delegations(i).expect("initialized in ext builder"); + assert!(top_delegations.delegations.is_empty()); + } + }); +} + +#[test] +fn cannot_execute_leave_delegators_before_delay() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + assert_noop!( + ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(2), 2, 1), + Error::::DelegatorCannotLeaveYet + ); + // can execute after delay + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(2), 2, 1)); + }); +} + +#[test] +fn cannot_execute_leave_delegators_if_single_delegation_revoke_manually_cancelled() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 20), (3, 30)]) + .with_candidates(vec![(1, 30), (3, 30)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + assert_ok!(ParachainStaking::cancel_delegation_request(RuntimeOrigin::signed(2), 3)); + roll_to(10); + assert_noop!( + ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(2), 2, 2), + Error::::DelegatorNotLeaving + ); + // can execute after manually scheduling revoke, and the round delay after which + // all revokes can be executed + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 3)); + roll_to(20); + assert_ok!(ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(2), 2, 2)); + }); +} + +#[test] +fn insufficient_execute_leave_delegators_weight_hint_fails() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 20), (6, 20)]) + .with_candidates(vec![(1, 20)]) + .with_delegations(vec![(3, 1, 10), (4, 1, 10), (5, 1, 10), (6, 1, 10)]) + .build() + .execute_with(|| { + for i in 3..7 { + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(i))); + } + roll_to(10); + for i in 3..7 { + assert_noop!( + ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(i), i, 0), + Error::::TooLowDelegationCountToLeaveDelegators + ); + } + }); +} + +#[test] +fn sufficient_execute_leave_delegators_weight_hint_succeeds() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 20), (6, 20)]) + .with_candidates(vec![(1, 20)]) + .with_delegations(vec![(3, 1, 10), (4, 1, 10), (5, 1, 10), (6, 1, 10)]) + .build() + .execute_with(|| { + for i in 3..7 { + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(i))); + } + roll_to(10); + for i in 3..7 { + assert_ok!(ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(i), i, 1)); + } + }); +} -use std::{convert::TryInto, iter}; +// CANCEL LEAVE DELEGATORS -use frame_support::{ - assert_noop, assert_ok, storage::bounded_btree_map::BoundedBTreeMap, traits::EstimateNextSessionRotation, - BoundedVec, -}; -use pallet_authorship::EventHandler; -use pallet_balances::{BalanceLock, Error as BalancesError, Reasons}; -use pallet_session::{SessionManager, ShouldEndSession}; -use sp_runtime::{traits::Zero, Perbill, Permill, Perquintill, SaturatedConversion}; +#[test] +fn cancel_leave_delegators_emits_correct_event() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + assert_ok!(ParachainStaking::cancel_leave_delegators(RuntimeOrigin::signed(2))); + assert_events_emitted!(Event::DelegatorExitCancelled { delegator: 2 }); + }); +} + +#[test] +fn cancel_leave_delegators_updates_delegator_state() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + assert_ok!(ParachainStaking::cancel_leave_delegators(RuntimeOrigin::signed(2))); + let delegator = ParachainStaking::delegator_state(&2).expect("just cancelled exit so exists"); + assert!(delegator.is_active()); + }); +} + +#[test] +fn cannot_cancel_leave_delegators_if_single_delegation_revoke_manually_cancelled() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 20), (3, 30)]) + .with_candidates(vec![(1, 30), (3, 30)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + assert_ok!(ParachainStaking::cancel_delegation_request(RuntimeOrigin::signed(2), 3)); + roll_to(10); + assert_noop!( + ParachainStaking::cancel_leave_delegators(RuntimeOrigin::signed(2)), + Error::::DelegatorNotLeaving + ); + // can execute after manually scheduling revoke, without waiting for round delay after + // which all revokes can be executed + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 3)); + assert_ok!(ParachainStaking::cancel_leave_delegators(RuntimeOrigin::signed(2))); + }); +} + +// SCHEDULE REVOKE DELEGATION + +#[test] +fn revoke_delegation_event_emits_correctly() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 20), (3, 30)]) + .with_candidates(vec![(1, 30), (3, 30)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + assert_events_eq!(Event::DelegationRevocationScheduled { + round: 1, + delegator: 2, + candidate: 1, + scheduled_exit: 3, + }); + roll_to_round_begin(3); + roll_blocks(1); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert_events_eq!( + Event::DelegatorLeftCandidate { + delegator: 2, + candidate: 1, + unstaked_amount: 10, + total_candidate_staked: 30 + }, + Event::DelegationRevoked { delegator: 2, candidate: 1, unstaked_amount: 10 }, + ); + }); +} + +#[test] +fn can_revoke_delegation_if_revoking_another_delegation() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 20), (3, 20)]) + .with_candidates(vec![(1, 30), (3, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + // this is an exit implicitly because last delegation revoked + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 3)); + }); +} + +#[test] +fn delegator_not_allowed_revoke_if_already_leaving() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 20), (3, 20)]) + .with_candidates(vec![(1, 30), (3, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + assert_noop!( + ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 3), + >::PendingDelegationRequestAlreadyExists, + ); + }); +} + +#[test] +fn cannot_revoke_delegation_if_not_delegator() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1), + Error::::DelegatorDNE + ); + }); +} + +#[test] +fn cannot_revoke_delegation_that_dne() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_noop!( + ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 3), + Error::::DelegationDNE + ); + }); +} + +#[test] +// See `cannot_execute_revoke_delegation_below_min_delegator_stake` for where the "must be above +// MinDelegatorStk" rule is now enforced. +fn can_schedule_revoke_delegation_below_min_delegator_stake() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (2, 8), (3, 20)]) + .with_candidates(vec![(1, 20), (3, 20)]) + .with_delegations(vec![(2, 1, 5), (2, 3, 3)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + }); +} + +// DELEGATOR BOND MORE + +#[test] +fn delegator_bond_more_reserves_balance() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 15)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&2), 5); + assert_ok!(ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(2), 1, 5)); + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&2), 0); + }); +} + +#[test] +fn delegator_bond_more_increases_total_staked() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 15)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_eq!(ParachainStaking::total(), 40); + assert_ok!(ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(2), 1, 5)); + assert_eq!(ParachainStaking::total(), 45); + }); +} + +#[test] +fn delegator_bond_more_updates_delegator_state() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 15)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_eq!(ParachainStaking::delegator_state(2).expect("exists").total(), 10); + assert_ok!(ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(2), 1, 5)); + assert_eq!(ParachainStaking::delegator_state(2).expect("exists").total(), 15); + }); +} + +#[test] +fn delegator_bond_more_updates_candidate_state_top_delegations() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 15)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_eq!(ParachainStaking::top_delegations(1).unwrap().delegations[0].owner, 2); + assert_eq!(ParachainStaking::top_delegations(1).unwrap().delegations[0].amount, 10); + assert_eq!(ParachainStaking::top_delegations(1).unwrap().total, 10); + assert_ok!(ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(2), 1, 5)); + assert_eq!(ParachainStaking::top_delegations(1).unwrap().delegations[0].owner, 2); + assert_eq!(ParachainStaking::top_delegations(1).unwrap().delegations[0].amount, 15); + assert_eq!(ParachainStaking::top_delegations(1).unwrap().total, 15); + }); +} + +#[test] +fn delegator_bond_more_updates_candidate_state_bottom_delegations() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 20), (3, 20), (4, 20), (5, 20), (6, 20)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10), (3, 1, 20), (4, 1, 20), (5, 1, 20), (6, 1, 20)]) + .build() + .execute_with(|| { + assert_eq!(ParachainStaking::bottom_delegations(1).expect("exists").delegations[0].owner, 2); + assert_eq!(ParachainStaking::bottom_delegations(1).expect("exists").delegations[0].amount, 10); + assert_eq!(ParachainStaking::bottom_delegations(1).unwrap().total, 10); + assert_ok!(ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(2), 1, 5)); + assert_events_eq!(Event::DelegationIncreased { delegator: 2, candidate: 1, amount: 5, in_top: false }); + assert_eq!(ParachainStaking::bottom_delegations(1).expect("exists").delegations[0].owner, 2); + assert_eq!(ParachainStaking::bottom_delegations(1).expect("exists").delegations[0].amount, 15); + assert_eq!(ParachainStaking::bottom_delegations(1).unwrap().total, 15); + }); +} + +#[test] +fn delegator_bond_more_increases_total() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 15)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_eq!(ParachainStaking::total(), 40); + assert_ok!(ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(2), 1, 5)); + assert_eq!(ParachainStaking::total(), 45); + }); +} + +#[test] +fn can_delegator_bond_more_for_leaving_candidate() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 15)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1)); + assert_ok!(ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(2), 1, 5)); + }); +} + +#[test] +fn delegator_bond_more_disallowed_when_revoke_scheduled() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 25)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + assert_noop!( + ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(2), 1, 5), + >::PendingDelegationRevoke + ); + }); +} + +#[test] +fn delegator_bond_more_allowed_when_bond_decrease_scheduled() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 25)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 15)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 5,)); + assert_ok!(ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(2), 1, 5)); + }); +} + +// DELEGATOR BOND LESS + +#[test] +fn delegator_bond_less_event_emits_correctly() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 5)); + assert_events_eq!(Event::DelegationDecreaseScheduled { + delegator: 2, + candidate: 1, + amount_to_decrease: 5, + execute_round: 3, + }); + }); +} + +#[test] +fn delegator_bond_less_updates_delegator_state() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 5)); + let state = ParachainStaking::delegation_scheduled_requests(&1); + assert_eq!( + state, + vec![ScheduledRequest { delegator: 2, when_executable: 3, action: DelegationAction::Decrease(5) }], + ); + }); +} + +#[test] +fn delegator_not_allowed_bond_less_if_leaving() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 15)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + assert_noop!( + ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 1), + >::PendingDelegationRequestAlreadyExists, + ); + }); +} + +#[test] +fn cannot_delegator_bond_less_if_revoking() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 25), (3, 20)]) + .with_candidates(vec![(1, 30), (3, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + assert_noop!( + ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 1), + Error::::PendingDelegationRequestAlreadyExists + ); + }); +} + +#[test] +fn cannot_delegator_bond_less_if_not_delegator() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 5), + Error::::DelegatorDNE + ); + }); +} + +#[test] +fn cannot_delegator_bond_less_if_candidate_dne() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_noop!( + ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 3, 5), + Error::::DelegationDNE + ); + }); +} + +#[test] +fn cannot_delegator_bond_less_if_delegation_dne() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10), (3, 30)]) + .with_candidates(vec![(1, 30), (3, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_noop!( + ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 3, 5), + Error::::DelegationDNE + ); + }); +} + +#[test] +fn cannot_delegator_bond_less_below_min_collator_stk() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_noop!( + ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 6), + Error::::DelegatorBondBelowMin + ); + }); +} + +#[test] +fn cannot_delegator_bond_less_more_than_total_delegation() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_noop!( + ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 11), + Error::::DelegatorBondBelowMin + ); + }); +} + +#[test] +fn cannot_delegator_bond_less_below_min_delegation() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 20), (3, 30)]) + .with_candidates(vec![(1, 30), (3, 30)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) + .build() + .execute_with(|| { + assert_noop!( + ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 8), + Error::::DelegationBelowMin + ); + }); +} + +// EXECUTE PENDING DELEGATION REQUEST + +// 1. REVOKE DELEGATION + +#[test] +fn execute_revoke_delegation_emits_exit_event_if_exit_happens() { + // last delegation is revocation + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + roll_to(10); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert_events_emitted!(Event::DelegatorLeftCandidate { + delegator: 2, + candidate: 1, + unstaked_amount: 10, + total_candidate_staked: 30 + }); + assert_events_emitted!(Event::DelegatorLeft { delegator: 2, unstaked_amount: 10 }); + }); +} + +#[test] +fn cannot_execute_revoke_delegation_below_min_delegator_stake() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (2, 8), (3, 20)]) + .with_candidates(vec![(1, 20), (3, 20)]) + .with_delegations(vec![(2, 1, 5), (2, 3, 3)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + roll_to(10); + assert_noop!( + ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1), + Error::::DelegatorBondBelowMin + ); + // but delegator can cancel the request and request to leave instead: + assert_ok!(ParachainStaking::cancel_delegation_request(RuntimeOrigin::signed(2), 1)); + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + roll_to(20); + assert_ok!(ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(2), 2, 2)); + }); +} + +#[test] +fn revoke_delegation_executes_exit_if_last_delegation() { + // last delegation is revocation + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + roll_to(10); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert_events_emitted!(Event::DelegatorLeftCandidate { + delegator: 2, + candidate: 1, + unstaked_amount: 10, + total_candidate_staked: 30 + }); + assert_events_emitted!(Event::DelegatorLeft { delegator: 2, unstaked_amount: 10 }); + }); +} -use kilt_runtime_api_staking::StakingRates; +#[test] +fn execute_revoke_delegation_emits_correct_event() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 20), (3, 30)]) + .with_candidates(vec![(1, 30), (3, 30)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + roll_to(10); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert_events_emitted!(Event::DelegatorLeftCandidate { + delegator: 2, + candidate: 1, + unstaked_amount: 10, + total_candidate_staked: 30 + }); + }); +} -use crate::{ - mock::{ - almost_equal, events, last_event, roll_to, roll_to_claim_rewards, AccountId, Balance, Balances, BlockNumber, - ExtBuilder, RuntimeOrigin, Session, StakePallet, System, Test, BLOCKS_PER_ROUND, DECIMALS, TREASURY_ACC, - }, - set::OrderedSet, - types::{ - BalanceOf, Candidate, CandidateStatus, DelegationCounter, Delegator, RoundInfo, Stake, StakeOf, TotalStake, - }, - CandidatePool, Config, Error, Event, Event as StakeEvent, InflationInfo, RewardRate, StakingInfo, STAKING_ID, -}; +#[test] +fn execute_revoke_delegation_unreserves_balance() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&2), 0); + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + roll_to(10); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&2), 10); + }); +} #[test] -fn should_select_collators_genesis_session() { +fn execute_revoke_delegation_adds_revocation_to_delegator_state() { ExtBuilder::default() - .with_balances(vec![ - (1, 20), - (2, 20), - (3, 20), - (4, 20), - (5, 20), - (6, 20), - (7, 20), - (8, 20), - (9, 20), - (10, 20), - (11, 20), - ]) - .with_collators(vec![(1, 20), (2, 20)]) + .with_balances(vec![(1, 30), (2, 20), (3, 20)]) + .with_candidates(vec![(1, 30), (3, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) .build() .execute_with(|| { - assert_eq!( - StakePallet::new_session(0) - .expect("first session must return new collators") - .len(), - 2 - ); - assert_eq!( - StakePallet::new_session(1) - .expect("second session must return new collators") - .len(), - 2 - ); + assert!(!ParachainStaking::delegation_scheduled_requests(&1).iter().any(|x| x.delegator == 2)); + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + assert!(ParachainStaking::delegation_scheduled_requests(&1).iter().any(|x| x.delegator == 2)); }); } #[test] -fn genesis() { +fn execute_revoke_delegation_removes_revocation_from_delegator_state_upon_execution() { ExtBuilder::default() - .with_balances(vec![ - (1, 1000), - (2, 300), - (3, 100), - (4, 100), - (5, 100), - (6, 100), - (7, 100), - (8, 9), - (9, 4), - ]) - .with_collators(vec![(1, 500), (2, 200)]) - .with_delegators(vec![(3, 1, 100), (4, 1, 100), (5, 2, 100), (6, 2, 100)]) + .with_balances(vec![(1, 30), (2, 20), (3, 20)]) + .with_candidates(vec![(1, 30), (3, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) .build() .execute_with(|| { - assert!(System::events().is_empty()); + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + roll_to(10); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert!(!ParachainStaking::delegation_scheduled_requests(&1).iter().any(|x| x.delegator == 2)); + }); +} - // Collators - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 700, - delegators: 400 - } - ); - assert_eq!( - vec![ - StakeOf:: { owner: 1, amount: 700 }, - StakeOf:: { owner: 2, amount: 400 } - ] - .try_into(), - Ok(StakePallet::top_candidates().into_bounded_vec()) - ); - assert_eq!(CandidatePool::::count(), 2); - - // 1 - assert_eq!(Balances::usable_balance(&1), 500); - assert_eq!(Balances::free_balance(&1), 1000); - assert!(StakePallet::is_active_candidate(&1).is_some()); - assert_eq!( - StakePallet::candidate_pool(&1), - Some( - Candidate::::MaxDelegatorsPerCollator> { - id: 1, - stake: 500, - delegators: OrderedSet::from_sorted_set( - vec![ - StakeOf:: { owner: 3, amount: 100 }, - StakeOf:: { owner: 4, amount: 100 } - ] - .try_into() - .unwrap() - ), - total: 700, - status: CandidateStatus::Active, - } - ) - ); - // 2 - assert_eq!(Balances::usable_balance(&2), 100); - assert_eq!(Balances::free_balance(&2), 300); - assert!(StakePallet::is_active_candidate(&2).is_some()); - assert_eq!( - StakePallet::candidate_pool(&2), - Some( - Candidate::::MaxDelegatorsPerCollator> { - id: 2, - stake: 200, - delegators: OrderedSet::from_sorted_set( - vec![ - StakeOf:: { owner: 5, amount: 100 }, - StakeOf:: { owner: 6, amount: 100 } - ] - .try_into() - .unwrap() - ), - total: 400, - status: CandidateStatus::Active, - } - ) - ); - // Delegators - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 700, - delegators: 400 - } - ); - for x in 3..7 { - assert!(StakePallet::is_delegator(&x)); - assert_eq!(Balances::usable_balance(&x), 0); - assert_eq!(Balances::free_balance(&x), 100); - } - // Uninvolved - for x in 7..10 { - assert!(!StakePallet::is_delegator(&x)); - } - assert_eq!(Balances::free_balance(&7), 100); - assert_eq!(Balances::usable_balance(&7), 100); - assert_eq!(Balances::free_balance(&8), 9); - assert_eq!(Balances::usable_balance(&8), 9); - assert_eq!(Balances::free_balance(&9), 4); - assert_eq!(Balances::usable_balance(&9), 4); - - // Safety first checks - assert_eq!( - StakePallet::max_selected_candidates(), - ::MinCollators::get() - ); - assert_eq!( - StakePallet::round(), - RoundInfo::new(0u32, 0u32.into(), ::DefaultBlocksPerRound::get()) +#[test] +fn execute_revoke_delegation_removes_revocation_from_state_for_single_delegation_leave() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 20), (3, 20)]) + .with_candidates(vec![(1, 30), (3, 20)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + roll_to(10); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert!( + !ParachainStaking::delegation_scheduled_requests(&1).iter().any(|x| x.delegator == 2), + "delegation was not removed" ); }); +} + +#[test] +fn execute_revoke_delegation_decreases_total_staked() { ExtBuilder::default() - .with_balances(vec![ - (1, 100), - (2, 100), - (3, 100), - (4, 100), - (5, 100), - (6, 100), - (7, 100), - (8, 100), - (9, 100), - (10, 100), - ]) - .with_collators(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 10)]) - .with_delegators(vec![(6, 1, 10), (7, 1, 10), (8, 2, 10), (9, 2, 10), (10, 1, 10)]) + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) .build() .execute_with(|| { - assert!(System::events().is_empty()); - assert_eq!(CandidatePool::::count(), 5); + assert_eq!(ParachainStaking::total(), 40); + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + roll_to(10); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert_eq!(ParachainStaking::total(), 30); + }); +} - // Collators - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 40, - delegators: 50 - } - ); - assert_eq!( - Ok(StakePallet::top_candidates().into_bounded_vec()), - vec![ - StakeOf:: { owner: 1, amount: 50 }, - StakeOf:: { owner: 2, amount: 40 }, - StakeOf:: { owner: 3, amount: 20 }, - StakeOf:: { owner: 4, amount: 20 }, - StakeOf:: { owner: 5, amount: 10 } - ] - .try_into() - ); - for x in 1..5 { - assert!(StakePallet::is_active_candidate(&x).is_some()); - assert_eq!(Balances::free_balance(&x), 100); - assert_eq!(Balances::usable_balance(&x), 80); - } - assert!(StakePallet::is_active_candidate(&5).is_some()); - assert_eq!(Balances::free_balance(&5), 100); - assert_eq!(Balances::usable_balance(&5), 90); - // Delegators - for x in 6..11 { - assert!(StakePallet::is_delegator(&x)); - assert_eq!(Balances::free_balance(&x), 100); - assert_eq!(Balances::usable_balance(&x), 90); - } +#[test] +fn execute_revoke_delegation_for_last_delegation_removes_delegator_state() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert!(ParachainStaking::delegator_state(2).is_some()); + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + roll_to(10); + // this will be confusing for people + // if status is leaving, then execute_delegation_request works if last delegation + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert!(ParachainStaking::delegator_state(2).is_none()); + }); +} - // Safety first checks - assert_eq!( - StakePallet::max_selected_candidates(), - ::MinCollators::get() - ); - assert_eq!( - StakePallet::round(), - RoundInfo::new(0, 0, ::DefaultBlocksPerRound::get()) - ); +#[test] +fn execute_revoke_delegation_removes_delegation_from_candidate_state() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_eq!(ParachainStaking::candidate_info(1).expect("exists").delegation_count, 1u32); + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + roll_to(10); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert!(ParachainStaking::candidate_info(1).expect("exists").delegation_count.is_zero()); }); } #[test] -fn join_collator_candidates() { +fn can_execute_revoke_delegation_for_leaving_candidate() { ExtBuilder::default() - .with_balances(vec![ - (1, 1000), - (2, 300), - (3, 100), - (4, 100), - (5, 100), - (6, 100), - (7, 100), - (8, 9), - (9, 4), - (10, 161_000_000 * DECIMALS), - ]) - .with_collators(vec![(1, 500), (2, 200)]) - .with_delegators(vec![(3, 1, 100), (4, 1, 100), (5, 2, 100), (6, 2, 100)]) + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) .build() .execute_with(|| { - assert_eq!(CandidatePool::::count(), 2); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 700, - delegators: 400 - } - ); - assert_noop!( - StakePallet::join_candidates(RuntimeOrigin::signed(1), 11u128,), - Error::::CandidateExists - ); - assert_noop!( - StakePallet::join_delegators(RuntimeOrigin::signed(1), 1, 11u128,), - Error::::CandidateExists - ); - assert_noop!( - StakePallet::join_candidates(RuntimeOrigin::signed(3), 11u128,), - Error::::DelegatorExists - ); - assert_noop!( - StakePallet::join_candidates(RuntimeOrigin::signed(7), 9u128,), - Error::::ValStakeBelowMin - ); - assert_noop!( - StakePallet::join_candidates(RuntimeOrigin::signed(8), 10u128,), - BalancesError::::InsufficientBalance - ); + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1)); + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + roll_to(10); + // can execute delegation request for leaving candidate + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + }); +} - assert_eq!(CandidatePool::::count(), 2); - assert!(System::events().is_empty()); +#[test] +fn can_execute_leave_candidates_if_revoking_candidate() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1)); + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + roll_to(10); + // revocation executes during execute leave candidates (callable by anyone) + assert_ok!(ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(1), 1, 1)); + assert!(!ParachainStaking::is_delegator(&2)); + assert_eq!(Balances::reserved_balance(&2), 0); + assert_eq!(Balances::free_balance(&2), 10); + }); +} - assert_ok!(StakePallet::set_max_selected_candidates(RuntimeOrigin::root(), 5)); - assert_ok!(StakePallet::join_candidates(RuntimeOrigin::signed(7), 10u128,)); - assert_eq!(last_event(), StakeEvent::JoinedCollatorCandidates(7, 10u128)); +#[test] +fn delegator_bond_more_after_revoke_delegation_does_not_effect_exit() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 30), (3, 30)]) + .with_candidates(vec![(1, 30), (3, 30)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + assert_ok!(ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(2), 3, 10)); + roll_to(100); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert!(ParachainStaking::is_delegator(&2)); + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&2), 10); + }); +} - // MaxCollatorCandidateStake +#[test] +fn delegator_bond_less_after_revoke_delegation_does_not_effect_exit() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 30), (3, 30)]) + .with_candidates(vec![(1, 30), (3, 30)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + assert_events_eq!(Event::DelegationRevocationScheduled { + round: 1, + delegator: 2, + candidate: 1, + scheduled_exit: 3, + }); assert_noop!( - StakePallet::join_candidates(RuntimeOrigin::signed(10), 161_000_000 * DECIMALS), - Error::::ValStakeAboveMax + ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 2), + Error::::PendingDelegationRequestAlreadyExists + ); + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 3, 2)); + roll_to(10); + roll_blocks(1); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 3)); + assert_events_eq!( + Event::DelegatorLeftCandidate { + delegator: 2, + candidate: 1, + unstaked_amount: 10, + total_candidate_staked: 30, + }, + Event::DelegationRevoked { delegator: 2, candidate: 1, unstaked_amount: 10 }, + Event::DelegationDecreased { delegator: 2, candidate: 3, amount: 2, in_top: true }, ); - assert_ok!(StakePallet::join_candidates( - RuntimeOrigin::signed(10), - StakePallet::max_candidate_stake() - )); - assert_eq!(CandidatePool::::count(), 4); + assert!(ParachainStaking::is_delegator(&2)); + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&2), 22); + }); +} - assert_eq!( - last_event(), - StakeEvent::JoinedCollatorCandidates(10, StakePallet::max_candidate_stake(),) - ); +// 2. EXECUTE BOND LESS + +#[test] +fn execute_delegator_bond_less_unreserves_balance() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&2), 0); + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 5)); + roll_to(10); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&2), 5); }); } #[test] -fn collator_exit_executes_after_delay() { +fn execute_delegator_bond_less_decreases_total_staked() { ExtBuilder::default() - .with_balances(vec![ - (1, 1000), - (2, 300), - (3, 110), - (4, 100), - (5, 100), - (6, 100), - (7, 100), - (8, 9), - (9, 4), - (10, 10), - ]) - .with_collators(vec![(1, 500), (2, 200), (7, 100)]) - .with_delegators(vec![(3, 1, 100), (4, 1, 100), (5, 2, 100), (6, 2, 100)]) + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) .build() .execute_with(|| { - assert_eq!(CandidatePool::::count(), 3); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 700, - delegators: 400 - } - ); - assert_ok!(StakePallet::set_max_selected_candidates(RuntimeOrigin::root(), 5)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 800, - delegators: 400 - } - ); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 7]); - roll_to(4, vec![]); - assert_noop!( - StakePallet::init_leave_candidates(RuntimeOrigin::signed(3)), - Error::::CandidateNotFound - ); + assert_eq!(ParachainStaking::total(), 40); + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 5)); + roll_to(10); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert_eq!(ParachainStaking::total(), 35); + }); +} - roll_to(11, vec![]); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(2))); - // Still three, candidate didn't leave yet - assert_eq!(CandidatePool::::count(), 3); - assert_noop!( - StakePallet::join_delegators(RuntimeOrigin::signed(10), 2, 10), - Error::::CannotDelegateIfLeaving - ); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 7]); - assert_eq!(last_event(), StakeEvent::CollatorScheduledExit(2, 2, 4)); - let info = StakePallet::candidate_pool(&2).unwrap(); - assert_eq!(info.status, CandidateStatus::Leaving(4)); +#[test] +fn execute_delegator_bond_less_updates_delegator_state() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 15)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_eq!(ParachainStaking::delegator_state(2).expect("exists").total(), 10); + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 5)); + roll_to(10); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert_eq!(ParachainStaking::delegator_state(2).expect("exists").total(), 5); + }); +} - roll_to(21, vec![]); - assert_ok!(StakePallet::execute_leave_candidates(RuntimeOrigin::signed(2), 2)); - assert_eq!(CandidatePool::::count(), 2); +#[test] +fn execute_delegator_bond_less_updates_candidate_state() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 15)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_eq!(ParachainStaking::top_delegations(1).unwrap().delegations[0].owner, 2); + assert_eq!(ParachainStaking::top_delegations(1).unwrap().delegations[0].amount, 10); + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 5)); + roll_to(10); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert_eq!(ParachainStaking::top_delegations(1).unwrap().delegations[0].owner, 2); + assert_eq!(ParachainStaking::top_delegations(1).unwrap().delegations[0].amount, 5); + }); +} - // we must exclude leaving collators from rewards while - // holding them retroactively accountable for previous faults - // (within the last T::StakeDuration blocks) - roll_to(25, vec![]); - let expected = vec![ - Event::MaxSelectedCandidatesSet(2, 5), - Event::NewRound(5, 1), - Event::NewRound(10, 2), - Event::LeftTopCandidates(2), - Event::CollatorScheduledExit(2, 2, 4), - Event::NewRound(15, 3), - Event::NewRound(20, 4), - Event::CandidateLeft(2, 400), - Event::NewRound(25, 5), - ]; - assert_eq!(events(), expected); +#[test] +fn execute_delegator_bond_less_decreases_total() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 15)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_eq!(ParachainStaking::total(), 40); + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 5)); + roll_to(10); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert_eq!(ParachainStaking::total(), 35); }); } #[test] -fn collator_selection_chooses_top_candidates() { +fn execute_delegator_bond_less_updates_just_bottom_delegations() { ExtBuilder::default() - .with_balances(vec![ - (1, 1000), - (2, 1000), - (3, 1000), - (4, 1000), - (5, 1000), - (6, 1000), - (7, 33), - (8, 33), - (9, 33), - ]) - .with_collators(vec![(1, 100), (2, 90), (3, 80), (4, 70), (5, 60), (6, 50)]) + .with_balances(vec![(1, 20), (2, 10), (3, 11), (4, 12), (5, 14), (6, 15)]) + .with_candidates(vec![(1, 20)]) + .with_delegations(vec![(2, 1, 10), (3, 1, 11), (4, 1, 12), (5, 1, 14), (6, 1, 15)]) .build() .execute_with(|| { - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2]); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 190, - delegators: 0 + let pre_call_candidate_info = ParachainStaking::candidate_info(&1).expect("delegated by all so exists"); + let pre_call_top_delegations = ParachainStaking::top_delegations(&1).expect("delegated by all so exists"); + let pre_call_bottom_delegations = + ParachainStaking::bottom_delegations(&1).expect("delegated by all so exists"); + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 2)); + roll_to(10); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + let post_call_candidate_info = ParachainStaking::candidate_info(&1).expect("delegated by all so exists"); + let post_call_top_delegations = ParachainStaking::top_delegations(&1).expect("delegated by all so exists"); + let post_call_bottom_delegations = + ParachainStaking::bottom_delegations(&1).expect("delegated by all so exists"); + let mut not_equal = false; + for Bond { owner, amount } in pre_call_bottom_delegations.delegations { + for Bond { owner: post_owner, amount: post_amount } in &post_call_bottom_delegations.delegations { + if &owner == post_owner { + if &amount != post_amount { + not_equal = true; + break + } + } } - ); - assert_ok!(StakePallet::set_max_selected_candidates(RuntimeOrigin::root(), 5)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 400, - delegators: 0 + } + assert!(not_equal); + let mut equal = true; + for Bond { owner, amount } in pre_call_top_delegations.delegations { + for Bond { owner: post_owner, amount: post_amount } in &post_call_top_delegations.delegations { + if &owner == post_owner { + if &amount != post_amount { + equal = false; + break + } + } } - ); - roll_to(8, vec![]); - // should choose top MaxSelectedCandidates (5), in order - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3, 4, 5]); - let expected = vec![Event::MaxSelectedCandidatesSet(2, 5), Event::NewRound(5, 1)]; - assert_eq!(events(), expected); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(6))); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3, 4, 5],); - assert_eq!(last_event(), StakeEvent::CollatorScheduledExit(1, 6, 3)); - - roll_to(15, vec![]); - assert_ok!(StakePallet::execute_leave_candidates(RuntimeOrigin::signed(6), 6)); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3, 4, 5]); - - roll_to(21, vec![]); - assert_ok!(StakePallet::join_candidates(RuntimeOrigin::signed(6), 69u128)); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3, 4, 6]); - assert_eq!(last_event(), StakeEvent::JoinedCollatorCandidates(6, 69u128)); - - roll_to(27, vec![]); - // should choose top MaxSelectedCandidates (5), in order - let expected = vec![ - Event::MaxSelectedCandidatesSet(2, 5), - Event::NewRound(5, 1), - Event::LeftTopCandidates(6), - Event::CollatorScheduledExit(1, 6, 3), - // TotalCollatorStake is updated once candidate 6 left in `execute_delayed_collator_exits` - Event::NewRound(10, 2), - Event::NewRound(15, 3), - Event::CandidateLeft(6, 50), - Event::NewRound(20, 4), - // 5 had staked 60 which was exceeded by 69 of 6 - Event::EnteredTopCandidates(6), - Event::JoinedCollatorCandidates(6, 69), - Event::NewRound(25, 5), - ]; - assert_eq!(events(), expected); - }); -} - -#[test] -fn exit_queue_with_events() { + } + assert!(equal); + assert_eq!(pre_call_candidate_info.total_counted, post_call_candidate_info.total_counted); + }); +} + +#[test] +fn execute_delegator_bond_less_does_not_delete_bottom_delegations() { ExtBuilder::default() - .with_balances(vec![ - (1, 1000), - (2, 1000), - (3, 1000), - (4, 1000), - (5, 1000), - (6, 1000), - (7, 33), - (8, 33), - (9, 33), - ]) - .with_collators(vec![(1, 100), (2, 90), (3, 80), (4, 70), (5, 60), (6, 50)]) - .with_inflation(100, 15, 40, 10, BLOCKS_PER_ROUND) - .build() - .execute_with(|| { - assert_eq!(CandidatePool::::count(), 6); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2]); - assert_ok!(StakePallet::set_max_selected_candidates(RuntimeOrigin::root(), 5)); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3, 4, 5]); - - roll_to(8, vec![]); - // should choose top MaxSelectedCandidates (5), in order - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3, 4, 5]); - let mut expected = vec![Event::MaxSelectedCandidatesSet(2, 5), Event::NewRound(5, 1)]; - assert_eq!(events(), expected); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(6))); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3, 4, 5]); - assert_eq!(last_event(), StakeEvent::CollatorScheduledExit(1, 6, 3)); - - roll_to(11, vec![]); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(5))); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3, 4]); - assert_eq!(last_event(), StakeEvent::CollatorScheduledExit(2, 5, 4)); - - assert_eq!(CandidatePool::::count(), 6, "No collators have left yet."); - roll_to(16, vec![]); - assert_ok!(StakePallet::execute_leave_candidates(RuntimeOrigin::signed(6), 6)); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(4))); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3]); - assert_eq!(last_event(), StakeEvent::CollatorScheduledExit(3, 4, 5)); - assert_noop!( - StakePallet::init_leave_candidates(RuntimeOrigin::signed(4)), - Error::::AlreadyLeaving - ); + .with_balances(vec![(1, 20), (2, 10), (3, 11), (4, 12), (5, 14), (6, 15)]) + .with_candidates(vec![(1, 20)]) + .with_delegations(vec![(2, 1, 10), (3, 1, 11), (4, 1, 12), (5, 1, 14), (6, 1, 15)]) + .build() + .execute_with(|| { + let pre_call_candidate_info = ParachainStaking::candidate_info(&1).expect("delegated by all so exists"); + let pre_call_top_delegations = ParachainStaking::top_delegations(&1).expect("delegated by all so exists"); + let pre_call_bottom_delegations = + ParachainStaking::bottom_delegations(&1).expect("delegated by all so exists"); + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(6), 1, 4)); + roll_to(10); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(6), 6, 1)); + let post_call_candidate_info = ParachainStaking::candidate_info(&1).expect("delegated by all so exists"); + let post_call_top_delegations = ParachainStaking::top_delegations(&1).expect("delegated by all so exists"); + let post_call_bottom_delegations = + ParachainStaking::bottom_delegations(&1).expect("delegated by all so exists"); + let mut equal = true; + for Bond { owner, amount } in pre_call_bottom_delegations.delegations { + for Bond { owner: post_owner, amount: post_amount } in &post_call_bottom_delegations.delegations { + if &owner == post_owner { + if &amount != post_amount { + equal = false; + break + } + } + } + } + assert!(equal); + let mut not_equal = false; + for Bond { owner, amount } in pre_call_top_delegations.delegations { + for Bond { owner: post_owner, amount: post_amount } in &post_call_top_delegations.delegations { + if &owner == post_owner { + if &amount != post_amount { + not_equal = true; + break + } + } + } + } + assert!(not_equal); + assert_eq!(pre_call_candidate_info.total_counted - 4, post_call_candidate_info.total_counted); + }); +} - assert_eq!(CandidatePool::::count(), 5, "Collator #5 left."); - roll_to(20, vec![]); - assert_ok!(StakePallet::execute_leave_candidates(RuntimeOrigin::signed(5), 5)); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3]); - assert_eq!(CandidatePool::::count(), 4, "Two out of six collators left."); +#[test] +fn can_execute_delegator_bond_less_for_leaving_candidate() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 15)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 15)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 1)); + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 5)); + roll_to(10); + // can execute bond more delegation request for leaving candidate + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + }); +} - roll_to(26, vec![]); - assert_ok!(StakePallet::execute_leave_candidates(RuntimeOrigin::signed(4), 4)); - assert_eq!(CandidatePool::::count(), 3, "Three out of six collators left."); +// CANCEL PENDING DELEGATION REQUEST +// 1. CANCEL REVOKE DELEGATION - roll_to(30, vec![]); - let mut new_events = vec![ - Event::LeftTopCandidates(6), - Event::CollatorScheduledExit(1, 6, 3), - Event::NewRound(10, 2), - Event::LeftTopCandidates(5), - Event::CollatorScheduledExit(2, 5, 4), - Event::NewRound(15, 3), - Event::CandidateLeft(6, 50), - Event::LeftTopCandidates(4), - Event::CollatorScheduledExit(3, 4, 5), - Event::NewRound(20, 4), - Event::CandidateLeft(5, 60), - Event::NewRound(25, 5), - Event::CandidateLeft(4, 70), - Event::NewRound(30, 6), - ]; - expected.append(&mut new_events); - assert_eq!(events(), expected); +#[test] +fn cancel_revoke_delegation_emits_correct_event() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + assert_ok!(ParachainStaking::cancel_delegation_request(RuntimeOrigin::signed(2), 1)); + assert_events_emitted!(Event::CancelledDelegationRequest { + delegator: 2, + collator: 1, + cancelled_request: CancelledScheduledRequest { + when_executable: 3, + action: DelegationAction::Revoke(10), + }, + }); }); } #[test] -fn execute_leave_candidates_with_delay() { +fn cancel_revoke_delegation_updates_delegator_state() { ExtBuilder::default() - .with_balances(vec![ - (1, 1000), - (2, 1000), - (3, 1000), - (4, 1000), - (5, 1000), - (6, 1000), - (7, 1000), - (8, 1000), - (9, 1000), - (10, 1000), - (11, 1000), - (12, 1000), - (13, 1000), - (14, 1000), - ]) - .with_collators(vec![ - (1, 10), - (2, 20), - (3, 30), - (4, 40), - (5, 50), - (6, 60), - (7, 70), - (8, 80), - (9, 90), - (10, 100), - ]) - .with_delegators(vec![(11, 1, 110), (12, 1, 120), (13, 2, 130), (14, 2, 140)]) - .with_inflation(100, 15, 40, 10, BLOCKS_PER_ROUND) + .with_balances(vec![(1, 30), (2, 10)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) .build() .execute_with(|| { - assert_eq!(CandidatePool::::count(), 10); + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + let state = ParachainStaking::delegation_scheduled_requests(&1); assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 30, - delegators: 500 - } - ); - assert_ok!(StakePallet::set_max_selected_candidates(RuntimeOrigin::root(), 5)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 300, - delegators: 500 - } + state, + vec![ScheduledRequest { delegator: 2, when_executable: 3, action: DelegationAction::Revoke(10) }], ); - - roll_to(5, vec![]); - // should choose top MaxSelectedCandidates (5), in order - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![2, 1, 10, 9, 8]); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(10))); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(9))); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(1))); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(7))); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(6))); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(5))); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(8))); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(2))); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![4, 3]); - for owner in vec![1, 2, 5, 6, 7, 8, 9, 10].iter() { - assert!(StakePallet::candidate_pool(owner) - .unwrap() - .can_exit(1 + ::ExitQueueDelay::get())); - } - let total_stake = TotalStake { - collators: 70, - delegators: 0, - }; - assert_eq!(StakePallet::total_collator_stake(), total_stake); assert_eq!( - StakePallet::candidate_pool(1), - Some( - Candidate::::MaxDelegatorsPerCollator> { - id: 1, - stake: 10, - delegators: OrderedSet::from( - vec![ - StakeOf:: { owner: 11, amount: 110 }, - StakeOf:: { owner: 12, amount: 120 } - ] - .try_into() - .unwrap() - ), - total: 240, - status: CandidateStatus::Leaving(3) - } - ) + ParachainStaking::delegator_state(&2).map(|x| x.less_total).expect("delegator state must exist"), + 10 ); + assert_ok!(ParachainStaking::cancel_delegation_request(RuntimeOrigin::signed(2), 1)); + assert!(!ParachainStaking::delegation_scheduled_requests(&1).iter().any(|x| x.delegator == 2)); assert_eq!( - StakePallet::candidate_pool(2), - Some( - Candidate::::MaxDelegatorsPerCollator> { - id: 2, - stake: 20, - delegators: OrderedSet::from( - vec![ - StakeOf:: { owner: 13, amount: 130 }, - StakeOf:: { owner: 14, amount: 140 } - ] - .try_into() - .unwrap() - ), - total: 290, - status: CandidateStatus::Leaving(3) - } - ) - ); - for collator in 5u64..=10u64 { - assert_eq!( - StakePallet::candidate_pool(collator), - Some( - Candidate::::MaxDelegatorsPerCollator> { - id: collator, - stake: collator as u128 * 10u128, - delegators: OrderedSet::from(BoundedVec::default()), - total: collator as u128 * 10u128, - status: CandidateStatus::Leaving(3) - } - ) - ); - assert!(StakePallet::is_active_candidate(&collator).is_some()); - assert!(StakePallet::unstaking(collator).is_empty()); - } - assert_eq!( - StakePallet::delegator_state(11), - Some(Delegator:: { owner: 1, amount: 110 }) + ParachainStaking::delegator_state(&2).map(|x| x.less_total).expect("delegator state must exist"), + 0 ); + }); +} + +// 2. CANCEL DELEGATOR BOND LESS + +#[test] +fn cancel_delegator_bond_less_correct_event() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 15)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 15)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 5)); + assert_ok!(ParachainStaking::cancel_delegation_request(RuntimeOrigin::signed(2), 1)); + assert_events_emitted!(Event::CancelledDelegationRequest { + delegator: 2, + collator: 1, + cancelled_request: CancelledScheduledRequest { + when_executable: 3, + action: DelegationAction::Decrease(5), + }, + }); + }); +} + +#[test] +fn cancel_delegator_bond_less_updates_delegator_state() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 15)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 15)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 5)); + let state = ParachainStaking::delegation_scheduled_requests(&1); assert_eq!( - StakePallet::delegator_state(12), - Some(Delegator:: { owner: 1, amount: 120 }) + state, + vec![ScheduledRequest { delegator: 2, when_executable: 3, action: DelegationAction::Decrease(5) }], ); assert_eq!( - StakePallet::delegator_state(13), - Some(Delegator:: { owner: 2, amount: 130 }) + ParachainStaking::delegator_state(&2).map(|x| x.less_total).expect("delegator state must exist"), + 5 ); + assert_ok!(ParachainStaking::cancel_delegation_request(RuntimeOrigin::signed(2), 1)); + assert!(!ParachainStaking::delegation_scheduled_requests(&1).iter().any(|x| x.delegator == 2)); assert_eq!( - StakePallet::delegator_state(14), - Some(Delegator:: { owner: 2, amount: 140 }) + ParachainStaking::delegator_state(&2).map(|x| x.less_total).expect("delegator state must exist"), + 0 ); - for delegator in 11u64..=14u64 { - assert!(StakePallet::is_delegator(&delegator)); - assert!(StakePallet::unstaking(delegator).is_empty()); - } + }); +} - // exits cannot be executed yet but in the next round - roll_to(10, vec![]); - assert_eq!(StakePallet::total_collator_stake(), total_stake); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![4, 3]); - for owner in vec![1, 2, 5, 6, 7, 8, 9, 10].iter() { - assert!(StakePallet::candidate_pool(owner) - .unwrap() - .can_exit(1 + ::ExitQueueDelay::get())); - assert_noop!( - StakePallet::execute_leave_candidates(RuntimeOrigin::signed(*owner), *owner), - Error::::CannotLeaveYet - ); - } - assert_eq!(StakePallet::total_collator_stake(), total_stake); +// ~~ PROPERTY-BASED TESTS ~~ + +#[test] +fn delegator_schedule_revocation_total() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (2, 40), (3, 20), (4, 20), (5, 20)]) + .with_candidates(vec![(1, 20), (3, 20), (4, 20), (5, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10), (2, 4, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); assert_eq!( - StakePallet::candidate_pool(1), - Some( - Candidate::::MaxDelegatorsPerCollator> { - id: 1, - stake: 10, - delegators: OrderedSet::from( - vec![ - StakeOf:: { owner: 11, amount: 110 }, - StakeOf:: { owner: 12, amount: 120 } - ] - .try_into() - .unwrap() - ), - total: 240, - status: CandidateStatus::Leaving(3) - } - ) + ParachainStaking::delegator_state(&2).map(|x| x.less_total).expect("delegator state must exist"), + 10 ); + roll_to(10); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); assert_eq!( - StakePallet::candidate_pool(2), - Some( - Candidate::::MaxDelegatorsPerCollator> { - id: 2, - stake: 20, - delegators: OrderedSet::from( - vec![ - StakeOf:: { owner: 13, amount: 130 }, - StakeOf:: { owner: 14, amount: 140 } - ] - .try_into() - .unwrap() - ), - total: 290, - status: CandidateStatus::Leaving(3) - } - ) - ); - for collator in 5u64..=10u64 { - assert_eq!( - StakePallet::candidate_pool(collator), - Some( - Candidate::::MaxDelegatorsPerCollator> { - id: collator, - stake: collator as u128 * 10u128, - delegators: OrderedSet::from(BoundedVec::default()), - total: collator as u128 * 10u128, - status: CandidateStatus::Leaving(3) - } - ) - ); - assert!(StakePallet::is_active_candidate(&collator).is_some()); - assert!(StakePallet::unstaking(collator).is_empty()); - } - assert_eq!( - StakePallet::delegator_state(11), - Some(Delegator:: { owner: 1, amount: 110 }) + ParachainStaking::delegator_state(&2).map(|x| x.less_total).expect("delegator state must exist"), + 0 ); + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(2), 5, 10, 0, 2)); + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 3)); + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 4)); assert_eq!( - StakePallet::delegator_state(12), - Some(Delegator:: { owner: 1, amount: 120 }) + ParachainStaking::delegator_state(&2).map(|x| x.less_total).expect("delegator state must exist"), + 20, ); + roll_to(20); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 3)); assert_eq!( - StakePallet::delegator_state(13), - Some(Delegator:: { owner: 2, amount: 130 }) + ParachainStaking::delegator_state(&2).map(|x| x.less_total).expect("delegator state must exist"), + 10, ); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 4)); assert_eq!( - StakePallet::delegator_state(14), - Some(Delegator:: { owner: 2, amount: 140 }) + ParachainStaking::delegator_state(&2).map(|x| x.less_total).expect("delegator state must exist"), + 0 ); - for delegator in 11u64..=14u64 { - assert!(StakePallet::is_delegator(&delegator)); - assert!(StakePallet::unstaking(delegator).is_empty()); - } - - // first five exits are executed - roll_to(15, vec![]); - assert_eq!(StakePallet::total_collator_stake(), total_stake); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![4, 3]); - for collator in vec![1u64, 2u64, 5u64, 6u64, 7u64].iter() { - assert_ok!(StakePallet::execute_leave_candidates( - RuntimeOrigin::signed(*collator), - *collator - )); - assert!(StakePallet::candidate_pool(&collator).is_none()); - assert!(StakePallet::is_active_candidate(collator).is_none()); - assert_eq!(StakePallet::unstaking(collator).len(), 1); - } - assert_eq!(CandidatePool::::count(), 5, "Five collators left."); - - assert_eq!(StakePallet::total_collator_stake(), total_stake); - for delegator in 11u64..=14u64 { - assert!(!StakePallet::is_delegator(&delegator)); - assert_eq!(StakePallet::unstaking(delegator).len(), 1); - } - - // last 3 exits are executed - roll_to(20, vec![]); - for collator in 8u64..=10u64 { - assert_ok!(StakePallet::execute_leave_candidates( - RuntimeOrigin::signed(collator), - collator - )); - assert!(StakePallet::candidate_pool(&collator).is_none()); - assert!(StakePallet::is_active_candidate(&collator).is_none()); - assert_eq!(StakePallet::unstaking(collator).len(), 1); - } - assert_eq!(CandidatePool::::count(), 2, "3 collators left."); }); } -// FIXME: Re-enable or potentially remove entirely +#[ignore] #[test] -fn multiple_delegations() { +fn parachain_bond_inflation_reserve_matches_config() { ExtBuilder::default() .with_balances(vec![ (1, 100), @@ -853,304 +2751,457 @@ fn multiple_delegations() { (8, 100), (9, 100), (10, 100), - (11, 100), - (12, 100), - // new - (13, 100), - (14, 100), - (15, 100), - (16, 100), - (17, 100), - (18, 100), - (99, 1), + (11, 1), ]) - .with_collators(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 10)]) - .with_delegators(vec![(6, 1, 10), (7, 1, 10), (8, 2, 10), (9, 2, 10), (10, 1, 10)]) - .set_blocks_per_round(5) + .with_candidates(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 10)]) + .with_delegations(vec![(6, 1, 10), (7, 1, 10), (8, 2, 10), (9, 2, 10), (10, 1, 10)]) .build() .execute_with(|| { - assert_ok!(StakePallet::set_max_selected_candidates(RuntimeOrigin::root(), 5)); - roll_to( - 8, - vec![Some(1), Some(2), Some(3), Some(4), Some(5), Some(1), Some(2), Some(3)], - ); - // chooses top MaxSelectedCandidates (5), in order - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 3, 4, 5]); - let mut expected = vec![Event::MaxSelectedCandidatesSet(2, 5), Event::NewRound(5, 1)]; - assert_eq!(events(), expected); - assert_noop!( - StakePallet::join_delegators(RuntimeOrigin::signed(13), 2, 2), - Error::::DelegationBelowMin, - ); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(13), 2, 10)); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(14), 4, 10)); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(15), 3, 10)); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 4, 3, 5]); - assert_noop!( - StakePallet::join_delegators(RuntimeOrigin::signed(6), 5, 10), - Error::::AlreadyDelegating, - ); - - roll_to( - 16, - vec![Some(1), Some(2), Some(3), Some(4), Some(5), Some(1), Some(2), Some(3)], - ); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2, 4, 3, 5]); - let mut new = vec![ - Event::Delegation(13, 10, 2, 50), - Event::Delegation(14, 10, 4, 30), - Event::Delegation(15, 10, 3, 30), - Event::NewRound(10, 2), - Event::NewRound(15, 3), - ]; - expected.append(&mut new); - assert_eq!(events(), expected); - - roll_to(21, vec![Some(1), Some(2), Some(3), Some(4), Some(5)]); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(16), 2, 80)); - assert_noop!( - StakePallet::join_delegators(RuntimeOrigin::signed(99), 3, 11), - BalancesError::::InsufficientBalance - ); - assert_noop!( - StakePallet::join_delegators(RuntimeOrigin::signed(17), 2, 10), - Error::::TooManyDelegators - ); - // kick 13 by staking 1 more (11 > 10) - assert!(StakePallet::unstaking(13).is_empty()); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(17), 2, 11)); - assert!(StakePallet::delegator_state(13).is_none()); - assert_eq!(StakePallet::unstaking(13).get(&23), Some(&10u128)); - // kick 9 by staking 1 more (11 > 10) - assert!(StakePallet::unstaking(9).is_empty()); - assert!(StakePallet::rewards(9).is_zero()); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(11), 2, 11)); - // 11 should be initiated with the same rewarded counter as the authored counter - // by their collator 2 - assert_eq!(StakePallet::blocks_rewarded(2), StakePallet::blocks_authored(11)); - - assert!(StakePallet::delegator_state(9).is_none()); - assert_eq!(StakePallet::unstaking(9).get(&23), Some(&10u128)); - assert!(!StakePallet::candidate_pool(2) - .unwrap() - .delegators - .contains(&StakeOf:: { owner: 9, amount: 10 })); - - roll_to(26, vec![Some(1), Some(2), Some(3), Some(4), Some(5)]); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![2, 1, 4, 3, 5]); - let mut new2 = vec![ - Event::NewRound(20, 4), - Event::Delegation(16, 80, 2, 130), - Event::DelegationReplaced(17, 11, 13, 10, 2, 131), - Event::Delegation(17, 11, 2, 131), - Event::DelegationReplaced(11, 11, 9, 10, 2, 132), - Event::Delegation(11, 11, 2, 132), - Event::NewRound(25, 5), - ]; - expected.append(&mut new2); - assert_eq!(events(), expected); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(2))); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 4, 3, 5]); - assert_eq!(last_event(), StakeEvent::CollatorScheduledExit(5, 2, 7)); - - roll_to(31, vec![Some(1), Some(2), Some(3), Some(4), Some(5)]); - let mut new3 = vec![ - Event::LeftTopCandidates(2), - Event::CollatorScheduledExit(5, 2, 7), - Event::NewRound(30, 6), - ]; - expected.append(&mut new3); - assert_eq!(events(), expected); - - // test join_delegator errors - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(18), 1, 10)); + assert_eq!(Balances::free_balance(&11), 1); + // set parachain bond account so DefaultParachainBondReservePercent = 30% of inflation + // is allocated to this account hereafter + assert_ok!(ParachainStaking::set_parachain_bond_account(RuntimeOrigin::root(), 11)); + assert_events_eq!(Event::ParachainBondAccountSet { old: 0, new: 11 }); + roll_to_round_begin(2); + // chooses top TotalSelectedCandidates (5), in order + assert_events_eq!( + Event::CollatorChosen { round: 2, collator_account: 1, total_exposed_amount: 50 }, + Event::CollatorChosen { round: 2, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 2, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 2, collator_account: 4, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 2, collator_account: 5, total_exposed_amount: 10 }, + Event::NewRound { starting_block: 5, round: 2, selected_collators_number: 5, total_balance: 140 }, + ); + assert_eq!(Balances::free_balance(&11), 1); + // ~ set block author as 1 for all blocks this round + set_author(2, 1, 100); + roll_to_round_begin(4); + // distribute total issuance to collator 1 and its delegators 6, 7, 19 + assert_eq!(Balances::free_balance(&11), 16); + // ~ set block author as 1 for all blocks this round + set_author(3, 1, 100); + set_author(4, 1, 100); + set_author(5, 1, 100); + // 1. ensure delegators are paid for 2 rounds after they leave assert_noop!( - StakePallet::join_delegators(RuntimeOrigin::signed(12), 1, 10), - Error::::TooManyDelegators - ); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(12), 1, 11)); - - // verify that delegations are removed after collator leaves, not before - assert!(StakePallet::candidate_pool(2) - .unwrap() - .delegators - .contains(&StakeOf:: { owner: 8, amount: 10 })); - assert!(StakePallet::candidate_pool(2) - .unwrap() - .delegators - .contains(&StakeOf:: { owner: 17, amount: 11 })); - assert_eq!(StakePallet::delegator_state(8).unwrap().amount, 10); - assert_eq!(StakePallet::delegator_state(17).unwrap().amount, 11); - assert_eq!(Balances::usable_balance(&8), 90); - assert_eq!(Balances::usable_balance(&17), 89); - assert_eq!(Balances::free_balance(&8), 100); - assert_eq!(Balances::free_balance(&17), 100); - - roll_to(35, vec![Some(1), Some(2), Some(3), Some(4)]); - assert_ok!(StakePallet::execute_leave_candidates(RuntimeOrigin::signed(2), 2)); - let mut unbonding_8: BoundedBTreeMap, ::MaxUnstakeRequests> = - BoundedBTreeMap::new(); - assert_ok!(unbonding_8.try_insert(35u64 + ::StakeDuration::get() as u64, 10)); - assert_eq!(StakePallet::unstaking(8), unbonding_8); - let mut unbonding_17: BoundedBTreeMap, ::MaxUnstakeRequests> = - BoundedBTreeMap::new(); - assert_ok!(unbonding_17.try_insert(35u64 + ::StakeDuration::get() as u64, 11)); - assert_eq!(StakePallet::unstaking(17), unbonding_17); - - roll_to(37, vec![Some(1), Some(2)]); - assert!(StakePallet::delegator_state(8).is_none()); - assert!(StakePallet::delegator_state(17).is_none()); - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(8), 8)); - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(17), 17)); - assert_noop!( - StakePallet::unlock_unstaked(RuntimeOrigin::signed(12), 12), - Error::::UnstakingIsEmpty - ); - assert_eq!(Balances::usable_balance(&17), 100); - assert_eq!(Balances::usable_balance(&8), 100); - assert_eq!(Balances::free_balance(&17), 100); - assert_eq!(Balances::free_balance(&8), 100); + ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(66)), + Error::::DelegatorDNE + ); + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(6))); + assert_events_eq!( + Event::ReservedForParachainBond { account: 11, value: 15 }, + Event::CollatorChosen { round: 4, collator_account: 1, total_exposed_amount: 50 }, + Event::CollatorChosen { round: 4, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 4, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 4, collator_account: 4, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 4, collator_account: 5, total_exposed_amount: 10 }, + Event::NewRound { starting_block: 15, round: 4, selected_collators_number: 5, total_balance: 140 }, + Event::DelegatorExitScheduled { round: 4, delegator: 6, scheduled_exit: 6 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 20 }, + Event::Rewarded { account: 6, rewards: 5 }, + Event::Rewarded { account: 7, rewards: 5 }, + Event::Rewarded { account: 10, rewards: 5 }, + ); + // fast forward to block in which delegator 6 exit executes + roll_to_round_begin(5); + assert_events_eq!( + Event::ReservedForParachainBond { account: 11, value: 16 }, + Event::CollatorChosen { round: 5, collator_account: 1, total_exposed_amount: 50 }, + Event::CollatorChosen { round: 5, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 5, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 5, collator_account: 4, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 5, collator_account: 5, total_exposed_amount: 10 }, + Event::NewRound { starting_block: 20, round: 5, selected_collators_number: 5, total_balance: 140 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 21 }, + Event::Rewarded { account: 6, rewards: 5 }, + Event::Rewarded { account: 7, rewards: 5 }, + Event::Rewarded { account: 10, rewards: 5 }, + ); + roll_to_round_begin(6); + assert_ok!(ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(6), 6, 10)); + assert_events_eq!( + Event::ReservedForParachainBond { account: 11, value: 16 }, + Event::CollatorChosen { round: 6, collator_account: 1, total_exposed_amount: 50 }, + Event::CollatorChosen { round: 6, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 6, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 6, collator_account: 4, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 6, collator_account: 5, total_exposed_amount: 10 }, + Event::NewRound { starting_block: 25, round: 6, selected_collators_number: 5, total_balance: 140 }, + Event::DelegatorLeftCandidate { + delegator: 6, + candidate: 1, + unstaked_amount: 10, + total_candidate_staked: 40, + }, + Event::DelegatorLeft { delegator: 6, unstaked_amount: 10 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 22 }, + Event::Rewarded { account: 6, rewards: 6 }, + Event::Rewarded { account: 7, rewards: 6 }, + Event::Rewarded { account: 10, rewards: 6 }, + ); + roll_to_round_begin(7); + assert_events_eq!( + Event::ReservedForParachainBond { account: 11, value: 17 }, + Event::CollatorChosen { round: 7, collator_account: 1, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 7, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 7, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 7, collator_account: 4, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 7, collator_account: 5, total_exposed_amount: 10 }, + Event::NewRound { starting_block: 30, round: 7, selected_collators_number: 5, total_balance: 130 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 26 }, + Event::Rewarded { account: 7, rewards: 7 }, + Event::Rewarded { account: 10, rewards: 7 }, + ); + assert_eq!(Balances::free_balance(&11), 65); + roll_blocks(1); + assert_ok!(ParachainStaking::set_parachain_bond_reserve_percent( + RuntimeOrigin::root(), + Percent::from_percent(50) + )); + assert_events_eq!(Event::ParachainBondReservePercentSet { + old: Percent::from_percent(30), + new: Percent::from_percent(50), + }); + // 6 won't be paid for this round because they left already + set_author(6, 1, 100); + roll_to_round_begin(8); + // keep paying 6 + assert_events_eq!( + Event::ReservedForParachainBond { account: 11, value: 30 }, + Event::CollatorChosen { round: 8, collator_account: 1, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 8, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 8, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 8, collator_account: 4, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 8, collator_account: 5, total_exposed_amount: 10 }, + Event::NewRound { starting_block: 35, round: 8, selected_collators_number: 5, total_balance: 130 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 21 }, + Event::Rewarded { account: 7, rewards: 5 }, + Event::Rewarded { account: 10, rewards: 5 }, + ); + assert_eq!(Balances::free_balance(&11), 95); + set_author(7, 1, 100); + roll_to_round_begin(9); + // no more paying 6 + assert_events_eq!( + Event::ReservedForParachainBond { account: 11, value: 32 }, + Event::CollatorChosen { round: 9, collator_account: 1, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 9, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 9, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 9, collator_account: 4, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 9, collator_account: 5, total_exposed_amount: 10 }, + Event::NewRound { starting_block: 40, round: 9, selected_collators_number: 5, total_balance: 130 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 22 }, + Event::Rewarded { account: 7, rewards: 5 }, + Event::Rewarded { account: 10, rewards: 5 }, + ); + assert_eq!(Balances::free_balance(&11), 127); + set_author(8, 1, 100); + roll_blocks(1); + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(8), 1, 10, 10, 10)); + assert_events_eq!(Event::Delegation { + delegator: 8, + locked_amount: 10, + candidate: 1, + delegator_position: DelegatorAdded::AddedToTop { new_total: 50 }, + auto_compound: Percent::zero(), + }); + roll_to_round_begin(10); + // new delegation is not rewarded yet + assert_events_eq!( + Event::ReservedForParachainBond { account: 11, value: 33 }, + Event::CollatorChosen { round: 10, collator_account: 1, total_exposed_amount: 50 }, + Event::CollatorChosen { round: 10, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 10, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 10, collator_account: 4, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 10, collator_account: 5, total_exposed_amount: 10 }, + Event::NewRound { starting_block: 45, round: 10, selected_collators_number: 5, total_balance: 140 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 23 }, + Event::Rewarded { account: 7, rewards: 5 }, + Event::Rewarded { account: 10, rewards: 5 }, + ); + assert_eq!(Balances::free_balance(&11), 160); + set_author(9, 1, 100); + set_author(10, 1, 100); + roll_to_round_begin(11); + // new delegation is still not rewarded yet + assert_events_eq!( + Event::ReservedForParachainBond { account: 11, value: 35 }, + Event::CollatorChosen { round: 11, collator_account: 1, total_exposed_amount: 50 }, + Event::CollatorChosen { round: 11, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 11, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 11, collator_account: 4, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 11, collator_account: 5, total_exposed_amount: 10 }, + Event::NewRound { starting_block: 50, round: 11, selected_collators_number: 5, total_balance: 140 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 24 }, + Event::Rewarded { account: 7, rewards: 5 }, + Event::Rewarded { account: 10, rewards: 5 }, + ); + assert_eq!(Balances::free_balance(&11), 195); + roll_to_round_begin(12); + // new delegation is rewarded, 2 rounds after joining (`RewardPaymentDelay` is 2) + assert_events_eq!( + Event::ReservedForParachainBond { account: 11, value: 37 }, + Event::CollatorChosen { round: 12, collator_account: 1, total_exposed_amount: 50 }, + Event::CollatorChosen { round: 12, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 12, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 12, collator_account: 4, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 12, collator_account: 5, total_exposed_amount: 10 }, + Event::NewRound { starting_block: 55, round: 12, selected_collators_number: 5, total_balance: 140 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 24 }, + Event::Rewarded { account: 7, rewards: 4 }, + Event::Rewarded { account: 10, rewards: 4 }, + Event::Rewarded { account: 8, rewards: 4 }, + ); + assert_eq!(Balances::free_balance(&11), 232); }); } #[test] -fn should_update_total_stake() { +fn paid_collator_commission_matches_config() { ExtBuilder::default() - .with_balances(vec![ - (1, 100), - (2, 100), - (3, 100), - (4, 100), - (5, 100), - (6, 100), - (7, 100), - (8, 100), - (9, 100), - (10, 100), - (11, 161_000_000 * DECIMALS), - ]) - .with_collators(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 10)]) - .with_delegators(vec![(7, 1, 10), (8, 2, 10), (9, 2, 10)]) - .set_blocks_per_round(5) + .with_balances(vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100), (6, 100)]) + .with_candidates(vec![(1, 20)]) + .with_delegations(vec![(2, 1, 10), (3, 1, 10)]) .build() .execute_with(|| { - let mut old_stake = StakePallet::total_collator_stake(); - assert_eq!( - old_stake, - TotalStake { - collators: 40, - delegators: 30 - } - ); - assert_ok!(StakePallet::candidate_stake_more(RuntimeOrigin::signed(1), 50)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: old_stake.collators + 50, - ..old_stake - } - ); - - old_stake = StakePallet::total_collator_stake(); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 50)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: old_stake.collators - 50, - ..old_stake - } + roll_to_round_begin(2); + assert_ok!(ParachainStaking::join_candidates(RuntimeOrigin::signed(4), 20u128, 100u32)); + assert_events_eq!( + Event::CollatorChosen { round: 2, collator_account: 1, total_exposed_amount: 40 }, + Event::NewRound { starting_block: 5, round: 2, selected_collators_number: 1, total_balance: 40 }, + Event::JoinedCollatorCandidates { account: 4, amount_locked: 20, new_total_amt_locked: 60 }, + ); + + roll_blocks(1); + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(5), 4, 10, 10, 10)); + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(6), 4, 10, 10, 10)); + assert_events_eq!( + Event::Delegation { + delegator: 5, + locked_amount: 10, + candidate: 4, + delegator_position: DelegatorAdded::AddedToTop { new_total: 30 }, + auto_compound: Percent::zero(), + }, + Event::Delegation { + delegator: 6, + locked_amount: 10, + candidate: 4, + delegator_position: DelegatorAdded::AddedToTop { new_total: 40 }, + auto_compound: Percent::zero(), + }, ); - old_stake = StakePallet::total_collator_stake(); - assert_ok!(StakePallet::delegator_stake_more(RuntimeOrigin::signed(7), 50)); - assert_noop!( - StakePallet::delegator_stake_more(RuntimeOrigin::signed(7), 0), - Error::::ValStakeZero - ); - assert_noop!( - StakePallet::delegator_stake_less(RuntimeOrigin::signed(7), 0), - Error::::ValStakeZero - ); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - delegators: old_stake.delegators + 50, - ..old_stake - } + roll_to_round_begin(3); + assert_events_eq!( + Event::CollatorChosen { round: 3, collator_account: 1, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 3, collator_account: 4, total_exposed_amount: 40 }, + Event::NewRound { starting_block: 10, round: 3, selected_collators_number: 2, total_balance: 80 }, ); - - old_stake = StakePallet::total_collator_stake(); - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(7), 50)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - delegators: old_stake.delegators - 50, - ..old_stake - } + // only reward author with id 4 + set_author(3, 4, 100); + roll_to_round_begin(5); + // 20% of 10 is commission + due_portion (0) = 2 + 4 = 6 + // all delegator payouts are 10-2 = 8 * stake_pct + assert_events_eq!( + Event::CollatorChosen { round: 5, collator_account: 1, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 5, collator_account: 4, total_exposed_amount: 40 }, + Event::NewRound { starting_block: 20, round: 5, selected_collators_number: 2, total_balance: 80 }, ); - old_stake = StakePallet::total_collator_stake(); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(11), 1, 200)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - delegators: old_stake.delegators + 200, - ..old_stake - } + roll_blocks(1); + assert_events_eq!( + Event::Rewarded { account: 4, rewards: 18 }, + Event::Rewarded { account: 5, rewards: 6 }, + Event::Rewarded { account: 6, rewards: 6 }, ); + }); +} - old_stake = StakePallet::total_collator_stake(); - assert_eq!(StakePallet::delegator_state(11).unwrap().amount, 200); - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(11))); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - delegators: old_stake.delegators - 200, - ..old_stake - } - ); +#[test] +fn collator_exit_executes_after_delay() { + ExtBuilder::default() + .with_balances(vec![(1, 1000), (2, 300), (3, 100), (4, 100), (5, 100), (6, 100), (7, 100), (8, 9), (9, 4)]) + .with_candidates(vec![(1, 500), (2, 200)]) + .with_delegations(vec![(3, 1, 100), (4, 1, 100), (5, 2, 100), (6, 2, 100)]) + .build() + .execute_with(|| { + roll_to(11); + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(2), 2)); + assert_events_eq!(Event::CandidateScheduledExit { exit_allowed_round: 3, candidate: 2, scheduled_exit: 5 }); + let info = ParachainStaking::candidate_info(&2).unwrap(); + assert_eq!(info.status, CollatorStatus::Leaving(5)); + roll_to(21); + assert_ok!(ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(2), 2, 2)); + // we must exclude leaving collators from rewards while + // holding them retroactively accountable for previous faults + // (within the last T::SlashingWindow blocks) + assert_events_eq!(Event::CandidateLeft { + ex_candidate: 2, + unlocked_amount: 400, + new_total_amt_locked: 700, + },); + }); +} - let old_stake = StakePallet::total_collator_stake(); - assert_eq!(StakePallet::delegator_state(8).unwrap().amount, 10); - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(8))); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - delegators: old_stake.delegators - 10, - ..old_stake - } +#[test] +fn collator_selection_chooses_top_candidates() { + ExtBuilder::default() + .with_balances(vec![ + (1, 1000), + (2, 1000), + (3, 1000), + (4, 1000), + (5, 1000), + (6, 1000), + (7, 33), + (8, 33), + (9, 33), + ]) + .with_candidates(vec![(1, 100), (2, 90), (3, 80), (4, 70), (5, 60), (6, 50)]) + .build() + .execute_with(|| { + roll_to_round_begin(2); + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(6), 6)); + // should choose top TotalSelectedCandidates (5), in order + assert_events_eq!( + Event::CollatorChosen { round: 2, collator_account: 1, total_exposed_amount: 100 }, + Event::CollatorChosen { round: 2, collator_account: 2, total_exposed_amount: 90 }, + Event::CollatorChosen { round: 2, collator_account: 3, total_exposed_amount: 80 }, + Event::CollatorChosen { round: 2, collator_account: 4, total_exposed_amount: 70 }, + Event::CollatorChosen { round: 2, collator_account: 5, total_exposed_amount: 60 }, + Event::NewRound { starting_block: 5, round: 2, selected_collators_number: 5, total_balance: 400 }, + Event::CandidateScheduledExit { exit_allowed_round: 2, candidate: 6, scheduled_exit: 4 }, + ); + roll_to_round_begin(4); + roll_blocks(1); + assert_ok!(ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(6), 6, 0)); + assert_ok!(ParachainStaking::join_candidates(RuntimeOrigin::signed(6), 69u128, 100u32)); + assert_events_eq!( + Event::CandidateLeft { ex_candidate: 6, unlocked_amount: 50, new_total_amt_locked: 400 }, + Event::JoinedCollatorCandidates { account: 6, amount_locked: 69u128, new_total_amt_locked: 469u128 }, + ); + roll_to_round_begin(6); + // should choose top TotalSelectedCandidates (5), in order + assert_events_eq!( + Event::CollatorChosen { round: 6, collator_account: 1, total_exposed_amount: 100 }, + Event::CollatorChosen { round: 6, collator_account: 2, total_exposed_amount: 90 }, + Event::CollatorChosen { round: 6, collator_account: 3, total_exposed_amount: 80 }, + Event::CollatorChosen { round: 6, collator_account: 4, total_exposed_amount: 70 }, + Event::CollatorChosen { round: 6, collator_account: 6, total_exposed_amount: 69 }, + Event::NewRound { starting_block: 25, round: 6, selected_collators_number: 5, total_balance: 409 }, ); + }); +} - // should immediately affect total stake because collator can't be chosen in - // active set from now on, thus delegated stake is reduced - let old_stake = StakePallet::total_collator_stake(); - assert_eq!(StakePallet::candidate_pool(2).unwrap().total, 30); - assert_eq!(StakePallet::candidate_pool(2).unwrap().stake, 20); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![2, 1]); - assert_eq!( - StakePallet::candidate_pool(2).unwrap().stake, - StakePallet::candidate_pool(3).unwrap().stake - ); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(2))); - let old_stake = TotalStake { - delegators: old_stake.delegators - 10, - // total active collator stake is unchanged because number of selected candidates is 2 and 2's - // replacement has the same self stake as 2 - collators: old_stake.collators, - }; - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 3]); - assert_eq!(StakePallet::total_collator_stake(), old_stake); - - // shouldn't change total stake when 2 leaves - roll_to(10, vec![]); - assert_eq!(StakePallet::total_collator_stake(), old_stake); - assert_ok!(StakePallet::execute_leave_candidates(RuntimeOrigin::signed(2), 2)); - assert_eq!(StakePallet::total_collator_stake(), old_stake); - }) +#[test] +fn payout_distribution_to_solo_collators() { + ExtBuilder::default() + .with_balances(vec![(1, 1000), (2, 1000), (3, 1000), (4, 1000), (7, 33), (8, 33), (9, 33)]) + .with_candidates(vec![(1, 100), (2, 90), (3, 80), (4, 70)]) + .build() + .execute_with(|| { + roll_to_round_begin(2); + // should choose top TotalCandidatesSelected (5), in order + assert_events_eq!( + Event::CollatorChosen { round: 2, collator_account: 1, total_exposed_amount: 100 }, + Event::CollatorChosen { round: 2, collator_account: 2, total_exposed_amount: 90 }, + Event::CollatorChosen { round: 2, collator_account: 3, total_exposed_amount: 80 }, + Event::CollatorChosen { round: 2, collator_account: 4, total_exposed_amount: 70 }, + Event::NewRound { starting_block: 5, round: 2, selected_collators_number: 4, total_balance: 340 }, + ); + // ~ set block author as 1 for all blocks this round + set_author(2, 1, 100); + roll_to_round_begin(4); + assert_events_eq!( + Event::CollatorChosen { round: 4, collator_account: 1, total_exposed_amount: 100 }, + Event::CollatorChosen { round: 4, collator_account: 2, total_exposed_amount: 90 }, + Event::CollatorChosen { round: 4, collator_account: 3, total_exposed_amount: 80 }, + Event::CollatorChosen { round: 4, collator_account: 4, total_exposed_amount: 70 }, + Event::NewRound { starting_block: 15, round: 4, selected_collators_number: 4, total_balance: 340 }, + ); + // pay total issuance to 1 at 2nd block + roll_blocks(3); + assert_events_eq!(Event::Rewarded { account: 1, rewards: 205 }); + // ~ set block author as 1 for 3 blocks this round + set_author(4, 1, 60); + // ~ set block author as 2 for 2 blocks this round + set_author(4, 2, 40); + roll_to_round_begin(6); + // pay 60% total issuance to 1 and 40% total issuance to 2 + assert_events_eq!( + Event::CollatorChosen { round: 6, collator_account: 1, total_exposed_amount: 100 }, + Event::CollatorChosen { round: 6, collator_account: 2, total_exposed_amount: 90 }, + Event::CollatorChosen { round: 6, collator_account: 3, total_exposed_amount: 80 }, + Event::CollatorChosen { round: 6, collator_account: 4, total_exposed_amount: 70 }, + Event::NewRound { starting_block: 25, round: 6, selected_collators_number: 4, total_balance: 340 }, + ); + roll_blocks(3); + assert_events_eq!(Event::Rewarded { account: 1, rewards: 129 }); + roll_blocks(1); + assert_events_eq!(Event::Rewarded { account: 2, rewards: 86 },); + // ~ each collator produces 1 block this round + set_author(6, 1, 20); + set_author(6, 2, 20); + set_author(6, 3, 20); + set_author(6, 4, 20); + roll_to_round_begin(8); + // pay 20% issuance for all collators + assert_events_eq!( + Event::CollatorChosen { round: 8, collator_account: 1, total_exposed_amount: 100 }, + Event::CollatorChosen { round: 8, collator_account: 2, total_exposed_amount: 90 }, + Event::CollatorChosen { round: 8, collator_account: 3, total_exposed_amount: 80 }, + Event::CollatorChosen { round: 8, collator_account: 4, total_exposed_amount: 70 }, + Event::NewRound { starting_block: 35, round: 8, selected_collators_number: 4, total_balance: 340 }, + ); + roll_blocks(1); + assert_events_eq!(Event::Rewarded { account: 3, rewards: 56 }); + roll_blocks(1); + assert_events_eq!(Event::Rewarded { account: 4, rewards: 56 }); + roll_blocks(1); + assert_events_eq!(Event::Rewarded { account: 1, rewards: 56 }); + roll_blocks(1); + assert_events_eq!(Event::Rewarded { account: 2, rewards: 56 }); + // check that distributing rewards clears awarded pts + assert!(ParachainStaking::awarded_pts(1, 1).is_zero()); + assert!(ParachainStaking::awarded_pts(4, 1).is_zero()); + assert!(ParachainStaking::awarded_pts(4, 2).is_zero()); + assert!(ParachainStaking::awarded_pts(6, 1).is_zero()); + assert!(ParachainStaking::awarded_pts(6, 2).is_zero()); + assert!(ParachainStaking::awarded_pts(6, 3).is_zero()); + assert!(ParachainStaking::awarded_pts(6, 4).is_zero()); + }); } #[test] -fn collators_bond() { +fn multiple_delegations() { ExtBuilder::default() .with_balances(vec![ (1, 100), @@ -1163,3185 +3214,2475 @@ fn collators_bond() { (8, 100), (9, 100), (10, 100), - (11, 161_000_000 * DECIMALS), ]) - .with_collators(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 10)]) - .with_delegators(vec![(6, 1, 10), (7, 1, 10), (8, 2, 10), (9, 2, 10), (10, 1, 10)]) - .set_blocks_per_round(5) + .with_candidates(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 10)]) + .with_delegations(vec![(6, 1, 10), (7, 1, 10), (8, 2, 10), (9, 2, 10), (10, 1, 10)]) .build() .execute_with(|| { - roll_to(4, vec![]); - assert_noop!( - StakePallet::candidate_stake_more(RuntimeOrigin::signed(6), 50), - Error::::CandidateNotFound + roll_to_round_begin(2); + // chooses top TotalSelectedCandidates (5), in order + assert_events_eq!( + Event::CollatorChosen { round: 2, collator_account: 1, total_exposed_amount: 50 }, + Event::CollatorChosen { round: 2, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 2, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 2, collator_account: 4, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 2, collator_account: 5, total_exposed_amount: 10 }, + Event::NewRound { starting_block: 5, round: 2, selected_collators_number: 5, total_balance: 140 }, + ); + roll_blocks(1); + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(6), 2, 10, 10, 10)); + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(6), 3, 10, 10, 10)); + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(6), 4, 10, 10, 10)); + assert_events_eq!( + Event::Delegation { + delegator: 6, + locked_amount: 10, + candidate: 2, + delegator_position: DelegatorAdded::AddedToTop { new_total: 50 }, + auto_compound: Percent::zero(), + }, + Event::Delegation { + delegator: 6, + locked_amount: 10, + candidate: 3, + delegator_position: DelegatorAdded::AddedToTop { new_total: 30 }, + auto_compound: Percent::zero(), + }, + Event::Delegation { + delegator: 6, + locked_amount: 10, + candidate: 4, + delegator_position: DelegatorAdded::AddedToTop { new_total: 30 }, + auto_compound: Percent::zero(), + }, ); - assert_noop!( - StakePallet::candidate_stake_less(RuntimeOrigin::signed(6), 50), - Error::::CandidateNotFound + roll_to_round_begin(6); + roll_blocks(1); + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(7), 2, 80, 10, 10)); + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(10), 2, 10, 10, 10)); + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(2), 5)); + assert_events_eq!( + Event::Delegation { + delegator: 7, + locked_amount: 80, + candidate: 2, + delegator_position: DelegatorAdded::AddedToTop { new_total: 130 }, + auto_compound: Percent::zero(), + }, + Event::Delegation { + delegator: 10, + locked_amount: 10, + candidate: 2, + delegator_position: DelegatorAdded::AddedToBottom, + auto_compound: Percent::zero(), + }, + Event::CandidateScheduledExit { exit_allowed_round: 6, candidate: 2, scheduled_exit: 8 }, ); - assert_ok!(StakePallet::candidate_stake_more(RuntimeOrigin::signed(1), 50)); - assert_noop!( - StakePallet::candidate_stake_more(RuntimeOrigin::signed(1), 40), - BalancesError::::InsufficientBalance + roll_to_round_begin(7); + assert_events_eq!( + Event::CollatorChosen { round: 7, collator_account: 1, total_exposed_amount: 50 }, + Event::CollatorChosen { round: 7, collator_account: 3, total_exposed_amount: 30 }, + Event::CollatorChosen { round: 7, collator_account: 4, total_exposed_amount: 30 }, + Event::CollatorChosen { round: 7, collator_account: 5, total_exposed_amount: 10 }, + Event::NewRound { starting_block: 30, round: 7, selected_collators_number: 4, total_balance: 120 }, ); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(1))); - assert!(StakePallet::candidate_pool(1) - .unwrap() - .can_exit(::ExitQueueDelay::get())); + // verify that delegations are removed after collator leaves, not before + assert_eq!(ParachainStaking::delegator_state(7).unwrap().total(), 90); + assert_eq!(ParachainStaking::delegator_state(7).unwrap().delegations.0.len(), 2usize); + assert_eq!(ParachainStaking::delegator_state(6).unwrap().total(), 40); + assert_eq!(ParachainStaking::delegator_state(6).unwrap().delegations.0.len(), 4usize); + assert_eq!(Balances::locks(&6)[0].amount, 40); + assert_eq!(Balances::locks(&7)[0].amount, 90); + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&6), 60); + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&7), 10); + roll_to_round_begin(8); + roll_blocks(1); + assert_ok!(ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(2), 2, 5)); + assert_events_eq!(Event::CandidateLeft { + ex_candidate: 2, + unlocked_amount: 140, + new_total_amt_locked: 120, + }); + assert_eq!(ParachainStaking::delegator_state(7).unwrap().total(), 10); + assert_eq!(ParachainStaking::delegator_state(6).unwrap().total(), 30); + assert_eq!(ParachainStaking::delegator_state(7).unwrap().delegations.0.len(), 1usize); + assert_eq!(ParachainStaking::delegator_state(6).unwrap().delegations.0.len(), 3usize); + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&6), 70); + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&7), 90); + }); +} - assert_noop!( - StakePallet::candidate_stake_more(RuntimeOrigin::signed(1), 30), - Error::::CannotStakeIfLeaving - ); - assert_noop!( - StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 10), - Error::::CannotStakeIfLeaving - ); +#[test] +// The test verifies that the pending revoke request is removed by 2's exit so there is no dangling +// revoke request after 2 exits +fn execute_leave_candidate_removes_delegations() { + ExtBuilder::default() + .with_balances(vec![(1, 100), (2, 100), (3, 100), (4, 100)]) + .with_candidates(vec![(1, 20), (2, 20)]) + .with_delegations(vec![(3, 1, 10), (3, 2, 10), (4, 1, 10), (4, 2, 10)]) + .build() + .execute_with(|| { + // Verifies the revocation request is initially empty + assert!(!ParachainStaking::delegation_scheduled_requests(&2).iter().any(|x| x.delegator == 3)); + + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(2), 2)); + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(3), 2)); + // Verifies the revocation request is present + assert!(ParachainStaking::delegation_scheduled_requests(&2).iter().any(|x| x.delegator == 3)); + + roll_to(16); + assert_ok!(ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(2), 2, 2)); + // Verifies the revocation request is again empty + assert!(!ParachainStaking::delegation_scheduled_requests(&2).iter().any(|x| x.delegator == 3)); + }); +} - roll_to(30, vec![]); - assert_ok!(StakePallet::execute_leave_candidates(RuntimeOrigin::signed(1), 1)); - assert_noop!( - StakePallet::candidate_stake_more(RuntimeOrigin::signed(1), 40), - Error::::CandidateNotFound - ); - assert_ok!(StakePallet::candidate_stake_more(RuntimeOrigin::signed(2), 80)); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(2), 90)); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(3), 10)); - assert_noop!( - StakePallet::candidate_stake_less(RuntimeOrigin::signed(2), 11), - Error::::Underflow - ); - assert_noop!( - StakePallet::candidate_stake_less(RuntimeOrigin::signed(2), 1), - Error::::ValStakeBelowMin - ); - assert_noop!( - StakePallet::candidate_stake_less(RuntimeOrigin::signed(3), 1), - Error::::ValStakeBelowMin - ); +#[test] +fn payouts_follow_delegation_changes() { + ExtBuilder::default() + .with_balances(vec![(1, 100), (2, 100), (3, 100), (4, 100), (6, 100), (7, 100), (8, 100), (9, 100), (10, 100)]) + .with_candidates(vec![(1, 20), (2, 20), (3, 20), (4, 20)]) + .with_delegations(vec![(6, 1, 10), (7, 1, 10), (8, 2, 10), (9, 2, 10), (10, 1, 10)]) + .build() + .execute_with(|| { + roll_to_round_begin(2); + // chooses top TotalSelectedCandidates (5), in order + assert_events_eq!( + Event::CollatorChosen { round: 2, collator_account: 1, total_exposed_amount: 50 }, + Event::CollatorChosen { round: 2, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 2, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 2, collator_account: 4, total_exposed_amount: 20 }, + Event::NewRound { starting_block: 5, round: 2, selected_collators_number: 4, total_balance: 130 }, + ); + // ~ set block author as 1 for all blocks this round + set_author(2, 1, 100); + roll_to_round_begin(4); + // distribute total issuance to collator 1 and its delegators 6, 7, 19 + assert_events_eq!( + Event::CollatorChosen { round: 4, collator_account: 1, total_exposed_amount: 50 }, + Event::CollatorChosen { round: 4, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 4, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 4, collator_account: 4, total_exposed_amount: 20 }, + Event::NewRound { starting_block: 15, round: 4, selected_collators_number: 4, total_balance: 130 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 23 }, + Event::Rewarded { account: 6, rewards: 7 }, + Event::Rewarded { account: 7, rewards: 7 }, + Event::Rewarded { account: 10, rewards: 7 }, + ); + // ~ set block author as 1 for all blocks this round + set_author(3, 1, 100); + set_author(4, 1, 100); + set_author(5, 1, 100); + set_author(6, 1, 100); + + roll_blocks(1); + // 1. ensure delegators are paid for 2 rounds after they leave assert_noop!( - StakePallet::candidate_stake_less(RuntimeOrigin::signed(4), 11), - Error::::ValStakeBelowMin - ); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(4), 10)); + ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(66)), + Error::::DelegatorDNE + ); + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(6))); + assert_events_eq!(Event::DelegatorExitScheduled { round: 4, delegator: 6, scheduled_exit: 6 }); + // fast forward to block in which delegator 6 exit executes + roll_to_round_begin(5); + assert_events_eq!( + Event::CollatorChosen { round: 5, collator_account: 1, total_exposed_amount: 50 }, + Event::CollatorChosen { round: 5, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 5, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 5, collator_account: 4, total_exposed_amount: 20 }, + Event::NewRound { starting_block: 20, round: 5, selected_collators_number: 4, total_balance: 130 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 24 }, + Event::Rewarded { account: 6, rewards: 8 }, + Event::Rewarded { account: 7, rewards: 8 }, + Event::Rewarded { account: 10, rewards: 8 }, + ); + // keep paying 6 (note: inflation is in terms of total issuance so that's why 1 is 21) + roll_to_round_begin(6); + assert_ok!(ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(6), 6, 10)); + assert_events_eq!( + Event::CollatorChosen { round: 6, collator_account: 1, total_exposed_amount: 50 }, + Event::CollatorChosen { round: 6, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 6, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 6, collator_account: 4, total_exposed_amount: 20 }, + Event::NewRound { starting_block: 25, round: 6, selected_collators_number: 4, total_balance: 130 }, + Event::DelegatorLeftCandidate { + delegator: 6, + candidate: 1, + unstaked_amount: 10, + total_candidate_staked: 40, + }, + Event::DelegatorLeft { delegator: 6, unstaked_amount: 10 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 26 }, + Event::Rewarded { account: 6, rewards: 8 }, + Event::Rewarded { account: 7, rewards: 8 }, + Event::Rewarded { account: 10, rewards: 8 }, + ); + // 6 won't be paid for this round because they left already + set_author(7, 1, 100); + roll_to_round_begin(7); + // keep paying 6 + assert_events_eq!( + Event::CollatorChosen { round: 7, collator_account: 1, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 7, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 7, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 7, collator_account: 4, total_exposed_amount: 20 }, + Event::NewRound { starting_block: 30, round: 7, selected_collators_number: 4, total_balance: 120 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 31 }, + Event::Rewarded { account: 7, rewards: 10 }, + Event::Rewarded { account: 10, rewards: 10 }, + ); + roll_to_round_begin(8); + assert_events_eq!( + Event::CollatorChosen { round: 8, collator_account: 1, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 8, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 8, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 8, collator_account: 4, total_exposed_amount: 20 }, + Event::NewRound { starting_block: 35, round: 8, selected_collators_number: 4, total_balance: 120 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 33 }, + Event::Rewarded { account: 7, rewards: 11 }, + Event::Rewarded { account: 10, rewards: 11 }, + ); + set_author(8, 1, 100); + roll_to_round_begin(9); + // no more paying 6 + assert_events_eq!( + Event::CollatorChosen { round: 9, collator_account: 1, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 9, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 9, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 9, collator_account: 4, total_exposed_amount: 20 }, + Event::NewRound { starting_block: 40, round: 9, selected_collators_number: 4, total_balance: 120 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 34 }, + Event::Rewarded { account: 7, rewards: 11 }, + Event::Rewarded { account: 10, rewards: 11 }, + ); + roll_blocks(1); + set_author(9, 1, 100); + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(8), 1, 10, 10, 10)); + assert_events_eq!(Event::Delegation { + delegator: 8, + locked_amount: 10, + candidate: 1, + delegator_position: DelegatorAdded::AddedToTop { new_total: 50 }, + auto_compound: Percent::zero(), + }); - // MaxCollatorCandidateStake - assert_ok!(StakePallet::join_candidates( - RuntimeOrigin::signed(11), - StakePallet::max_candidate_stake() - )); - assert_noop!( - StakePallet::candidate_stake_more(RuntimeOrigin::signed(11), 1u128), - Error::::ValStakeAboveMax, + roll_to_round_begin(10); + // new delegation is not rewarded yet + assert_events_eq!( + Event::CollatorChosen { round: 10, collator_account: 1, total_exposed_amount: 50 }, + Event::CollatorChosen { round: 10, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 10, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 10, collator_account: 4, total_exposed_amount: 20 }, + Event::NewRound { starting_block: 45, round: 10, selected_collators_number: 4, total_balance: 130 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 36 }, + Event::Rewarded { account: 7, rewards: 12 }, + Event::Rewarded { account: 10, rewards: 12 }, + ); + set_author(10, 1, 100); + roll_to_round_begin(11); + // new delegation not rewarded yet + assert_events_eq!( + Event::CollatorChosen { round: 11, collator_account: 1, total_exposed_amount: 50 }, + Event::CollatorChosen { round: 11, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 11, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 11, collator_account: 4, total_exposed_amount: 20 }, + Event::NewRound { starting_block: 50, round: 11, selected_collators_number: 4, total_balance: 130 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 38 }, + Event::Rewarded { account: 7, rewards: 12 }, + Event::Rewarded { account: 10, rewards: 12 }, + ); + roll_to_round_begin(12); + // new delegation is rewarded for first time + // 2 rounds after joining (`RewardPaymentDelay` = 2) + assert_events_eq!( + Event::CollatorChosen { round: 12, collator_account: 1, total_exposed_amount: 50 }, + Event::CollatorChosen { round: 12, collator_account: 2, total_exposed_amount: 40 }, + Event::CollatorChosen { round: 12, collator_account: 3, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 12, collator_account: 4, total_exposed_amount: 20 }, + Event::NewRound { starting_block: 55, round: 12, selected_collators_number: 4, total_balance: 130 }, + ); + roll_blocks(3); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 34 }, + Event::Rewarded { account: 7, rewards: 11 }, + Event::Rewarded { account: 10, rewards: 11 }, + Event::Rewarded { account: 8, rewards: 11 }, ); }); } #[test] -fn delegators_bond() { +fn bottom_delegations_are_empty_when_top_delegations_not_full() { ExtBuilder::default() - .with_balances(vec![ - (1, 100), - (2, 100), - (3, 100), - (4, 100), - (5, 100), - (6, 100), - (7, 100), - (8, 100), - (9, 100), - (10, 100), + .with_balances(vec![(1, 20), (2, 10), (3, 10), (4, 10), (5, 10)]) + .with_candidates(vec![(1, 20)]) + .build() + .execute_with(|| { + // no top delegators => no bottom delegators + let top_delegations = ParachainStaking::top_delegations(1).unwrap(); + let bottom_delegations = ParachainStaking::bottom_delegations(1).unwrap(); + assert!(top_delegations.delegations.is_empty()); + assert!(bottom_delegations.delegations.is_empty()); + // 1 delegator => 1 top delegator, 0 bottom delegators + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(2), 1, 10, 10, 10)); + let top_delegations = ParachainStaking::top_delegations(1).unwrap(); + let bottom_delegations = ParachainStaking::bottom_delegations(1).unwrap(); + assert_eq!(top_delegations.delegations.len(), 1usize); + assert!(bottom_delegations.delegations.is_empty()); + // 2 delegators => 2 top delegators, 0 bottom delegators + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(3), 1, 10, 10, 10)); + let top_delegations = ParachainStaking::top_delegations(1).unwrap(); + let bottom_delegations = ParachainStaking::bottom_delegations(1).unwrap(); + assert_eq!(top_delegations.delegations.len(), 2usize); + assert!(bottom_delegations.delegations.is_empty()); + // 3 delegators => 3 top delegators, 0 bottom delegators + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(4), 1, 10, 10, 10)); + let top_delegations = ParachainStaking::top_delegations(1).unwrap(); + let bottom_delegations = ParachainStaking::bottom_delegations(1).unwrap(); + assert_eq!(top_delegations.delegations.len(), 3usize); + assert!(bottom_delegations.delegations.is_empty()); + // 4 delegators => 4 top delegators, 0 bottom delegators + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(5), 1, 10, 10, 10)); + let top_delegations = ParachainStaking::top_delegations(1).unwrap(); + let bottom_delegations = ParachainStaking::bottom_delegations(1).unwrap(); + assert_eq!(top_delegations.delegations.len(), 4usize); + assert!(bottom_delegations.delegations.is_empty()); + }); +} + +#[test] +fn candidate_pool_updates_when_total_counted_changes() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (3, 19), (4, 20), (5, 21), (6, 22), (7, 15), (8, 16), (9, 17), (10, 18)]) + .with_candidates(vec![(1, 20)]) + .with_delegations(vec![ + (3, 1, 11), + (4, 1, 12), + (5, 1, 13), + (6, 1, 14), + (7, 1, 15), + (8, 1, 16), + (9, 1, 17), + (10, 1, 18), ]) - .with_collators(vec![(1, 20), (2, 20), (3, 20), (4, 20), (5, 10)]) - .with_delegators(vec![(6, 1, 10), (7, 1, 10), (8, 2, 10), (9, 2, 10)]) - .set_blocks_per_round(5) .build() .execute_with(|| { - roll_to(4, vec![]); - assert_noop!( - StakePallet::join_delegators(RuntimeOrigin::signed(6), 2, 50), - Error::::AlreadyDelegating - ); - assert_noop!( - StakePallet::delegator_stake_more(RuntimeOrigin::signed(1), 50), - Error::::DelegatorNotFound - ); - assert_noop!( - StakePallet::delegator_stake_less(RuntimeOrigin::signed(1), 50), - Error::::DelegatorNotFound - ); - assert_noop!( - StakePallet::delegator_stake_less(RuntimeOrigin::signed(6), 11), - Error::::Underflow - ); - assert_noop!( - StakePallet::delegator_stake_less(RuntimeOrigin::signed(6), 8), - Error::::DelegationBelowMin - ); - assert_ok!(StakePallet::delegator_stake_more(RuntimeOrigin::signed(6), 10)); - assert_noop!( - StakePallet::delegator_stake_more(RuntimeOrigin::signed(6), 81), - BalancesError::::InsufficientBalance - ); - assert_noop!( - StakePallet::join_delegators(RuntimeOrigin::signed(10), 1, 4), - Error::::DelegationBelowMin - ); + fn is_candidate_pool_bond(account: u64, bond: u128) { + let pool = ParachainStaking::candidate_pool(); + for candidate in pool.0 { + if candidate.owner == account { + assert_eq!( + candidate.amount, bond, + "Candidate Bond {:?} is Not Equal to Expected: {:?}", + candidate.amount, bond + ); + } + } + } + // 15 + 16 + 17 + 18 + 20 = 86 (top 4 + self bond) + is_candidate_pool_bond(1, 86); + assert_ok!(ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(3), 1, 8)); + // 3: 11 -> 19 => 3 is in top, bumps out 7 + // 16 + 17 + 18 + 19 + 20 = 90 (top 4 + self bond) + is_candidate_pool_bond(1, 90); + assert_ok!(ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(4), 1, 8)); + // 4: 12 -> 20 => 4 is in top, bumps out 8 + // 17 + 18 + 19 + 20 + 20 = 94 (top 4 + self bond) + is_candidate_pool_bond(1, 94); + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(10), 1, 3)); + roll_to(30); + // 10: 18 -> 15 => 10 bumped to bottom, 8 bumped to top (- 18 + 16 = -2 for count) + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(10), 10, 1)); + // 16 + 17 + 19 + 20 + 20 = 92 (top 4 + self bond) + is_candidate_pool_bond(1, 92); + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(9), 1, 4)); + roll_to(40); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(9), 9, 1)); + // 15 + 16 + 19 + 20 + 20 = 90 (top 4 + self bond) + is_candidate_pool_bond(1, 90); + }); +} - roll_to(9, vec![]); - assert_eq!(Balances::usable_balance(&6), 80); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(1))); - assert!(StakePallet::candidate_pool(1) - .unwrap() - .can_exit(1 + ::ExitQueueDelay::get())); +#[test] +fn only_top_collators_are_counted() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (3, 19), (4, 20), (5, 21), (6, 22), (7, 15), (8, 16), (9, 17), (10, 18)]) + .with_candidates(vec![(1, 20)]) + .with_delegations(vec![ + (3, 1, 11), + (4, 1, 12), + (5, 1, 13), + (6, 1, 14), + (7, 1, 15), + (8, 1, 16), + (9, 1, 17), + (10, 1, 18), + ]) + .build() + .execute_with(|| { + // sanity check that 3-10 are delegators immediately + for i in 3..11 { + assert!(ParachainStaking::is_delegator(&i)); + } + let collator_state = ParachainStaking::candidate_info(1).unwrap(); + // 15 + 16 + 17 + 18 + 20 = 86 (top 4 + self bond) + assert_eq!(collator_state.total_counted, 86); + // bump bottom to the top + assert_ok!(ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(3), 1, 8)); + assert_events_emitted!(Event::DelegationIncreased { delegator: 3, candidate: 1, amount: 8, in_top: true }); + let collator_state = ParachainStaking::candidate_info(1).unwrap(); + // 16 + 17 + 18 + 19 + 20 = 90 (top 4 + self bond) + assert_eq!(collator_state.total_counted, 90); + // bump bottom to the top + assert_ok!(ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(4), 1, 8)); + assert_events_emitted!(Event::DelegationIncreased { delegator: 4, candidate: 1, amount: 8, in_top: true }); + let collator_state = ParachainStaking::candidate_info(1).unwrap(); + // 17 + 18 + 19 + 20 + 20 = 94 (top 4 + self bond) + assert_eq!(collator_state.total_counted, 94); + // bump bottom to the top + assert_ok!(ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(5), 1, 8)); + assert_events_emitted!(Event::DelegationIncreased { delegator: 5, candidate: 1, amount: 8, in_top: true }); + let collator_state = ParachainStaking::candidate_info(1).unwrap(); + // 18 + 19 + 20 + 21 + 20 = 98 (top 4 + self bond) + assert_eq!(collator_state.total_counted, 98); + // bump bottom to the top + assert_ok!(ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(6), 1, 8)); + assert_events_emitted!(Event::DelegationIncreased { delegator: 6, candidate: 1, amount: 8, in_top: true }); + let collator_state = ParachainStaking::candidate_info(1).unwrap(); + // 19 + 20 + 21 + 22 + 20 = 102 (top 4 + self bond) + assert_eq!(collator_state.total_counted, 102); + }); +} - roll_to(31, vec![]); - assert!(StakePallet::is_delegator(&6)); - assert_ok!(StakePallet::execute_leave_candidates(RuntimeOrigin::signed(1), 1)); - assert!(!StakePallet::is_delegator(&6)); - assert_eq!(Balances::usable_balance(&6), 80); - assert_eq!(Balances::free_balance(&6), 100); +#[test] +fn delegation_events_convey_correct_position() { + ExtBuilder::default() + .with_balances(vec![ + (1, 100), + (2, 100), + (3, 100), + (4, 100), + (5, 100), + (6, 100), + (7, 100), + (8, 100), + (9, 100), + (10, 100), + ]) + .with_candidates(vec![(1, 20), (2, 20)]) + .with_delegations(vec![(3, 1, 11), (4, 1, 12), (5, 1, 13), (6, 1, 14)]) + .build() + .execute_with(|| { + let collator1_state = ParachainStaking::candidate_info(1).unwrap(); + // 11 + 12 + 13 + 14 + 20 = 70 (top 4 + self bond) + assert_eq!(collator1_state.total_counted, 70); + // Top delegations are full, new highest delegation is made + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(7), 1, 15, 10, 10)); + assert_events_emitted!(Event::Delegation { + delegator: 7, + locked_amount: 15, + candidate: 1, + delegator_position: DelegatorAdded::AddedToTop { new_total: 74 }, + auto_compound: Percent::zero(), + }); + let collator1_state = ParachainStaking::candidate_info(1).unwrap(); + // 12 + 13 + 14 + 15 + 20 = 70 (top 4 + self bond) + assert_eq!(collator1_state.total_counted, 74); + // New delegation is added to the bottom + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(8), 1, 10, 10, 10)); + assert_events_emitted!(Event::Delegation { + delegator: 8, + locked_amount: 10, + candidate: 1, + delegator_position: DelegatorAdded::AddedToBottom, + auto_compound: Percent::zero(), + }); + let collator1_state = ParachainStaking::candidate_info(1).unwrap(); + // 12 + 13 + 14 + 15 + 20 = 70 (top 4 + self bond) + assert_eq!(collator1_state.total_counted, 74); + // 8 increases delegation to the top + assert_ok!(ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(8), 1, 3)); + assert_events_emitted!(Event::DelegationIncreased { delegator: 8, candidate: 1, amount: 3, in_top: true }); + let collator1_state = ParachainStaking::candidate_info(1).unwrap(); + // 13 + 13 + 14 + 15 + 20 = 75 (top 4 + self bond) + assert_eq!(collator1_state.total_counted, 75); + // 3 increases delegation but stays in bottom + assert_ok!(ParachainStaking::delegator_bond_more(RuntimeOrigin::signed(3), 1, 1)); + assert_events_emitted!(Event::DelegationIncreased { delegator: 3, candidate: 1, amount: 1, in_top: false }); + let collator1_state = ParachainStaking::candidate_info(1).unwrap(); + // 13 + 13 + 14 + 15 + 20 = 75 (top 4 + self bond) + assert_eq!(collator1_state.total_counted, 75); + // 6 decreases delegation but stays in top + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(6), 1, 2)); + assert_events_emitted!(Event::DelegationDecreaseScheduled { + delegator: 6, + candidate: 1, + amount_to_decrease: 2, + execute_round: 3, + }); + roll_to(30); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(6), 6, 1)); + assert_events_emitted!(Event::DelegationDecreased { delegator: 6, candidate: 1, amount: 2, in_top: true }); + let collator1_state = ParachainStaking::candidate_info(1).unwrap(); + // 12 + 13 + 13 + 15 + 20 = 73 (top 4 + self bond)ƒ + assert_eq!(collator1_state.total_counted, 73); + // 6 decreases delegation and is bumped to bottom + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(6), 1, 1)); + assert_events_emitted!(Event::DelegationDecreaseScheduled { + delegator: 6, + candidate: 1, + amount_to_decrease: 1, + execute_round: 9, + }); + roll_to(40); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(6), 6, 1)); + assert_events_emitted!(Event::DelegationDecreased { delegator: 6, candidate: 1, amount: 1, in_top: false }); + let collator1_state = ParachainStaking::candidate_info(1).unwrap(); + // 12 + 13 + 13 + 15 + 20 = 73 (top 4 + self bond) + assert_eq!(collator1_state.total_counted, 73); }); } #[test] -fn should_leave_delegators() { +fn no_rewards_paid_until_after_reward_payment_delay() { ExtBuilder::default() - .with_balances(vec![(1, 100), (2, 100)]) - .with_collators(vec![(1, 100)]) - .with_delegators(vec![(2, 1, 100)]) + .with_balances(vec![(1, 20), (2, 20), (3, 20)]) + .with_candidates(vec![(1, 20), (2, 20), (3, 20)]) .build() .execute_with(|| { - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(2))); - assert!(StakePallet::delegator_state(2).is_none()); - assert!(!StakePallet::candidate_pool(1) - .unwrap() - .delegators - .contains(&StakeOf:: { owner: 2, amount: 100 })); - assert_noop!( - StakePallet::leave_delegators(RuntimeOrigin::signed(2)), - Error::::DelegatorNotFound - ); - assert_noop!( - StakePallet::leave_delegators(RuntimeOrigin::signed(1)), - Error::::DelegatorNotFound - ); + roll_to_round_begin(2); + // payouts for round 1 + set_author(1, 1, 1); + set_author(1, 2, 1); + set_author(1, 2, 1); + set_author(1, 3, 1); + set_author(1, 3, 1); + assert_events_eq!( + Event::CollatorChosen { round: 2, collator_account: 1, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 2, collator_account: 2, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 2, collator_account: 3, total_exposed_amount: 20 }, + Event::NewRound { starting_block: 5, round: 2, selected_collators_number: 3, total_balance: 60 }, + ); + + roll_to_round_begin(3); + assert_events_eq!( + Event::CollatorChosen { round: 3, collator_account: 1, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 3, collator_account: 2, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 3, collator_account: 3, total_exposed_amount: 20 }, + Event::NewRound { starting_block: 10, round: 3, selected_collators_number: 3, total_balance: 60 }, + ); + + roll_blocks(1); + assert_events_eq!(Event::Rewarded { account: 3, rewards: 1 }); + + roll_blocks(1); + assert_events_eq!(Event::Rewarded { account: 1, rewards: 1 }); + + roll_blocks(1); + assert_events_eq!(Event::Rewarded { account: 2, rewards: 1 }); + + // there should be no more payments in this round... + let num_blocks_rolled = roll_to_round_end(3); + assert_no_events!(); + assert_eq!(num_blocks_rolled, 1); }); } #[test] -fn round_transitions() { - let col_max = 10; - let col_rewards = 15; - let d_max = 40; - let d_rewards = 10; - let inflation = InflationInfo::new( - ::BLOCKS_PER_YEAR, - Perquintill::from_percent(col_max), - Perquintill::from_percent(col_rewards), - Perquintill::from_percent(d_max), - Perquintill::from_percent(d_rewards), - ); +fn deferred_payment_storage_items_are_cleaned_up() { + use crate::*; + + // this test sets up two collators, gives them points in round one, and focuses on the + // storage over the next several blocks to show that it is properly cleaned up - // round_immediately_jumps_if_current_duration_exceeds_new_blocks_per_round - // change from 5 bpr to 3 in block 5 -> 8 should be new round ExtBuilder::default() - .with_balances(vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100), (6, 100)]) - .with_collators(vec![(1, 20)]) - .with_delegators(vec![(2, 1, 10), (3, 1, 10)]) - .with_inflation(col_max, col_rewards, d_max, d_rewards, 5) + .with_balances(vec![(1, 20), (2, 20)]) + .with_candidates(vec![(1, 20), (2, 20)]) .build() .execute_with(|| { - assert_eq!(inflation, StakePallet::inflation_config()); - roll_to(5, vec![]); - let init = vec![Event::NewRound(5, 1)]; - assert_eq!(events(), init); - assert_ok!(StakePallet::set_blocks_per_round(RuntimeOrigin::root(), 3)); - assert_noop!( - StakePallet::set_blocks_per_round(RuntimeOrigin::root(), 1), - Error::::CannotSetBelowMin + set_author(1, 1, 1); + set_author(1, 2, 1); + + // reflects genesis? + assert!(>::contains_key(1, 1)); + assert!(>::contains_key(1, 2)); + + roll_to_round_begin(2); + assert_events_eq!( + Event::CollatorChosen { round: 2, collator_account: 1, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 2, collator_account: 2, total_exposed_amount: 20 }, + Event::NewRound { starting_block: 5, round: 2, selected_collators_number: 2, total_balance: 40 }, ); - assert_eq!(last_event(), StakeEvent::BlocksPerRoundSet(1, 5, 5, 3)); - // inflation config should be untouched after per_block update - assert_eq!(inflation, StakePallet::inflation_config()); + // we should have AtStake snapshots as soon as we start a round... + assert!(>::contains_key(2, 1)); + assert!(>::contains_key(2, 2)); + // ...and it should persist until the round is fully paid out + assert!(>::contains_key(1, 1)); + assert!(>::contains_key(1, 2)); - // last round startet at 5 but we are already at 9, so we expect 9 to be the new - // round - roll_to(8, vec![]); - assert_eq!(last_event(), StakeEvent::NewRound(8, 2)) - }); + assert!( + !>::contains_key(1), + "DelayedPayouts shouldn't be populated until after RewardPaymentDelay" + ); + assert!(>::contains_key(1), "Points should be populated during current round"); + assert!(>::contains_key(1), "Staked should be populated when round changes"); - // if duration of current round is less than new bpr, round waits until new bpr - // passes - // change from 5 bpr to 3 in block 6 -> 8 should be new round - ExtBuilder::default() - .with_balances(vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100), (6, 100)]) - .with_collators(vec![(1, 20)]) - .with_delegators(vec![(2, 1, 10), (3, 1, 10)]) - .with_inflation(col_max, col_rewards, d_max, d_rewards, 5) - .build() - .execute_with(|| { - assert_eq!(inflation, StakePallet::inflation_config()); - // Default round every 5 blocks, but MinBlocksPerRound is 3 and we set it to min - // 3 blocks - roll_to(6, vec![]); - // chooses top MaxSelectedCandidates (5), in order - let init = vec![Event::NewRound(5, 1)]; - assert_eq!(events(), init); - assert_ok!(StakePallet::set_blocks_per_round(RuntimeOrigin::root(), 3)); - assert_eq!(last_event(), StakeEvent::BlocksPerRoundSet(1, 5, 5, 3)); + assert!(!>::contains_key(2), "Points should not be populated until author noted"); + assert!(>::contains_key(2), "Staked should be populated when round changes"); - // inflation config should be untouched after per_block update - assert_eq!(inflation, StakePallet::inflation_config()); + // first payout occurs in round 3 + roll_to_round_begin(3); + assert_events_eq!( + Event::CollatorChosen { round: 3, collator_account: 1, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 3, collator_account: 2, total_exposed_amount: 20 }, + Event::NewRound { starting_block: 10, round: 3, selected_collators_number: 2, total_balance: 40 }, + ); - // there should not be a new event - roll_to(7, vec![]); - assert_eq!(last_event(), StakeEvent::BlocksPerRoundSet(1, 5, 5, 3)); + roll_blocks(1); + assert_events_eq!(Event::Rewarded { account: 1, rewards: 1 },); - roll_to(8, vec![]); - assert_eq!(last_event(), StakeEvent::NewRound(8, 2)) - }); + // payouts should exist for past rounds that haven't been paid out yet.. + assert!(>::contains_key(3, 1)); + assert!(>::contains_key(3, 2)); + assert!(>::contains_key(2, 1)); + assert!(>::contains_key(2, 2)); - // round_immediately_jumps_if_current_duration_exceeds_new_blocks_per_round - // change from 5 bpr (blocks_per_round) to 3 in block 7 -> 8 should be new round - ExtBuilder::default() - .with_balances(vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100), (6, 100)]) - .with_collators(vec![(1, 20)]) - .with_delegators(vec![(2, 1, 10), (3, 1, 10)]) - .with_inflation(col_max, col_rewards, d_max, d_rewards, 5) - .build() - .execute_with(|| { - // Default round every 5 blocks, but MinBlocksPerRound is 3 and we set it to min - // 3 blocks - assert_eq!(inflation, StakePallet::inflation_config()); - roll_to(7, vec![]); - // chooses top MaxSelectedCandidates (5), in order - let init = vec![Event::NewRound(5, 1)]; - assert_eq!(events(), init); - assert_ok!(StakePallet::set_blocks_per_round(RuntimeOrigin::root(), 3)); + assert!( + >::contains_key(1), + "DelayedPayouts should be populated after RewardPaymentDelay" + ); + assert!(>::contains_key(1)); + assert!(!>::contains_key(1), "Staked should be cleaned up after round change"); - // inflation config should be untouched after per_block update - assert_eq!(inflation, StakePallet::inflation_config()); + assert!(!>::contains_key(2)); + assert!(!>::contains_key(2), "We never rewarded points for round 2"); + assert!(>::contains_key(2)); - assert_eq!( - StakePallet::inflation_config(), - InflationInfo::new( - ::BLOCKS_PER_YEAR, - Perquintill::from_percent(col_max), - Perquintill::from_percent(col_rewards), - Perquintill::from_percent(d_max), - Perquintill::from_percent(d_rewards) - ) + assert!(!>::contains_key(3)); + assert!(!>::contains_key(3), "We never awarded points for round 3"); + assert!(>::contains_key(3)); + + // collator 1 has been paid in this last block and associated storage cleaned up + assert!(!>::contains_key(1, 1)); + assert!(!>::contains_key(1, 1)); + + // but collator 2 hasn't been paid + assert!(>::contains_key(1, 2)); + assert!(>::contains_key(1, 2)); + + // second payout occurs in next block + roll_blocks(1); + assert_events_eq!(Event::Rewarded { account: 2, rewards: 1 },); + + roll_to_round_begin(4); + assert_events_eq!( + Event::CollatorChosen { round: 4, collator_account: 1, total_exposed_amount: 20 }, + Event::CollatorChosen { round: 4, collator_account: 2, total_exposed_amount: 20 }, + Event::NewRound { starting_block: 15, round: 4, selected_collators_number: 2, total_balance: 40 }, ); - assert_eq!(last_event(), StakeEvent::BlocksPerRoundSet(1, 5, 5, 3)); - roll_to(8, vec![]); - // last round startet at 5, so we expect 8 to be the new round - assert_eq!(last_event(), StakeEvent::NewRound(8, 2)) + // collators have both been paid and storage fully cleaned up for round 1 + assert!(!>::contains_key(1, 2)); + assert!(!>::contains_key(1, 2)); + assert!(!>::contains_key(1)); + assert!(!>::contains_key(1)); // points should be cleaned up + assert!(!>::contains_key(1)); + + roll_to_round_end(4); + + // no more events expected + assert_no_events!(); }); } #[test] -fn coinbase_rewards_few_blocks_detailed_check() { - ExtBuilder::default() - .with_balances(vec![ - (1, 40_000_000 * DECIMALS), - (2, 40_000_000 * DECIMALS), - (3, 40_000_000 * DECIMALS), - (4, 20_000_000 * DECIMALS), - (5, 20_000_000 * DECIMALS), - ]) - .with_collators(vec![(1, 8_000_000 * DECIMALS), (2, 8_000_000 * DECIMALS)]) - .with_delegators(vec![ - (3, 1, 32_000_000 * DECIMALS), - (4, 1, 16_000_000 * DECIMALS), - (5, 2, 16_000_000 * DECIMALS), - ]) - .with_inflation(10, 15, 40, 15, 5) - .build() - .execute_with(|| { - let inflation = StakePallet::inflation_config(); - let total_issuance = ::Currency::total_issuance(); - assert_eq!(total_issuance, 160_000_000 * DECIMALS); - - // compute rewards - let c_staking_rate = Perquintill::from_rational(16_000_000 * DECIMALS, total_issuance); - let c_rewards: BalanceOf = - inflation - .collator - .compute_reward::(16_000_000 * DECIMALS, c_staking_rate, 1u128); - let d_staking_rate = Perquintill::from_rational(64_000_000 * DECIMALS, total_issuance); - let d_rewards: BalanceOf = - inflation - .delegator - .compute_reward::(64_000_000 * DECIMALS, d_staking_rate, 2u128); - - // set 1 to be author for blocks 1-3, then 2 for blocks 4-5 - let authors: Vec> = - vec![None, Some(1u64), Some(1u64), Some(1u64), Some(2u64), Some(2u64)]; - // let d_rewards: Balance = 3 * 2469135802453333 / 2; - let user_1 = Balances::usable_balance(&1); - let user_2 = Balances::usable_balance(&2); - let user_3 = Balances::usable_balance(&3); - let user_4 = Balances::usable_balance(&4); - let user_5 = Balances::usable_balance(&5); - - assert_eq!(Balances::usable_balance(&1), user_1); - assert_eq!(Balances::usable_balance(&2), user_2); - assert_eq!(Balances::usable_balance(&3), user_3); - assert_eq!(Balances::usable_balance(&4), user_4); - assert_eq!(Balances::usable_balance(&5), user_5); - - // 1 is block author for 1st block - roll_to_claim_rewards(2, authors.clone()); - assert_eq!(Balances::usable_balance(&1), user_1 + c_rewards); - assert_eq!(Balances::usable_balance(&2), user_2); - assert_eq!(Balances::usable_balance(&3), user_3 + d_rewards / 2); - assert_eq!(Balances::usable_balance(&4), user_4 + d_rewards / 4); - assert_eq!(Balances::usable_balance(&5), user_5); - - // 1 is block author for 2nd block - roll_to_claim_rewards(3, authors.clone()); - assert_eq!(Balances::usable_balance(&1), user_1 + 2 * c_rewards); - assert_eq!(Balances::usable_balance(&2), user_2); - assert_eq!(Balances::usable_balance(&3), user_3 + d_rewards); - assert_eq!(Balances::usable_balance(&4), user_4 + d_rewards / 2); - assert_eq!(Balances::usable_balance(&5), user_5); - - // 1 is block author for 3rd block - roll_to_claim_rewards(4, authors.clone()); - assert_eq!(Balances::usable_balance(&1), user_1 + 3 * c_rewards); - assert_eq!(Balances::usable_balance(&2), user_2); - assert_eq!(Balances::usable_balance(&3), user_3 + d_rewards / 2 * 3); - assert_eq!(Balances::usable_balance(&4), user_4 + d_rewards / 4 * 3); - assert_eq!(Balances::usable_balance(&5), user_5); - - // 2 is block author for 4th block - roll_to_claim_rewards(5, authors.clone()); - assert_eq!(Balances::usable_balance(&1), user_1 + 3 * c_rewards); - assert_eq!(Balances::usable_balance(&2), user_2 + c_rewards); - assert_eq!(Balances::usable_balance(&3), user_3 + d_rewards / 2 * 3); - assert_eq!(Balances::usable_balance(&4), user_4 + d_rewards / 4 * 3); - assert_eq!(Balances::usable_balance(&5), user_5 + d_rewards / 4); - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(5))); - - // 2 is block author for 5th block - roll_to_claim_rewards(6, authors); - assert_eq!(Balances::usable_balance(&1), user_1 + 3 * c_rewards); - assert_eq!(Balances::usable_balance(&2), user_2 + 2 * c_rewards); - assert_eq!(Balances::usable_balance(&3), user_3 + d_rewards / 2 * 3); - assert_eq!(Balances::usable_balance(&4), user_4 + d_rewards / 4 * 3); - // should not receive rewards due to revoked delegation - assert_eq!(Balances::usable_balance(&5), user_5 + d_rewards / 4); - }); -} - -#[test] -fn delegator_should_not_receive_rewards_after_revoking() { - // test edge case of 1 delegator - ExtBuilder::default() - .with_balances(vec![(1, 10_000_000 * DECIMALS), (2, 10_000_000 * DECIMALS)]) - .with_collators(vec![(1, 10_000_000 * DECIMALS)]) - .with_delegators(vec![(2, 1, 10_000_000 * DECIMALS)]) - .with_inflation(10, 15, 40, 15, 5) - .build() - .execute_with(|| { - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(2))); - let authors: Vec> = (1u64..100u64).map(|_| Some(1u64)).collect(); - assert_eq!(Balances::usable_balance(&1), Balance::zero()); - assert_eq!(Balances::usable_balance(&2), Balance::zero()); - roll_to_claim_rewards(100, authors); - assert!(Balances::usable_balance(&1) > Balance::zero()); - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(2), 2)); - assert_eq!(Balances::usable_balance(&2), 10_000_000 * DECIMALS); - }); +fn deferred_payment_and_at_stake_storage_items_cleaned_up_for_candidates_not_producing_blocks() { + use crate::*; ExtBuilder::default() - .with_balances(vec![ - (1, 10_000_000 * DECIMALS), - (2, 10_000_000 * DECIMALS), - (3, 10_000_000 * DECIMALS), - ]) - .with_collators(vec![(1, 10_000_000 * DECIMALS)]) - .with_delegators(vec![(2, 1, 10_000_000 * DECIMALS), (3, 1, 10_000_000 * DECIMALS)]) - .with_inflation(10, 15, 40, 15, 5) + .with_balances(vec![(1, 20), (2, 20), (3, 20)]) + .with_candidates(vec![(1, 20), (2, 20), (3, 20)]) .build() .execute_with(|| { - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(3))); - let authors: Vec> = (1u64..100u64).map(|_| Some(1u64)).collect(); - assert_eq!(Balances::usable_balance(&1), Balance::zero()); - assert_eq!(Balances::usable_balance(&2), Balance::zero()); - assert_eq!(Balances::usable_balance(&3), Balance::zero()); - roll_to_claim_rewards(100, authors); - assert!(Balances::usable_balance(&1) > Balance::zero()); - assert!(Balances::usable_balance(&2) > Balance::zero()); - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(3), 3)); - assert_eq!(Balances::usable_balance(&3), 10_000_000 * DECIMALS); + // candidate 3 will not produce blocks + set_author(1, 1, 1); + set_author(1, 2, 1); + + // reflects genesis? + assert!(>::contains_key(1, 1)); + assert!(>::contains_key(1, 2)); + + roll_to_round_begin(2); + assert!(>::contains_key(1, 1)); + assert!(>::contains_key(1, 2)); + assert!(>::contains_key(1, 3)); + assert!(>::contains_key(1, 1)); + assert!(>::contains_key(1, 2)); + assert!(!>::contains_key(1, 3)); + assert!(>::contains_key(1)); + assert!(>::contains_key(1)); + roll_to_round_begin(3); + assert!(>::contains_key(1)); + + // all storage items must be cleaned up + roll_to_round_begin(4); + assert!(!>::contains_key(1, 1)); + assert!(!>::contains_key(1, 2)); + assert!(!>::contains_key(1, 3)); + assert!(!>::contains_key(1, 1)); + assert!(!>::contains_key(1, 2)); + assert!(!>::contains_key(1, 3)); + assert!(!>::contains_key(1)); + assert!(!>::contains_key(1)); + assert!(!>::contains_key(1)); }); } + #[test] -fn coinbase_rewards_many_blocks_simple_check() { - let num_of_years: Perquintill = Perquintill::from_perthousand(2); +fn deferred_payment_steady_state_event_flow() { + use frame_support::traits::{Currency, ExistenceRequirement, WithdrawReasons}; + + // this test "flows" through a number of rounds, asserting that certain things do/don't happen + // once the staking pallet is in a "steady state" (specifically, once we are past the first few + // rounds to clear RewardPaymentDelay) + ExtBuilder::default() .with_balances(vec![ - (1, 40_000_000 * DECIMALS), - (2, 40_000_000 * DECIMALS), - (3, 40_000_000 * DECIMALS), - (4, 20_000_000 * DECIMALS), - (5, 20_000_000 * DECIMALS), + // collators + (1, 200), + (2, 200), + (3, 200), + (4, 200), + // delegators + (11, 200), + (22, 200), + (33, 200), + (44, 200), + // burn account, see `reset_issuance()` + (111, 1000), ]) - .with_collators(vec![(1, 8_000_000 * DECIMALS), (2, 8_000_000 * DECIMALS)]) - .with_delegators(vec![ - (3, 1, 32_000_000 * DECIMALS), - (4, 1, 16_000_000 * DECIMALS), - (5, 2, 16_000_000 * DECIMALS), + .with_candidates(vec![(1, 200), (2, 200), (3, 200), (4, 200)]) + .with_delegations(vec![ + // delegator 11 delegates 100 to 1 and 2 + (11, 1, 100), + (11, 2, 100), + // delegator 22 delegates 100 to 2 and 3 + (22, 2, 100), + (22, 3, 100), + // delegator 33 delegates 100 to 3 and 4 + (33, 3, 100), + (33, 4, 100), + // delegator 44 delegates 100 to 4 and 1 + (44, 4, 100), + (44, 1, 100), ]) - .with_inflation(10, 15, 40, 15, 5) - .build() - .execute_with(|| { - let inflation = StakePallet::inflation_config(); - let total_issuance = ::Currency::total_issuance(); - assert_eq!(total_issuance, 160_000_000 * DECIMALS); - let end_block: BlockNumber = num_of_years * Test::BLOCKS_PER_YEAR as BlockNumber; - // set round robin authoring - let authors: Vec> = (0u64..=end_block).map(|i| Some(i % 2 + 1)).collect(); - roll_to_claim_rewards(end_block, authors); - - let rewards_1 = Balances::free_balance(&1).saturating_sub(40_000_000 * DECIMALS); - let rewards_2 = Balances::free_balance(&2).saturating_sub(40_000_000 * DECIMALS); - let rewards_3 = Balances::free_balance(&3).saturating_sub(40_000_000 * DECIMALS); - let rewards_4 = Balances::free_balance(&4).saturating_sub(20_000_000 * DECIMALS); - let rewards_5 = Balances::free_balance(&5).saturating_sub(20_000_000 * DECIMALS); - let expected_collator_rewards = - num_of_years * inflation.collator.reward_rate.annual * 16_000_000 * DECIMALS; - let expected_delegator_rewards = - num_of_years * inflation.delegator.reward_rate.annual * 64_000_000 * DECIMALS; - - // 1200000000000000000000 - // 2399074074058720000 - - // collator rewards should be about the same - assert!(almost_equal(rewards_1, rewards_2, Perbill::from_perthousand(1))); - assert!( - almost_equal( - rewards_1, - num_of_years * inflation.collator.reward_rate.annual * 8_000_000 * DECIMALS, - Perbill::from_perthousand(1) - ), - "left {:?}, right {:?}", - rewards_1, - inflation.collator.reward_rate.annual * 8_000_000 * DECIMALS, - ); + .build() + .execute_with(|| { + // convenience to set the round points consistently + let set_round_points = |round: BlockNumber| { + set_author(round as BlockNumber, 1, 1); + set_author(round as BlockNumber, 2, 1); + set_author(round as BlockNumber, 3, 1); + set_author(round as BlockNumber, 4, 1); + }; - // delegator rewards should be about the same - assert!( - almost_equal(rewards_3, rewards_4 + rewards_5, Perbill::from_perthousand(1)), - "left {:?}, right {:?}", - rewards_3, - rewards_4 + rewards_5 - ); - assert!(almost_equal( - rewards_3, - num_of_years * inflation.delegator.reward_rate.annual * 32_000_000 * DECIMALS, - Perbill::from_perthousand(1) - )); + // grab initial issuance -- we will reset it before round issuance is calculated so that + // it is consistent every round + let initial_issuance = Balances::total_issuance(); + let reset_issuance = || { + let new_issuance = Balances::total_issuance(); + let diff = new_issuance - initial_issuance; + let burned = Balances::burn(diff); + Balances::settle(&111, burned, WithdrawReasons::FEE, ExistenceRequirement::AllowDeath) + .expect("Account can absorb burn"); + }; - // check rewards in total - assert!( - almost_equal( - rewards_1 + rewards_2, - expected_collator_rewards, - Perbill::from_perthousand(1), - ), - "left {:?}, right {:?}", - rewards_1 + rewards_2, - expected_collator_rewards, - ); - assert!( - almost_equal( - rewards_3 + rewards_4 + rewards_5, - expected_delegator_rewards, - Perbill::from_perthousand(1), - ), - "left {:?}, right {:?}", - rewards_3 + rewards_4 + rewards_5, - expected_delegator_rewards, - ); + // fn to roll through the first RewardPaymentDelay rounds. returns new round index + let roll_through_initial_rounds = |mut round: BlockNumber| -> BlockNumber { + while round < crate::mock::RewardPaymentDelay::get() + 1 { + set_round_points(round); - // old issuance + rewards should equal new issuance - assert!( - almost_equal( - total_issuance + expected_collator_rewards + expected_delegator_rewards, - ::Currency::total_issuance(), - Perbill::from_perthousand(1), - ), - "left {:?}, right {:?}", - total_issuance + expected_collator_rewards + expected_delegator_rewards, - ::Currency::total_issuance(), - ); - }); -} + roll_to_round_end(round); + round += 1; + } -// Could only occur if we increase MinDelegatorStakeOf::via runtime -// upgrade and don't migrate delegators which fall below minimum -#[test] -fn should_not_reward_delegators_below_min_stake() { - ExtBuilder::default() - .with_balances(vec![(1, 10 * DECIMALS), (2, 10 * DECIMALS), (3, 10 * DECIMALS), (4, 5)]) - .with_collators(vec![(1, 10 * DECIMALS), (2, 10 * DECIMALS)]) - .with_delegators(vec![(3, 2, 10 * DECIMALS)]) - .with_inflation(10, 15, 40, 15, 5) - .build() - .execute_with(|| { - // impossible but lets assume it happened - let mut state = StakePallet::candidate_pool(&1).expect("CollatorState cannot be missing"); - let delegator_stake_below_min = ::MinDelegatorStake::get() - 1; - state.stake += delegator_stake_below_min; - state.total += delegator_stake_below_min; - let impossible_bond = StakeOf:: { - owner: 4u64, - amount: delegator_stake_below_min, + reset_issuance(); + + round }; - assert_eq!(state.delegators.try_insert(impossible_bond), Ok(true)); - >::insert(1u64, state); - let authors: Vec> = vec![Some(1u64), Some(1u64), Some(1u64), Some(1u64)]; - assert_eq!(Balances::usable_balance(&1), Balance::zero()); - assert_eq!(Balances::usable_balance(&2), Balance::zero()); - assert_eq!(Balances::usable_balance(&3), Balance::zero()); - assert_eq!(Balances::usable_balance(&4), 5); + // roll through a "steady state" round and make all of our assertions + // returns new round index + let roll_through_steady_state_round = |round: BlockNumber| -> BlockNumber { + let num_rounds_rolled = roll_to_round_begin(round); + assert!(num_rounds_rolled <= 1, "expected to be at round begin already"); + + assert_events_eq!( + Event::CollatorChosen { round: round as u32, collator_account: 1, total_exposed_amount: 400 }, + Event::CollatorChosen { round: round as u32, collator_account: 2, total_exposed_amount: 400 }, + Event::CollatorChosen { round: round as u32, collator_account: 3, total_exposed_amount: 400 }, + Event::CollatorChosen { round: round as u32, collator_account: 4, total_exposed_amount: 400 }, + Event::NewRound { + starting_block: (round - 1) * 5, + round: round as u32, + selected_collators_number: 4, + total_balance: 1600, + }, + ); - // should only reward 1 - roll_to_claim_rewards(4, authors); - assert!(Balances::usable_balance(&1) > Balance::zero()); - assert_eq!(Balances::usable_balance(&4), 5); - assert_eq!(Balances::usable_balance(&2), Balance::zero()); - assert_eq!(Balances::usable_balance(&3), Balance::zero()); - }); -} + set_round_points(round); -#[test] -#[should_panic] -fn should_deny_low_delegator_stake() { - ExtBuilder::default() - .with_balances(vec![(1, 10 * DECIMALS), (2, 10 * DECIMALS), (3, 10 * DECIMALS), (4, 1)]) - .with_collators(vec![(1, 10 * DECIMALS), (2, 10 * DECIMALS)]) - .with_delegators(vec![(4, 2, 1)]) - .build() - .execute_with(|| {}); + roll_blocks(1); + assert_events_eq!( + Event::Rewarded { account: 3, rewards: 19 }, + Event::Rewarded { account: 22, rewards: 6 }, + Event::Rewarded { account: 33, rewards: 6 }, + ); + + roll_blocks(1); + assert_events_eq!( + Event::Rewarded { account: 4, rewards: 19 }, + Event::Rewarded { account: 33, rewards: 6 }, + Event::Rewarded { account: 44, rewards: 6 }, + ); + + roll_blocks(1); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 19 }, + Event::Rewarded { account: 11, rewards: 6 }, + Event::Rewarded { account: 44, rewards: 6 }, + ); + + roll_blocks(1); + assert_events_eq!( + Event::Rewarded { account: 2, rewards: 19 }, + Event::Rewarded { account: 11, rewards: 6 }, + Event::Rewarded { account: 22, rewards: 6 }, + ); + + roll_blocks(1); + // Since we defer first deferred staking payout, this test have the maximum amout of + // supported collators. This eman that the next round is trigerred one block after + // the last reward. + //assert_no_events!(); + + let num_rounds_rolled = roll_to_round_end(round); + assert_eq!(num_rounds_rolled, 0, "expected to be at round end already"); + + reset_issuance(); + + round + 1 + }; + + let mut round = 1; + round = roll_through_initial_rounds(round); // we should be at RewardPaymentDelay + for _ in 1..2 { + round = roll_through_steady_state_round(round); + } + }); } #[test] -#[should_panic] -fn should_deny_low_collator_stake() { +fn delegation_kicked_from_bottom_removes_pending_request() { ExtBuilder::default() - .with_balances(vec![(1, 10 * DECIMALS), (2, 5)]) - .with_collators(vec![(1, 10 * DECIMALS), (2, 5)]) + .with_balances(vec![ + (1, 30), + (2, 29), + (3, 20), + (4, 20), + (5, 20), + (6, 20), + (7, 20), + (8, 20), + (9, 20), + (10, 20), + (11, 30), + ]) + .with_candidates(vec![(1, 30), (11, 30)]) + .with_delegations(vec![ + (2, 1, 19), + (2, 11, 10), // second delegation so not left after first is kicked + (3, 1, 20), + (4, 1, 20), + (5, 1, 20), + (6, 1, 20), + (7, 1, 20), + (8, 1, 20), + (9, 1, 20), + ]) .build() - .execute_with(|| {}); + .execute_with(|| { + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + // 10 delegates to full 1 => kicks lowest delegation (2, 19) + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(10), 1, 20, 8, 0)); + // check the event + assert_events_emitted!(Event::DelegationKicked { delegator: 2, candidate: 1, unstaked_amount: 19 }); + // ensure request DNE + assert!(!ParachainStaking::delegation_scheduled_requests(&1).iter().any(|x| x.delegator == 2)); + }); } #[test] -#[should_panic] -fn should_deny_duplicate_collators() { +fn no_selected_candidates_defaults_to_last_round_collators() { ExtBuilder::default() - .with_balances(vec![(1, 10 * DECIMALS)]) - .with_collators(vec![(1, 10 * DECIMALS), (1, 10 * DECIMALS)]) + .with_balances(vec![(1, 30), (2, 30), (3, 30), (4, 30), (5, 30)]) + .with_candidates(vec![(1, 30), (2, 30), (3, 30), (4, 30), (5, 30)]) .build() - .execute_with(|| {}); + .execute_with(|| { + roll_to_round_begin(1); + // schedule to leave + for i in 1..6 { + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(i), 5)); + } + let old_round = ParachainStaking::round().current; + let old_selected_candidates = ParachainStaking::selected_candidates(); + let mut old_at_stake_snapshots = Vec::new(); + for account in old_selected_candidates.clone() { + old_at_stake_snapshots.push(>::get(old_round, account)); + } + roll_to_round_begin(3); + // execute leave + for i in 1..6 { + assert_ok!(ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(i), i, 0,)); + } + // next round + roll_to_round_begin(4); + let new_round = ParachainStaking::round().current; + // check AtStake matches previous + let new_selected_candidates = ParachainStaking::selected_candidates(); + assert_eq!(old_selected_candidates, new_selected_candidates); + let mut index = 0usize; + for account in new_selected_candidates { + assert_eq!(old_at_stake_snapshots[index], >::get(new_round, account)); + index += 1usize; + } + }); } #[test] -fn reach_max_top_candidates() { +fn test_delegator_scheduled_for_revoke_is_rewarded_for_previous_rounds_but_not_for_future() { ExtBuilder::default() - .with_balances(vec![ - (1, 11), - (2, 20), - (3, 11), - (4, 11), - (5, 11), - (6, 11), - (7, 11), - (8, 11), - (9, 11), - (10, 11), - (11, 11), - (12, 12), - (13, 13), - ]) - .with_collators(vec![ - (1, 10), - (2, 20), - (3, 10), - (4, 10), - (5, 10), - (6, 10), - (7, 10), - (8, 10), - (9, 10), - (10, 10), - ]) + .with_balances(vec![(1, 20), (2, 40), (3, 20), (4, 20)]) + .with_candidates(vec![(1, 20), (3, 20), (4, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) .build() .execute_with(|| { + // preset rewards for rounds 1, 2 and 3 + (1..=3).for_each(|round| set_author(round, 1, 1)); + + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + assert_events_eq!(Event::DelegationRevocationScheduled { + round: 1, + delegator: 2, + candidate: 1, + scheduled_exit: 3, + }); + let collator = ParachainStaking::candidate_info(1).expect("candidate must exist"); + assert_eq!(1, collator.delegation_count, "collator's delegator count was reduced unexpectedly"); + assert_eq!(30, collator.total_counted, "collator's total was reduced unexpectedly"); + + roll_to_round_begin(3); + assert_events_emitted_match!(Event::NewRound { round: 3, .. }); + roll_blocks(3); + assert_events_eq!(Event::Rewarded { account: 1, rewards: 4 }, Event::Rewarded { account: 2, rewards: 1 },); + + roll_to_round_begin(4); + assert_events_emitted_match!(Event::NewRound { round: 4, .. }); + roll_blocks(3); + assert_events_eq!(Event::Rewarded { account: 1, rewards: 5 },); + let collator_snapshot = ParachainStaking::at_stake(ParachainStaking::round().current, 1); assert_eq!( - StakePallet::top_candidates().len().saturated_into::(), - ::MaxTopCandidates::get() - ); - // should not be possible to join candidate pool, even with more stake - assert_ok!(StakePallet::join_candidates(RuntimeOrigin::signed(11), 11)); - assert_eq!( - StakePallet::top_candidates() - .into_iter() - .map(|s| s.owner) - .collect::>(), - vec![2, 11, 1, 3, 4, 5, 6, 7, 8, 9] - ); - // last come, last one in the list - assert_ok!(StakePallet::join_candidates(RuntimeOrigin::signed(12), 11)); - assert_eq!( - StakePallet::top_candidates() - .into_iter() - .map(|s| s.owner) - .collect::>(), - vec![2, 11, 12, 1, 3, 4, 5, 6, 7, 8] - ); - assert_ok!(StakePallet::candidate_stake_more(RuntimeOrigin::signed(1), 1)); - assert_ok!(StakePallet::candidate_stake_more(RuntimeOrigin::signed(3), 1)); - assert_ok!(StakePallet::candidate_stake_more(RuntimeOrigin::signed(4), 1)); - assert_ok!(StakePallet::candidate_stake_more(RuntimeOrigin::signed(5), 1)); - assert_ok!(StakePallet::candidate_stake_more(RuntimeOrigin::signed(6), 1)); - assert_ok!(StakePallet::candidate_stake_more(RuntimeOrigin::signed(7), 1)); - assert_ok!(StakePallet::candidate_stake_more(RuntimeOrigin::signed(8), 1)); - assert_eq!( - StakePallet::top_candidates() - .into_iter() - .map(|s| s.owner) - .collect::>(), - vec![2, 11, 12, 1, 3, 4, 5, 6, 7, 8] + 1, + collator_snapshot.delegations.len(), + "collator snapshot's delegator count was reduced unexpectedly" ); + assert_eq!(20, collator_snapshot.total, "collator snapshot's total was reduced unexpectedly",); }); } #[test] -fn should_estimate_current_session_progress() { +fn test_delegator_scheduled_for_revoke_is_rewarded_when_request_cancelled() { ExtBuilder::default() - .set_blocks_per_round(100) - .with_balances(vec![ - (1, 10), - (2, 20), - (3, 10), - (4, 10), - (5, 10), - (6, 10), - (7, 10), - (8, 10), - (9, 10), - (10, 10), - (11, 10), - ]) - .with_collators(vec![ - (1, 10), - (2, 20), - (3, 10), - (4, 10), - (5, 10), - (6, 10), - (7, 10), - (8, 10), - (9, 10), - (10, 10), - ]) + .with_balances(vec![(1, 20), (2, 40), (3, 20), (4, 20)]) + .with_candidates(vec![(1, 20), (3, 20), (4, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) .build() .execute_with(|| { + // preset rewards for rounds 2, 3 and 4 + (2..=4).for_each(|round| set_author(round, 1, 1)); + + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + assert_events_eq!(Event::DelegationRevocationScheduled { + round: 1, + delegator: 2, + candidate: 1, + scheduled_exit: 3, + }); + let collator = ParachainStaking::candidate_info(1).expect("candidate must exist"); + assert_eq!(1, collator.delegation_count, "collator's delegator count was reduced unexpectedly"); + assert_eq!(30, collator.total_counted, "collator's total was reduced unexpectedly"); + + roll_to_round_begin(2); + assert_ok!(ParachainStaking::cancel_delegation_request(RuntimeOrigin::signed(2), 1)); + + roll_to_round_begin(4); + assert_events_emitted_match!(Event::NewRound { round: 4, .. }); + roll_blocks(3); + assert_events_eq!(Event::Rewarded { account: 1, rewards: 5 },); + let collator_snapshot = ParachainStaking::at_stake(ParachainStaking::round().current, 1); assert_eq!( - StakePallet::estimate_current_session_progress(10).0.unwrap(), - Permill::from_percent(10) - ); - assert_eq!( - StakePallet::estimate_current_session_progress(20).0.unwrap(), - Permill::from_percent(20) - ); - assert_eq!( - StakePallet::estimate_current_session_progress(30).0.unwrap(), - Permill::from_percent(30) - ); - assert_eq!( - StakePallet::estimate_current_session_progress(60).0.unwrap(), - Permill::from_percent(60) - ); - assert_eq!( - StakePallet::estimate_current_session_progress(100).0.unwrap(), - Permill::from_percent(100) + 1, + collator_snapshot.delegations.len(), + "collator snapshot's delegator count was reduced unexpectedly" ); + assert_eq!(30, collator_snapshot.total, "collator snapshot's total was reduced unexpectedly",); + + roll_to_round_begin(5); + assert_events_emitted_match!(Event::NewRound { round: 5, .. }); + roll_blocks(3); + assert_events_eq!(Event::Rewarded { account: 1, rewards: 4 }, Event::Rewarded { account: 2, rewards: 1 },); }); } #[test] -fn should_estimate_next_session_rotation() { +fn test_delegator_scheduled_for_bond_decrease_is_rewarded_for_previous_rounds_but_less_for_future() { ExtBuilder::default() - .set_blocks_per_round(100) - .with_balances(vec![ - (1, 10), - (2, 20), - (3, 10), - (4, 10), - (5, 10), - (6, 10), - (7, 10), - (8, 10), - (9, 10), - (10, 10), - (11, 10), - ]) - .with_collators(vec![ - (1, 10), - (2, 20), - (3, 10), - (4, 10), - (5, 10), - (6, 10), - (7, 10), - (8, 10), - (9, 10), - (10, 10), - ]) + .with_balances(vec![(1, 20), (2, 40), (3, 20), (4, 20)]) + .with_candidates(vec![(1, 20), (3, 20), (4, 20)]) + .with_delegations(vec![(2, 1, 20), (2, 3, 10)]) .build() .execute_with(|| { - assert_eq!(StakePallet::estimate_next_session_rotation(10).0.unwrap(), 100); - assert_eq!(StakePallet::estimate_next_session_rotation(20).0.unwrap(), 100); - assert_eq!(StakePallet::estimate_next_session_rotation(30).0.unwrap(), 100); - assert_eq!(StakePallet::estimate_next_session_rotation(60).0.unwrap(), 100); - assert_eq!(StakePallet::estimate_next_session_rotation(100).0.unwrap(), 100); + // preset rewards for rounds 1, 2 and 3 + (1..=3).for_each(|round| set_author(round, 1, 1)); + + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 10,)); + assert_events_eq!(Event::DelegationDecreaseScheduled { + execute_round: 3, + delegator: 2, + candidate: 1, + amount_to_decrease: 10, + }); + let collator = ParachainStaking::candidate_info(1).expect("candidate must exist"); + assert_eq!(1, collator.delegation_count, "collator's delegator count was reduced unexpectedly"); + assert_eq!(40, collator.total_counted, "collator's total was reduced unexpectedly"); + + roll_to_round_begin(3); + assert_events_emitted_match!(Event::NewRound { round: 3, .. }); + roll_blocks(3); + assert_events_eq!(Event::Rewarded { account: 1, rewards: 3 }, Event::Rewarded { account: 2, rewards: 2 },); + + roll_to_round_begin(4); + assert_events_emitted_match!(Event::NewRound { round: 4, .. }); + roll_blocks(3); + assert_events_eq!(Event::Rewarded { account: 1, rewards: 4 }, Event::Rewarded { account: 2, rewards: 1 },); + let collator_snapshot = ParachainStaking::at_stake(ParachainStaking::round().current, 1); + assert_eq!( + 1, + collator_snapshot.delegations.len(), + "collator snapshot's delegator count was reduced unexpectedly" + ); + assert_eq!(30, collator_snapshot.total, "collator snapshot's total was reduced unexpectedly",); }); } #[test] -fn should_end_session_when_appropriate() { +fn test_delegator_scheduled_for_bond_decrease_is_rewarded_when_request_cancelled() { ExtBuilder::default() - .set_blocks_per_round(100) - .with_balances(vec![ - (1, 10), - (2, 20), - (3, 10), - (4, 10), - (5, 10), - (6, 10), - (7, 10), - (8, 10), - (9, 10), - (10, 10), - (11, 10), - ]) - .with_collators(vec![ - (1, 10), - (2, 20), - (3, 10), - (4, 10), - (5, 10), - (6, 10), - (7, 10), - (8, 10), - (9, 10), - (10, 10), - ]) + .with_balances(vec![(1, 20), (2, 40), (3, 20), (4, 20)]) + .with_candidates(vec![(1, 20), (3, 20), (4, 20)]) + .with_delegations(vec![(2, 1, 20), (2, 3, 10)]) .build() .execute_with(|| { - assert!(!StakePallet::should_end_session(10)); - assert!(!StakePallet::should_end_session(20)); - assert!(!StakePallet::should_end_session(30)); - assert!(!StakePallet::should_end_session(60)); - assert!(StakePallet::should_end_session(100)); + // preset rewards for rounds 2, 3 and 4 + (2..=4).for_each(|round| set_author(round, 1, 1)); + + assert_ok!(ParachainStaking::schedule_delegator_bond_less(RuntimeOrigin::signed(2), 1, 10,)); + assert_events_eq!(Event::DelegationDecreaseScheduled { + execute_round: 3, + delegator: 2, + candidate: 1, + amount_to_decrease: 10, + }); + let collator = ParachainStaking::candidate_info(1).expect("candidate must exist"); + assert_eq!(1, collator.delegation_count, "collator's delegator count was reduced unexpectedly"); + assert_eq!(40, collator.total_counted, "collator's total was reduced unexpectedly"); + + roll_to_round_begin(2); + assert_ok!(ParachainStaking::cancel_delegation_request(RuntimeOrigin::signed(2), 1)); + + roll_to_round_begin(4); + assert_events_emitted_match!(Event::NewRound { round: 4, .. }); + roll_blocks(3); + assert_events_eq!(Event::Rewarded { account: 1, rewards: 4 }, Event::Rewarded { account: 2, rewards: 1 },); + let collator_snapshot = ParachainStaking::at_stake(ParachainStaking::round().current, 1); + assert_eq!( + 1, + collator_snapshot.delegations.len(), + "collator snapshot's delegator count was reduced unexpectedly" + ); + assert_eq!(40, collator_snapshot.total, "collator snapshot's total was reduced unexpectedly",); + + roll_to_round_begin(5); + assert_events_emitted_match!(Event::NewRound { round: 5, .. }); + roll_blocks(3); + assert_events_eq!(Event::Rewarded { account: 1, rewards: 3 }, Event::Rewarded { account: 2, rewards: 2 },); }); } #[test] -fn set_max_selected_candidates_safe_guards() { +fn test_delegator_scheduled_for_leave_is_rewarded_for_previous_rounds_but_not_for_future() { ExtBuilder::default() - .with_balances(vec![(1, 10)]) - .with_collators(vec![(1, 10)]) + .with_balances(vec![(1, 20), (2, 40), (3, 20), (4, 20)]) + .with_candidates(vec![(1, 20), (3, 20), (4, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) .build() .execute_with(|| { - assert_noop!( - StakePallet::set_max_selected_candidates( - RuntimeOrigin::root(), - ::MinCollators::get() - 1 - ), - Error::::CannotSetBelowMin - ); - assert_noop!( - StakePallet::set_max_selected_candidates( - RuntimeOrigin::root(), - ::MaxTopCandidates::get() + 1 - ), - Error::::CannotSetAboveMax + // preset rewards for rounds 1, 2 and 3 + (1..=3).for_each(|round| set_author(round, 1, 1)); + + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2),)); + assert_events_eq!(Event::DelegatorExitScheduled { round: 1, delegator: 2, scheduled_exit: 3 }); + let collator = ParachainStaking::candidate_info(1).expect("candidate must exist"); + assert_eq!(1, collator.delegation_count, "collator's delegator count was reduced unexpectedly"); + assert_eq!(30, collator.total_counted, "collator's total was reduced unexpectedly"); + + roll_to_round_begin(3); + assert_events_emitted_match!(Event::NewRound { round: 3, .. }); + roll_blocks(3); + assert_events_eq!(Event::Rewarded { account: 1, rewards: 4 }, Event::Rewarded { account: 2, rewards: 1 },); + + roll_to_round_begin(4); + assert_events_emitted_match!(Event::NewRound { round: 4, .. }); + roll_blocks(3); + assert_events_eq!(Event::Rewarded { account: 1, rewards: 5 },); + let collator_snapshot = ParachainStaking::at_stake(ParachainStaking::round().current, 1); + assert_eq!( + 1, + collator_snapshot.delegations.len(), + "collator snapshot's delegator count was reduced unexpectedly" ); - assert_ok!(StakePallet::set_max_selected_candidates( - RuntimeOrigin::root(), - ::MinCollators::get() + 1 - )); + assert_eq!(20, collator_snapshot.total, "collator snapshot's total was reduced unexpectedly",); }); } #[test] -fn set_max_selected_candidates_total_stake() { - let balances: Vec<(AccountId, Balance)> = (1..19).map(|x| (x, 100)).collect(); +fn test_delegator_scheduled_for_leave_is_rewarded_when_request_cancelled() { ExtBuilder::default() - .with_balances(balances) - .with_collators(vec![ - (1, 11), - (2, 12), - (3, 13), - (4, 14), - (5, 15), - (6, 16), - (7, 17), - (8, 18), - ]) - .with_delegators(vec![ - (11, 1, 21), - (12, 2, 22), - (13, 3, 23), - (14, 4, 24), - (15, 5, 25), - (16, 6, 26), - (17, 7, 27), - (18, 8, 28), - ]) + .with_balances(vec![(1, 20), (2, 40), (3, 20), (4, 20)]) + .with_candidates(vec![(1, 20), (3, 20), (4, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) .build() .execute_with(|| { + // preset rewards for rounds 2, 3 and 4 + (2..=4).for_each(|round| set_author(round, 1, 1)); + + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + assert_events_eq!(Event::DelegatorExitScheduled { round: 1, delegator: 2, scheduled_exit: 3 }); + let collator = ParachainStaking::candidate_info(1).expect("candidate must exist"); + assert_eq!(1, collator.delegation_count, "collator's delegator count was reduced unexpectedly"); + assert_eq!(30, collator.total_counted, "collator's total was reduced unexpectedly"); + + roll_to_round_begin(2); + assert_ok!(ParachainStaking::cancel_leave_delegators(RuntimeOrigin::signed(2))); + + roll_to_round_begin(4); + assert_events_emitted_match!(Event::NewRound { round: 4, .. }); + roll_blocks(3); + assert_events_eq!(Event::Rewarded { account: 1, rewards: 5 },); + let collator_snapshot = ParachainStaking::at_stake(ParachainStaking::round().current, 1); assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 35, - delegators: 55 - } - ); - - assert_ok!(StakePallet::set_max_selected_candidates(RuntimeOrigin::root(), 3)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 51, - delegators: 81 - } - ); - - assert_ok!(StakePallet::set_max_selected_candidates(RuntimeOrigin::root(), 5)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 80, - delegators: 130 - } - ); - - assert_ok!(StakePallet::set_max_selected_candidates(RuntimeOrigin::root(), 10)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 116, - delegators: 196 - } - ); - - assert_ok!(StakePallet::set_max_selected_candidates(RuntimeOrigin::root(), 2)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 35, - delegators: 55 - } + 1, + collator_snapshot.delegations.len(), + "collator snapshot's delegator count was reduced unexpectedly" ); + assert_eq!(30, collator_snapshot.total, "collator snapshot's total was reduced unexpectedly",); + + roll_to_round_begin(5); + assert_events_emitted_match!(Event::NewRound { round: 5, .. }); + roll_blocks(3); + assert_events_eq!(Event::Rewarded { account: 1, rewards: 4 }, Event::Rewarded { account: 2, rewards: 1 },); }); } #[test] -fn update_inflation() { +fn test_delegation_request_exists_returns_false_when_nothing_exists() { ExtBuilder::default() - .with_balances(vec![(1, 10)]) - .with_collators(vec![(1, 10)]) + .with_balances(vec![(1, 30), (2, 25)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) .build() .execute_with(|| { - let mut invalid_inflation = InflationInfo { - collator: StakingInfo { - max_rate: Perquintill::one(), - reward_rate: RewardRate { - annual: Perquintill::from_percent(99), - per_block: Perquintill::from_percent(1), - }, - }, - delegator: StakingInfo { - max_rate: Perquintill::one(), - reward_rate: RewardRate { - annual: Perquintill::from_percent(99), - per_block: Perquintill::from_percent(1), - }, - }, - }; - assert!(!invalid_inflation.is_valid(::BLOCKS_PER_YEAR)); - invalid_inflation.collator.reward_rate.per_block = Perquintill::zero(); - assert!(!invalid_inflation.is_valid(::BLOCKS_PER_YEAR)); - - assert_ok!(StakePallet::set_inflation( - RuntimeOrigin::root(), - Perquintill::from_percent(0), - Perquintill::from_percent(100), - Perquintill::from_percent(100), - Perquintill::from_percent(100), - )); - assert_ok!(StakePallet::set_inflation( - RuntimeOrigin::root(), - Perquintill::from_percent(100), - Perquintill::from_percent(0), - Perquintill::from_percent(100), - Perquintill::from_percent(100), - )); - assert_ok!(StakePallet::set_inflation( - RuntimeOrigin::root(), - Perquintill::from_percent(100), - Perquintill::from_percent(100), - Perquintill::from_percent(0), - Perquintill::from_percent(100), - )); - assert_ok!(StakePallet::set_inflation( - RuntimeOrigin::root(), - Perquintill::from_percent(100), - Perquintill::from_percent(100), - Perquintill::from_percent(100), - Perquintill::from_percent(0), - )); + assert!(!ParachainStaking::delegation_request_exists(&1, &2)); }); } #[test] -fn unlock_unstaked() { - // same_unstaked_as_restaked - // block 1: stake & unstake for 100 - // block 2: stake & unstake for 100 - // should remove first entry in unstaking BoundedBTreeMap when staking in block - // 2 should still have 100 locked until unlocking +fn test_delegation_request_exists_returns_true_when_decrease_exists() { ExtBuilder::default() - .with_balances(vec![(1, 10), (2, 100)]) - .with_collators(vec![(1, 10)]) - .with_delegators(vec![(2, 1, 100)]) + .with_balances(vec![(1, 30), (2, 25)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) .build() .execute_with(|| { - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(2))); - let mut unstaking: BoundedBTreeMap, ::MaxUnstakeRequests> = - BoundedBTreeMap::new(); - assert_ok!(unstaking.try_insert(3, 100)); - let lock = BalanceLock { - id: STAKING_ID, - amount: 100, - reasons: Reasons::All, - }; - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - // shouldn't be able to unlock anything - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(2), 2)); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - - // join delegators and revoke again --> consume unstaking at block 3 - roll_to(2, vec![]); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(2), 1, 100)); - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(2))); - unstaking.remove(&3); - assert_ok!(unstaking.try_insert(4, 100)); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - // shouldn't be able to unlock anything - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(2), 2)); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - - // should reduce unlocking but not unlock anything - roll_to(3, vec![]); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - // shouldn't be able to unlock anything - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(2), 2)); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - - roll_to(4, vec![]); - unstaking.remove(&4); - assert_eq!(Balances::locks(2), vec![lock]); - // shouldn't be able to unlock anything - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(2), 2)); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![]); - }); - - // less_unstaked_than_restaked - // block 1: stake & unstake for 10 - // block 2: stake & unstake for 100 - // should remove first entry in unstaking BoundedBTreeMap when staking in block - // 2 should still have 90 locked until unlocking in block 4 - ExtBuilder::default() - .with_balances(vec![(1, 10), (2, 100)]) - .with_collators(vec![(1, 10)]) - .with_delegators(vec![(2, 1, 10)]) - .build() - .execute_with(|| { - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(2))); - let mut unstaking: BoundedBTreeMap, ::MaxUnstakeRequests> = - BoundedBTreeMap::new(); - assert_ok!(unstaking.try_insert(3, 10)); - let mut lock = BalanceLock { - id: STAKING_ID, - amount: 10, - reasons: Reasons::All, - }; - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - // shouldn't be able to unlock anything - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(2), 2)); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - - // join delegators and revoke again - roll_to(2, vec![]); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(2), 1, 100)); - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(2))); - unstaking.remove(&3); - assert_ok!(unstaking.try_insert(4, 100)); - lock.amount = 100; - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - // shouldn't be able to unlock anything - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(2), 2)); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - - roll_to(3, vec![]); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - // shouldn't be able to unlock anything - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(2), 2)); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - - // unlock unstaked, remove lock, empty unlocking - roll_to(4, vec![]); - unstaking.remove(&4); - assert_eq!(Balances::locks(2), vec![lock]); - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(2), 2)); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![]); - }); - - // more_unstaked_than_restaked - // block 1: stake & unstake for 100 - // block 2: stake & unstake for 10 - // should reduce first entry from amount 100 to 90 in unstaking BoundedBTreeMap - // when staking in block 2 - // should have 100 locked until unlocking in block 3, then 10 - // should have 10 locked until further unlocking in block 4 - ExtBuilder::default() - .with_balances(vec![(1, 10), (2, 100)]) - .with_collators(vec![(1, 10)]) - .with_delegators(vec![(2, 1, 100)]) - .build() - .execute_with(|| { - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(2))); - let mut unstaking: BoundedBTreeMap, ::MaxUnstakeRequests> = - BoundedBTreeMap::new(); - assert_ok!(unstaking.try_insert(3, 100)); - let mut lock = BalanceLock { - id: STAKING_ID, - amount: 100, - reasons: Reasons::All, - }; - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - // shouldn't be able to unlock anything - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(2), 2)); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - - // join delegators and revoke again - roll_to(2, vec![]); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(2), 1, 10)); - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(2))); - assert_ok!(unstaking.try_insert(3, 90)); - assert_ok!(unstaking.try_insert(4, 10)); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - // shouldn't be able to unlock anything - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(2), 2)); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - - // should reduce unlocking but not unlock anything - roll_to(3, vec![]); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - // should be able to unlock 90 of 100 from unstaking - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(2), 2)); - unstaking.remove(&3); - lock.amount = 10; - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - - roll_to(4, vec![]); - assert_eq!(Balances::locks(2), vec![lock]); - // should be able to unlock 10 of remaining 10 - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(2), 2)); - unstaking.remove(&4); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(2), vec![]); - }); - - // test_stake_less - // block 1: stake & unstake for 100 - // block 2: stake & unstake for 10 - // should reduce first entry from amount 100 to 90 in unstaking BoundedBTreeMap - // when staking in block 2 - // should have 100 locked until unlocking in block 3, then 10 - // should have 10 locked until further unlocking in block 4 - ExtBuilder::default() - .with_balances(vec![(1, 200), (2, 200)]) - .with_collators(vec![(1, 200)]) - .with_delegators(vec![(2, 1, 200)]) - .build() - .execute_with(|| { - // should be able to decrease more often than MaxUnstakeRequests because it's - // the same block and thus unstaking is increased at block 3 instead of having - // multiple entries for the same block - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 10)); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 10)); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 10)); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 10)); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 10)); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 10),); - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(2), 10)); - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(2), 10)); - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(2), 10)); - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(2), 10)); - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(2), 10)); - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(2), 10),); - let mut unstaking: BoundedBTreeMap, ::MaxUnstakeRequests> = - BoundedBTreeMap::new(); - assert_ok!(unstaking.try_insert(3, 60)); - let mut lock = BalanceLock { - id: STAKING_ID, - amount: 200, - reasons: Reasons::All, - }; - assert_eq!(Balances::locks(1), vec![lock.clone()]); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - assert_eq!(StakePallet::unstaking(1), unstaking); - assert_eq!(StakePallet::unstaking(2), unstaking); - // shouldn't be able to unlock anything - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(1), 1)); - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(2), 2)); - assert_eq!(StakePallet::unstaking(1), unstaking); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(1), vec![lock.clone()]); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - - roll_to(2, vec![]); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 10),); - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(2), 10),); - assert_ok!(unstaking.try_insert(4, 10)); - assert_eq!(Balances::locks(1), vec![lock.clone()]); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - assert_eq!(StakePallet::unstaking(1), unstaking); - assert_eq!(StakePallet::unstaking(2), unstaking); - // shouldn't be able to unlock anything - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(1), 1)); - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(2), 2)); - assert_eq!(StakePallet::unstaking(1), unstaking); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(1), vec![lock.clone()]); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - - roll_to(3, vec![]); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 10),); - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(2), 10),); - assert_ok!(unstaking.try_insert(5, 10)); - assert_ok!(unstaking.try_insert(5, 10)); - assert_eq!(Balances::locks(1), vec![lock.clone()]); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - assert_eq!(StakePallet::unstaking(1), unstaking); - assert_eq!(StakePallet::unstaking(2), unstaking); - // should unlock 60 - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(1), 1)); - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(2), 2)); - lock.amount = 140; - unstaking.remove(&3); - assert_eq!(StakePallet::unstaking(1), unstaking); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(1), vec![lock.clone()]); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - - // reach MaxUnstakeRequests - roll_to(4, vec![]); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 10)); - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(2), 10)); - roll_to(5, vec![]); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 10)); - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(2), 10)); - roll_to(6, vec![]); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 10)); - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(2), 10)); - assert_ok!(unstaking.try_insert(6, 10)); - assert_ok!(unstaking.try_insert(7, 10)); - assert_ok!(unstaking.try_insert(8, 10)); - assert_eq!(StakePallet::unstaking(1), unstaking); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(1), vec![lock.clone()]); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - - roll_to(7, vec![]); - assert_noop!( - StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 10), - Error::::NoMoreUnstaking - ); - assert_noop!( - StakePallet::delegator_stake_less(RuntimeOrigin::signed(2), 10), - Error::::NoMoreUnstaking - ); - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(1), 1)); - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(2), 2)); - unstaking.remove(&4); - unstaking.remove(&5); - unstaking.remove(&6); - unstaking.remove(&7); - lock.amount = 100; - assert_eq!(StakePallet::unstaking(1), unstaking); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(1), vec![lock.clone()]); - assert_eq!(Balances::locks(2), vec![lock.clone()]); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 40)); - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(2), 40)); - assert_ok!(unstaking.try_insert(9, 40)); - assert_ok!(StakePallet::candidate_stake_more(RuntimeOrigin::signed(1), 30)); - assert_ok!(StakePallet::delegator_stake_more(RuntimeOrigin::signed(2), 30)); - unstaking.remove(&8); - assert_ok!(unstaking.try_insert(9, 20)); - assert_eq!(StakePallet::unstaking(1), unstaking); - assert_eq!(StakePallet::unstaking(2), unstaking); - assert_eq!(Balances::locks(1), vec![lock.clone()]); - assert_eq!(Balances::locks(2), vec![lock]); - }); -} - -#[test] -fn kick_candidate_with_full_unstaking() { - ExtBuilder::default() - .with_balances(vec![(1, 200), (2, 200), (3, 300)]) - .with_collators(vec![(1, 200), (2, 200), (3, 200)]) - .build() - .execute_with(|| { - let max_unstake_reqs: usize = ::MaxUnstakeRequests::get() - .saturating_sub(1) - .saturated_into(); - // Fill unstake requests - for block in 1u64..1u64.saturating_add(max_unstake_reqs as u64) { - System::set_block_number(block); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(3), 1)); - } - assert_eq!(StakePallet::unstaking(3).into_inner().len(), max_unstake_reqs); - - // Additional unstake should fail - System::set_block_number(100); - assert_noop!( - StakePallet::candidate_stake_less(RuntimeOrigin::signed(3), 1), - Error::::NoMoreUnstaking - ); - - // Fill last unstake request by removing candidate and unstaking all stake - assert_ok!(StakePallet::force_remove_candidate(RuntimeOrigin::root(), 3)); - - // Cannot join with full unstaking - assert_eq!(StakePallet::unstaking(3).into_inner().len(), max_unstake_reqs + 1); - assert_noop!( - StakePallet::join_candidates(RuntimeOrigin::signed(3), 100), - Error::::CannotJoinBeforeUnlocking + >::insert( + 1, + vec![ScheduledRequest { delegator: 2, when_executable: 3, action: DelegationAction::Decrease(5) }], ); - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(3), 3)); - assert_ok!(StakePallet::join_candidates(RuntimeOrigin::signed(3), 100)); + assert!(ParachainStaking::delegation_request_exists(&1, &2)); }); } + #[test] -fn kick_delegator_with_full_unstaking() { +fn test_delegation_request_exists_returns_true_when_revoke_exists() { ExtBuilder::default() - .with_balances(vec![(1, 200), (2, 200), (3, 200), (4, 200), (5, 420), (6, 200)]) - .with_collators(vec![(1, 200)]) - .with_delegators(vec![(2, 1, 200), (3, 1, 200), (4, 1, 200), (5, 1, 200)]) + .with_balances(vec![(1, 30), (2, 25)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) .build() .execute_with(|| { - let max_unstake_reqs: usize = ::MaxUnstakeRequests::get() - .saturating_sub(1) - .saturated_into(); - // Fill unstake requests - for block in 1u64..1u64.saturating_add(max_unstake_reqs as u64) { - System::set_block_number(block); - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(5), 1)); - } - assert_eq!(StakePallet::unstaking(5).into_inner().len(), max_unstake_reqs); - - // Additional unstake should fail - System::set_block_number(100); - assert_noop!( - StakePallet::delegator_stake_less(RuntimeOrigin::signed(5), 1), - Error::::NoMoreUnstaking + >::insert( + 1, + vec![ScheduledRequest { delegator: 2, when_executable: 3, action: DelegationAction::Revoke(5) }], ); + assert!(ParachainStaking::delegation_request_exists(&1, &2)); + }); +} - // Fill last unstake request by replacing delegator - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(6), 1, 200)); - assert_eq!(StakePallet::unstaking(5).into_inner().len(), max_unstake_reqs + 1); - assert!(!StakePallet::is_delegator(&5)); +#[test] +fn test_delegation_request_revoke_exists_returns_false_when_nothing_exists() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 25)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert!(!ParachainStaking::delegation_request_revoke_exists(&1, &2)); + }); +} - // Cannot join with full unstaking - assert_noop!( - StakePallet::join_delegators(RuntimeOrigin::signed(5), 1, 100), - Error::::CannotJoinBeforeUnlocking +#[test] +fn test_delegation_request_revoke_exists_returns_false_when_decrease_exists() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 25)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + >::insert( + 1, + vec![ScheduledRequest { delegator: 2, when_executable: 3, action: DelegationAction::Decrease(5) }], ); - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(5), 5)); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(5), 1, 220)); + assert!(!ParachainStaking::delegation_request_revoke_exists(&1, &2)); }); } #[test] -fn candidate_leaves() { - let balances: Vec<(AccountId, Balance)> = (1u64..=15u64).map(|id| (id, 100)).collect(); +fn test_delegation_request_revoke_exists_returns_true_when_revoke_exists() { ExtBuilder::default() - .with_balances(balances) - .with_collators(vec![(1, 100), (2, 100)]) - .with_delegators(vec![(12, 1, 100), (13, 1, 10)]) + .with_balances(vec![(1, 30), (2, 25)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) .build() .execute_with(|| { - assert_eq!( - StakePallet::top_candidates() - .into_iter() - .map(|s| s.owner) - .collect::>(), - vec![1, 2] - ); - assert_noop!( - StakePallet::init_leave_candidates(RuntimeOrigin::signed(11)), - Error::::CandidateNotFound - ); - assert_noop!( - StakePallet::init_leave_candidates(RuntimeOrigin::signed(1)), - Error::::TooFewCollatorCandidates - ); - // add five more collator to max fill TopCandidates - for candidate in 3u64..11u64 { - assert_ok!(StakePallet::join_candidates(RuntimeOrigin::signed(candidate), 100)); - } - assert_eq!( - StakePallet::top_candidates() - .into_iter() - .map(|s| s.owner) - .collect::>(), - (1u64..11u64).collect::>() - ); - assert_eq!(CandidatePool::::count(), 10); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(1))); - assert_eq!( - StakePallet::top_candidates() - .into_iter() - .map(|s| s.owner) - .collect::>(), - (2u64..11u64).collect::>() - ); - assert_noop!( - StakePallet::join_delegators(RuntimeOrigin::signed(15), 1, 10), - Error::::CannotDelegateIfLeaving - ); - assert_noop!( - StakePallet::delegator_stake_more(RuntimeOrigin::signed(12), 1), - Error::::CannotDelegateIfLeaving - ); - assert_noop!( - StakePallet::delegator_stake_less(RuntimeOrigin::signed(12), 1), - Error::::CannotDelegateIfLeaving - ); - assert_noop!( - StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 1), - Error::::CannotStakeIfLeaving + >::insert( + 1, + vec![ScheduledRequest { delegator: 2, when_executable: 3, action: DelegationAction::Revoke(5) }], ); - assert_noop!( - StakePallet::candidate_stake_more(RuntimeOrigin::signed(1), 1), - Error::::CannotStakeIfLeaving - ); - assert_noop!( - StakePallet::init_leave_candidates(RuntimeOrigin::signed(1)), - Error::::AlreadyLeaving - ); - assert_eq!( - StakePallet::candidate_pool(1).unwrap().status, - CandidateStatus::Leaving(2) - ); - assert!(StakePallet::candidate_pool(1).unwrap().can_exit(2)); - assert!(!StakePallet::candidate_pool(1).unwrap().can_exit(1)); - assert!(StakePallet::candidate_pool(1).unwrap().can_exit(3)); + assert!(ParachainStaking::delegation_request_revoke_exists(&1, &2)); + }); +} - // next rounds starts, cannot leave yet - roll_to(5, vec![]); - assert_noop!( - StakePallet::execute_leave_candidates(RuntimeOrigin::signed(2), 2), - Error::::NotLeaving - ); - assert_noop!( - StakePallet::execute_leave_candidates(RuntimeOrigin::signed(2), 1), - Error::::CannotLeaveYet - ); - // add 11 as candidate to reach max size for TopCandidates and then try leave - // again as 1 which should not be possible - assert_ok!(StakePallet::join_candidates(RuntimeOrigin::signed(11), 100)); - assert_eq!( - StakePallet::top_candidates() - .into_iter() - .map(|s| s.owner) - .collect::>(), - (2u64..12u64).collect::>() - ); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(11))); - // join back - assert_ok!(StakePallet::cancel_leave_candidates(RuntimeOrigin::signed(1))); - assert_eq!( - StakePallet::top_candidates() - .into_iter() - .map(|s| s.owner) - .collect::>(), - (1u64..11u64).collect::>() - ); +#[test] +fn test_hotfix_remove_delegation_requests_exited_candidates_cleans_up() { + ExtBuilder::default().with_balances(vec![(1, 20)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + // invalid state + >::insert(2, Vec::>::new()); + >::insert(3, Vec::>::new()); + assert_ok!(ParachainStaking::hotfix_remove_delegation_requests_exited_candidates( + RuntimeOrigin::signed(1), + vec![2, 3, 4] // 4 does not exist, but is OK for idempotency + )); + + assert!(!>::contains_key(2)); + assert!(!>::contains_key(3)); + }); +} - let stake: Vec> = (1u64..11u64) - .zip(iter::once(210).chain(iter::repeat(100))) - .map(|(id, amount)| StakeOf:: { owner: id, amount }) - .collect(); - assert_eq!( - StakePallet::top_candidates(), - OrderedSet::from(stake.try_into().unwrap()) - ); - let state = StakePallet::candidate_pool(1).unwrap(); - assert_eq!(state.status, CandidateStatus::Active); - assert_eq!(state.delegators.len(), 2); - assert_eq!(state.total, 210); - assert_eq!( - state.total, - StakePallet::top_candidates() - .into_bounded_vec() - .iter() - .find(|other| other.owner == 1) - .unwrap() - .amount - ); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2]); - - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(1))); - - roll_to(15, vec![]); - assert_ok!(StakePallet::execute_leave_candidates(RuntimeOrigin::signed(13), 1)); - let mut unstaking: BoundedBTreeMap, ::MaxUnstakeRequests> = - BoundedBTreeMap::new(); - assert_ok!(unstaking.try_insert(17, 100)); - assert_eq!(StakePallet::unstaking(1), unstaking); - assert_eq!(StakePallet::unstaking(12), unstaking); - - // cannot unlock yet - roll_to(16, vec![]); - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(4), 1)); - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(4), 12)); - assert_eq!(StakePallet::unstaking(1), unstaking); - assert_eq!(StakePallet::unstaking(12), unstaking); - - // can unlock now - roll_to(17, vec![]); - unstaking.remove(&17); - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(4), 1)); - assert_ok!(StakePallet::unlock_unstaked(RuntimeOrigin::signed(4), 12)); - assert_eq!(StakePallet::unstaking(1), unstaking); - assert_eq!(StakePallet::unstaking(12), unstaking); - }); -} - -#[test] -fn adjust_reward_rates() { - ExtBuilder::default() - .with_balances(vec![(1, 10_000_000 * DECIMALS), (2, 90_000_000 * DECIMALS)]) - .with_collators(vec![(1, 10_000_000 * DECIMALS)]) - .with_delegators(vec![(2, 1, 40_000_000 * DECIMALS)]) - .with_inflation(10, 10, 40, 8, 5) - .build() - .execute_with(|| { - let inflation_0 = StakePallet::inflation_config(); - let num_of_years = 3 * ::BLOCKS_PER_YEAR; - // 1 authors every block - let authors: Vec> = (0u64..=num_of_years).map(|_| Some(1u64)).collect(); - - // reward once in first year - roll_to_claim_rewards(2, authors.clone()); - let c_rewards_0 = Balances::free_balance(&1).saturating_sub(10_000_000 * DECIMALS); - let d_rewards_0 = Balances::free_balance(&2).saturating_sub(90_000_000 * DECIMALS); - assert!(!c_rewards_0.is_zero()); - assert!(!d_rewards_0.is_zero()); - - // finish first year - System::set_block_number(::BLOCKS_PER_YEAR); - roll_to_claim_rewards(::BLOCKS_PER_YEAR + 1, vec![]); - // reward reduction should not happen automatically anymore - assert_eq!(StakePallet::last_reward_reduction(), 0u64); - assert_ok!(StakePallet::execute_scheduled_reward_change(RuntimeOrigin::signed(1))); - assert_eq!(StakePallet::last_reward_reduction(), 1u64); - let inflation_1 = InflationInfo::new( - ::BLOCKS_PER_YEAR, - inflation_0.collator.max_rate, - Perquintill::from_parts(98000000000000000), - inflation_0.delegator.max_rate, - Perquintill::from_percent(6), - ); - assert_eq!(StakePallet::inflation_config(), inflation_1); - // reward once in 2nd year - roll_to_claim_rewards(::BLOCKS_PER_YEAR + 2, authors.clone()); - let c_rewards_1 = Balances::free_balance(&1) - .saturating_sub(10_000_000 * DECIMALS) - .saturating_sub(c_rewards_0); - let d_rewards_1 = Balances::free_balance(&2) - .saturating_sub(90_000_000 * DECIMALS) - .saturating_sub(d_rewards_0); - assert!( - c_rewards_0 > c_rewards_1, - "left {:?}, right {:?}", - c_rewards_0, - c_rewards_1 - ); - assert!(d_rewards_0 > d_rewards_1); - - // finish 2nd year - System::set_block_number(2 * ::BLOCKS_PER_YEAR); - roll_to_claim_rewards(2 * ::BLOCKS_PER_YEAR + 1, vec![]); - // reward reduction should not happen automatically anymore - assert_eq!(StakePallet::last_reward_reduction(), 1u64); - assert_ok!(StakePallet::execute_scheduled_reward_change(RuntimeOrigin::signed(1))); - assert_eq!(StakePallet::last_reward_reduction(), 2u64); - let inflation_2 = InflationInfo::new( - ::BLOCKS_PER_YEAR, - inflation_0.collator.max_rate, - Perquintill::from_parts(96040000000000000), - inflation_0.delegator.max_rate, - Perquintill::zero(), - ); - assert_eq!(StakePallet::inflation_config(), inflation_2); - // reward once in 3rd year - roll_to_claim_rewards(2 * ::BLOCKS_PER_YEAR + 2, authors); - let c_rewards_2 = Balances::free_balance(&1) - .saturating_sub(10_000_000 * DECIMALS) - .saturating_sub(c_rewards_0) - .saturating_sub(c_rewards_1); - assert!(c_rewards_1 > c_rewards_2); - // should be zero because we set reward rate to zero - let d_rewards_2 = Balances::free_balance(&2) - .saturating_sub(90_000_000 * DECIMALS) - .saturating_sub(d_rewards_0) - .saturating_sub(d_rewards_1); - assert!(d_rewards_2.is_zero()); - }); -} - -#[test] -fn increase_max_candidate_stake() { - let max_stake = 160_000_000 * DECIMALS; - ExtBuilder::default() - .with_balances(vec![(1, 200_000_000 * DECIMALS)]) - .with_collators(vec![(1, max_stake)]) - .build() - .execute_with(|| { - assert_eq!(StakePallet::max_candidate_stake(), max_stake); - assert_noop!( - StakePallet::candidate_stake_more(RuntimeOrigin::signed(1), 1), - Error::::ValStakeAboveMax - ); +#[test] +fn test_hotfix_remove_delegation_requests_exited_candidates_cleans_up_only_specified_keys() { + ExtBuilder::default().with_balances(vec![(1, 20)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + // invalid state + >::insert(2, Vec::>::new()); + >::insert(3, Vec::>::new()); + assert_ok!(ParachainStaking::hotfix_remove_delegation_requests_exited_candidates( + RuntimeOrigin::signed(1), + vec![2] + )); + + assert!(!>::contains_key(2)); + assert!(>::contains_key(3)); + }); +} - assert_ok!(StakePallet::set_max_candidate_stake( - RuntimeOrigin::root(), - max_stake + 1 - )); - assert_eq!(last_event(), StakeEvent::MaxCandidateStakeChanged(max_stake + 1)); - assert_eq!(StakePallet::max_candidate_stake(), max_stake + 1); - assert_ok!(StakePallet::candidate_stake_more(RuntimeOrigin::signed(1), 1)); - assert_noop!( - StakePallet::candidate_stake_more(RuntimeOrigin::signed(1), 1), - Error::::ValStakeAboveMax - ); - }); +#[test] +fn test_hotfix_remove_delegation_requests_exited_candidates_errors_when_requests_not_empty() { + ExtBuilder::default().with_balances(vec![(1, 20)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + // invalid state + >::insert(2, Vec::>::new()); + >::insert( + 3, + vec![ScheduledRequest { delegator: 10, when_executable: 1, action: DelegationAction::Revoke(10) }], + ); + + assert_noop!( + ParachainStaking::hotfix_remove_delegation_requests_exited_candidates(RuntimeOrigin::signed(1), vec![2, 3]), + >::CandidateNotLeaving, + ); + }); +} + +#[test] +fn test_hotfix_remove_delegation_requests_exited_candidates_errors_when_candidate_not_exited() { + ExtBuilder::default().with_balances(vec![(1, 20)]).with_candidates(vec![(1, 20)]).build().execute_with(|| { + // invalid state + >::insert(1, Vec::>::new()); + assert_noop!( + ParachainStaking::hotfix_remove_delegation_requests_exited_candidates(RuntimeOrigin::signed(1), vec![1]), + >::CandidateNotLeaving, + ); + }); +} + +#[test] +fn locking_zero_amount_is_ignored() { + use frame_support::traits::{LockableCurrency, WithdrawReasons}; + + // this test demonstrates the behavior of pallet Balance's `LockableCurrency` implementation of + // `set_locks()` when an amount of 0 is provided: it is a no-op + + ExtBuilder::default().with_balances(vec![(1, 100)]).build().execute_with(|| { + assert_eq!(crate::mock::query_lock_amount(1, DELEGATOR_LOCK_ID), None); + + Balances::set_lock(DELEGATOR_LOCK_ID, &1, 1, WithdrawReasons::all()); + assert_eq!(crate::mock::query_lock_amount(1, DELEGATOR_LOCK_ID), Some(1)); + + Balances::set_lock(DELEGATOR_LOCK_ID, &1, 0, WithdrawReasons::all()); + // Note that we tried to call `set_lock(0)` and it ignored it, we still have our lock + assert_eq!(crate::mock::query_lock_amount(1, DELEGATOR_LOCK_ID), Some(1)); + }); } #[test] -fn decrease_max_candidate_stake() { +fn revoke_last_removes_lock() { ExtBuilder::default() - .with_balances(vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100)]) - .with_collators(vec![(1, 100), (2, 90), (3, 40)]) - .with_delegators(vec![(4, 2, 10), (5, 3, 20)]) + .with_balances(vec![(1, 100), (2, 100), (3, 100)]) + .with_candidates(vec![(1, 25), (2, 25)]) + .with_delegations(vec![(3, 1, 30), (3, 2, 25)]) .build() .execute_with(|| { - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2]); - assert_eq!( - StakePallet::top_candidates(), - OrderedSet::from_sorted_set( - vec![ - StakeOf:: { owner: 1, amount: 100 }, - StakeOf:: { owner: 2, amount: 100 }, - StakeOf:: { owner: 3, amount: 60 } - ] - .try_into() - .unwrap() - ) - ); + assert_eq!(crate::mock::query_lock_amount(3, DELEGATOR_LOCK_ID), Some(55)); + + // schedule and remove one... + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(3), 1)); + roll_to_round_begin(3); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(3), 3, 1)); + assert_eq!(crate::mock::query_lock_amount(3, DELEGATOR_LOCK_ID), Some(25)); + + // schedule and remove the other... + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(3), 2)); + roll_to_round_begin(5); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(3), 3, 2)); + assert_eq!(crate::mock::query_lock_amount(3, DELEGATOR_LOCK_ID), None); + }); +} - assert_ok!(StakePallet::set_max_candidate_stake(RuntimeOrigin::root(), 50)); - assert_eq!(StakePallet::max_candidate_stake(), 50); - assert_eq!(last_event(), StakeEvent::MaxCandidateStakeChanged(50)); +#[allow(deprecated)] +#[test] +fn test_delegator_with_deprecated_status_leaving_can_schedule_leave_delegators_as_fix() { + ExtBuilder::default() + .with_balances(vec![(1, 20), (2, 40)]) + .with_candidates(vec![(1, 20)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + >::mutate(2, |value| { + value.as_mut().map(|mut state| { + state.status = DelegatorStatus::Leaving(2); + }) + }); + let state = >::get(2); + assert!(matches!(state.unwrap().status, DelegatorStatus::Leaving(_))); - // check collator states, nothing changed - assert_eq!( - StakePallet::top_candidates(), - OrderedSet::from_sorted_set( - vec![ - StakeOf:: { owner: 1, amount: 100 }, - StakeOf:: { owner: 2, amount: 100 }, - StakeOf:: { owner: 3, amount: 60 } - ] - .try_into() - .unwrap() - ) - ); + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + assert!(>::get(1) + .iter() + .any(|r| r.delegator == 2 && matches!(r.action, DelegationAction::Revoke(_)))); + assert_events_eq!(Event::DelegatorExitScheduled { round: 1, delegator: 2, scheduled_exit: 3 }); - assert_noop!( - StakePallet::candidate_stake_more(RuntimeOrigin::signed(1), 0), - Error::::ValStakeZero - ); - assert_noop!( - StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 0), - Error::::ValStakeZero - ); - assert_noop!( - StakePallet::candidate_stake_more(RuntimeOrigin::signed(1), 1), - Error::::ValStakeAboveMax - ); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 50)); - assert_noop!( - StakePallet::set_max_candidate_stake(RuntimeOrigin::root(), 9), - Error::::CannotSetBelowMin - ); + let state = >::get(2); + assert!(matches!(state.unwrap().status, DelegatorStatus::Active)); }); } +#[allow(deprecated)] #[test] -fn exceed_delegations_per_round() { +fn test_delegator_with_deprecated_status_leaving_can_cancel_leave_delegators_as_fix() { ExtBuilder::default() - .with_balances(vec![(1, 100), (2, 100)]) - .with_collators(vec![(1, 100)]) - .with_delegators(vec![(2, 1, 100)]) + .with_balances(vec![(1, 20), (2, 40)]) + .with_candidates(vec![(1, 20)]) + .with_delegations(vec![(2, 1, 10)]) .build() .execute_with(|| { - // leave and re-join to set counter to 2 (= MaxDelegationsPerRound) - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(2))); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(2), 1, 100)); - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(2))); - // reached max delegations in this round - assert_noop!( - StakePallet::join_delegators(RuntimeOrigin::signed(2), 1, 100), - Error::::DelegationsPerRoundExceeded - ); + >::mutate(2, |value| { + value.as_mut().map(|mut state| { + state.status = DelegatorStatus::Leaving(2); + }) + }); + let state = >::get(2); + assert!(matches!(state.unwrap().status, DelegatorStatus::Leaving(_))); - // roll to next round to clear DelegationCounter - roll_to(5, vec![]); - assert_eq!( - StakePallet::last_delegation(2), - DelegationCounter { round: 0, counter: 2 } - ); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(2), 1, 100)); - // counter should be reset because the round changed - assert_eq!( - StakePallet::last_delegation(2), - DelegationCounter { round: 1, counter: 1 } - ); - // leave and re-join to set counter to 2 (= MaxDelegationsPerRound)) - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(2))); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(2), 1, 100)); - assert_noop!( - StakePallet::join_delegators(RuntimeOrigin::signed(2), 1, 100), - Error::::AlreadyDelegating - ); - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(2))); - assert_noop!( - StakePallet::join_delegators(RuntimeOrigin::signed(2), 1, 100), - Error::::DelegationsPerRoundExceeded - ); - assert_eq!( - StakePallet::last_delegation(2), - DelegationCounter { round: 1, counter: 2 } - ); + assert_ok!(ParachainStaking::cancel_leave_delegators(RuntimeOrigin::signed(2))); + assert_events_eq!(Event::DelegatorExitCancelled { delegator: 2 }); + + let state = >::get(2); + assert!(matches!(state.unwrap().status, DelegatorStatus::Active)); }); } +#[allow(deprecated)] #[test] -fn force_remove_candidate() { +fn test_delegator_with_deprecated_status_leaving_can_execute_leave_delegators_as_fix() { ExtBuilder::default() - .with_balances(vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100), (6, 100)]) - .with_collators(vec![(1, 100), (2, 100), (3, 100)]) - .with_delegators(vec![(4, 1, 50), (5, 1, 50)]) + .with_balances(vec![(1, 20), (2, 40)]) + .with_candidates(vec![(1, 20)]) + .with_delegations(vec![(2, 1, 10)]) .build() .execute_with(|| { - assert_eq!(CandidatePool::::count(), 3); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(6), 2, 50)); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2]); - assert!(StakePallet::unstaking(1).get(&3).is_none()); - assert!(StakePallet::unstaking(2).get(&3).is_none()); - assert!(StakePallet::unstaking(3).get(&3).is_none()); - - // force remove 1 - assert!(Session::disabled_validators().is_empty()); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 200, - delegators: 150 - } - ); - assert_ok!(StakePallet::force_remove_candidate(RuntimeOrigin::root(), 1)); - // collator stake does not change since 3, who took 1's place, has staked the - // same amount - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 200, - delegators: 50 - } - ); - assert_eq!(Session::disabled_validators(), vec![0]); - assert_eq!(last_event(), StakeEvent::CollatorRemoved(1, 200)); - assert!(!StakePallet::top_candidates().contains(&StakeOf:: { owner: 1, amount: 100 })); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![2, 3]); - assert_eq!(CandidatePool::::count(), 2); - assert!(StakePallet::candidate_pool(1).is_none()); - assert!(StakePallet::delegator_state(4).is_none()); - assert!(StakePallet::delegator_state(5).is_none()); - assert_eq!(StakePallet::unstaking(1).get(&3), Some(&100)); - assert_eq!(StakePallet::unstaking(4).get(&3), Some(&50)); - assert_eq!(StakePallet::unstaking(5).get(&3), Some(&50)); - - assert_noop!( - StakePallet::force_remove_candidate(RuntimeOrigin::root(), 2), - Error::::TooFewCollatorCandidates - ); - assert_noop!( - StakePallet::force_remove_candidate(RuntimeOrigin::root(), 4), - Error::::CandidateNotFound - ); + >::mutate(2, |value| { + value.as_mut().map(|mut state| { + state.status = DelegatorStatus::Leaving(2); + }) + }); + let state = >::get(2); + assert!(matches!(state.unwrap().status, DelegatorStatus::Leaving(_))); - // session 1: expect 1 to still be in validator set but as disabled - roll_to(5, vec![]); - assert_eq!(Session::current_index(), 1); - assert_eq!(Session::validators(), vec![1, 2]); - assert_eq!(Session::disabled_validators(), vec![0]); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(2), 2, 1)); + assert_events_emitted!(Event::DelegatorLeft { delegator: 2, unstaked_amount: 10 }); - // session 2: expect validator set to have changed - roll_to(10, vec![]); - assert_eq!(Session::validators(), vec![2, 3]); - assert!(Session::disabled_validators().is_empty()); + let state = >::get(2); + assert!(state.is_none()); }); } +#[allow(deprecated)] #[test] -fn prioritize_collators() { +fn test_delegator_with_deprecated_status_leaving_cannot_execute_leave_delegators_early_no_fix() { ExtBuilder::default() - .with_balances(vec![ - (1, 200), - (2, 200), - (3, 200), - (4, 200), - (5, 200), - (6, 200), - (7, 200), - ]) - .with_collators(vec![(2, 100), (3, 100)]) + .with_balances(vec![(1, 20), (2, 40)]) + .with_candidates(vec![(1, 20)]) + .with_delegations(vec![(2, 1, 10)]) .build() .execute_with(|| { - assert_eq!( - StakePallet::top_candidates(), - OrderedSet::from_sorted_set( - vec![2, 3] - .into_iter() - .map(|id| StakeOf:: { owner: id, amount: 100 }) - .collect::>>() - .try_into() - .unwrap() - ) - ); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![2, 3]); - assert_ok!(StakePallet::join_candidates(RuntimeOrigin::signed(1), 100)); - assert_eq!( - StakePallet::top_candidates(), - OrderedSet::from_sorted_set( - vec![2, 3, 1] - .into_iter() - .map(|id| StakeOf:: { owner: id, amount: 100 }) - .collect::>>() - .try_into() - .unwrap() - ) - ); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![2, 3]); - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(2))); - assert_eq!(StakePallet::top_candidates().len(), 2); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![3, 1]); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(3), 10)); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 3]); - - // add 6 - assert_ok!(StakePallet::join_candidates(RuntimeOrigin::signed(6), 100)); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 6]); - assert_eq!( - StakePallet::top_candidates(), - OrderedSet::from_sorted_set( - vec![1, 6] - .into_iter() - .map(|id| StakeOf:: { owner: id, amount: 100 }) - .chain(vec![StakeOf:: { owner: 3, amount: 90 }]) - .collect::>>() - .try_into() - .unwrap() - ) - ); - - // add 4 - assert_ok!(StakePallet::join_candidates(RuntimeOrigin::signed(4), 100)); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 6]); - assert_eq!( - StakePallet::top_candidates(), - OrderedSet::from_sorted_set( - vec![1, 6, 4] - .into_iter() - .map(|id| StakeOf:: { owner: id, amount: 100 }) - .chain(vec![StakeOf:: { owner: 3, amount: 90 }]) - .collect::>>() - .try_into() - .unwrap() - ) - ); - - // add 5 - assert_ok!(StakePallet::join_candidates(RuntimeOrigin::signed(5), 100)); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 6]); - assert_eq!( - StakePallet::top_candidates(), - OrderedSet::from_sorted_set( - vec![1, 6, 4, 5] - .into_iter() - .map(|id| StakeOf:: { owner: id, amount: 100 }) - .chain(vec![StakeOf:: { owner: 3, amount: 90 }]) - .collect::>>() - .try_into() - .unwrap() - ) - ); - - // 3 stake_more - assert_ok!(StakePallet::candidate_stake_more(RuntimeOrigin::signed(3), 20)); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![3, 1]); - assert_eq!( - StakePallet::top_candidates(), - OrderedSet::from_sorted_set( - vec![ - StakeOf:: { owner: 3, amount: 110 }, - StakeOf:: { owner: 1, amount: 100 }, - StakeOf:: { owner: 6, amount: 100 }, - StakeOf:: { owner: 4, amount: 100 }, - StakeOf:: { owner: 5, amount: 100 }, - ] - .try_into() - .unwrap() - ) - ); + >::mutate(2, |value| { + value.as_mut().map(|mut state| { + state.status = DelegatorStatus::Leaving(2); + }) + }); + let state = >::get(2); + assert!(matches!(state.unwrap().status, DelegatorStatus::Leaving(_))); - // 1 stake_less - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), 1)); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![3, 6]); - assert_eq!( - StakePallet::top_candidates(), - OrderedSet::from_sorted_set( - vec![ - StakeOf:: { owner: 3, amount: 110 }, - StakeOf:: { owner: 6, amount: 100 }, - StakeOf:: { owner: 4, amount: 100 }, - StakeOf:: { owner: 5, amount: 100 }, - StakeOf:: { owner: 1, amount: 99 }, - ] - .try_into() - .unwrap() - ) + assert_noop!( + ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(2), 2, 1), + Error::::DelegatorCannotLeaveYet ); + }); +} - // 7 delegates to 4 - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(7), 5, 20)); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![5, 3]); - assert_eq!( - StakePallet::top_candidates(), - OrderedSet::from_sorted_set( - vec![ - StakeOf:: { owner: 5, amount: 120 }, - StakeOf:: { owner: 3, amount: 110 }, - StakeOf:: { owner: 6, amount: 100 }, - StakeOf:: { owner: 4, amount: 100 }, - StakeOf:: { owner: 1, amount: 99 }, - ] - .try_into() - .unwrap() - ) - ); +#[test] +fn test_set_auto_compound_fails_if_invalid_delegation_hint() { + ExtBuilder::default() + .with_balances(vec![(1, 30), (2, 25)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + let candidate_auto_compounding_delegation_count_hint = 0; + let delegation_hint = 0; // is however, 1 - // 7 decreases delegation - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(7), 10)); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![5, 3]); - assert_eq!( - StakePallet::top_candidates(), - OrderedSet::from_sorted_set( - vec![ - StakeOf:: { owner: 5, amount: 110 }, - StakeOf:: { owner: 3, amount: 110 }, - StakeOf:: { owner: 6, amount: 100 }, - StakeOf:: { owner: 4, amount: 100 }, - StakeOf:: { owner: 1, amount: 99 }, - ] - .try_into() - .unwrap() - ) - ); - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(7))); - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![3, 5]); - assert_eq!( - StakePallet::top_candidates(), - OrderedSet::from_sorted_set( - vec![ - StakeOf:: { owner: 3, amount: 110 }, - StakeOf:: { owner: 5, amount: 100 }, - StakeOf:: { owner: 6, amount: 100 }, - StakeOf:: { owner: 4, amount: 100 }, - StakeOf:: { owner: 1, amount: 99 }, - ] - .try_into() - .unwrap() - ) + assert_noop!( + ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(2), + 1, + Percent::from_percent(50), + candidate_auto_compounding_delegation_count_hint, + delegation_hint, + ), + >::TooLowDelegationCountToAutoCompound, ); }); } #[test] -fn prioritize_delegators() { +fn test_set_auto_compound_fails_if_invalid_candidate_auto_compounding_hint() { ExtBuilder::default() - .with_balances(vec![ - (1, 1000), - (2, 1000), - (3, 1000), - (4, 1000), - (5, 1000), - (6, 1000), - (7, 1000), - (8, 1000), - (9, 1000), - ]) - .with_collators(vec![(1, 100), (2, 100), (3, 100)]) - .with_delegators(vec![(4, 2, 100), (7, 2, 100), (6, 2, 100)]) + .with_balances(vec![(1, 30), (2, 25)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) .build() .execute_with(|| { - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![2, 1]); - assert_eq!( - StakePallet::candidate_pool(2).unwrap().delegators, - OrderedSet::from_sorted_set( - vec![ - StakeOf:: { owner: 4, amount: 100 }, - StakeOf:: { owner: 7, amount: 100 }, - StakeOf:: { owner: 6, amount: 100 }, - ] - .try_into() - .unwrap() - ) - ); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(5), 2, 110)); - assert_eq!( - StakePallet::candidate_pool(2).unwrap().delegators, - OrderedSet::from_sorted_set( - vec![ - StakeOf:: { owner: 5, amount: 110 }, - StakeOf:: { owner: 4, amount: 100 }, - StakeOf:: { owner: 7, amount: 100 }, - StakeOf:: { owner: 6, amount: 100 }, - ] + >::new( + vec![AutoCompoundConfig { delegator: 2, value: Percent::from_percent(10) }] .try_into() - .unwrap() - ) - ); - - // delegate_less - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(5), 10)); - assert_eq!( - StakePallet::candidate_pool(2).unwrap().delegators, - OrderedSet::from_sorted_set( - vec![ - StakeOf:: { owner: 5, amount: 100 }, - StakeOf:: { owner: 4, amount: 100 }, - StakeOf:: { owner: 7, amount: 100 }, - StakeOf:: { owner: 6, amount: 100 }, - ] - .try_into() - .unwrap() - ) - ); + .expect("must succeed"), + ) + .set_storage(&1); + let candidate_auto_compounding_delegation_count_hint = 0; // is however, 1 + let delegation_hint = 1; - // delegate_more - assert_ok!(StakePallet::delegator_stake_more(RuntimeOrigin::signed(6), 10)); - assert_eq!( - StakePallet::candidate_pool(2).unwrap().delegators, - OrderedSet::from_sorted_set( - vec![ - StakeOf:: { owner: 6, amount: 110 }, - StakeOf:: { owner: 5, amount: 100 }, - StakeOf:: { owner: 4, amount: 100 }, - StakeOf:: { owner: 7, amount: 100 }, - ] - .try_into() - .unwrap() - ) - ); - assert_ok!(StakePallet::delegator_stake_more(RuntimeOrigin::signed(7), 10)); - assert_eq!( - StakePallet::candidate_pool(2).unwrap().delegators, - OrderedSet::from_sorted_set( - vec![ - StakeOf:: { owner: 6, amount: 110 }, - StakeOf:: { owner: 7, amount: 110 }, - StakeOf:: { owner: 5, amount: 100 }, - StakeOf:: { owner: 4, amount: 100 }, - ] - .try_into() - .unwrap() - ) + assert_noop!( + ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(2), + 1, + Percent::from_percent(50), + candidate_auto_compounding_delegation_count_hint, + delegation_hint, + ), + >::TooLowCandidateAutoCompoundingDelegationCountToAutoCompound, ); }); } #[test] -fn authorities_per_round() { - let stake = 100 * DECIMALS; +fn test_set_auto_compound_inserts_if_not_exists() { ExtBuilder::default() - .with_balances(vec![ - (1, stake), - (2, stake), - (3, stake), - (4, stake), - (5, stake), - (6, stake), - (7, stake), - (8, stake), - (9, stake), - (10, stake), - (11, 100 * stake), - ]) - .with_collators(vec![(1, stake), (2, stake), (3, stake), (4, stake)]) - .build() - .execute_with(|| { - assert_eq!(StakePallet::selected_candidates().into_inner(), vec![1, 2]); - // reward 1 once per round - let authors: Vec> = (0u64..=100) - .map(|i| if i % 5 == 2 { Some(1u64) } else { None }) - .collect(); - let inflation = StakePallet::inflation_config(); - - // roll to last block of round 0 - roll_to_claim_rewards(4, authors.clone()); - let reward_0 = inflation.collator.reward_rate.per_block * stake * 2; - assert_eq!(Balances::free_balance(1), stake + reward_0); - // increase max selected candidates which will become effective in round 2 - assert_ok!(StakePallet::set_max_selected_candidates(RuntimeOrigin::root(), 10)); - - // roll to last block of round 1 - // should still multiply with 2 because the Authority set was chosen at start of - // round 1 - roll_to_claim_rewards(9, authors.clone()); - let reward_1 = inflation.collator.reward_rate.per_block * stake * 2; - assert_eq!(Balances::free_balance(1), stake + reward_0 + reward_1); - - // roll to last block of round 2 - // should multiply with 4 because there are only 4 candidates - roll_to_claim_rewards(14, authors.clone()); - let reward_2 = inflation.collator.reward_rate.per_block * stake * 4; - assert_eq!(Balances::free_balance(1), stake + reward_0 + reward_1 + reward_2); - - // roll to last block of round 3 - // should multiply with 4 because there are only 4 candidates - roll_to_claim_rewards(19, authors); - let reward_3 = inflation.collator.reward_rate.per_block * stake * 4; + .with_balances(vec![(1, 30), (2, 25)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) + .build() + .execute_with(|| { + assert_ok!(ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(2), + 1, + Percent::from_percent(50), + 0, + 1, + )); + assert_events_emitted!(Event::AutoCompoundSet { + candidate: 1, + delegator: 2, + value: Percent::from_percent(50), + }); assert_eq!( - Balances::free_balance(1), - stake + reward_0 + reward_1 + reward_2 + reward_3 + vec![AutoCompoundConfig { delegator: 2, value: Percent::from_percent(50) }], + ParachainStaking::auto_compounding_delegations(&1).into_inner(), ); }); } #[test] -fn force_new_round() { +fn test_set_auto_compound_updates_if_existing() { ExtBuilder::default() - .with_balances(vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100), (6, 100)]) - .with_collators(vec![(1, 100), (2, 100), (3, 100), (4, 100)]) + .with_balances(vec![(1, 30), (2, 25)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) .build() .execute_with(|| { - let mut round = RoundInfo { - current: 0, - first: 0, - length: 5, - }; - assert_eq!(StakePallet::round(), round); - assert_eq!(Session::validators(), vec![1, 2]); - assert_eq!(Session::current_index(), 0); - // 3 should be validator in round 2 - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(5), 3, 100)); - - // init force new round from 0 to 1, updating the authorities - assert_ok!(StakePallet::force_new_round(RuntimeOrigin::root())); - assert_eq!(StakePallet::round(), round); - assert_eq!(Session::current_index(), 0); - assert!(StakePallet::new_round_forced()); - - // force new round should become active by starting next block - roll_to(2, vec![]); - round = RoundInfo { - current: 1, - first: 2, - length: 5, - }; - assert_eq!(Session::current_index(), 1); - assert_eq!(Session::validators(), vec![1, 2]); - assert!(!StakePallet::new_round_forced()); - - // roll to next block in same round 1 - roll_to(3, vec![]); - assert_eq!(Session::current_index(), 1); - assert_eq!(StakePallet::round(), round); - // assert_eq!(Session::validators(), vec![3, 1]); - assert!(!StakePallet::new_round_forced()); - // 4 should become validator in session 3 if we do not force a new round - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(6), 4, 100)); - - // end session 2 naturally - roll_to(7, vec![]); - round = RoundInfo { - current: 2, - first: 7, - length: 5, - }; - assert_eq!(StakePallet::round(), round); - assert_eq!(Session::current_index(), 2); - assert!(!StakePallet::new_round_forced()); - assert_eq!(Session::validators(), vec![3, 1]); - - // force new round 3 - assert_ok!(StakePallet::force_new_round(RuntimeOrigin::root())); - assert_eq!(StakePallet::round(), round); - assert_eq!(Session::current_index(), 2); - // validator set should not change until next round - assert_eq!(Session::validators(), vec![3, 1]); - assert!(StakePallet::new_round_forced()); - - // force new round should become active by starting next block - roll_to(8, vec![]); - round = RoundInfo { - current: 3, - first: 8, - length: 5, - }; - assert_eq!(Session::current_index(), 3); - assert_eq!(StakePallet::round(), round); - assert_eq!(Session::validators(), vec![3, 4]); - assert!(!StakePallet::new_round_forced()); + >::new( + vec![AutoCompoundConfig { delegator: 2, value: Percent::from_percent(10) }] + .try_into() + .expect("must succeed"), + ) + .set_storage(&1); + + assert_ok!(ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(2), + 1, + Percent::from_percent(50), + 1, + 1, + )); + assert_events_emitted!(Event::AutoCompoundSet { + candidate: 1, + delegator: 2, + value: Percent::from_percent(50), + }); + assert_eq!( + vec![AutoCompoundConfig { delegator: 2, value: Percent::from_percent(50) }], + ParachainStaking::auto_compounding_delegations(&1).into_inner(), + ); }); } #[test] -fn replace_lowest_delegator() { +fn test_set_auto_compound_removes_if_auto_compound_zero_percent() { ExtBuilder::default() - .with_balances(vec![(1, 100), (2, 100), (3, 100), (4, 100), (5, 100), (6, 100)]) - .with_collators(vec![(1, 100)]) - .with_delegators(vec![(2, 1, 51), (3, 1, 51), (4, 1, 51), (5, 1, 50)]) + .with_balances(vec![(1, 30), (2, 25)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(2, 1, 10)]) .build() .execute_with(|| { - assert_eq!( - StakePallet::candidate_pool(1).unwrap().delegators.len() as u32, - ::MaxDelegatorsPerCollator::get() - ); - - // 6 replaces 5 - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(6), 1, 51)); - assert!(StakePallet::delegator_state(5).is_none()); - assert_eq!( - StakePallet::candidate_pool(1) - .unwrap() - .delegators - .into_bounded_vec() - .into_inner(), - vec![ - Stake { owner: 2, amount: 51 }, - Stake { owner: 3, amount: 51 }, - Stake { owner: 4, amount: 51 }, - Stake { owner: 6, amount: 51 } - ] - ); + >::new( + vec![AutoCompoundConfig { delegator: 2, value: Percent::from_percent(10) }] + .try_into() + .expect("must succeed"), + ) + .set_storage(&1); - // 5 attempts to replace 6 with more balance than available - frame_support::assert_noop!( - StakePallet::join_delegators(RuntimeOrigin::signed(5), 1, 101), - BalancesError::::InsufficientBalance - ); - assert!(StakePallet::delegator_state(6).is_some()); - }) + assert_ok!(ParachainStaking::set_auto_compound(RuntimeOrigin::signed(2), 1, Percent::zero(), 1, 1,)); + assert_events_emitted!(Event::AutoCompoundSet { candidate: 1, delegator: 2, value: Percent::zero() }); + assert_eq!(0, ParachainStaking::auto_compounding_delegations(&1).len(),); + }); } #[test] -fn network_reward_multiple_blocks() { - let max_stake: Balance = 160_000_000 * DECIMALS; - let collators: Vec<(AccountId, Balance)> = (1u64..=::MinCollators::get().saturating_add(1).into()) - .map(|acc_id| (acc_id, max_stake)) - .collect(); - +fn test_execute_revoke_delegation_removes_auto_compounding_from_state_for_delegation_revoke() { ExtBuilder::default() - .with_balances(collators.clone()) - .with_collators(collators) + .with_balances(vec![(1, 30), (2, 30), (3, 20)]) + .with_candidates(vec![(1, 30), (3, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) .build() .execute_with(|| { - assert_eq!(max_stake, StakePallet::max_candidate_stake()); - let total_collator_stake = max_stake.saturating_mul(::MinCollators::get().into()); - assert_eq!(total_collator_stake, StakePallet::total_collator_stake().collators); - assert!(Balances::free_balance(&TREASURY_ACC).is_zero()); - let total_issuance = ::Currency::total_issuance(); - - // total issuance should not increase when not noting authors because we haven't - // reached NetworkRewardStart yet - roll_to(10, vec![None]); - assert!(Balances::free_balance(&TREASURY_ACC).is_zero()); - assert_eq!(total_issuance, ::Currency::total_issuance()); - - // set current block to one block before NetworkRewardStart - let network_reward_start = ::NetworkRewardStart::get(); - System::set_block_number(network_reward_start.saturating_sub(1)); - - // network rewards should only appear 1 block after start - roll_to(network_reward_start, vec![None]); - assert!(Balances::free_balance(&TREASURY_ACC).is_zero()); - assert_eq!(total_issuance, ::Currency::total_issuance()); - - // should mint to treasury now - roll_to(network_reward_start + 1, vec![None]); - let network_reward = Balances::free_balance(&TREASURY_ACC); - assert!(!network_reward.is_zero()); - assert_eq!( - total_issuance + network_reward, - ::Currency::total_issuance() - ); - let inflation_config = StakePallet::inflation_config(); - let col_rewards = inflation_config.collator.reward_rate.per_block * total_collator_stake; - assert_eq!(network_reward, ::NetworkRewardRate::get() * col_rewards); - - // should mint exactly the same amount - roll_to(network_reward_start + 2, vec![None]); - assert_eq!(2 * network_reward, Balances::free_balance(&TREASURY_ACC)); - assert_eq!( - total_issuance + 2 * network_reward, - ::Currency::total_issuance() - ); - - // should mint exactly the same amount in each block - roll_to(network_reward_start + 100, vec![None]); - assert_eq!(100 * network_reward, Balances::free_balance(&TREASURY_ACC)); - assert_eq!( - total_issuance + 100 * network_reward, - ::Currency::total_issuance() + assert_ok!(ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(2), + 1, + Percent::from_percent(50), + 0, + 2, + )); + assert_ok!(ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(2), + 3, + Percent::from_percent(50), + 0, + 2, + )); + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + roll_to(10); + assert_ok!(ParachainStaking::execute_delegation_request(RuntimeOrigin::signed(2), 2, 1)); + assert!( + !ParachainStaking::auto_compounding_delegations(&1).iter().any(|x| x.delegator == 2), + "delegation auto-compound config was not removed" ); - - // should mint the same amount even if a collator exits because reward is only - // based on MaxCollatorCandidateStake and MaxSelectedCandidates - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(1))); - roll_to(network_reward_start + 101, vec![None]); - assert_eq!(101 * network_reward, Balances::free_balance(&TREASURY_ACC)); - assert_eq!( - total_issuance + 101 * network_reward, - ::Currency::total_issuance() + assert!( + ParachainStaking::auto_compounding_delegations(&3).iter().any(|x| x.delegator == 2), + "delegation auto-compound config was erroneously removed" ); }); } #[test] -fn network_reward_increase_max_candidate_stake() { - let max_stake: Balance = 160_000_000 * DECIMALS; - let collators: Vec<(AccountId, Balance)> = (1u64..=::MinCollators::get().into()) - .map(|acc_id| (acc_id, max_stake)) - .collect(); - +fn test_execute_leave_delegators_removes_auto_compounding_state() { ExtBuilder::default() - .with_balances(collators.clone()) - .with_collators(collators) + .with_balances(vec![(1, 30), (2, 20), (3, 20)]) + .with_candidates(vec![(1, 30), (3, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) .build() .execute_with(|| { - let network_reward_start = ::NetworkRewardStart::get(); - let total_issuance = ::Currency::total_issuance(); - System::set_block_number(network_reward_start); + assert_ok!(ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(2), + 1, + Percent::from_percent(50), + 0, + 2, + )); + assert_ok!(ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(2), + 3, + Percent::from_percent(50), + 0, + 2, + )); - // should mint to treasury now - roll_to(network_reward_start + 1, vec![None]); - let reward_before = Balances::free_balance(&TREASURY_ACC); - assert!(!reward_before.is_zero()); - assert_eq!( - total_issuance + reward_before, - ::Currency::total_issuance() - ); + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(2), 2, 2,)); - // double max stake - let max_stake_doubled = 320_000_000 * DECIMALS; - let reward_after = 2 * reward_before; - assert_ok!(StakePallet::set_max_candidate_stake( - RuntimeOrigin::root(), - max_stake_doubled - )); - roll_to(network_reward_start + 2, vec![None]); - assert_eq!(reward_before + reward_after, Balances::free_balance(&TREASURY_ACC)); - assert_eq!( - reward_before + reward_after + total_issuance, - ::Currency::total_issuance() + assert!( + !ParachainStaking::auto_compounding_delegations(&1).iter().any(|x| x.delegator == 2), + "delegation auto-compound config was not removed" + ); + assert!( + !ParachainStaking::auto_compounding_delegations(&3).iter().any(|x| x.delegator == 2), + "delegation auto-compound config was not removed" ); }); } +#[allow(deprecated)] #[test] -fn network_reward_increase_max_collator_count() { - let max_stake: Balance = 160_000_000 * DECIMALS; - let collators: Vec<(AccountId, Balance)> = (1u64..=::MinCollators::get().into()) - .map(|acc_id| (acc_id, max_stake)) - .collect(); - +fn test_execute_leave_delegators_with_deprecated_status_leaving_removes_auto_compounding_state() { ExtBuilder::default() - .with_balances(collators.clone()) - .with_collators(collators) + .with_balances(vec![(1, 30), (2, 20), (3, 20)]) + .with_candidates(vec![(1, 30), (3, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) .build() .execute_with(|| { - let network_reward_start = ::NetworkRewardStart::get(); - let total_issuance = ::Currency::total_issuance(); - System::set_block_number(network_reward_start); + assert_ok!(ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(2), + 1, + Percent::from_percent(50), + 0, + 2, + )); + assert_ok!(ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(2), + 3, + Percent::from_percent(50), + 0, + 2, + )); - // should mint to treasury now - roll_to(network_reward_start + 1, vec![None]); - let reward_before = Balances::free_balance(&TREASURY_ACC); - assert!(!reward_before.is_zero()); - assert_eq!( - total_issuance + reward_before, - ::Currency::total_issuance() - ); + >::mutate(2, |value| { + value.as_mut().map(|mut state| { + state.status = DelegatorStatus::Leaving(2); + }) + }); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_delegators(RuntimeOrigin::signed(2), 2, 2,)); - // tripple number of max collators - let reward_after = 3 * reward_before; - assert_ok!(StakePallet::set_max_selected_candidates( - RuntimeOrigin::root(), - ::MinCollators::get() * 3 - )); - roll_to(network_reward_start + 2, vec![None]); - assert_eq!(reward_before + reward_after, Balances::free_balance(&TREASURY_ACC)); - assert_eq!( - reward_before + reward_after + total_issuance, - ::Currency::total_issuance() + assert!( + !ParachainStaking::auto_compounding_delegations(&1).iter().any(|x| x.delegator == 2), + "delegation auto-compound config was not removed" + ); + assert!( + !ParachainStaking::auto_compounding_delegations(&3).iter().any(|x| x.delegator == 2), + "delegation auto-compound config was not removed" ); }); } #[test] -fn update_total_stake_collators_stay() { +fn test_execute_leave_candidates_removes_auto_compounding_state() { ExtBuilder::default() - .with_balances(vec![(1, 200), (2, 200), (3, 200), (4, 200)]) - .with_collators(vec![(1, 100), (2, 50)]) - .with_delegators(vec![(3, 1, 100), (4, 2, 50)]) + .with_balances(vec![(1, 30), (2, 20), (3, 20)]) + .with_candidates(vec![(1, 30), (3, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) .build() .execute_with(|| { - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 150, - delegators: 150 - } - ); - assert_ok!(StakePallet::candidate_stake_more(RuntimeOrigin::signed(1), 10)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 160, - delegators: 150 - } - ); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(2), 5)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 155, - delegators: 150 - } - ); - assert_ok!(StakePallet::delegator_stake_more(RuntimeOrigin::signed(3), 10)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 155, - delegators: 160 - } + assert_ok!(ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(2), + 1, + Percent::from_percent(50), + 0, + 2, + )); + assert_ok!(ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(2), + 3, + Percent::from_percent(50), + 0, + 2, + )); + + assert_ok!(ParachainStaking::schedule_leave_candidates(RuntimeOrigin::signed(1), 2)); + roll_to(10); + assert_ok!(ParachainStaking::execute_leave_candidates(RuntimeOrigin::signed(1), 1, 1,)); + + assert!( + !ParachainStaking::auto_compounding_delegations(&1).iter().any(|x| x.delegator == 2), + "delegation auto-compound config was not removed" ); - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(4), 5)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 155, - delegators: 155 - } + assert!( + ParachainStaking::auto_compounding_delegations(&3).iter().any(|x| x.delegator == 2), + "delegation auto-compound config was erroneously removed" ); }); } #[test] -fn update_total_stake_displace_collators() { +fn test_delegation_kicked_from_bottom_delegation_removes_auto_compounding_state() { ExtBuilder::default() .with_balances(vec![ - (1, 200), - (2, 200), - (3, 200), - (4, 200), - (5, 200), - (6, 200), - (7, 200), - (8, 200), - (1337, 200), + (1, 30), + (2, 29), + (3, 20), + (4, 20), + (5, 20), + (6, 20), + (7, 20), + (8, 20), + (9, 20), + (10, 20), + (11, 30), + ]) + .with_candidates(vec![(1, 30), (11, 30)]) + .with_delegations(vec![ + (2, 11, 10), // extra delegation to avoid leaving the delegator set + (2, 1, 19), + (3, 1, 20), + (4, 1, 20), + (5, 1, 20), + (6, 1, 20), + (7, 1, 20), + (8, 1, 20), + (9, 1, 20), ]) - .with_collators(vec![(1, 10), (2, 20), (3, 30), (4, 40)]) - .with_delegators(vec![(5, 1, 50), (6, 2, 50), (7, 3, 55), (8, 4, 55)]) .build() .execute_with(|| { - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 70, - delegators: 110 - } - ); - - // 4 is pushed out by staking less - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(4), 30)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 50, - delegators: 105 - } - ); - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(8), 45)); + assert_ok!(ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(2), + 1, + Percent::from_percent(50), + 0, + 2, + )); - // 3 is pushed out by delegator staking less - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(7), 45)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 30, - delegators: 100 - } - ); + // kicks lowest delegation (2, 19) + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(10), 1, 20, 8, 0)); - // 1 is pushed out by new candidate - assert_ok!(StakePallet::join_candidates(RuntimeOrigin::signed(1337), 100)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 120, - delegators: 50 - } + assert!( + !ParachainStaking::auto_compounding_delegations(&1).iter().any(|x| x.delegator == 2), + "delegation auto-compound config was not removed" ); }); } #[test] -fn update_total_stake_new_collators() { +fn test_rewards_do_not_auto_compound_on_payment_if_delegation_scheduled_revoke_exists() { ExtBuilder::default() - .with_balances(vec![(1, 100), (2, 100), (3, 100), (4, 100)]) - .with_collators(vec![(1, 100)]) - .with_delegators(vec![(4, 1, 100)]) + .with_balances(vec![(1, 100), (2, 200), (3, 200)]) + .with_candidates(vec![(1, 100)]) + .with_delegations(vec![(2, 1, 200), (3, 1, 200)]) .build() .execute_with(|| { - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 100, - delegators: 100 - } - ); - assert_ok!(StakePallet::join_candidates(RuntimeOrigin::signed(2), 100)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 200, - delegators: 100 - } - ); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(3), 2, 50)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 200, - delegators: 150 - } + (2..=5).for_each(|round| set_author(round, 1, 1)); + assert_ok!(ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(2), + 1, + Percent::from_percent(50), + 0, + 1, + )); + assert_ok!(ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(3), + 1, + Percent::from_percent(50), + 1, + 1, + )); + roll_to_round_begin(3); + + // schedule revoke for delegator 2; no rewards should be compounded + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + roll_to_round_begin(4); + + assert_events_eq!( + Event::CollatorChosen { round: 4, collator_account: 1, total_exposed_amount: 500 }, + Event::NewRound { starting_block: 15, round: 4, selected_collators_number: 1, total_balance: 500 }, ); - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(4))); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 200, - delegators: 50 - } + + roll_blocks(1); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 9 }, + // no compound since revoke request exists + Event::Rewarded { account: 2, rewards: 8 }, + // 50% + Event::Rewarded { account: 3, rewards: 8 }, + Event::Compounded { candidate: 1, delegator: 3, amount: 4 }, ); }); } #[test] -fn update_total_stake_no_collator_changes() { +fn test_rewards_auto_compound_on_payment_as_per_auto_compound_config() { ExtBuilder::default() - .with_balances(vec![ - (1, 200), - (2, 200), - (3, 200), - (4, 200), - (5, 200), - (6, 200), - (7, 200), - (8, 200), - (1337, 200), - ]) - .with_collators(vec![(1, 10), (2, 20), (3, 30), (4, 40)]) - .with_delegators(vec![(5, 1, 50), (6, 2, 50), (7, 3, 55), (8, 4, 55)]) + .with_balances(vec![(1, 100), (2, 200), (3, 200), (4, 200), (5, 200)]) + .with_candidates(vec![(1, 100)]) + .with_delegations(vec![(2, 1, 200), (3, 1, 200), (4, 1, 200), (5, 1, 200)]) .build() .execute_with(|| { - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 70, - delegators: 110 - } - ); - assert_ok!(StakePallet::candidate_stake_more(RuntimeOrigin::signed(1), 10)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 70, - delegators: 110 - } - ); - assert_ok!(StakePallet::delegator_stake_more(RuntimeOrigin::signed(5), 10)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 70, - delegators: 110 - } - ); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(2), 10)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 70, - delegators: 110 - } - ); - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(6), 10)); - assert_eq!( - StakePallet::total_collator_stake(), - TotalStake { - collators: 70, - delegators: 110 - } + (2..=6).for_each(|round| set_author(round, 1, 1)); + assert_ok!(ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(2), + 1, + Percent::from_percent(0), + 0, + 1, + )); + assert_ok!(ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(3), + 1, + Percent::from_percent(50), + 1, + 1, + )); + assert_ok!(ParachainStaking::set_auto_compound( + RuntimeOrigin::signed(4), + 1, + Percent::from_percent(100), + 2, + 1, + )); + roll_to_round_begin(4); + + assert_events_eq!( + Event::CollatorChosen { round: 4, collator_account: 1, total_exposed_amount: 900 }, + Event::NewRound { starting_block: 15, round: 4, selected_collators_number: 1, total_balance: 900 }, + ); + + roll_blocks(1); + assert_events_eq!( + Event::Rewarded { account: 1, rewards: 13 }, + // 0% + Event::Rewarded { account: 2, rewards: 8 }, + // 50% + Event::Rewarded { account: 3, rewards: 8 }, + Event::Compounded { candidate: 1, delegator: 3, amount: 4 }, + // 100% + Event::Rewarded { account: 4, rewards: 8 }, + Event::Compounded { candidate: 1, delegator: 4, amount: 8 }, + // no-config + Event::Rewarded { account: 5, rewards: 8 }, ); }); } #[test] -fn rewards_candidate_stake_more() { +fn test_delegate_with_auto_compound_fails_if_invalid_delegation_hint() { ExtBuilder::default() - .with_balances(vec![(1, 2 * DECIMALS), (2, DECIMALS), (3, DECIMALS)]) - .with_collators(vec![(1, DECIMALS)]) - .with_delegators(vec![(2, 1, DECIMALS), (3, 1, DECIMALS)]) + .with_balances(vec![(1, 30), (2, 25), (3, 30)]) + .with_candidates(vec![(1, 30), (3, 30)]) + .with_delegations(vec![(2, 3, 10)]) .build() .execute_with(|| { - // note once to set counter to 1 - StakePallet::note_author(1); - assert_eq!(StakePallet::blocks_authored(1), 1); - assert!(StakePallet::blocks_authored(2).is_zero()); - assert!(StakePallet::blocks_authored(3).is_zero()); - (1..=3).for_each(|id| { - assert!(StakePallet::blocks_rewarded(id).is_zero()); - assert!(StakePallet::rewards(id).is_zero()); - }); + let candidate_delegation_count_hint = 0; + let candidate_auto_compounding_delegation_count_hint = 0; + let delegation_hint = 0; // is however, 1 - // stake less to trigger reward incrementing for collator - assert_ok!(StakePallet::candidate_stake_more(RuntimeOrigin::signed(1), DECIMALS)); - assert!(!StakePallet::rewards(1).is_zero()); - assert!(!StakePallet::blocks_rewarded(1).is_zero()); - // delegator reward storage should be untouched - (2..=3).for_each(|id| { - assert!( - StakePallet::rewards(id).is_zero(), - "Rewards not zero for acc_id {:?}", - id - ); - assert!( - StakePallet::blocks_rewarded(id).is_zero(), - "BlocksRewaeded not zero for acc_id {:?}", - id - ); - }); + assert_noop!( + ParachainStaking::delegate_with_auto_compound( + RuntimeOrigin::signed(2), + 1, + 10, + Percent::from_percent(50), + candidate_delegation_count_hint, + candidate_auto_compounding_delegation_count_hint, + delegation_hint, + ), + >::TooLowDelegationCountToDelegate, + ); }); } #[test] -fn rewards_candidate_stake_less() { +fn test_delegate_with_auto_compound_fails_if_invalid_candidate_delegation_count_hint() { ExtBuilder::default() - .with_balances(vec![(1, 2 * DECIMALS), (2, DECIMALS), (3, DECIMALS)]) - .with_collators(vec![(1, 2 * DECIMALS)]) - .with_delegators(vec![(2, 1, DECIMALS), (3, 1, DECIMALS)]) + .with_balances(vec![(1, 30), (2, 25), (3, 30)]) + .with_candidates(vec![(1, 30)]) + .with_delegations(vec![(3, 1, 10)]) .build() .execute_with(|| { - // note once to set counter to 1 - StakePallet::note_author(1); - assert_eq!(StakePallet::blocks_authored(1), 1); - assert!(StakePallet::blocks_authored(2).is_zero()); - assert!(StakePallet::blocks_authored(3).is_zero()); - (1..=3).for_each(|id| { - assert!(StakePallet::blocks_rewarded(id).is_zero()); - assert!(StakePallet::rewards(id).is_zero()); - }); + let candidate_delegation_count_hint = 0; // is however, 1 + let candidate_auto_compounding_delegation_count_hint = 0; + let delegation_hint = 0; - // stake less to trigger reward incrementing for collator - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), DECIMALS)); - assert!(!StakePallet::rewards(1).is_zero()); - assert!(!StakePallet::blocks_rewarded(1).is_zero()); - // delegator reward storage should be untouched - (2..=3).for_each(|id| { - assert!( - StakePallet::rewards(id).is_zero(), - "Rewards not zero for acc_id {:?}", - id - ); - assert!( - StakePallet::blocks_rewarded(id).is_zero(), - "BlocksRewaeded not zero for acc_id {:?}", - id - ); - }); + assert_noop!( + ParachainStaking::delegate_with_auto_compound( + RuntimeOrigin::signed(2), + 1, + 10, + Percent::from_percent(50), + candidate_delegation_count_hint, + candidate_auto_compounding_delegation_count_hint, + delegation_hint, + ), + >::TooLowCandidateDelegationCountToDelegate, + ); }); } #[test] -fn rewards_candidate_leave_network() { +fn test_delegate_with_auto_compound_fails_if_invalid_candidate_auto_compounding_delegations_hint() { ExtBuilder::default() - .with_balances(vec![ - (1, 2 * DECIMALS), - (2, DECIMALS), - (3, DECIMALS), - (4, DECIMALS), - (5, DECIMALS), - ]) - .with_collators(vec![(1, 2 * DECIMALS), (4, DECIMALS), (5, DECIMALS)]) - .with_delegators(vec![(2, 1, DECIMALS), (3, 1, DECIMALS)]) + .with_balances(vec![(1, 30), (2, 25), (3, 30)]) + .with_candidates(vec![(1, 30)]) + .with_auto_compounding_delegations(vec![(3, 1, 10, Percent::from_percent(10))]) .build() .execute_with(|| { - // init does not increment rewards - assert_ok!(StakePallet::init_leave_candidates(RuntimeOrigin::signed(1))); + let candidate_delegation_count_hint = 1; + let candidate_auto_compounding_delegation_count_hint = 0; // is however, 1 + let delegation_hint = 0; + + assert_noop!( + ParachainStaking::delegate_with_auto_compound( + RuntimeOrigin::signed(2), + 1, + 10, + Percent::from_percent(50), + candidate_delegation_count_hint, + candidate_auto_compounding_delegation_count_hint, + delegation_hint, + ), + >::TooLowCandidateAutoCompoundingDelegationCountToDelegate, + ); + }); +} - // advance two rounds to enable leaving - roll_to( +#[test] +fn test_delegate_with_auto_compound_sets_auto_compound_config() { + ExtBuilder::default().with_balances(vec![(1, 30), (2, 25)]).with_candidates(vec![(1, 30)]).build().execute_with( + || { + assert_ok!(ParachainStaking::delegate_with_auto_compound( + RuntimeOrigin::signed(2), + 1, 10, - vec![ - // we're already in block 1, so cant note_author for block 1 - None, - Some(1), - Some(2), - Some(1), - Some(2), - Some(1), - Some(2), - Some(1), - Some(2), - ], - ); - // Only authored should be bumped for collator, not rewarded - assert_eq!(StakePallet::blocks_authored(1), 4 * 2); - assert!(StakePallet::blocks_rewarded(1).is_zero()); - - // count for delegators should not be incremented - assert!(StakePallet::blocks_rewarded(2).is_zero()); - assert!(StakePallet::blocks_rewarded(3).is_zero()); - - // rewards should not be incremented - (1..=3).for_each(|id| { - assert!(StakePallet::rewards(id).is_zero()); + Percent::from_percent(50), + 0, + 0, + 0, + )); + assert_events_emitted!(Event::Delegation { + delegator: 2, + locked_amount: 10, + candidate: 1, + delegator_position: DelegatorAdded::AddedToTop { new_total: 40 }, + auto_compound: Percent::from_percent(50), }); + assert_eq!( + vec![AutoCompoundConfig { delegator: 2, value: Percent::from_percent(50) }], + ParachainStaking::auto_compounding_delegations(&1).into_inner(), + ); + }, + ); +} - // execute leave intent to trigger reward incrementing for collator and - // delegators - assert_ok!(StakePallet::execute_leave_candidates(RuntimeOrigin::signed(1), 1)); - - // reward counting storages should be killed for collator - assert!(StakePallet::blocks_authored(1).is_zero()); - assert!(StakePallet::blocks_rewarded(1).is_zero()); - assert!(!StakePallet::rewards(1).is_zero()); - - // reward counting storages should NOT be killed for delegators - (2..=3).for_each(|id| { - assert!(!StakePallet::rewards(id).is_zero(), "Zero rewards acc_id {:?}", id); - assert_eq!( - StakePallet::blocks_rewarded(id), - 4 * 2, - "Rewarded blocks Delegator {:?} do not match up with exited collator", - id - ); +#[test] +fn test_delegate_with_auto_compound_skips_storage_but_emits_event_for_zero_auto_compound() { + ExtBuilder::default().with_balances(vec![(1, 30), (2, 10)]).with_candidates(vec![(1, 30)]).build().execute_with( + || { + assert_ok!(ParachainStaking::delegate_with_auto_compound( + RuntimeOrigin::signed(2), + 1, + 10, + Percent::zero(), + 0, + 0, + 0, + )); + assert_eq!(0, ParachainStaking::auto_compounding_delegations(&1).len(),); + assert_events_eq!(Event::Delegation { + delegator: 2, + locked_amount: 10, + candidate: 1, + delegator_position: DelegatorAdded::AddedToTop { new_total: 40 }, + auto_compound: Percent::zero(), }); - }); + }, + ); } #[test] -fn rewards_force_remove_candidate() { - ExtBuilder::default() - .with_balances(vec![ - (1, DECIMALS), - (2, DECIMALS), - (3, DECIMALS), - (4, DECIMALS), - (5, DECIMALS), - ]) - .with_collators(vec![(1, DECIMALS), (4, DECIMALS), (5, DECIMALS)]) - .with_delegators(vec![(2, 1, DECIMALS), (3, 1, DECIMALS)]) - .build() - .execute_with(|| { - // init does not increment rewards - StakePallet::note_author(1); - StakePallet::note_author(2); - - // removing triggers reward increment for collator 1 and delegators 4, 5 - assert_ok!(StakePallet::force_remove_candidate(RuntimeOrigin::root(), 1)); - // rewarded counter storage should be killed for collator - assert!(StakePallet::blocks_authored(1).is_zero()); - assert!(StakePallet::blocks_rewarded(1).is_zero()); - // rewards should be set - assert!(!StakePallet::rewards(1).is_zero()); - - (1..=3).for_each(|id| { - // rewards should be non zero - assert!(!StakePallet::rewards(id).is_zero(), "Zero rewards for acc_id {:?}", id); - // rewards should equal API call - assert_eq!( - StakePallet::get_unclaimed_staking_rewards(&id), - StakePallet::rewards(id) - ); - if id > 1 { - assert_eq!( - StakePallet::blocks_rewarded(id), - 2, - "Rewarded counter does not match for delegator {:?}", - id - ); - } - }); - assert_eq!(StakePallet::get_unclaimed_staking_rewards(&1), StakePallet::rewards(1)); +fn test_delegate_with_auto_compound_reserves_balance() { + ExtBuilder::default().with_balances(vec![(1, 30), (2, 10)]).with_candidates(vec![(1, 30)]).build().execute_with( + || { + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&2), 10); + assert_ok!(ParachainStaking::delegate_with_auto_compound( + RuntimeOrigin::signed(2), + 1, + 10, + Percent::from_percent(50), + 0, + 0, + 0, + )); + assert_eq!(ParachainStaking::get_delegator_stakable_free_balance(&2), 0); + }, + ); +} - (4..=5).for_each(|id| { - assert!(StakePallet::rewards(id).is_zero(), "acc_id {:?}", id); - assert!(StakePallet::blocks_rewarded(id).is_zero(), "acc_id {:?}", id); - }); - }); +#[test] +fn test_delegate_with_auto_compound_updates_delegator_state() { + ExtBuilder::default().with_balances(vec![(1, 30), (2, 10)]).with_candidates(vec![(1, 30)]).build().execute_with( + || { + assert!(ParachainStaking::delegator_state(2).is_none()); + assert_ok!(ParachainStaking::delegate_with_auto_compound( + RuntimeOrigin::signed(2), + 1, + 10, + Percent::from_percent(50), + 0, + 0, + 0 + )); + let delegator_state = ParachainStaking::delegator_state(2).expect("just delegated => exists"); + assert_eq!(delegator_state.total(), 10); + assert_eq!(delegator_state.delegations.0[0].owner, 1); + assert_eq!(delegator_state.delegations.0[0].amount, 10); + }, + ); } #[test] -fn blocks_rewarded_join_delegators() { - ExtBuilder::default() - .with_balances(vec![(1, 100), (2, 100)]) - .with_collators(vec![(1, 100)]) - .build() - .execute_with(|| { - // note once to set counter to 1 - StakePallet::note_author(1); - assert_eq!(StakePallet::blocks_authored(1), 1); - assert!(StakePallet::blocks_rewarded(1).is_zero()); - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(2), 1, 100)); - // delegator's rewarded counter should equal of collator's authored counter upon - // joining - assert_eq!(StakePallet::blocks_rewarded(2), StakePallet::blocks_authored(1)); - }); +fn test_delegate_with_auto_compound_updates_collator_state() { + ExtBuilder::default().with_balances(vec![(1, 30), (2, 10)]).with_candidates(vec![(1, 30)]).build().execute_with( + || { + let candidate_state = ParachainStaking::candidate_info(1).expect("registered in genesis"); + assert_eq!(candidate_state.total_counted, 30); + let top_delegations = ParachainStaking::top_delegations(1).expect("registered in genesis"); + assert!(top_delegations.delegations.is_empty()); + assert!(top_delegations.total.is_zero()); + assert_ok!(ParachainStaking::delegate_with_auto_compound( + RuntimeOrigin::signed(2), + 1, + 10, + Percent::from_percent(50), + 0, + 0, + 0 + )); + let candidate_state = ParachainStaking::candidate_info(1).expect("just delegated => exists"); + assert_eq!(candidate_state.total_counted, 40); + let top_delegations = ParachainStaking::top_delegations(1).expect("just delegated => exists"); + assert_eq!(top_delegations.delegations[0].owner, 2); + assert_eq!(top_delegations.delegations[0].amount, 10); + assert_eq!(top_delegations.total, 10); + }, + ); +} + +#[test] +fn test_delegate_with_auto_compound_can_delegate_immediately_after_other_join_candidates() { + ExtBuilder::default().with_balances(vec![(1, 20), (2, 20)]).build().execute_with(|| { + assert_ok!(ParachainStaking::join_candidates(RuntimeOrigin::signed(1), 20, 0)); + assert_ok!(ParachainStaking::delegate_with_auto_compound( + RuntimeOrigin::signed(2), + 1, + 20, + Percent::from_percent(50), + 0, + 0, + 0 + )); + }); } #[test] -fn rewards_delegator_stake_more() { +fn test_delegate_with_auto_compound_can_delegate_to_other_if_revoking() { ExtBuilder::default() - .with_balances(vec![(1, DECIMALS), (2, DECIMALS), (3, 2 * DECIMALS)]) - .with_collators(vec![(1, DECIMALS)]) - .with_delegators(vec![(2, 1, DECIMALS), (3, 1, DECIMALS)]) + .with_balances(vec![(1, 20), (2, 30), (3, 20), (4, 20)]) + .with_candidates(vec![(1, 20), (3, 20), (4, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10)]) .build() .execute_with(|| { - // note once to set counter to 1 - StakePallet::note_author(1); - assert_eq!(StakePallet::blocks_authored(1), 1); - assert!(StakePallet::blocks_rewarded(2).is_zero()); - assert!(StakePallet::blocks_rewarded(3).is_zero()); - (1..=3).for_each(|id| { - assert!(StakePallet::rewards(id).is_zero(), "acc_id {:?}", id); - }); - - // stake less to trigger reward incrementing just for 3 - assert_ok!(StakePallet::delegator_stake_more(RuntimeOrigin::signed(3), DECIMALS)); - // 1 should still have counter 1 but no rewards - assert_eq!(StakePallet::blocks_authored(1), 1); - assert!(StakePallet::blocks_rewarded(1).is_zero()); - assert!(StakePallet::rewards(1).is_zero()); - // 2 should still have neither rewards nor counter - assert!(StakePallet::blocks_rewarded(2).is_zero()); - assert!(StakePallet::rewards(2).is_zero()); - // 3 should have rewards and the same counter as 1 - assert_eq!(StakePallet::blocks_rewarded(3), 1); - assert!(!StakePallet::rewards(3).is_zero()); + assert_ok!(ParachainStaking::schedule_revoke_delegation(RuntimeOrigin::signed(2), 1)); + assert_ok!(ParachainStaking::delegate_with_auto_compound( + RuntimeOrigin::signed(2), + 4, + 10, + Percent::from_percent(50), + 0, + 0, + 2 + )); }); } #[test] -fn rewards_delegator_stake_less() { +fn test_delegate_with_auto_compound_cannot_delegate_if_less_than_or_equal_lowest_bottom() { ExtBuilder::default() - .with_balances(vec![(1, DECIMALS), (2, DECIMALS), (3, 2 * DECIMALS)]) - .with_collators(vec![(1, DECIMALS)]) - .with_delegators(vec![(2, 1, DECIMALS), (3, 1, 2 * DECIMALS)]) + .with_balances(vec![ + (1, 20), + (2, 10), + (3, 10), + (4, 10), + (5, 10), + (6, 10), + (7, 10), + (8, 10), + (9, 10), + (10, 10), + (11, 10), + ]) + .with_candidates(vec![(1, 20)]) + .with_delegations(vec![ + (2, 1, 10), + (3, 1, 10), + (4, 1, 10), + (5, 1, 10), + (6, 1, 10), + (8, 1, 10), + (9, 1, 10), + (10, 1, 10), + ]) .build() .execute_with(|| { - // note once to set counter to 1 - StakePallet::note_author(1); - assert_eq!(StakePallet::blocks_authored(1), 1); - assert!(StakePallet::blocks_rewarded(2).is_zero()); - assert!(StakePallet::blocks_rewarded(3).is_zero()); - (1..=3).for_each(|id| { - assert!(StakePallet::rewards(id).is_zero(), "acc_id {:?}", id); - }); - - // stake less to trigger reward incrementing just for 3 - assert_ok!(StakePallet::delegator_stake_less(RuntimeOrigin::signed(3), DECIMALS)); - // 1 should still have counter 1 but no rewards - assert_eq!(StakePallet::blocks_authored(1), 1); - assert!(StakePallet::blocks_rewarded(1).is_zero()); - assert!(StakePallet::rewards(1).is_zero()); - // 2 should still have neither rewards nor counter - assert!(StakePallet::blocks_rewarded(2).is_zero()); - assert!(StakePallet::rewards(2).is_zero()); - // 3 should have rewards and the same counter as 1 - assert_eq!(StakePallet::blocks_rewarded(3), 1); - assert!(!StakePallet::rewards(3).is_zero()); + assert_noop!( + ParachainStaking::delegate_with_auto_compound( + RuntimeOrigin::signed(11), + 1, + 10, + Percent::from_percent(50), + 8, + 0, + 0 + ), + Error::::CannotDelegateLessThanOrEqualToLowestBottomWhenFull + ); }); } #[test] -fn rewards_delegator_replaced() { +fn test_delegate_with_auto_compound_can_delegate_if_greater_than_lowest_bottom() { ExtBuilder::default() .with_balances(vec![ - (1, 2 * DECIMALS), - (2, 2 * DECIMALS), - (3, 2 * DECIMALS), - (4, 2 * DECIMALS), - (5, 2 * DECIMALS), - (6, 2 * DECIMALS), + (1, 20), + (2, 10), + (3, 10), + (4, 10), + (5, 10), + (6, 10), + (7, 10), + (8, 10), + (9, 10), + (10, 10), + (11, 11), ]) - .with_collators(vec![(1, 2 * DECIMALS)]) - .with_delegators(vec![ - (2, 1, 2 * DECIMALS), - (3, 1, 2 * DECIMALS), - (4, 1, 2 * DECIMALS), - (5, 1, DECIMALS), + .with_candidates(vec![(1, 20)]) + .with_delegations(vec![ + (2, 1, 10), + (3, 1, 10), + (4, 1, 10), + (5, 1, 10), + (6, 1, 10), + (8, 1, 10), + (9, 1, 10), + (10, 1, 10), ]) .build() .execute_with(|| { - // note once to set counter to 1 - StakePallet::note_author(1); - assert_eq!(StakePallet::blocks_authored(1), 1); - - // 6 kicks 5 - assert_ok!(StakePallet::join_delegators(RuntimeOrigin::signed(6), 1, 2 * DECIMALS)); - // 5 should have rewards and counter updated - assert!(!StakePallet::rewards(5).is_zero()); - assert_eq!(StakePallet::blocks_rewarded(5), 1); - // 6 should not have rewards but same counter as former collator - assert!(StakePallet::rewards(6).is_zero()); - assert_eq!(StakePallet::blocks_rewarded(6), 1); + assert_ok!(ParachainStaking::delegate_with_auto_compound( + RuntimeOrigin::signed(11), + 1, + 11, + Percent::from_percent(50), + 8, + 0, + 0 + )); + assert_events_emitted!(Event::DelegationKicked { delegator: 10, candidate: 1, unstaked_amount: 10 }); + assert_events_emitted!(Event::DelegatorLeft { delegator: 10, unstaked_amount: 10 }); }); } #[test] -fn rewards_delegator_leaves() { +fn test_delegate_with_auto_compound_can_still_delegate_to_other_if_leaving() { ExtBuilder::default() - .with_balances(vec![(1, DECIMALS), (2, DECIMALS), (3, DECIMALS)]) - .with_collators(vec![(1, DECIMALS)]) - .with_delegators(vec![(2, 1, DECIMALS), (3, 1, DECIMALS)]) + .with_balances(vec![(1, 20), (2, 20), (3, 20)]) + .with_candidates(vec![(1, 20), (3, 20)]) + .with_delegations(vec![(2, 1, 10)]) .build() .execute_with(|| { - // note collator once to set their counter to 1 - StakePallet::note_author(1); - assert_eq!(StakePallet::blocks_authored(1), 1); - assert!(StakePallet::blocks_rewarded(2).is_zero()); - assert!(StakePallet::blocks_rewarded(3).is_zero()); - (1..=3).for_each(|id| { - assert!(StakePallet::rewards(id).is_zero(), "acc_id {:?}", id); - }); - - // only 3 should have non-zero rewards - assert_ok!(StakePallet::leave_delegators(RuntimeOrigin::signed(3))); - assert!(StakePallet::blocks_rewarded(1).is_zero()); - assert!(StakePallet::rewards(1).is_zero()); - assert!(StakePallet::blocks_rewarded(2).is_zero()); - assert!(StakePallet::rewards(2).is_zero()); - assert!(!StakePallet::rewards(3).is_zero()); - assert_eq!(StakePallet::get_unclaimed_staking_rewards(&3), StakePallet::rewards(3)); - // counter should be reset due to leaving - assert!(StakePallet::blocks_rewarded(3).is_zero()); + assert_ok!(ParachainStaking::schedule_leave_delegators(RuntimeOrigin::signed(2))); + assert_ok!(ParachainStaking::delegate_with_auto_compound( + RuntimeOrigin::signed(2), + 3, + 10, + Percent::from_percent(50), + 0, + 0, + 1 + ),); }); } #[test] -fn rewards_set_inflation() { - let hundred = Perquintill::from_percent(100); +fn test_delegate_with_auto_compound_cannot_delegate_if_candidate() { ExtBuilder::default() - .with_balances(vec![ - (1, DECIMALS), - (2, DECIMALS), - (3, DECIMALS), - (4, DECIMALS), - (5, DECIMALS), - ]) - .with_collators(vec![(1, DECIMALS), (2, DECIMALS)]) - .with_delegators(vec![(3, 1, DECIMALS), (4, 1, DECIMALS), (5, 2, DECIMALS)]) + .with_balances(vec![(1, 20), (2, 30)]) + .with_candidates(vec![(1, 20), (2, 20)]) .build() .execute_with(|| { - // note collators - StakePallet::note_author(1); - StakePallet::note_author(1); - StakePallet::note_author(2); - - // set inflation to trigger reward setting - assert_ok!(StakePallet::set_inflation( - RuntimeOrigin::root(), - hundred, - hundred, - hundred, - hundred - )); - // rewards and counters should be set - (1..=5).for_each(|id| { - assert!(!StakePallet::blocks_rewarded(id).is_zero(), "acc_id {:?}", id); - assert!(!StakePallet::rewards(id).is_zero(), "acc_id {:?}", id); - }); + assert_noop!( + ParachainStaking::delegate_with_auto_compound( + RuntimeOrigin::signed(2), + 1, + 10, + Percent::from_percent(50), + 0, + 0, + 0 + ), + Error::::CandidateExists + ); }); } #[test] -fn rewards_yearly_inflation_adjustment() { +fn test_delegate_with_auto_compound_cannot_delegate_if_already_delegated() { ExtBuilder::default() - .with_balances(vec![ - (1, DECIMALS), - (2, DECIMALS), - (3, DECIMALS), - (4, DECIMALS), - (5, DECIMALS), - ]) - .with_collators(vec![(1, DECIMALS), (2, DECIMALS)]) - .with_delegators(vec![(3, 1, DECIMALS), (4, 1, DECIMALS), (5, 2, DECIMALS)]) + .with_balances(vec![(1, 20), (2, 30)]) + .with_candidates(vec![(1, 20)]) + .with_delegations(vec![(2, 1, 20)]) .build() .execute_with(|| { - // init counter and go to next year - StakePallet::note_author(1); - StakePallet::note_author(2); - System::set_block_number(::BLOCKS_PER_YEAR - 1); - roll_to_claim_rewards(::BLOCKS_PER_YEAR + 1, vec![]); - assert!(!StakePallet::blocks_authored(1).is_zero()); - assert!(!StakePallet::blocks_authored(2).is_zero()); - - // rewards should not be triggered before executing pending adjustment - (1..=5).for_each(|id| { - assert!(StakePallet::rewards(id).is_zero(), "acc_id {:?}", id); - }); - - // execute to trigger reward increment - assert_ok!(StakePallet::execute_scheduled_reward_change(RuntimeOrigin::signed(1))); - (1..=5).for_each(|id| { - assert!( - !StakePallet::blocks_rewarded(id).is_zero(), - "Zero rewarded blocks for acc_id {:?}", - id - ); - assert!(!StakePallet::rewards(id).is_zero(), "Zero rewards for acc_id {:?}", id); - }); + assert_noop!( + ParachainStaking::delegate_with_auto_compound( + RuntimeOrigin::signed(2), + 1, + 10, + Percent::from_percent(50), + 0, + 1, + 1 + ), + Error::::AlreadyDelegatedCandidate + ); }); } #[test] -fn rewards_incrementing_and_claiming() { +fn test_delegate_with_auto_compound_cannot_delegate_more_than_max_delegations() { ExtBuilder::default() - .with_balances(vec![(1, DECIMALS), (2, DECIMALS), (3, DECIMALS)]) - .with_collators(vec![(1, DECIMALS)]) - .with_delegators(vec![(2, 1, DECIMALS), (3, 1, DECIMALS)]) + .with_balances(vec![(1, 20), (2, 50), (3, 20), (4, 20), (5, 20), (6, 20)]) + .with_candidates(vec![(1, 20), (3, 20), (4, 20), (5, 20), (6, 20)]) + .with_delegations(vec![(2, 1, 10), (2, 3, 10), (2, 4, 10), (2, 5, 10)]) .build() .execute_with(|| { - // claiming should not be possible with zero counters - (1..=3).for_each(|id| { - assert_noop!( - StakePallet::claim_rewards(RuntimeOrigin::signed(id)), - Error::::RewardsNotFound, - ); - }); - - // note once to set counter to 1 - StakePallet::note_author(1); - assert_eq!(StakePallet::blocks_authored(1), 1); - assert!(StakePallet::blocks_rewarded(2).is_zero()); - - // claiming should not be possible before incrementing rewards - (1..=3).for_each(|id| { - assert_noop!( - StakePallet::claim_rewards(RuntimeOrigin::signed(id)), - Error::::RewardsNotFound - ); - }); - - // increment rewards for 2 and match counter to collator - assert_ok!(StakePallet::increment_delegator_rewards(RuntimeOrigin::signed(2))); - assert_eq!(StakePallet::blocks_rewarded(2), 1); - let rewards_2 = StakePallet::rewards(2); - assert!(!rewards_2.is_zero()); - assert!(StakePallet::blocks_rewarded(3).is_zero()); - assert!(StakePallet::rewards(3).is_zero()); - - // should only update rewards for collator as well - assert_ok!(StakePallet::increment_collator_rewards(RuntimeOrigin::signed(1))); - assert_eq!(StakePallet::blocks_rewarded(1), StakePallet::blocks_authored(1)); - assert!(!StakePallet::rewards(1).is_zero()); - // rewards of 2 should not be changed - assert_eq!(StakePallet::rewards(2), rewards_2); - // 3 should still not have blocks rewarded bumped - assert!(StakePallet::blocks_rewarded(3).is_zero()); - - // claim for 1 to move rewards into balance - assert_ok!(StakePallet::claim_rewards(RuntimeOrigin::signed(1))); - assert!(StakePallet::rewards(1).is_zero()); - // delegator situation should be unchanged - assert!(Balances::free_balance(&1) > DECIMALS); - assert_eq!(Balances::free_balance(&2), DECIMALS); - assert_eq!(Balances::free_balance(&3), DECIMALS); - - // incrementing again should not change anything because collator has not - // authored blocks since last inc - assert_ok!(StakePallet::increment_delegator_rewards(RuntimeOrigin::signed(2))); - assert_eq!(StakePallet::blocks_rewarded(2), 1); - // claim for 2 to move rewards into balance - assert_ok!(StakePallet::claim_rewards(RuntimeOrigin::signed(2))); - assert!(Balances::free_balance(&2) > DECIMALS); - assert!(StakePallet::rewards(2).is_zero()); - assert_eq!(Balances::free_balance(&3), DECIMALS); - - // should not be able to claim for incorrect role - assert_noop!( - StakePallet::increment_collator_rewards(RuntimeOrigin::signed(2)), - Error::::CandidateNotFound - ); assert_noop!( - StakePallet::increment_delegator_rewards(RuntimeOrigin::signed(1)), - Error::::DelegatorNotFound + ParachainStaking::delegate_with_auto_compound( + RuntimeOrigin::signed(2), + 6, + 10, + Percent::from_percent(50), + 0, + 0, + 4 + ), + Error::::ExceedMaxDelegationsPerDelegator, ); }); } #[test] -fn api_get_unclaimed_staking_rewards() { - let stake = 100_000 * DECIMALS; +fn test_delegate_skips_auto_compound_storage_but_emits_event_for_zero_auto_compound() { ExtBuilder::default() - .with_balances(vec![(1, stake), (2, stake), (3, 100 * stake)]) - .with_collators(vec![(1, stake), (3, 2 * stake)]) - .with_delegators(vec![(2, 1, stake)]) + .with_balances(vec![(1, 30), (2, 20), (3, 30)]) + .with_candidates(vec![(1, 30)]) + .with_auto_compounding_delegations(vec![(3, 1, 10, Percent::from_percent(50))]) .build() .execute_with(|| { - let inflation_config = StakePallet::inflation_config(); - - // Increment rewards of 1 and 2 - roll_to(2, vec![None, Some(1)]); - assert_eq!( - StakePallet::get_unclaimed_staking_rewards(&1), - // Multiplying with 2 because there are two authors - inflation_config.collator.reward_rate.per_block * stake * 2 - ); - assert_eq!( - StakePallet::get_unclaimed_staking_rewards(&2), - inflation_config.delegator.reward_rate.per_block * stake * 2 - ); - assert!(StakePallet::get_unclaimed_staking_rewards(&3).is_zero()); - - // Should only increment rewards of 3 - roll_to(3, vec![None, None, Some(3)]); - let rewards_1 = StakePallet::get_unclaimed_staking_rewards(&1); - let rewards_2 = StakePallet::get_unclaimed_staking_rewards(&2); - let rewards_3 = StakePallet::get_unclaimed_staking_rewards(&3); - assert_eq!(2 * rewards_1, rewards_3,); - assert_eq!(rewards_2, inflation_config.delegator.reward_rate.per_block * stake * 2); - - // API and actual claiming should match - assert_ok!(StakePallet::increment_collator_rewards(RuntimeOrigin::signed(1))); - assert_ok!(StakePallet::claim_rewards(RuntimeOrigin::signed(1))); - assert_eq!(rewards_1, Balances::usable_balance(&1)); - assert!(StakePallet::get_unclaimed_staking_rewards(&1).is_zero()); + // We already have an auto-compounding delegation from 3 -> 1, so the hint validation + // would cause a failure if the auto-compounding isn't skipped properly. + assert_ok!(ParachainStaking::delegate(RuntimeOrigin::signed(2), 1, 10, 1, 0,)); + assert_eq!(1, ParachainStaking::auto_compounding_delegations(&1).len(),); + assert_events_eq!(Event::Delegation { + delegator: 2, + locked_amount: 10, + candidate: 1, + delegator_position: DelegatorAdded::AddedToTop { new_total: 50 }, + auto_compound: Percent::zero(), + }); + }); +} - assert_ok!(StakePallet::increment_delegator_rewards(RuntimeOrigin::signed(2))); - assert_ok!(StakePallet::claim_rewards(RuntimeOrigin::signed(2))); - assert_eq!(rewards_2, Balances::usable_balance(&2)); - assert!(StakePallet::get_unclaimed_staking_rewards(&2).is_zero()); +#[test] +fn test_on_initialize_weights() { + use crate::{ + mock::System, + weights::{SubstrateWeight as PalletWeights, WeightInfo}, + *, + }; + use frame_support::{pallet_prelude::*, weights::constants::RocksDbWeight}; + + // generate balance, candidate, and delegation vecs to "fill" out delegations + let mut balances = Vec::new(); + let mut candidates = Vec::new(); + let mut delegations = Vec::new(); + + for collator in 1..30 { + balances.push((collator, 100)); + candidates.push((collator, 10)); + let starting_delegator = collator * 1000; + for delegator in starting_delegator..starting_delegator + 300 { + balances.push((delegator, 100)); + delegations.push((delegator, collator, 10)); + } + } - assert_ok!(StakePallet::increment_collator_rewards(RuntimeOrigin::signed(3))); - assert_ok!(StakePallet::claim_rewards(RuntimeOrigin::signed(3))); - assert_eq!(rewards_3 + 98 * stake, Balances::usable_balance(&3)); - assert!(StakePallet::get_unclaimed_staking_rewards(&3).is_zero()); + ExtBuilder::default() + .with_balances(balances) + .with_candidates(candidates) + .with_delegations(delegations) + .build() + .execute_with(|| { + let weight = ParachainStaking::on_initialize(1); + + // TODO: build this with proper db reads/writes + assert_eq!(Weight::from_parts(277065000, 0), weight); + + // roll to the end of the round, then run on_init again, we should see round change... + roll_to_round_end(3); + set_author(2, 1, 100); // must set some points for prepare_staking_payouts + let block = System::block_number() + 1; + let weight = ParachainStaking::on_initialize(block); + + // the total on_init weight during our round change. this number is taken from running + // the fn with a given weights.rs benchmark, so will need to be updated as benchmarks + // change. + // + // following this assertion, we add individual weights together to show that we can + // derive this number independently. + let expected_on_init = 2479994997; + assert_eq!(Weight::from_parts(expected_on_init, 186592), weight); + + // assemble weight manually to ensure it is well understood + let mut expected_weight = 0u64; + expected_weight += PalletWeights::::base_on_initialize().ref_time(); + expected_weight += PalletWeights::::prepare_staking_payouts().ref_time(); + + // TODO: this should be the same as >. I believe this relates to + // genesis building + let num_avg_delegations = 8; + expected_weight += + PalletWeights::::select_top_candidates(>::get(), num_avg_delegations) + .ref_time(); + // Round and Staked writes, done in on-round-change code block inside on_initialize() + expected_weight += RocksDbWeight::get().reads_writes(0, 2).ref_time(); + // more reads/writes manually accounted for for on_finalize + expected_weight += RocksDbWeight::get().reads_writes(3, 2).ref_time(); + + assert_eq!(Weight::from_parts(expected_weight, 186592), weight); + assert_eq!(expected_on_init, expected_weight); // magic number == independent accounting }); } #[test] -fn api_get_staking_rates() { - let stake = 100_000 * DECIMALS; +fn test_compute_top_candidates_is_stable() { ExtBuilder::default() - .with_balances(vec![(1, stake), (2, stake), (3, 2 * stake)]) - .with_collators(vec![(1, stake), (2, stake)]) - .with_delegators(vec![(3, 1, stake)]) - .with_inflation(25, 10, 25, 8, ::BLOCKS_PER_YEAR) + .with_balances(vec![(1, 30), (2, 30), (3, 30), (4, 30), (5, 30), (6, 30)]) + .with_candidates(vec![(1, 30), (2, 30), (3, 30), (4, 30), (5, 30), (6, 30)]) .build() .execute_with(|| { - let mut rates = StakingRates { - collator_staking_rate: Perquintill::from_percent(50), - collator_reward_rate: Perquintill::from_percent(5), - delegator_staking_rate: Perquintill::from_percent(25), - delegator_reward_rate: Perquintill::from_percent(8), - }; - // collators exceed max staking rate - assert_eq!(rates, StakePallet::get_staking_rates()); - - // candidates stake less to not exceed max staking rate - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(1), stake / 2)); - assert_ok!(StakePallet::candidate_stake_less(RuntimeOrigin::signed(2), stake / 2)); - // delegator stakes more to exceed - assert_ok!(StakePallet::delegator_stake_more(RuntimeOrigin::signed(3), stake)); - rates.collator_staking_rate = Perquintill::from_percent(25); - rates.collator_reward_rate = Perquintill::from_percent(10); - rates.delegator_staking_rate = Perquintill::from_percent(50); - rates.delegator_reward_rate = Perquintill::from_percent(4); - assert_eq!(rates, StakePallet::get_staking_rates()); + // There are 6 candidates with equal amount, but only 5 can be selected + assert_eq!(ParachainStaking::candidate_pool().0.len(), 6); + assert_eq!(ParachainStaking::total_selected(), 5); + // Returns the 5 candidates with greater AccountId, because they are iterated in reverse + assert_eq!(ParachainStaking::compute_top_candidates(), vec![2, 3, 4, 5, 6]); }); } diff --git a/pallets/parachain-staking/src/traits.rs b/pallets/parachain-staking/src/traits.rs new file mode 100644 index 000000000..746d193e2 --- /dev/null +++ b/pallets/parachain-staking/src/traits.rs @@ -0,0 +1,58 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + +//! traits for parachain-staking + +use frame_support::pallet_prelude::Weight; + +pub trait OnCollatorPayout { + fn on_collator_payout(for_round: crate::RoundIndex, collator_id: AccountId, amount: Balance) -> Weight; +} +impl OnCollatorPayout for () { + fn on_collator_payout(_for_round: crate::RoundIndex, _collator_id: AccountId, _amount: Balance) -> Weight { + Weight::zero() + } +} + +pub trait OnNewRound { + fn on_new_round(round_index: crate::RoundIndex) -> Weight; +} +impl OnNewRound for () { + fn on_new_round(_round_index: crate::RoundIndex) -> Weight { + Weight::zero() + } +} + +/// Defines the behavior to payout the collator's reward. +pub trait PayoutCollatorReward { + fn payout_collator_reward( + round_index: crate::RoundIndex, + collator_id: Runtime::AccountId, + amount: crate::BalanceOf, + ) -> Weight; +} + +/// Defines the default behavior for paying out the collator's reward. The amount is directly +/// deposited into the collator's account. +impl PayoutCollatorReward for () { + fn payout_collator_reward( + for_round: crate::RoundIndex, + collator_id: Runtime::AccountId, + amount: crate::BalanceOf, + ) -> Weight { + crate::Pallet::::mint_collator_reward(for_round, collator_id, amount) + } +} diff --git a/pallets/parachain-staking/src/types.rs b/pallets/parachain-staking/src/types.rs index 0bc0d59ad..18b98c8c4 100644 --- a/pallets/parachain-staking/src/types.rs +++ b/pallets/parachain-staking/src/types.rs @@ -1,321 +1,1597 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. -// The KILT Blockchain is free software: you can redistribute it and/or modify +// Moonbeam 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. -// The KILT Blockchain is distributed in the hope that it will be useful, +// Moonbeam 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 . +// along with Moonbeam. If not, see . -// If you feel like getting in touch with us, you can do so at info@botlabs.org +//! Types for parachain-staking -use frame_support::traits::{Currency, Get}; -use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; -use sp_runtime::{ - traits::{AtLeast32BitUnsigned, CheckedSub, Saturating, Zero}, - RuntimeDebug, +use crate::{ + auto_compound::AutoCompoundDelegations, set::OrderedSet, BalanceOf, BottomDelegations, CandidateInfo, Config, + DelegatorState, Error, Event, Pallet, Round, RoundIndex, TopDelegations, Total, COLLATOR_LOCK_ID, + DELEGATOR_LOCK_ID, +}; +use frame_support::{ + pallet_prelude::*, + traits::{tokens::WithdrawReasons, LockableCurrency}, }; -use sp_staking::SessionIndex; -use sp_std::{ - cmp::Ordering, - fmt::Debug, - ops::{Add, Sub}, +use parity_scale_codec::{Decode, Encode}; +use sp_runtime::{ + traits::{AtLeast32BitUnsigned, Saturating, Zero}, + Perbill, Percent, RuntimeDebug, }; +use sp_std::{cmp::Ordering, collections::btree_map::BTreeMap, prelude::*}; -use crate::{set::OrderedSet, Config}; - -/// A struct represented an amount of staked funds. -/// -/// The stake has a destination account (to which the stake is directed) and an -/// amount of funds staked. -#[derive(Default, Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo, MaxEncodedLen)] -#[codec(mel_bound(AccountId: MaxEncodedLen, Balance: MaxEncodedLen))] -pub struct Stake -where - AccountId: Eq + Ord, - Balance: Eq + Ord, -{ - /// The account that is backed by the stake. - pub owner: AccountId, +pub struct CountedDelegations { + pub uncounted_stake: BalanceOf, + pub rewardable_delegations: Vec>>, +} - /// The amount of backing the `owner` received. +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct Bond { + pub owner: AccountId, pub amount: Balance, } -impl From for Stake -where - A: Eq + Ord, - B: Default + Eq + Ord, -{ - fn from(owner: A) -> Self { - Stake { - owner, +impl Default for Bond { + fn default() -> Bond { + Bond { + owner: A::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) + .expect("infinite length input; no invalid inputs for type; qed"), amount: B::default(), } } } -impl PartialOrd for Stake { +impl Bond { + pub fn from_owner(owner: A) -> Self { + Bond { owner, amount: B::default() } + } +} + +impl Eq for Bond {} + +impl Ord for Bond { + fn cmp(&self, other: &Self) -> Ordering { + self.owner.cmp(&other.owner) + } +} + +impl PartialOrd for Bond { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -// We order by stake and only return an equal order, if both account ids match. -// This prevents the same account ids to be in the same OrderedSet. Otherwise, -// it is ordered from greatest to lowest stake (primary) and from first joined -// to last joined (primary). -impl Ord for Stake { - fn cmp(&self, other: &Self) -> Ordering { - match (self.owner.cmp(&other.owner), self.amount.cmp(&other.amount)) { - // enforce unique account ids - (Ordering::Equal, _) => Ordering::Equal, - // prioritize existing members if stakes match - (_, Ordering::Equal) => Ordering::Greater, - // order by stake - (_, ord) => ord, - } +impl PartialEq for Bond { + fn eq(&self, other: &Self) -> bool { + self.owner == other.owner } } -/// The activity status of the collator. -#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub enum CandidateStatus { +#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +/// The activity status of the collator +#[derive(Default)] +pub enum CollatorStatus { /// Committed to be online and producing valid blocks (not equivocating) + #[default] Active, - /// Staked until the inner round - Leaving(SessionIndex), + /// Temporarily inactive and excused for inactivity + Idle, + /// Bonded until the inner round + Leaving(RoundIndex), +} + +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +pub struct BondWithAutoCompound { + pub owner: AccountId, + pub amount: Balance, + pub auto_compound: Percent, } -impl Default for CandidateStatus { - fn default() -> CandidateStatus { - CandidateStatus::Active +impl Default for BondWithAutoCompound { + fn default() -> BondWithAutoCompound { + BondWithAutoCompound { + owner: A::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) + .expect("infinite length input; no invalid inputs for type; qed"), + amount: B::default(), + auto_compound: Percent::zero(), + } } } -#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo, MaxEncodedLen)] -#[scale_info(skip_type_params(MaxDelegatorsPerCandidate))] -#[codec(mel_bound(AccountId: MaxEncodedLen, Balance: MaxEncodedLen))] -/// Global collator state with commission fee, staked funds, and delegations -pub struct Candidate -where - AccountId: Eq + Ord + Debug, - Balance: Eq + Ord + Debug, - MaxDelegatorsPerCandidate: Get + Debug + PartialEq, -{ - /// Account id of the candidate. +#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +/// Snapshot of collator state at the start of the round for which they are selected +pub struct CollatorSnapshot { + /// The total value locked by the collator. + pub bond: Balance, + + /// The rewardable delegations. This list is a subset of total delegators, where certain + /// delegators are adjusted based on their scheduled + /// [DelegationChange::Revoke] or [DelegationChange::Decrease] action. + pub delegations: Vec>, + + /// The total counted value locked for the collator, including the self bond + total staked by + /// top delegators. + pub total: Balance, +} + +impl PartialEq for CollatorSnapshot { + fn eq(&self, other: &Self) -> bool { + let must_be_true = self.bond == other.bond && self.total == other.total; + if !must_be_true { + return false + } + for ( + BondWithAutoCompound { owner: o1, amount: a1, auto_compound: c1 }, + BondWithAutoCompound { owner: o2, amount: a2, auto_compound: c2 }, + ) in self.delegations.iter().zip(other.delegations.iter()) + { + if o1 != o2 || a1 != a2 || c1 != c2 { + return false + } + } + true + } +} + +impl Default for CollatorSnapshot { + fn default() -> CollatorSnapshot { + CollatorSnapshot { bond: B::default(), delegations: Vec::new(), total: B::default() } + } +} + +#[derive(Default, Encode, Decode, RuntimeDebug, TypeInfo)] +/// Info needed to make delayed payments to stakers after round end +pub struct DelayedPayout { + /// Total round reward (result of compute_issuance() at round end) + pub round_issuance: Balance, + /// The total inflation paid this round to stakers (e.g. less parachain bond fund) + pub total_staking_reward: Balance, + /// Snapshot of collator commission rate at the end of the round + pub collator_commission: Perbill, +} + +#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +/// DEPRECATED +/// Collator state with commission fee, bonded stake, and delegations +pub struct Collator2 { + /// The account of this collator pub id: AccountId, + /// This collator's self stake. + pub bond: Balance, + /// Set of all nominator AccountIds (to prevent >1 nomination per AccountId) + pub nominators: OrderedSet, + /// Top T::MaxDelegatorsPerCollator::get() nominators, ordered greatest to least + pub top_nominators: Vec>, + /// Bottom nominators (unbounded), ordered least to greatest + pub bottom_nominators: Vec>, + /// Sum of top delegations + self.bond + pub total_counted: Balance, + /// Sum of all delegations + self.bond = (total_counted + uncounted) + pub total_backing: Balance, + /// Current status of the collator + pub state: CollatorStatus, +} - /// The stake that the candidate put down. - pub stake: Balance, +impl From> for CollatorCandidate { + fn from(other: Collator2) -> CollatorCandidate { + CollatorCandidate { + id: other.id, + bond: other.bond, + delegators: other.nominators, + top_delegations: other.top_nominators, + bottom_delegations: other.bottom_nominators, + total_counted: other.total_counted, + total_backing: other.total_backing, + request: None, + state: other.state, + } + } +} - /// The delegators that back the candidate. - pub delegators: OrderedSet, MaxDelegatorsPerCandidate>, +#[derive(PartialEq, Clone, Copy, Encode, Decode, RuntimeDebug, TypeInfo)] +/// Request scheduled to change the collator candidate self-bond +pub struct CandidateBondLessRequest { + pub amount: Balance, + pub when_executable: RoundIndex, +} - /// The total backing a collator has. - /// - /// Should equal the sum of all delegators stake adding collators stake +#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +/// DEPRECATED, replaced by `CandidateMetadata` and two storage instances of `Delegations` +/// Collator candidate state with self bond + delegations +pub struct CollatorCandidate { + /// The account of this collator + pub id: AccountId, + /// This collator's self stake. + pub bond: Balance, + /// Set of all delegator AccountIds (to prevent >1 delegation per AccountId) + pub delegators: OrderedSet, + /// Top T::MaxDelegatorsPerCollator::get() delegations, ordered greatest to least + pub top_delegations: Vec>, + /// Bottom delegations (unbounded), ordered least to greatest + pub bottom_delegations: Vec>, + /// Sum of top delegations + self.bond + pub total_counted: Balance, + /// Sum of all delegations + self.bond = (total_counted + uncounted) + pub total_backing: Balance, + /// Maximum 1 pending request to decrease candidate self bond at any given time + pub request: Option>, + /// Current status of the collator + pub state: CollatorStatus, +} + +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +/// Type for top and bottom delegation storage item +pub struct Delegations { + pub delegations: Vec>, pub total: Balance, +} + +impl Default for Delegations { + fn default() -> Delegations { + Delegations { delegations: Vec::new(), total: B::default() } + } +} + +impl Delegations { + pub fn sort_greatest_to_least(&mut self) { + self.delegations.sort_by(|a, b| b.amount.cmp(&a.amount)); + } + + /// Insert sorted greatest to least and increase .total accordingly + /// Insertion respects first come first serve so new delegations are pushed after existing + /// delegations if the amount is the same + pub fn insert_sorted_greatest_to_least(&mut self, delegation: Bond) { + self.total = self.total.saturating_add(delegation.amount); + // if delegations nonempty && last_element == delegation.amount => push input and return + if !self.delegations.is_empty() { + // if last_element == delegation.amount => push the delegation and return early + if self.delegations[self.delegations.len() - 1].amount == delegation.amount { + self.delegations.push(delegation); + // early return + return + } + } + // else binary search insertion + match self.delegations.binary_search_by(|x| delegation.amount.cmp(&x.amount)) { + // sorted insertion on sorted vec + // enforces first come first serve for equal bond amounts + Ok(i) => { + let mut new_index = i + 1; + while new_index <= (self.delegations.len() - 1) { + if self.delegations[new_index].amount == delegation.amount { + new_index = new_index.saturating_add(1); + } else { + self.delegations.insert(new_index, delegation); + return + } + } + self.delegations.push(delegation) + }, + Err(i) => self.delegations.insert(i, delegation), + } + } + + /// Return the capacity status for top delegations + pub fn top_capacity(&self) -> CapacityStatus { + match &self.delegations { + x if x.len() as u32 >= T::MaxTopDelegationsPerCandidate::get() => CapacityStatus::Full, + x if x.is_empty() => CapacityStatus::Empty, + _ => CapacityStatus::Partial, + } + } + + /// Return the capacity status for bottom delegations + pub fn bottom_capacity(&self) -> CapacityStatus { + match &self.delegations { + x if x.len() as u32 >= T::MaxBottomDelegationsPerCandidate::get() => CapacityStatus::Full, + x if x.is_empty() => CapacityStatus::Empty, + _ => CapacityStatus::Partial, + } + } + + /// Return last delegation amount without popping the delegation + pub fn lowest_delegation_amount(&self) -> Balance { + self.delegations.last().map(|x| x.amount).unwrap_or(Balance::zero()) + } + + /// Return highest delegation amount + pub fn highest_delegation_amount(&self) -> Balance { + self.delegations.first().map(|x| x.amount).unwrap_or(Balance::zero()) + } +} + +#[derive(PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] +/// Capacity status for top or bottom delegations +pub enum CapacityStatus { + /// Reached capacity + Full, + /// Empty aka contains no delegations + Empty, + /// Partially full (nonempty and not full) + Partial, +} - /// The current status of the candidate. Indicates whether a candidate is - /// active or leaving the candidate pool - pub status: CandidateStatus, +#[derive(Encode, Decode, RuntimeDebug, TypeInfo)] +/// All candidate info except the top and bottom delegations +pub struct CandidateMetadata { + /// This candidate's self bond amount + pub bond: Balance, + /// Total number of delegations to this candidate + pub delegation_count: u32, + /// Self bond + sum of top delegations + pub total_counted: Balance, + /// The smallest top delegation amount + pub lowest_top_delegation_amount: Balance, + /// The highest bottom delegation amount + pub highest_bottom_delegation_amount: Balance, + /// The smallest bottom delegation amount + pub lowest_bottom_delegation_amount: Balance, + /// Capacity status for top delegations + pub top_capacity: CapacityStatus, + /// Capacity status for bottom delegations + pub bottom_capacity: CapacityStatus, + /// Maximum 1 pending request to decrease candidate self bond at any given time + pub request: Option>, + /// Current status of the collator + pub status: CollatorStatus, } -impl Candidate -where - A: Ord + Clone + Debug, - B: AtLeast32BitUnsigned + Ord + Copy + Saturating + Debug + Zero, - S: Get + Debug + PartialEq, +impl< + Balance: Copy + + Zero + + PartialOrd + + sp_std::ops::AddAssign + + sp_std::ops::SubAssign + + sp_std::ops::Sub + + sp_std::fmt::Debug + + Saturating, + > CandidateMetadata { - pub fn new(id: A, stake: B) -> Self { - let total = stake; - Candidate { - id, - stake, - delegators: OrderedSet::new(), - total, - status: CandidateStatus::default(), // default active + pub fn new(bond: Balance) -> Self { + CandidateMetadata { + bond, + delegation_count: 0u32, + total_counted: bond, + lowest_top_delegation_amount: Zero::zero(), + highest_bottom_delegation_amount: Zero::zero(), + lowest_bottom_delegation_amount: Zero::zero(), + top_capacity: CapacityStatus::Empty, + bottom_capacity: CapacityStatus::Empty, + request: None, + status: CollatorStatus::Active, } } pub fn is_active(&self) -> bool { - self.status == CandidateStatus::Active + matches!(self.status, CollatorStatus::Active) } pub fn is_leaving(&self) -> bool { - matches!(self.status, CandidateStatus::Leaving(_)) + matches!(self.status, CollatorStatus::Leaving(_)) + } + + pub fn schedule_leave(&mut self) -> Result<(RoundIndex, RoundIndex), DispatchError> { + ensure!(!self.is_leaving(), Error::::CandidateAlreadyLeaving); + let now = >::get().current; + let when = now + T::LeaveCandidatesDelay::get(); + self.status = CollatorStatus::Leaving(when); + Ok((now, when)) + } + + pub fn can_leave(&self) -> DispatchResult { + if let CollatorStatus::Leaving(when) = self.status { + ensure!(>::get().current >= when, Error::::CandidateCannotLeaveYet); + Ok(()) + } else { + Err(Error::::CandidateNotLeaving.into()) + } + } + + pub fn go_offline(&mut self) { + self.status = CollatorStatus::Idle; } - pub fn can_exit(&self, when: u32) -> bool { - matches!(self.status, CandidateStatus::Leaving(at) if at <= when ) + pub fn go_online(&mut self) { + self.status = CollatorStatus::Active; } - pub fn revert_leaving(&mut self) { - self.status = CandidateStatus::Active; + pub fn bond_more(&mut self, who: T::AccountId, more: Balance) -> DispatchResult + where + BalanceOf: From, + { + ensure!(>::get_collator_stakable_free_balance(&who) >= more.into(), Error::::InsufficientBalance); + let new_total = >::get().saturating_add(more.into()); + >::put(new_total); + self.bond = self.bond.saturating_add(more); + T::Currency::set_lock(COLLATOR_LOCK_ID, &who, self.bond.into(), WithdrawReasons::all()); + self.total_counted = self.total_counted.saturating_add(more); + >::deposit_event(Event::CandidateBondedMore { + candidate: who, + amount: more.into(), + new_total_bond: self.bond.into(), + }); + Ok(()) } - pub fn stake_more(&mut self, more: B) { - self.stake = self.stake.saturating_add(more); - self.total = self.total.saturating_add(more); + /// Schedule executable decrease of collator candidate self bond + /// Returns the round at which the collator can execute the pending request + pub fn schedule_bond_less(&mut self, less: Balance) -> Result + where + BalanceOf: Into, + { + // ensure no pending request + ensure!(self.request.is_none(), Error::::PendingCandidateRequestAlreadyExists); + // ensure bond above min after decrease + ensure!(self.bond > less, Error::::CandidateBondBelowMin); + ensure!(self.bond - less >= T::MinCandidateStk::get().into(), Error::::CandidateBondBelowMin); + let when_executable = >::get().current + T::CandidateBondLessDelay::get(); + self.request = Some(CandidateBondLessRequest { amount: less, when_executable }); + Ok(when_executable) } - // Returns None if underflow or less == self.stake (in which case collator - // should leave). - pub fn stake_less(&mut self, less: B) -> Option { - if self.stake > less { - self.stake = self.stake.saturating_sub(less); - self.total = self.total.saturating_sub(less); - Some(self.stake) + /// Execute pending request to decrease the collator self bond + /// Returns the event to be emitted + pub fn execute_bond_less(&mut self, who: T::AccountId) -> DispatchResult + where + BalanceOf: From, + { + let request = self.request.ok_or(Error::::PendingCandidateRequestsDNE)?; + ensure!(request.when_executable <= >::get().current, Error::::PendingCandidateRequestNotDueYet); + let new_total_staked = >::get().saturating_sub(request.amount.into()); + >::put(new_total_staked); + // Arithmetic assumptions are self.bond > less && self.bond - less > CollatorMinBond + // (assumptions enforced by `schedule_bond_less`; if storage corrupts, must re-verify) + self.bond = self.bond.saturating_sub(request.amount); + T::Currency::set_lock(COLLATOR_LOCK_ID, &who, self.bond.into(), WithdrawReasons::all()); + self.total_counted = self.total_counted.saturating_sub(request.amount); + let event = Event::CandidateBondedLess { + candidate: who.clone(), + amount: request.amount.into(), + new_bond: self.bond.into(), + }; + // reset s.t. no pending request + self.request = None; + // update candidate pool value because it must change if self bond changes + if self.is_active() { + Pallet::::update_active(who, self.total_counted.into()); + } + Pallet::::deposit_event(event); + Ok(()) + } + + /// Cancel candidate bond less request + pub fn cancel_bond_less(&mut self, who: T::AccountId) -> DispatchResult + where + BalanceOf: From, + { + let request = self.request.ok_or(Error::::PendingCandidateRequestsDNE)?; + let event = Event::CancelledCandidateBondLess { + candidate: who, + amount: request.amount.into(), + execute_round: request.when_executable, + }; + self.request = None; + Pallet::::deposit_event(event); + Ok(()) + } + + /// Reset top delegations metadata + pub fn reset_top_data( + &mut self, + candidate: T::AccountId, + top_delegations: &Delegations>, + ) where + BalanceOf: Into + From, + { + self.lowest_top_delegation_amount = top_delegations.lowest_delegation_amount().into(); + self.top_capacity = top_delegations.top_capacity::(); + let old_total_counted = self.total_counted; + self.total_counted = self.bond.saturating_add(top_delegations.total.into()); + // CandidatePool value for candidate always changes if top delegations total changes + // so we moved the update into this function to deduplicate code and patch a bug that + // forgot to apply the update when increasing top delegation + if old_total_counted != self.total_counted && self.is_active() { + Pallet::::update_active(candidate, self.total_counted.into()); + } + } + + /// Reset bottom delegations metadata + pub fn reset_bottom_data(&mut self, bottom_delegations: &Delegations>) + where + BalanceOf: Into, + { + self.lowest_bottom_delegation_amount = bottom_delegations.lowest_delegation_amount().into(); + self.highest_bottom_delegation_amount = bottom_delegations.highest_delegation_amount().into(); + self.bottom_capacity = bottom_delegations.bottom_capacity::(); + } + + /// Add delegation + /// Returns whether delegator was added and an optional negative total counted remainder + /// for if a bottom delegation was kicked + /// MUST ensure no delegation exists for this candidate in the `DelegatorState` before call + pub fn add_delegation( + &mut self, + candidate: &T::AccountId, + delegation: Bond>, + ) -> Result<(DelegatorAdded, Option), DispatchError> + where + BalanceOf: Into + From, + { + let mut less_total_staked = None; + let delegator_added = match self.top_capacity { + CapacityStatus::Full => { + // top is full, insert into top iff the lowest_top < amount + if self.lowest_top_delegation_amount < delegation.amount.into() { + // bumps lowest top to the bottom inside this function call + less_total_staked = self.add_top_delegation::(candidate, delegation); + DelegatorAdded::AddedToTop { new_total: self.total_counted } + } else { + // if bottom is full, only insert if greater than lowest bottom (which will + // be bumped out) + if matches!(self.bottom_capacity, CapacityStatus::Full) { + ensure!( + delegation.amount.into() > self.lowest_bottom_delegation_amount, + Error::::CannotDelegateLessThanOrEqualToLowestBottomWhenFull + ); + // need to subtract from total staked + less_total_staked = Some(self.lowest_bottom_delegation_amount); + } + // insert into bottom + self.add_bottom_delegation::(false, candidate, delegation); + DelegatorAdded::AddedToBottom + } + }, + // top is either empty or partially full + _ => { + self.add_top_delegation::(candidate, delegation); + DelegatorAdded::AddedToTop { new_total: self.total_counted } + }, + }; + Ok((delegator_added, less_total_staked)) + } + + /// Add delegation to top delegation + /// Returns Option + /// Only call if lowest top delegation is less than delegation.amount || !top_full + pub fn add_top_delegation( + &mut self, + candidate: &T::AccountId, + delegation: Bond>, + ) -> Option + where + BalanceOf: Into + From, + { + let mut less_total_staked = None; + let mut top_delegations = + >::get(candidate).expect("CandidateInfo existence => TopDelegations existence"); + let max_top_delegations_per_candidate = T::MaxTopDelegationsPerCandidate::get(); + if top_delegations.delegations.len() as u32 == max_top_delegations_per_candidate { + // pop lowest top delegation + let new_bottom_delegation = top_delegations.delegations.pop().expect(""); + top_delegations.total = top_delegations.total.saturating_sub(new_bottom_delegation.amount); + if matches!(self.bottom_capacity, CapacityStatus::Full) { + less_total_staked = Some(self.lowest_bottom_delegation_amount); + } + self.add_bottom_delegation::(true, candidate, new_bottom_delegation); + } + // insert into top + top_delegations.insert_sorted_greatest_to_least(delegation); + // update candidate info + self.reset_top_data::(candidate.clone(), &top_delegations); + if less_total_staked.is_none() { + // only increment delegation count if we are not kicking a bottom delegation + self.delegation_count = self.delegation_count.saturating_add(1u32); + } + >::insert(candidate, top_delegations); + less_total_staked + } + + /// Add delegation to bottom delegations + /// Check before call that if capacity is full, inserted delegation is higher than lowest + /// bottom delegation (and if so, need to adjust the total storage item) + /// CALLER MUST ensure(lowest_bottom_to_be_kicked.amount < delegation.amount) + pub fn add_bottom_delegation( + &mut self, + bumped_from_top: bool, + candidate: &T::AccountId, + delegation: Bond>, + ) where + BalanceOf: Into + From, + { + let mut bottom_delegations = + >::get(candidate).expect("CandidateInfo existence => BottomDelegations existence"); + // if bottom is full, kick the lowest bottom (which is expected to be lower than input + // as per check) + let increase_delegation_count = + if bottom_delegations.delegations.len() as u32 == T::MaxBottomDelegationsPerCandidate::get() { + let lowest_bottom_to_be_kicked = bottom_delegations + .delegations + .pop() + .expect("if at full capacity (>0), then >0 bottom delegations exist; qed"); + // EXPECT lowest_bottom_to_be_kicked.amount < delegation.amount enforced by caller + // if lowest_bottom_to_be_kicked.amount == delegation.amount, we will still kick + // the lowest bottom to enforce first come first served + bottom_delegations.total = bottom_delegations.total.saturating_sub(lowest_bottom_to_be_kicked.amount); + // update delegator state + // total staked is updated via propagation of lowest bottom delegation amount prior + // to call + let mut delegator_state = >::get(&lowest_bottom_to_be_kicked.owner) + .expect("Delegation existence => DelegatorState existence"); + let leaving = delegator_state.delegations.0.len() == 1usize; + delegator_state.rm_delegation::(candidate); + >::delegation_remove_request_with_state( + candidate, + &lowest_bottom_to_be_kicked.owner, + &mut delegator_state, + ); + >::remove_auto_compound(candidate, &lowest_bottom_to_be_kicked.owner); + + Pallet::::deposit_event(Event::DelegationKicked { + delegator: lowest_bottom_to_be_kicked.owner.clone(), + candidate: candidate.clone(), + unstaked_amount: lowest_bottom_to_be_kicked.amount, + }); + if leaving { + >::remove(&lowest_bottom_to_be_kicked.owner); + Pallet::::deposit_event(Event::DelegatorLeft { + delegator: lowest_bottom_to_be_kicked.owner, + unstaked_amount: lowest_bottom_to_be_kicked.amount, + }); + } else { + >::insert(&lowest_bottom_to_be_kicked.owner, delegator_state); + } + false + } else { + !bumped_from_top + }; + // only increase delegation count if new bottom delegation (1) doesn't come from top && + // (2) doesn't pop the lowest delegation from the bottom + if increase_delegation_count { + self.delegation_count = self.delegation_count.saturating_add(1u32); + } + bottom_delegations.insert_sorted_greatest_to_least(delegation); + self.reset_bottom_data::(&bottom_delegations); + >::insert(candidate, bottom_delegations); + } + + /// Remove delegation + /// Removes from top if amount is above lowest top or top is not full + /// Return Ok(if_total_counted_changed) + pub fn rm_delegation_if_exists( + &mut self, + candidate: &T::AccountId, + delegator: T::AccountId, + amount: Balance, + ) -> Result + where + BalanceOf: Into + From, + { + let amount_geq_lowest_top = amount >= self.lowest_top_delegation_amount; + let top_is_not_full = !matches!(self.top_capacity, CapacityStatus::Full); + let lowest_top_eq_highest_bottom = self.lowest_top_delegation_amount == self.highest_bottom_delegation_amount; + let delegation_dne_err: DispatchError = Error::::DelegationDNE.into(); + if top_is_not_full || (amount_geq_lowest_top && !lowest_top_eq_highest_bottom) { + self.rm_top_delegation::(candidate, delegator) + } else if amount_geq_lowest_top && lowest_top_eq_highest_bottom { + let result = self.rm_top_delegation::(candidate, delegator.clone()); + if result == Err(delegation_dne_err) { + // worst case removal + self.rm_bottom_delegation::(candidate, delegator) + } else { + result + } } else { - None + self.rm_bottom_delegation::(candidate, delegator) + } + } + + /// Remove top delegation, bumps top bottom delegation if exists + pub fn rm_top_delegation( + &mut self, + candidate: &T::AccountId, + delegator: T::AccountId, + ) -> Result + where + BalanceOf: Into + From, + { + let old_total_counted = self.total_counted; + // remove top delegation + let mut top_delegations = + >::get(candidate).expect("CandidateInfo exists => TopDelegations exists"); + let mut actual_amount_option: Option> = None; + top_delegations.delegations = top_delegations + .delegations + .clone() + .into_iter() + .filter(|d| { + if d.owner != delegator { + true + } else { + actual_amount_option = Some(d.amount); + false + } + }) + .collect(); + let actual_amount = actual_amount_option.ok_or(Error::::DelegationDNE)?; + top_delegations.total = top_delegations.total.saturating_sub(actual_amount); + // if bottom nonempty => bump top bottom to top + if !matches!(self.bottom_capacity, CapacityStatus::Empty) { + let mut bottom_delegations = + >::get(candidate).expect("bottom is nonempty as just checked"); + // expect already stored greatest to least by bond amount + let highest_bottom_delegation = bottom_delegations.delegations.remove(0); + bottom_delegations.total = bottom_delegations.total.saturating_sub(highest_bottom_delegation.amount); + self.reset_bottom_data::(&bottom_delegations); + >::insert(candidate, bottom_delegations); + // insert highest bottom into top delegations + top_delegations.insert_sorted_greatest_to_least(highest_bottom_delegation); + } + // update candidate info + self.reset_top_data::(candidate.clone(), &top_delegations); + self.delegation_count = self.delegation_count.saturating_sub(1u32); + >::insert(candidate, top_delegations); + // return whether total counted changed + Ok(old_total_counted == self.total_counted) + } + + /// Remove bottom delegation + /// Returns if_total_counted_changed: bool + pub fn rm_bottom_delegation( + &mut self, + candidate: &T::AccountId, + delegator: T::AccountId, + ) -> Result + where + BalanceOf: Into, + { + // remove bottom delegation + let mut bottom_delegations = + >::get(candidate).expect("CandidateInfo exists => BottomDelegations exists"); + let mut actual_amount_option: Option> = None; + bottom_delegations.delegations = bottom_delegations + .delegations + .clone() + .into_iter() + .filter(|d| { + if d.owner != delegator { + true + } else { + actual_amount_option = Some(d.amount); + false + } + }) + .collect(); + let actual_amount = actual_amount_option.ok_or(Error::::DelegationDNE)?; + bottom_delegations.total = bottom_delegations.total.saturating_sub(actual_amount); + // update candidate info + self.reset_bottom_data::(&bottom_delegations); + self.delegation_count = self.delegation_count.saturating_sub(1u32); + >::insert(candidate, bottom_delegations); + Ok(false) + } + + /// Increase delegation amount + pub fn increase_delegation( + &mut self, + candidate: &T::AccountId, + delegator: T::AccountId, + bond: BalanceOf, + more: BalanceOf, + ) -> Result + where + BalanceOf: Into + From, + { + let lowest_top_eq_highest_bottom = self.lowest_top_delegation_amount == self.highest_bottom_delegation_amount; + let bond_geq_lowest_top = bond.into() >= self.lowest_top_delegation_amount; + let delegation_dne_err: DispatchError = Error::::DelegationDNE.into(); + if bond_geq_lowest_top && !lowest_top_eq_highest_bottom { + // definitely in top + self.increase_top_delegation::(candidate, delegator, more) + } else if bond_geq_lowest_top && lowest_top_eq_highest_bottom { + // update top but if error then update bottom (because could be in bottom because + // lowest_top_eq_highest_bottom) + let result = self.increase_top_delegation::(candidate, delegator.clone(), more); + if result == Err(delegation_dne_err) { + self.increase_bottom_delegation::(candidate, delegator, bond, more) + } else { + result + } + } else { + self.increase_bottom_delegation::(candidate, delegator, bond, more) } } - pub fn inc_delegator(&mut self, delegator: A, more: B) { - if let Ok(i) = self.delegators.linear_search(&Stake:: { - owner: delegator, - amount: B::zero(), - }) { - self.delegators - .mutate(|vec| vec[i].amount = vec[i].amount.saturating_add(more)); - self.total = self.total.saturating_add(more); - self.delegators.sort_greatest_to_lowest() + /// Increase top delegation + pub fn increase_top_delegation( + &mut self, + candidate: &T::AccountId, + delegator: T::AccountId, + more: BalanceOf, + ) -> Result + where + BalanceOf: Into + From, + { + let mut top_delegations = + >::get(candidate).expect("CandidateInfo exists => TopDelegations exists"); + let mut in_top = false; + top_delegations.delegations = top_delegations + .delegations + .clone() + .into_iter() + .map(|d| { + if d.owner != delegator { + d + } else { + in_top = true; + let new_amount = d.amount.saturating_add(more); + Bond { owner: d.owner, amount: new_amount } + } + }) + .collect(); + ensure!(in_top, Error::::DelegationDNE); + top_delegations.total = top_delegations.total.saturating_add(more); + top_delegations.sort_greatest_to_least(); + self.reset_top_data::(candidate.clone(), &top_delegations); + >::insert(candidate, top_delegations); + Ok(true) + } + + /// Increase bottom delegation + pub fn increase_bottom_delegation( + &mut self, + candidate: &T::AccountId, + delegator: T::AccountId, + bond: BalanceOf, + more: BalanceOf, + ) -> Result + where + BalanceOf: Into + From, + { + let mut bottom_delegations = >::get(candidate).ok_or(Error::::CandidateDNE)?; + let mut delegation_option: Option>> = None; + let in_top_after = if (bond.saturating_add(more)).into() > self.lowest_top_delegation_amount { + // bump it from bottom + bottom_delegations.delegations = bottom_delegations + .delegations + .clone() + .into_iter() + .filter(|d| { + if d.owner != delegator { + true + } else { + delegation_option = + Some(Bond { owner: d.owner.clone(), amount: d.amount.saturating_add(more) }); + false + } + }) + .collect(); + let delegation = delegation_option.ok_or(Error::::DelegationDNE)?; + bottom_delegations.total = bottom_delegations.total.saturating_sub(bond); + // add it to top + let mut top_delegations = + >::get(candidate).expect("CandidateInfo existence => TopDelegations existence"); + // if top is full, pop lowest top + if matches!(top_delegations.top_capacity::(), CapacityStatus::Full) { + // pop lowest top delegation + let new_bottom_delegation = + top_delegations.delegations.pop().expect("Top capacity full => Exists at least 1 top delegation"); + top_delegations.total = top_delegations.total.saturating_sub(new_bottom_delegation.amount); + bottom_delegations.insert_sorted_greatest_to_least(new_bottom_delegation); + } + // insert into top + top_delegations.insert_sorted_greatest_to_least(delegation); + self.reset_top_data::(candidate.clone(), &top_delegations); + >::insert(candidate, top_delegations); + true + } else { + let mut in_bottom = false; + // just increase the delegation + bottom_delegations.delegations = bottom_delegations + .delegations + .clone() + .into_iter() + .map(|d| { + if d.owner != delegator { + d + } else { + in_bottom = true; + Bond { owner: d.owner, amount: d.amount.saturating_add(more) } + } + }) + .collect(); + ensure!(in_bottom, Error::::DelegationDNE); + bottom_delegations.total = bottom_delegations.total.saturating_add(more); + bottom_delegations.sort_greatest_to_least(); + false + }; + self.reset_bottom_data::(&bottom_delegations); + >::insert(candidate, bottom_delegations); + Ok(in_top_after) + } + + /// Decrease delegation + pub fn decrease_delegation( + &mut self, + candidate: &T::AccountId, + delegator: T::AccountId, + bond: Balance, + less: BalanceOf, + ) -> Result + where + BalanceOf: Into + From, + { + let lowest_top_eq_highest_bottom = self.lowest_top_delegation_amount == self.highest_bottom_delegation_amount; + let bond_geq_lowest_top = bond >= self.lowest_top_delegation_amount; + let delegation_dne_err: DispatchError = Error::::DelegationDNE.into(); + if bond_geq_lowest_top && !lowest_top_eq_highest_bottom { + // definitely in top + self.decrease_top_delegation::(candidate, delegator, bond.into(), less) + } else if bond_geq_lowest_top && lowest_top_eq_highest_bottom { + // update top but if error then update bottom (because could be in bottom because + // lowest_top_eq_highest_bottom) + let result = self.decrease_top_delegation::(candidate, delegator.clone(), bond.into(), less); + if result == Err(delegation_dne_err) { + self.decrease_bottom_delegation::(candidate, delegator, less) + } else { + result + } + } else { + self.decrease_bottom_delegation::(candidate, delegator, less) } } - pub fn dec_delegator(&mut self, delegator: A, less: B) { - if let Ok(i) = self.delegators.linear_search(&Stake:: { - owner: delegator, - amount: B::zero(), - }) { - self.delegators - .mutate(|vec| vec[i].amount = vec[i].amount.saturating_sub(less)); - self.total = self.total.saturating_sub(less); - self.delegators.sort_greatest_to_lowest() + /// Decrease top delegation + pub fn decrease_top_delegation( + &mut self, + candidate: &T::AccountId, + delegator: T::AccountId, + bond: BalanceOf, + less: BalanceOf, + ) -> Result + where + BalanceOf: Into + From, + { + // The delegation after the `decrease-delegation` will be strictly less than the + // highest bottom delegation + let bond_after_less_than_highest_bottom = + bond.saturating_sub(less).into() < self.highest_bottom_delegation_amount; + // The top delegations is full and the bottom delegations has at least one delegation + let full_top_and_nonempty_bottom = + matches!(self.top_capacity, CapacityStatus::Full) && !matches!(self.bottom_capacity, CapacityStatus::Empty); + let mut top_delegations = >::get(candidate).ok_or(Error::::CandidateDNE)?; + let in_top_after = if bond_after_less_than_highest_bottom && full_top_and_nonempty_bottom { + let mut delegation_option: Option>> = None; + // take delegation from top + top_delegations.delegations = top_delegations + .delegations + .clone() + .into_iter() + .filter(|d| { + if d.owner != delegator { + true + } else { + top_delegations.total = top_delegations.total.saturating_sub(d.amount); + delegation_option = + Some(Bond { owner: d.owner.clone(), amount: d.amount.saturating_sub(less) }); + false + } + }) + .collect(); + let delegation = delegation_option.ok_or(Error::::DelegationDNE)?; + // pop highest bottom by reverse and popping + let mut bottom_delegations = + >::get(candidate).expect("CandidateInfo existence => BottomDelegations existence"); + let highest_bottom_delegation = bottom_delegations.delegations.remove(0); + bottom_delegations.total = bottom_delegations.total.saturating_sub(highest_bottom_delegation.amount); + // insert highest bottom into top + top_delegations.insert_sorted_greatest_to_least(highest_bottom_delegation); + // insert previous top into bottom + bottom_delegations.insert_sorted_greatest_to_least(delegation); + self.reset_bottom_data::(&bottom_delegations); + >::insert(candidate, bottom_delegations); + false + } else { + // keep it in the top + let mut is_in_top = false; + top_delegations.delegations = top_delegations + .delegations + .clone() + .into_iter() + .map(|d| { + if d.owner != delegator { + d + } else { + is_in_top = true; + Bond { owner: d.owner, amount: d.amount.saturating_sub(less) } + } + }) + .collect(); + ensure!(is_in_top, Error::::DelegationDNE); + top_delegations.total = top_delegations.total.saturating_sub(less); + top_delegations.sort_greatest_to_least(); + true + }; + self.reset_top_data::(candidate.clone(), &top_delegations); + >::insert(candidate, top_delegations); + Ok(in_top_after) + } + + /// Decrease bottom delegation + pub fn decrease_bottom_delegation( + &mut self, + candidate: &T::AccountId, + delegator: T::AccountId, + less: BalanceOf, + ) -> Result + where + BalanceOf: Into, + { + let mut bottom_delegations = + >::get(candidate).expect("CandidateInfo exists => BottomDelegations exists"); + let mut in_bottom = false; + bottom_delegations.delegations = bottom_delegations + .delegations + .clone() + .into_iter() + .map(|d| { + if d.owner != delegator { + d + } else { + in_bottom = true; + Bond { owner: d.owner, amount: d.amount.saturating_sub(less) } + } + }) + .collect(); + ensure!(in_bottom, Error::::DelegationDNE); + bottom_delegations.sort_greatest_to_least(); + self.reset_bottom_data::(&bottom_delegations); + >::insert(candidate, bottom_delegations); + Ok(false) + } +} + +// Temporary manual implementation for migration testing purposes +impl PartialEq for CollatorCandidate { + fn eq(&self, other: &Self) -> bool { + let must_be_true = self.id == other.id && + self.bond == other.bond && + self.total_counted == other.total_counted && + self.total_backing == other.total_backing && + self.request == other.request && + self.state == other.state; + if !must_be_true { + return false + } + for (x, y) in self.delegators.0.iter().zip(other.delegators.0.iter()) { + if x != y { + return false + } + } + for (Bond { owner: o1, amount: a1 }, Bond { owner: o2, amount: a2 }) in + self.top_delegations.iter().zip(other.top_delegations.iter()) + { + if o1 != o2 || a1 != a2 { + return false + } + } + for (Bond { owner: o1, amount: a1 }, Bond { owner: o2, amount: a2 }) in + self.bottom_delegations.iter().zip(other.bottom_delegations.iter()) + { + if o1 != o2 || a1 != a2 { + return false + } } + true + } +} + +/// Convey relevant information describing if a delegator was added to the top or bottom +/// Delegations added to the top yield a new total +#[derive(Clone, Copy, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum DelegatorAdded { + AddedToTop { new_total: B }, + AddedToBottom, +} + +impl< + A: Ord + Clone + sp_std::fmt::Debug, + B: AtLeast32BitUnsigned + Ord + Copy + sp_std::ops::AddAssign + sp_std::ops::SubAssign + sp_std::fmt::Debug, + > CollatorCandidate +{ + pub fn is_active(&self) -> bool { + self.state == CollatorStatus::Active } +} - pub fn leave_candidates(&mut self, round: SessionIndex) { - self.status = CandidateStatus::Leaving(round); +impl From> for CollatorSnapshot { + fn from(other: CollatorCandidate) -> CollatorSnapshot { + CollatorSnapshot { + bond: other.bond, + delegations: other + .top_delegations + .into_iter() + .map(|d| BondWithAutoCompound { owner: d.owner, amount: d.amount, auto_compound: Percent::zero() }) + .collect(), + total: other.total_counted, + } } } -pub type Delegator = Stake; -impl Delegator -where - AccountId: Eq + Ord + Clone + Debug, - Balance: Copy + Add + Saturating + PartialOrd + Eq + Ord + Debug + Zero + Default + CheckedSub, +#[allow(deprecated)] +#[derive(Clone, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] +pub enum DelegatorStatus { + /// Active with no scheduled exit + Active, + /// Schedule exit to revoke all ongoing delegations + #[deprecated(note = "must only be used for backwards compatibility reasons")] + Leaving(RoundIndex), +} + +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +/// Delegator state +pub struct Delegator { + /// Delegator account + pub id: AccountId, + /// All current delegations + pub delegations: OrderedSet>, + /// Total balance locked for this delegator + pub total: Balance, + /// Sum of pending revocation amounts + bond less amounts + pub less_total: Balance, + /// Status for this delegator + pub status: DelegatorStatus, +} + +// Temporary manual implementation for migration testing purposes +impl PartialEq for Delegator { + fn eq(&self, other: &Self) -> bool { + let must_be_true = self.id == other.id && + self.total == other.total && + self.less_total == other.less_total && + self.status == other.status; + if !must_be_true { + return false + } + for (Bond { owner: o1, amount: a1 }, Bond { owner: o2, amount: a2 }) in + self.delegations.0.iter().zip(other.delegations.0.iter()) + { + if o1 != o2 || a1 != a2 { + return false + } + } + true + } +} + +impl< + AccountId: Ord + Clone, + Balance: Copy + + sp_std::ops::AddAssign + + sp_std::ops::Add + + sp_std::ops::SubAssign + + sp_std::ops::Sub + + Ord + + Zero + + Default + + Saturating, + > Delegator { - /// Returns Ok if the delegation for the - /// collator exists and `Err` otherwise. - pub fn try_clear(&mut self, collator: AccountId) -> Result<(), ()> { - if self.owner == collator { - self.amount = Balance::zero(); - Ok(()) + pub fn new(id: AccountId, collator: AccountId, amount: Balance) -> Self { + Delegator { + id, + delegations: OrderedSet::from(vec![Bond { owner: collator, amount }]), + total: amount, + less_total: Balance::zero(), + status: DelegatorStatus::Active, + } + } + + pub fn default_with_total(id: AccountId, amount: Balance) -> Self { + Delegator { + id, + total: amount, + delegations: OrderedSet::from(vec![]), + less_total: Balance::zero(), + status: DelegatorStatus::Active, + } + } + + pub fn total(&self) -> Balance { + self.total + } + + pub fn total_sub_if(&mut self, amount: Balance, check: F) -> DispatchResult + where + T: Config, + T::AccountId: From, + BalanceOf: From, + F: Fn(Balance) -> DispatchResult, + { + let total = self.total.saturating_sub(amount); + check(total)?; + self.total = total; + self.adjust_bond_lock::(BondAdjust::Decrease)?; + Ok(()) + } + + pub fn total_add(&mut self, amount: Balance) -> DispatchResult + where + T: Config, + T::AccountId: From, + BalanceOf: From, + { + self.total = self.total.saturating_add(amount); + self.adjust_bond_lock::(BondAdjust::Increase(amount))?; + Ok(()) + } + + pub fn total_sub(&mut self, amount: Balance) -> DispatchResult + where + T: Config, + T::AccountId: From, + BalanceOf: From, + { + self.total = self.total.saturating_sub(amount); + self.adjust_bond_lock::(BondAdjust::Decrease)?; + Ok(()) + } + + pub fn is_active(&self) -> bool { + matches!(self.status, DelegatorStatus::Active) + } + + pub fn add_delegation(&mut self, bond: Bond) -> bool { + let amt = bond.amount; + if self.delegations.insert(bond) { + self.total = self.total.saturating_add(amt); + true } else { - Err(()) + false } } - /// Returns Ok(delegated_amount) if successful, `Err` if delegation was - /// not found. - pub fn try_increment(&mut self, collator: AccountId, more: Balance) -> Result { - if self.owner == collator { - self.amount = self.amount.saturating_add(more); - Ok(self.amount) + // Return Some(remaining balance), must be more than MinDelegatorStk + // Return None if delegation not found + pub fn rm_delegation(&mut self, collator: &AccountId) -> Option + where + BalanceOf: From, + T::AccountId: From, + { + let mut amt: Option = None; + let delegations = self + .delegations + .0 + .iter() + .filter_map(|x| { + if &x.owner == collator { + amt = Some(x.amount); + None + } else { + Some(x.clone()) + } + }) + .collect(); + if let Some(balance) = amt { + self.delegations = OrderedSet::from(delegations); + self.total_sub::(balance).expect("Decreasing lock cannot fail, qed"); + Some(self.total) } else { - Err(()) + None + } + } + + /// Increases the delegation amount and returns `true` if the delegation is part of the + /// TopDelegations set, `false` otherwise. + pub fn increase_delegation( + &mut self, + candidate: AccountId, + amount: Balance, + ) -> Result + where + BalanceOf: From, + T::AccountId: From, + Delegator>: From>, + { + let delegator_id: T::AccountId = self.id.clone().into(); + let candidate_id: T::AccountId = candidate.clone().into(); + let balance_amt: BalanceOf = amount.into(); + // increase delegation + for x in &mut self.delegations.0 { + if x.owner == candidate { + let before_amount: BalanceOf = x.amount.into(); + x.amount = x.amount.saturating_add(amount); + self.total = self.total.saturating_add(amount); + self.adjust_bond_lock::(BondAdjust::Increase(amount))?; + + // update collator state delegation + let mut collator_state = >::get(&candidate_id).ok_or(Error::::CandidateDNE)?; + let before = collator_state.total_counted; + let in_top = collator_state.increase_delegation::( + &candidate_id, + delegator_id.clone(), + before_amount, + balance_amt, + )?; + let after = collator_state.total_counted; + if collator_state.is_active() && (before != after) { + Pallet::::update_active(candidate_id.clone(), after); + } + >::insert(&candidate_id, collator_state); + let new_total_staked = >::get().saturating_add(balance_amt); + >::put(new_total_staked); + let nom_st: Delegator> = self.clone().into(); + >::insert(&delegator_id, nom_st); + return Ok(in_top) + } } + Err(Error::::DelegationDNE.into()) } - /// Returns Ok(Some(delegated_amount)) if successful, `Err` if delegation - /// was not found and Ok(None) if delegated stake would underflow. - pub fn try_decrement(&mut self, collator: AccountId, less: Balance) -> Result, ()> { - if self.owner == collator { - Ok(self.amount.checked_sub(&less).map(|new| { - self.amount = new; - self.amount - })) + /// Updates the bond locks for this delegator. + /// + /// This will take the current self.total and ensure that a lock of the same amount is applied + /// and when increasing the bond lock will also ensure that the account has enough free balance. + /// + /// `additional_required_balance` should reflect the change to the amount that should be locked if + /// positive, 0 otherwise (e.g. `min(0, change_in_total_bond)`). This is necessary because it is + /// not possible to query the amount that is locked for a given lock id. + pub fn adjust_bond_lock(&mut self, additional_required_balance: BondAdjust) -> DispatchResult + where + BalanceOf: From, + T::AccountId: From, + { + match additional_required_balance { + BondAdjust::Increase(amount) => { + ensure!( + >::get_delegator_stakable_free_balance(&self.id.clone().into()) >= amount.into(), + Error::::InsufficientBalance, + ); + + // additional sanity check: shouldn't ever want to lock more than total + if amount > self.total { + log::warn!("LOGIC ERROR: request to reserve more than bond total"); + return Err(DispatchError::Other("Invalid additional_required_balance")) + } + }, + BondAdjust::Decrease => (), // do nothing on decrease + }; + + if self.total.is_zero() { + T::Currency::remove_lock(DELEGATOR_LOCK_ID, &self.id.clone().into()); } else { - Err(()) + T::Currency::set_lock( + DELEGATOR_LOCK_ID, + &self.id.clone().into(), + self.total.into(), + WithdrawReasons::all(), + ); } + Ok(()) + } + + /// Retrieves the bond amount that a delegator has provided towards a collator. + /// Returns `None` if missing. + pub fn get_bond_amount(&self, collator: &AccountId) -> Option { + self.delegations.0.iter().find(|b| &b.owner == collator).map(|b| b.amount) } } -/// The current round index and transition information. -#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub mod deprecated { + #![allow(deprecated)] + + use super::*; + + #[deprecated(note = "use DelegationAction")] + #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] + /// Changes requested by the delegator + /// - limit of 1 ongoing change per delegation + pub enum DelegationChange { + Revoke, + Decrease, + } + + #[deprecated(note = "use ScheduledRequest")] + #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] + pub struct DelegationRequest { + pub collator: AccountId, + pub amount: Balance, + pub when_executable: RoundIndex, + pub action: DelegationChange, + } + + #[deprecated(note = "use DelegationScheduledRequests storage item")] + #[derive(Clone, Encode, PartialEq, Decode, RuntimeDebug, TypeInfo)] + /// Pending requests to mutate delegations for each delegator + pub struct PendingDelegationRequests { + /// Number of pending revocations (necessary for determining whether revoke is exit) + pub revocations_count: u32, + /// Map from collator -> Request (enforces at most 1 pending request per delegation) + pub requests: BTreeMap>, + /// Sum of pending revocation amounts + bond less amounts + pub less_total: Balance, + } + + impl Default for PendingDelegationRequests { + fn default() -> PendingDelegationRequests { + PendingDelegationRequests { revocations_count: 0u32, requests: BTreeMap::new(), less_total: B::zero() } + } + } + + impl< + A: Ord + Clone, + B: Zero + + Ord + + Copy + + Clone + + sp_std::ops::AddAssign + + sp_std::ops::Add + + sp_std::ops::SubAssign + + sp_std::ops::Sub + + Saturating, + > PendingDelegationRequests + { + /// New default (empty) pending requests + pub fn new() -> Self { + Self::default() + } + } + + #[deprecated(note = "use new crate::types::Delegator struct")] + #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] + /// Delegator state + pub struct Delegator { + /// Delegator account + pub id: AccountId, + /// All current delegations + pub delegations: OrderedSet>, + /// Total balance locked for this delegator + pub total: Balance, + /// Requests to change delegations, relevant iff active + pub requests: PendingDelegationRequests, + /// Status for this delegator + pub status: DelegatorStatus, + } + + // CollatorSnapshot + + #[deprecated(note = "use CollatorSnapshot with BondWithAutoCompound delegations")] + #[derive(Encode, Decode, RuntimeDebug, TypeInfo)] + /// Snapshot of collator state at the start of the round for which they are selected + pub struct CollatorSnapshot { + /// The total value locked by the collator. + pub bond: Balance, + + /// The rewardable delegations. This list is a subset of total delegators, where certain + /// delegators are adjusted based on their scheduled + /// [DelegationChange::Revoke] or [DelegationChange::Decrease] action. + pub delegations: Vec>, + + /// The total counted value locked for the collator, including the self bond + total staked by + /// top delegators. + pub total: Balance, + } + + impl PartialEq for CollatorSnapshot { + fn eq(&self, other: &Self) -> bool { + let must_be_true = self.bond == other.bond && self.total == other.total; + if !must_be_true { + return false + } + for (Bond { owner: o1, amount: a1 }, Bond { owner: o2, amount: a2 }) in + self.delegations.iter().zip(other.delegations.iter()) + { + if o1 != o2 || a1 != a2 { + return false + } + } + true + } + } + + impl Default for CollatorSnapshot { + fn default() -> CollatorSnapshot { + CollatorSnapshot { bond: B::default(), delegations: Vec::new(), total: B::default() } + } + } +} + +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +/// DEPRECATED in favor of Delegator +/// Nominator state +pub struct Nominator2 { + /// All current delegations + pub delegations: OrderedSet>, + /// Delegations scheduled to be revoked + pub revocations: OrderedSet, + /// Total balance locked for this nominator + pub total: Balance, + /// Total number of revocations scheduled to be executed + pub scheduled_revocations_count: u32, + /// Total amount to be unbonded once revocations are executed + pub scheduled_revocations_total: Balance, + /// Status for this nominator + pub status: DelegatorStatus, +} + +// /// Temporary function to migrate state +// pub(crate) fn migrate_nominator_to_delegator_state( +// id: T::AccountId, +// nominator: Nominator2>, +// ) -> Delegator> { +// Delegator { +// id, +// delegations: nominator.delegations, +// total: nominator.total, +// requests: PendingDelegationRequests::new(), +// status: nominator.status, +// } +// } + +#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +/// The current round index and transition information pub struct RoundInfo { - /// Current round index. - pub current: SessionIndex, - /// The first block of the current round. + /// Current round index + pub current: RoundIndex, + /// The first block of the current round pub first: BlockNumber, - /// The length of the current round in blocks. - pub length: BlockNumber, + /// The length of the current round in number of blocks + pub length: u32, } - -impl RoundInfo -where - B: Copy + Saturating + From + PartialOrd, -{ - pub fn new(current: SessionIndex, first: B, length: B) -> RoundInfo { +impl + sp_std::ops::Sub + From + PartialOrd> RoundInfo { + pub fn new(current: RoundIndex, first: B, length: u32) -> RoundInfo { RoundInfo { current, first, length } } - /// Checks if the round should be updated. - /// - /// The round should update if `self.length` or more blocks where produced - /// after `self.first`. + /// Check if the round should be updated pub fn should_update(&self, now: B) -> bool { - let l = now.saturating_sub(self.first); - l >= self.length + now - self.first >= self.length.into() } - /// Starts a new round. + /// New round pub fn update(&mut self, now: B) { self.current = self.current.saturating_add(1u32); self.first = now; } } - -impl Default for RoundInfo -where - B: Copy + Saturating + Add + Sub + From + PartialOrd, +impl + sp_std::ops::Sub + From + PartialOrd> Default + for RoundInfo { fn default() -> RoundInfo { - RoundInfo::new(0u32, 0u32.into(), 20.into()) + RoundInfo::new(1u32, 1u32.into(), 20u32) } } -/// The total stake of the pallet. -/// -/// The stake includes both collators' and delegators' staked funds. -#[derive(Default, Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo, MaxEncodedLen)] -pub struct TotalStake { - pub collators: Balance, - pub delegators: Balance, +#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo)] +/// Reserve information { account, percent_of_inflation } +pub struct ParachainBondConfig { + /// Account which receives funds intended for parachain bond + pub account: AccountId, + /// Percent of inflation set aside for parachain bond account + pub percent: Percent, } - -/// The number of delegations a delegator has done within the last session in -/// which they delegated. -#[derive(Default, Clone, Encode, Decode, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] -pub struct DelegationCounter { - /// The index of the last delegation. - pub round: SessionIndex, - /// The number of delegations made within round. - pub counter: u32, +impl Default for ParachainBondConfig { + fn default() -> ParachainBondConfig { + ParachainBondConfig { + account: A::decode(&mut sp_runtime::traits::TrailingZeroInput::zeroes()) + .expect("infinite length input; no invalid inputs for type; qed"), + percent: Percent::zero(), + } + } } -pub type AccountIdOf = ::AccountId; -pub type BalanceOf = <::Currency as Currency>>::Balance; -pub type CandidateOf = Candidate, BalanceOf, S>; -pub type StakeOf = Stake, BalanceOf>; -pub type NegativeImbalanceOf = <::Currency as Currency>>::NegativeImbalance; +pub enum BondAdjust { + Increase(Balance), + Decrease, +} diff --git a/pallets/parachain-staking/src/weights.rs b/pallets/parachain-staking/src/weights.rs new file mode 100644 index 000000000..ac72c2bb6 --- /dev/null +++ b/pallets/parachain-staking/src/weights.rs @@ -0,0 +1,1418 @@ +// Copyright 2019-2022 PureStake Inc. +// This file is part of Moonbeam. + +// Moonbeam 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. + +// Moonbeam 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 Moonbeam. If not, see . + + +//! Autogenerated weights for parachain_staking +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-04-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `benchmarker`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 + +// Executed Command: +// ./target/release/moonbeam +// benchmark +// pallet +// --execution=wasm +// --wasm-execution=compiled +// --pallet +// * +// --extrinsic +// * +// --steps +// 50 +// --repeat +// 20 +// --template=./benchmarking/frame-weight-template.hbs +// --json-file +// raw.json +// --output +// weights/ + +#![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 parachain_staking. +pub trait WeightInfo { + fn set_staking_expectations() -> Weight; + fn set_inflation() -> Weight; + fn set_parachain_bond_account() -> Weight; + fn set_parachain_bond_reserve_percent() -> Weight; + fn set_total_selected() -> Weight; + fn set_collator_commission() -> Weight; + fn set_blocks_per_round() -> Weight; + fn join_candidates(x: u32, ) -> Weight; + fn schedule_leave_candidates(x: u32, ) -> Weight; + fn execute_leave_candidates(x: u32, ) -> Weight; + fn cancel_leave_candidates(x: u32, ) -> Weight; + fn go_offline() -> Weight; + fn go_online() -> Weight; + fn candidate_bond_more() -> Weight; + fn schedule_candidate_bond_less() -> Weight; + fn execute_candidate_bond_less() -> Weight; + fn cancel_candidate_bond_less() -> Weight; + fn delegate(x: u32, y: u32, ) -> Weight; + fn schedule_leave_delegators() -> Weight; + fn execute_leave_delegators(x: u32, ) -> Weight; + fn cancel_leave_delegators() -> Weight; + fn schedule_revoke_delegation() -> Weight; + fn delegator_bond_more() -> Weight; + fn schedule_delegator_bond_less() -> Weight; + fn execute_revoke_delegation() -> Weight; + fn execute_delegator_bond_less() -> Weight; + fn cancel_revoke_delegation() -> Weight; + fn cancel_delegator_bond_less() -> Weight; + fn prepare_staking_payouts() -> Weight; + fn get_rewardable_delegators(y: u32, ) -> Weight; + fn select_top_candidates(x: u32, y: u32, ) -> Weight; + fn pay_one_collator_reward(y: u32, ) -> Weight; + fn base_on_initialize() -> Weight; + fn set_auto_compound(x: u32, y: u32, ) -> Weight; + fn delegate_with_auto_compound(x: u32, y: u32, z: u32, ) -> Weight; + fn mint_collator_reward() -> Weight; +} + +/// Weights for parachain_staking using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: ParachainStaking InflationConfig (r:1 w:1) + /// Proof Skipped: ParachainStaking InflationConfig (max_values: Some(1), max_size: None, mode: Measured) + fn set_staking_expectations() -> Weight { + // Proof Size summary in bytes: + // Measured: `88` + // Estimated: `1573` + // Minimum execution time: 18_070_000 picoseconds. + Weight::from_parts(18_325_000, 1573) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: ParachainStaking InflationConfig (r:1 w:1) + /// Proof Skipped: ParachainStaking InflationConfig (max_values: Some(1), max_size: None, mode: Measured) + fn set_inflation() -> Weight { + // Proof Size summary in bytes: + // Measured: `88` + // Estimated: `1573` + // Minimum execution time: 47_600_000 picoseconds. + Weight::from_parts(48_094_000, 1573) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: ParachainStaking ParachainBondInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking ParachainBondInfo (max_values: Some(1), max_size: None, mode: Measured) + fn set_parachain_bond_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `1491` + // Minimum execution time: 15_818_000 picoseconds. + Weight::from_parts(16_256_000, 1491) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: ParachainStaking ParachainBondInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking ParachainBondInfo (max_values: Some(1), max_size: None, mode: Measured) + fn set_parachain_bond_reserve_percent() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `1491` + // Minimum execution time: 15_327_000 picoseconds. + Weight::from_parts(15_488_000, 1491) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: ParachainStaking TotalSelected (r:1 w:1) + /// Proof Skipped: ParachainStaking TotalSelected (max_values: Some(1), max_size: None, mode: Measured) + fn set_total_selected() -> Weight { + // Proof Size summary in bytes: + // Measured: `28` + // Estimated: `1513` + // Minimum execution time: 16_629_000 picoseconds. + Weight::from_parts(17_245_000, 1513) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: ParachainStaking CollatorCommission (r:1 w:1) + /// Proof Skipped: ParachainStaking CollatorCommission (max_values: Some(1), max_size: None, mode: Measured) + fn set_collator_commission() -> Weight { + // Proof Size summary in bytes: + // Measured: `27` + // Estimated: `1512` + // Minimum execution time: 15_586_000 picoseconds. + Weight::from_parts(16_060_000, 1512) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: ParachainStaking TotalSelected (r:1 w:0) + /// Proof Skipped: ParachainStaking TotalSelected (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking InflationConfig (r:1 w:1) + /// Proof Skipped: ParachainStaking InflationConfig (max_values: Some(1), max_size: None, mode: Measured) + fn set_blocks_per_round() -> Weight { + // Proof Size summary in bytes: + // Measured: `116` + // Estimated: `3202` + // Minimum execution time: 52_085_000 picoseconds. + Weight::from_parts(52_439_000, 3202) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegatorState (r:1 w:0) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:0 w:1) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking BottomDelegations (r:0 w:1) + /// Proof Skipped: ParachainStaking BottomDelegations (max_values: None, max_size: None, mode: Measured) + /// The range of component `x` is `[3, 1000]`. + fn join_candidates(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1821 + x * (37 ±0)` + // Estimated: `27743 + x * (228 ±0)` + // Minimum execution time: 62_721_000 picoseconds. + Weight::from_parts(59_951_661, 27743) + // Standard Error: 1_080 + .saturating_add(Weight::from_parts(83_856, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(Weight::from_parts(0, 228).saturating_mul(x.into())) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `x` is `[3, 1000]`. + fn schedule_leave_candidates(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `865 + x * (36 ±0)` + // Estimated: `6542 + x * (74 ±0)` + // Minimum execution time: 29_088_000 picoseconds. + Weight::from_parts(23_948_090, 6542) + // Standard Error: 1_107 + .saturating_add(Weight::from_parts(72_705, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 74).saturating_mul(x.into())) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegatorState (r:349 w:349) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:350 w:350) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: System Account (r:350 w:350) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking AutoCompoundingDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking AutoCompoundingDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking BottomDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking BottomDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `x` is `[2, 350]`. + fn execute_leave_candidates(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `979 + x * (431 ±0)` + // Estimated: `30725 + x * (11823 ±0)` + // Minimum execution time: 102_273_000 picoseconds. + Weight::from_parts(102_546_000, 30725) + // Standard Error: 76_720 + .saturating_add(Weight::from_parts(33_831_394, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().writes(5_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 11823).saturating_mul(x.into())) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `x` is `[3, 1000]`. + fn cancel_leave_candidates(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `833 + x * (36 ±0)` + // Estimated: `6478 + x * (74 ±0)` + // Minimum execution time: 28_142_000 picoseconds. + Weight::from_parts(22_767_262, 6478) + // Standard Error: 1_102 + .saturating_add(Weight::from_parts(73_806, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 74).saturating_mul(x.into())) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + fn go_offline() -> Weight { + // Proof Size summary in bytes: + // Measured: `271` + // Estimated: `5492` + // Minimum execution time: 27_523_000 picoseconds. + Weight::from_parts(27_792_000, 5492) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + fn go_online() -> Weight { + // Proof Size summary in bytes: + // Measured: `234` + // Estimated: `5418` + // Minimum execution time: 27_667_000 picoseconds. + Weight::from_parts(27_972_000, 5418) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + fn candidate_bond_more() -> Weight { + // Proof Size summary in bytes: + // Measured: `527` + // Estimated: `16349` + // Minimum execution time: 56_424_000 picoseconds. + Weight::from_parts(57_028_000, 16349) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + fn schedule_candidate_bond_less() -> Weight { + // Proof Size summary in bytes: + // Measured: `171` + // Estimated: `3636` + // Minimum execution time: 22_764_000 picoseconds. + Weight::from_parts(23_511_000, 3636) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + fn execute_candidate_bond_less() -> Weight { + // Proof Size summary in bytes: + // Measured: `547` + // Estimated: `16409` + // Minimum execution time: 55_133_000 picoseconds. + Weight::from_parts(55_704_000, 16409) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(5_u64)) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + fn cancel_candidate_bond_less() -> Weight { + // Proof Size summary in bytes: + // Measured: `191` + // Estimated: `3656` + // Minimum execution time: 20_773_000 picoseconds. + Weight::from_parts(21_485_000, 3656) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `x` is `[3, 100]`. + /// The range of component `y` is `[2, 300]`. + fn delegate(x: u32, y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `2479 + x * (79 ±0) + y * (38 ±0)` + // Estimated: `32988 + x * (405 ±0) + y * (195 ±0)` + // Minimum execution time: 94_976_000 picoseconds. + Weight::from_parts(83_764_148, 32988) + // Standard Error: 1_433 + .saturating_add(Weight::from_parts(154_670, 0).saturating_mul(x.into())) + // Standard Error: 470 + .saturating_add(Weight::from_parts(48_242, 0).saturating_mul(y.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + .saturating_add(Weight::from_parts(0, 405).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 195).saturating_mul(y.into())) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + fn schedule_leave_delegators() -> Weight { + // Proof Size summary in bytes: + // Measured: `107` + // Estimated: `7144` + // Minimum execution time: 28_255_000 picoseconds. + Weight::from_parts(28_539_000, 7144) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:99 w:99) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidateInfo (r:99 w:99) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:99 w:99) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking AutoCompoundingDelegations (r:99 w:0) + /// Proof Skipped: ParachainStaking AutoCompoundingDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// The range of component `x` is `[2, 100]`. + fn execute_leave_delegators(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `824 + x * (376 ±0)` + // Estimated: `34626 + x * (12238 ±1)` + // Minimum execution time: 88_582_000 picoseconds. + Weight::from_parts(88_972_000, 34626) + // Standard Error: 40_214 + .saturating_add(Weight::from_parts(30_393_572, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 12238).saturating_mul(x.into())) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + fn cancel_leave_delegators() -> Weight { + // Proof Size summary in bytes: + // Measured: `173` + // Estimated: `7276` + // Minimum execution time: 30_396_000 picoseconds. + Weight::from_parts(30_758_000, 7276) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + fn schedule_revoke_delegation() -> Weight { + // Proof Size summary in bytes: + // Measured: `107` + // Estimated: `7144` + // Minimum execution time: 27_434_000 picoseconds. + Weight::from_parts(27_725_000, 7144) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:0) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + fn delegator_bond_more() -> Weight { + // Proof Size summary in bytes: + // Measured: `843` + // Estimated: `30221` + // Minimum execution time: 76_944_000 picoseconds. + Weight::from_parts(77_695_000, 30221) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(7_u64)) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + fn schedule_delegator_bond_less() -> Weight { + // Proof Size summary in bytes: + // Measured: `107` + // Estimated: `7144` + // Minimum execution time: 27_633_000 picoseconds. + Weight::from_parts(27_950_000, 7144) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: ParachainStaking AutoCompoundingDelegations (r:1 w:0) + /// Proof Skipped: ParachainStaking AutoCompoundingDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + fn execute_revoke_delegation() -> Weight { + // Proof Size summary in bytes: + // Measured: `964` + // Estimated: `35376` + // Minimum execution time: 92_054_000 picoseconds. + Weight::from_parts(93_161_000, 35376) + .saturating_add(T::DbWeight::get().reads(9_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: ParachainStaking TopDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + fn execute_delegator_bond_less() -> Weight { + // Proof Size summary in bytes: + // Measured: `909` + // Estimated: `30617` + // Minimum execution time: 77_509_000 picoseconds. + Weight::from_parts(78_070_000, 30617) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + fn cancel_revoke_delegation() -> Weight { + // Proof Size summary in bytes: + // Measured: `173` + // Estimated: `7276` + // Minimum execution time: 27_469_000 picoseconds. + Weight::from_parts(28_047_000, 7276) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + fn cancel_delegator_bond_less() -> Weight { + // Proof Size summary in bytes: + // Measured: `173` + // Estimated: `7276` + // Minimum execution time: 28_572_000 picoseconds. + Weight::from_parts(28_806_000, 7276) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: ParachainStaking Points (r:1 w:0) + /// Proof Skipped: ParachainStaking Points (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking Staked (r:1 w:1) + /// Proof Skipped: ParachainStaking Staked (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking InflationConfig (r:1 w:0) + /// Proof Skipped: ParachainStaking InflationConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking ParachainBondInfo (r:1 w:0) + /// Proof Skipped: ParachainStaking ParachainBondInfo (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: ParachainStaking CollatorCommission (r:1 w:0) + /// Proof Skipped: ParachainStaking CollatorCommission (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking DelayedPayouts (r:0 w:1) + /// Proof Skipped: ParachainStaking DelayedPayouts (max_values: None, max_size: None, mode: Measured) + fn prepare_staking_payouts() -> Weight { + // Proof Size summary in bytes: + // Measured: `380` + // Estimated: `17246` + // Minimum execution time: 43_338_000 picoseconds. + Weight::from_parts(43_786_000, 17246) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:0) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:1 w:0) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// The range of component `y` is `[0, 100]`. + fn get_rewardable_delegators(y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `73 + y * (36 ±0)` + // Estimated: `7074 + y * (72 ±0)` + // Minimum execution time: 8_392_000 picoseconds. + Weight::from_parts(9_785_180, 7074) + // Standard Error: 388 + .saturating_add(Weight::from_parts(24_123, 0).saturating_mul(y.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_parts(0, 72).saturating_mul(y.into())) + } + /// Storage: ParachainStaking TotalSelected (r:1 w:0) + /// Proof Skipped: ParachainStaking TotalSelected (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:0) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidateInfo (r:51 w:0) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:51 w:0) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:51 w:0) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking AutoCompoundingDelegations (r:51 w:0) + /// Proof Skipped: ParachainStaking AutoCompoundingDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking SelectedCandidates (r:0 w:1) + /// Proof Skipped: ParachainStaking SelectedCandidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking AtStake (r:0 w:51) + /// Proof Skipped: ParachainStaking AtStake (max_values: None, max_size: None, mode: Measured) + /// The range of component `x` is `[0, 50]`. + /// The range of component `y` is `[0, 100]`. + fn select_top_candidates(x: u32, y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + x * (3816 ±0) + y * (1800 ±0)` + // Estimated: `18950 + x * (21900 ±39) + y * (5112 ±19)` + // Minimum execution time: 32_303_000 picoseconds. + Weight::from_parts(32_680_000, 18950) + // Standard Error: 82_316 + .saturating_add(Weight::from_parts(23_158_353, 0).saturating_mul(x.into())) + // Standard Error: 41_048 + .saturating_add(Weight::from_parts(1_334_029, 0).saturating_mul(y.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(x.into()))) + .saturating_add(T::DbWeight::get().writes(2_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 21900).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 5112).saturating_mul(y.into())) + } + /// Storage: ParachainStaking DelayedPayouts (r:1 w:0) + /// Proof Skipped: ParachainStaking DelayedPayouts (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking Points (r:1 w:0) + /// Proof Skipped: ParachainStaking Points (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking AtStake (r:2 w:1) + /// Proof Skipped: ParachainStaking AtStake (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking AwardedPts (r:1 w:1) + /// Proof Skipped: ParachainStaking AwardedPts (max_values: None, max_size: None, mode: Measured) + /// Storage: MoonbeamOrbiters OrbiterPerRound (r:1 w:0) + /// Proof Skipped: MoonbeamOrbiters OrbiterPerRound (max_values: None, max_size: None, mode: Measured) + /// Storage: System Account (r:301 w:301) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// The range of component `y` is `[0, 300]`. + fn pay_one_collator_reward(y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1132 + y * (160 ±0)` + // Estimated: `28331 + y * (3396 ±0)` + // Minimum execution time: 58_105_000 picoseconds. + Weight::from_parts(53_052_308, 28331) + // Standard Error: 6_526 + .saturating_add(Weight::from_parts(19_017_961, 0).saturating_mul(y.into())) + .saturating_add(T::DbWeight::get().reads(7_u64)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(y.into()))) + .saturating_add(T::DbWeight::get().writes(3_u64)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(y.into()))) + .saturating_add(Weight::from_parts(0, 3396).saturating_mul(y.into())) + } + fn base_on_initialize() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_008_000 picoseconds. + Weight::from_parts(2_065_000, 0) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:0) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking AutoCompoundingDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking AutoCompoundingDelegations (max_values: None, max_size: None, mode: Measured) + /// The range of component `x` is `[0, 300]`. + /// The range of component `y` is `[0, 100]`. + fn set_auto_compound(x: u32, y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `671 + x * (22 ±0) + y * (36 ±0)` + // Estimated: `8054 + x * (46 ±0) + y * (72 ±0)` + // Minimum execution time: 29_102_000 picoseconds. + Weight::from_parts(26_155_259, 8054) + // Standard Error: 278 + .saturating_add(Weight::from_parts(49_717, 0).saturating_mul(x.into())) + // Standard Error: 833 + .saturating_add(Weight::from_parts(48_123, 0).saturating_mul(y.into())) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_parts(0, 46).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 72).saturating_mul(y.into())) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking AutoCompoundingDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking AutoCompoundingDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking BottomDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking BottomDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `x` is `[0, 350]`. + /// The range of component `y` is `[0, 350]`. + /// The range of component `z` is `[0, 100]`. + fn delegate_with_auto_compound(x: u32, y: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + x * (58 ±0) + y * (21 ±0) + z * (41 ±0)` + // Estimated: `59323 + x * (145 ±0) + y * (132 ±0) + z * (873144491150315 ±3)` + // Minimum execution time: 100_647_000 picoseconds. + Weight::from_parts(84_809_337, 59323) + // Standard Error: 1_211 + .saturating_add(Weight::from_parts(15_186, 0).saturating_mul(x.into())) + // Standard Error: 1_211 + .saturating_add(Weight::from_parts(30_270, 0).saturating_mul(y.into())) + // Standard Error: 4_227 + .saturating_add(Weight::from_parts(173_069, 0).saturating_mul(z.into())) + .saturating_add(T::DbWeight::get().reads(8_u64)) + .saturating_add(T::DbWeight::get().writes(8_u64)) + .saturating_add(Weight::from_parts(0, 145).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 132).saturating_mul(y.into())) + .saturating_add(Weight::from_parts(0, 307).saturating_mul(z.into())) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + fn mint_collator_reward() -> Weight { + // Proof Size summary in bytes: + // Measured: `128` + // Estimated: `3581` + // Minimum execution time: 24_224_000 picoseconds. + Weight::from_parts(24_514_000, 3581) + .saturating_add(T::DbWeight::get().reads(1_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: ParachainStaking InflationConfig (r:1 w:1) + /// Proof Skipped: ParachainStaking InflationConfig (max_values: Some(1), max_size: None, mode: Measured) + fn set_staking_expectations() -> Weight { + // Proof Size summary in bytes: + // Measured: `88` + // Estimated: `1573` + // Minimum execution time: 18_070_000 picoseconds. + Weight::from_parts(18_325_000, 1573) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: ParachainStaking InflationConfig (r:1 w:1) + /// Proof Skipped: ParachainStaking InflationConfig (max_values: Some(1), max_size: None, mode: Measured) + fn set_inflation() -> Weight { + // Proof Size summary in bytes: + // Measured: `88` + // Estimated: `1573` + // Minimum execution time: 47_600_000 picoseconds. + Weight::from_parts(48_094_000, 1573) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: ParachainStaking ParachainBondInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking ParachainBondInfo (max_values: Some(1), max_size: None, mode: Measured) + fn set_parachain_bond_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `1491` + // Minimum execution time: 15_818_000 picoseconds. + Weight::from_parts(16_256_000, 1491) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: ParachainStaking ParachainBondInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking ParachainBondInfo (max_values: Some(1), max_size: None, mode: Measured) + fn set_parachain_bond_reserve_percent() -> Weight { + // Proof Size summary in bytes: + // Measured: `6` + // Estimated: `1491` + // Minimum execution time: 15_327_000 picoseconds. + Weight::from_parts(15_488_000, 1491) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: ParachainStaking TotalSelected (r:1 w:1) + /// Proof Skipped: ParachainStaking TotalSelected (max_values: Some(1), max_size: None, mode: Measured) + fn set_total_selected() -> Weight { + // Proof Size summary in bytes: + // Measured: `28` + // Estimated: `1513` + // Minimum execution time: 16_629_000 picoseconds. + Weight::from_parts(17_245_000, 1513) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: ParachainStaking CollatorCommission (r:1 w:1) + /// Proof Skipped: ParachainStaking CollatorCommission (max_values: Some(1), max_size: None, mode: Measured) + fn set_collator_commission() -> Weight { + // Proof Size summary in bytes: + // Measured: `27` + // Estimated: `1512` + // Minimum execution time: 15_586_000 picoseconds. + Weight::from_parts(16_060_000, 1512) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: ParachainStaking TotalSelected (r:1 w:0) + /// Proof Skipped: ParachainStaking TotalSelected (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking InflationConfig (r:1 w:1) + /// Proof Skipped: ParachainStaking InflationConfig (max_values: Some(1), max_size: None, mode: Measured) + fn set_blocks_per_round() -> Weight { + // Proof Size summary in bytes: + // Measured: `116` + // Estimated: `3202` + // Minimum execution time: 52_085_000 picoseconds. + Weight::from_parts(52_439_000, 3202) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegatorState (r:1 w:0) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:0 w:1) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking BottomDelegations (r:0 w:1) + /// Proof Skipped: ParachainStaking BottomDelegations (max_values: None, max_size: None, mode: Measured) + /// The range of component `x` is `[3, 1000]`. + fn join_candidates(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1821 + x * (37 ±0)` + // Estimated: `27743 + x * (228 ±0)` + // Minimum execution time: 62_721_000 picoseconds. + Weight::from_parts(59_951_661, 27743) + // Standard Error: 1_080 + .saturating_add(Weight::from_parts(83_856, 0).saturating_mul(x.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(Weight::from_parts(0, 228).saturating_mul(x.into())) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `x` is `[3, 1000]`. + fn schedule_leave_candidates(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `865 + x * (36 ±0)` + // Estimated: `6542 + x * (74 ±0)` + // Minimum execution time: 29_088_000 picoseconds. + Weight::from_parts(23_948_090, 6542) + // Standard Error: 1_107 + .saturating_add(Weight::from_parts(72_705, 0).saturating_mul(x.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 74).saturating_mul(x.into())) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegatorState (r:349 w:349) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:350 w:350) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: System Account (r:350 w:350) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking AutoCompoundingDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking AutoCompoundingDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking BottomDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking BottomDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `x` is `[2, 350]`. + fn execute_leave_candidates(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `979 + x * (431 ±0)` + // Estimated: `30725 + x * (11823 ±0)` + // Minimum execution time: 102_273_000 picoseconds. + Weight::from_parts(102_546_000, 30725) + // Standard Error: 76_720 + .saturating_add(Weight::from_parts(33_831_394, 0).saturating_mul(x.into())) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().reads((3_u64).saturating_mul(x.into()))) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 11823).saturating_mul(x.into())) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `x` is `[3, 1000]`. + fn cancel_leave_candidates(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `833 + x * (36 ±0)` + // Estimated: `6478 + x * (74 ±0)` + // Minimum execution time: 28_142_000 picoseconds. + Weight::from_parts(22_767_262, 6478) + // Standard Error: 1_102 + .saturating_add(Weight::from_parts(73_806, 0).saturating_mul(x.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(Weight::from_parts(0, 74).saturating_mul(x.into())) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + fn go_offline() -> Weight { + // Proof Size summary in bytes: + // Measured: `271` + // Estimated: `5492` + // Minimum execution time: 27_523_000 picoseconds. + Weight::from_parts(27_792_000, 5492) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + fn go_online() -> Weight { + // Proof Size summary in bytes: + // Measured: `234` + // Estimated: `5418` + // Minimum execution time: 27_667_000 picoseconds. + Weight::from_parts(27_972_000, 5418) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + fn candidate_bond_more() -> Weight { + // Proof Size summary in bytes: + // Measured: `527` + // Estimated: `16349` + // Minimum execution time: 56_424_000 picoseconds. + Weight::from_parts(57_028_000, 16349) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + fn schedule_candidate_bond_less() -> Weight { + // Proof Size summary in bytes: + // Measured: `171` + // Estimated: `3636` + // Minimum execution time: 22_764_000 picoseconds. + Weight::from_parts(23_511_000, 3636) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + fn execute_candidate_bond_less() -> Weight { + // Proof Size summary in bytes: + // Measured: `547` + // Estimated: `16409` + // Minimum execution time: 55_133_000 picoseconds. + Weight::from_parts(55_704_000, 16409) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(5_u64)) + } + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + fn cancel_candidate_bond_less() -> Weight { + // Proof Size summary in bytes: + // Measured: `191` + // Estimated: `3656` + // Minimum execution time: 20_773_000 picoseconds. + Weight::from_parts(21_485_000, 3656) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `x` is `[3, 100]`. + /// The range of component `y` is `[2, 300]`. + fn delegate(x: u32, y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `2479 + x * (79 ±0) + y * (38 ±0)` + // Estimated: `32988 + x * (405 ±0) + y * (195 ±0)` + // Minimum execution time: 94_976_000 picoseconds. + Weight::from_parts(83_764_148, 32988) + // Standard Error: 1_433 + .saturating_add(Weight::from_parts(154_670, 0).saturating_mul(x.into())) + // Standard Error: 470 + .saturating_add(Weight::from_parts(48_242, 0).saturating_mul(y.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) + .saturating_add(Weight::from_parts(0, 405).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 195).saturating_mul(y.into())) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + fn schedule_leave_delegators() -> Weight { + // Proof Size summary in bytes: + // Measured: `107` + // Estimated: `7144` + // Minimum execution time: 28_255_000 picoseconds. + Weight::from_parts(28_539_000, 7144) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:99 w:99) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidateInfo (r:99 w:99) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:99 w:99) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking AutoCompoundingDelegations (r:99 w:0) + /// Proof Skipped: ParachainStaking AutoCompoundingDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// The range of component `x` is `[2, 100]`. + fn execute_leave_delegators(x: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `824 + x * (376 ±0)` + // Estimated: `34626 + x * (12238 ±1)` + // Minimum execution time: 88_582_000 picoseconds. + Weight::from_parts(88_972_000, 34626) + // Standard Error: 40_214 + .saturating_add(Weight::from_parts(30_393_572, 0).saturating_mul(x.into())) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(x.into()))) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 12238).saturating_mul(x.into())) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + fn cancel_leave_delegators() -> Weight { + // Proof Size summary in bytes: + // Measured: `173` + // Estimated: `7276` + // Minimum execution time: 30_396_000 picoseconds. + Weight::from_parts(30_758_000, 7276) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + fn schedule_revoke_delegation() -> Weight { + // Proof Size summary in bytes: + // Measured: `107` + // Estimated: `7144` + // Minimum execution time: 27_434_000 picoseconds. + Weight::from_parts(27_725_000, 7144) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:0) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + fn delegator_bond_more() -> Weight { + // Proof Size summary in bytes: + // Measured: `843` + // Estimated: `30221` + // Minimum execution time: 76_944_000 picoseconds. + Weight::from_parts(77_695_000, 30221) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(7_u64)) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + fn schedule_delegator_bond_less() -> Weight { + // Proof Size summary in bytes: + // Measured: `107` + // Estimated: `7144` + // Minimum execution time: 27_633_000 picoseconds. + Weight::from_parts(27_950_000, 7144) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: ParachainStaking AutoCompoundingDelegations (r:1 w:0) + /// Proof Skipped: ParachainStaking AutoCompoundingDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + fn execute_revoke_delegation() -> Weight { + // Proof Size summary in bytes: + // Measured: `964` + // Estimated: `35376` + // Minimum execution time: 92_054_000 picoseconds. + Weight::from_parts(93_161_000, 35376) + .saturating_add(RocksDbWeight::get().reads(9_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: ParachainStaking TopDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + fn execute_delegator_bond_less() -> Weight { + // Proof Size summary in bytes: + // Measured: `909` + // Estimated: `30617` + // Minimum execution time: 77_509_000 picoseconds. + Weight::from_parts(78_070_000, 30617) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + fn cancel_revoke_delegation() -> Weight { + // Proof Size summary in bytes: + // Measured: `173` + // Estimated: `7276` + // Minimum execution time: 27_469_000 picoseconds. + Weight::from_parts(28_047_000, 7276) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + fn cancel_delegator_bond_less() -> Weight { + // Proof Size summary in bytes: + // Measured: `173` + // Estimated: `7276` + // Minimum execution time: 28_572_000 picoseconds. + Weight::from_parts(28_806_000, 7276) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: ParachainStaking Points (r:1 w:0) + /// Proof Skipped: ParachainStaking Points (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking Staked (r:1 w:1) + /// Proof Skipped: ParachainStaking Staked (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking InflationConfig (r:1 w:0) + /// Proof Skipped: ParachainStaking InflationConfig (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking ParachainBondInfo (r:1 w:0) + /// Proof Skipped: ParachainStaking ParachainBondInfo (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: ParachainStaking CollatorCommission (r:1 w:0) + /// Proof Skipped: ParachainStaking CollatorCommission (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking DelayedPayouts (r:0 w:1) + /// Proof Skipped: ParachainStaking DelayedPayouts (max_values: None, max_size: None, mode: Measured) + fn prepare_staking_payouts() -> Weight { + // Proof Size summary in bytes: + // Measured: `380` + // Estimated: `17246` + // Minimum execution time: 43_338_000 picoseconds. + Weight::from_parts(43_786_000, 17246) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: ParachainStaking DelegationScheduledRequests (r:1 w:0) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:1 w:0) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// The range of component `y` is `[0, 100]`. + fn get_rewardable_delegators(y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `73 + y * (36 ±0)` + // Estimated: `7074 + y * (72 ±0)` + // Minimum execution time: 8_392_000 picoseconds. + Weight::from_parts(9_785_180, 7074) + // Standard Error: 388 + .saturating_add(Weight::from_parts(24_123, 0).saturating_mul(y.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(Weight::from_parts(0, 72).saturating_mul(y.into())) + } + /// Storage: ParachainStaking TotalSelected (r:1 w:0) + /// Proof Skipped: ParachainStaking TotalSelected (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:0) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidateInfo (r:51 w:0) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking DelegationScheduledRequests (r:51 w:0) + /// Proof Skipped: ParachainStaking DelegationScheduledRequests (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:51 w:0) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking AutoCompoundingDelegations (r:51 w:0) + /// Proof Skipped: ParachainStaking AutoCompoundingDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking SelectedCandidates (r:0 w:1) + /// Proof Skipped: ParachainStaking SelectedCandidates (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking AtStake (r:0 w:51) + /// Proof Skipped: ParachainStaking AtStake (max_values: None, max_size: None, mode: Measured) + /// The range of component `x` is `[0, 50]`. + /// The range of component `y` is `[0, 100]`. + fn select_top_candidates(x: u32, y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + x * (3816 ±0) + y * (1800 ±0)` + // Estimated: `18950 + x * (21900 ±39) + y * (5112 ±19)` + // Minimum execution time: 32_303_000 picoseconds. + Weight::from_parts(32_680_000, 18950) + // Standard Error: 82_316 + .saturating_add(Weight::from_parts(23_158_353, 0).saturating_mul(x.into())) + // Standard Error: 41_048 + .saturating_add(Weight::from_parts(1_334_029, 0).saturating_mul(y.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(x.into()))) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(x.into()))) + .saturating_add(Weight::from_parts(0, 21900).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 5112).saturating_mul(y.into())) + } + /// Storage: ParachainStaking DelayedPayouts (r:1 w:0) + /// Proof Skipped: ParachainStaking DelayedPayouts (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking Points (r:1 w:0) + /// Proof Skipped: ParachainStaking Points (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking AtStake (r:2 w:1) + /// Proof Skipped: ParachainStaking AtStake (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking AwardedPts (r:1 w:1) + /// Proof Skipped: ParachainStaking AwardedPts (max_values: None, max_size: None, mode: Measured) + /// Storage: MoonbeamOrbiters OrbiterPerRound (r:1 w:0) + /// Proof Skipped: MoonbeamOrbiters OrbiterPerRound (max_values: None, max_size: None, mode: Measured) + /// Storage: System Account (r:301 w:301) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// The range of component `y` is `[0, 300]`. + fn pay_one_collator_reward(y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1132 + y * (160 ±0)` + // Estimated: `28331 + y * (3396 ±0)` + // Minimum execution time: 58_105_000 picoseconds. + Weight::from_parts(53_052_308, 28331) + // Standard Error: 6_526 + .saturating_add(Weight::from_parts(19_017_961, 0).saturating_mul(y.into())) + .saturating_add(RocksDbWeight::get().reads(7_u64)) + .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(y.into()))) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + .saturating_add(RocksDbWeight::get().writes((1_u64).saturating_mul(y.into()))) + .saturating_add(Weight::from_parts(0, 3396).saturating_mul(y.into())) + } + fn base_on_initialize() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_008_000 picoseconds. + Weight::from_parts(2_065_000, 0) + } + /// Storage: ParachainStaking DelegatorState (r:1 w:0) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking AutoCompoundingDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking AutoCompoundingDelegations (max_values: None, max_size: None, mode: Measured) + /// The range of component `x` is `[0, 300]`. + /// The range of component `y` is `[0, 100]`. + fn set_auto_compound(x: u32, y: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `671 + x * (22 ±0) + y * (36 ±0)` + // Estimated: `8054 + x * (46 ±0) + y * (72 ±0)` + // Minimum execution time: 29_102_000 picoseconds. + Weight::from_parts(26_155_259, 8054) + // Standard Error: 278 + .saturating_add(Weight::from_parts(49_717, 0).saturating_mul(x.into())) + // Standard Error: 833 + .saturating_add(Weight::from_parts(48_123, 0).saturating_mul(y.into())) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(Weight::from_parts(0, 46).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 72).saturating_mul(y.into())) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + /// Storage: ParachainStaking DelegatorState (r:1 w:1) + /// Proof Skipped: ParachainStaking DelegatorState (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidateInfo (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidateInfo (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking AutoCompoundingDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking AutoCompoundingDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking BottomDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking BottomDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1287), added: 3762, mode: MaxEncodedLen) + /// Storage: ParachainStaking Total (r:1 w:1) + /// Proof Skipped: ParachainStaking Total (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: ParachainStaking TopDelegations (r:1 w:1) + /// Proof Skipped: ParachainStaking TopDelegations (max_values: None, max_size: None, mode: Measured) + /// Storage: ParachainStaking CandidatePool (r:1 w:1) + /// Proof Skipped: ParachainStaking CandidatePool (max_values: Some(1), max_size: None, mode: Measured) + /// The range of component `x` is `[0, 350]`. + /// The range of component `y` is `[0, 350]`. + /// The range of component `z` is `[0, 100]`. + fn delegate_with_auto_compound(x: u32, y: u32, z: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + x * (58 ±0) + y * (21 ±0) + z * (41 ±0)` + // Estimated: `59323 + x * (145 ±0) + y * (132 ±0) + z * (873144491150315 ±3)` + // Minimum execution time: 100_647_000 picoseconds. + Weight::from_parts(84_809_337, 59323) + // Standard Error: 1_211 + .saturating_add(Weight::from_parts(15_186, 0).saturating_mul(x.into())) + // Standard Error: 1_211 + .saturating_add(Weight::from_parts(30_270, 0).saturating_mul(y.into())) + // Standard Error: 4_227 + .saturating_add(Weight::from_parts(173_069, 0).saturating_mul(z.into())) + .saturating_add(RocksDbWeight::get().reads(8_u64)) + .saturating_add(RocksDbWeight::get().writes(8_u64)) + .saturating_add(Weight::from_parts(0, 145).saturating_mul(x.into())) + .saturating_add(Weight::from_parts(0, 132).saturating_mul(y.into())) + .saturating_add(Weight::from_parts(0, 307).saturating_mul(z.into())) + } + /// Storage: System Account (r:1 w:1) + /// Proof: System Account (max_values: None, max_size: Some(116), added: 2591, mode: MaxEncodedLen) + fn mint_collator_reward() -> Weight { + // Proof Size summary in bytes: + // Measured: `128` + // Estimated: `3581` + // Minimum execution time: 24_224_000 picoseconds. + Weight::from_parts(24_514_000, 3581) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} \ No newline at end of file diff --git a/pallets/sandbox/Cargo.toml b/pallets/sandbox/Cargo.toml index 7fd58da17..a0cc28996 100644 --- a/pallets/sandbox/Cargo.toml +++ b/pallets/sandbox/Cargo.toml @@ -23,7 +23,6 @@ frame-system.workspace = true sp-std.workspace = true sp-runtime.workspace = true sp-arithmetic.workspace = true -polimec-traits.workspace = true parachains-common.workspace = true pallet-funding.workspace = true @@ -40,7 +39,6 @@ sp-runtime.workspace = true pallet-balances.workspace = true pallet-insecure-randomness-collective-flip.workspace = true pallet-assets.workspace = true -pallet-credentials.workspace = true [features] @@ -58,8 +56,6 @@ std = [ "sp-runtime/std", "pallet-assets/std", "pallet-balances/std", - "pallet-credentials/std", - "polimec-traits/std", "frame-benchmarking?/std", "parachains-common/std", ] diff --git a/pallets/sandbox/src/lib.rs b/pallets/sandbox/src/lib.rs index 97ec6cbff..202b411d4 100644 --- a/pallets/sandbox/src/lib.rs +++ b/pallets/sandbox/src/lib.rs @@ -27,7 +27,8 @@ pub mod pallet { /// Buy tokens for a project in the community round if it achieved at least 500k USDT funding #[pallet::weight(0)] pub fn buy_if_popular( - origin: OriginFor, project_id: ::ProjectIdParameter, + origin: OriginFor, + project_id: ::ProjectIdParameter, amount: ::Balance, ) -> DispatchResult { let retail_user = ensure_signed(origin)?; diff --git a/pallets/sandbox/src/mock.rs b/pallets/sandbox/src/mock.rs index b1dacf3bf..b94682855 100644 --- a/pallets/sandbox/src/mock.rs +++ b/pallets/sandbox/src/mock.rs @@ -50,7 +50,6 @@ frame_support::construct_runtime!( Assets: pallet_assets, Balances: pallet_balances, FundingModule: pallet_funding, - Credentials: pallet_credentials, Sandbox: crate, } ); @@ -62,30 +61,30 @@ parameter_types! { } impl system::Config for TestRuntime { + type AccountData = pallet_balances::AccountData; + type AccountId = AccountId; type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); + type BlockHashCount = BlockHashCount; type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Index = u64; type BlockNumber = BlockNumber; + type BlockWeights = (); + type DbWeight = (); type Hash = H256; type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; type Header = Header; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); + type Index = u64; + type Lookup = IdentityLookup; + type MaxConsumers = frame_support::traits::ConstU32<16>; type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = ConstU16<42>; + type OnNewAccount = (); type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + type PalletInfo = PalletInfo; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type SS58Prefix = ConstU16<42>; + type SystemWeightInfo = (); + type Version = (); } parameter_types! { @@ -93,51 +92,44 @@ parameter_types! { } impl pallet_balances::Config for TestRuntime { + type AccountStore = System; + type Balance = Balance; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type FreezeIdentifier = pallet_funding::BondType; + type HoldIdentifier = pallet_funding::BondType; + type MaxFreezes = (); + type MaxHolds = (); type MaxLocks = frame_support::traits::ConstU32<1024>; type MaxReserves = frame_support::traits::ConstU32<1024>; type ReserveIdentifier = pallet_funding::BondType; - type Balance = Balance; type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; type WeightInfo = (); } impl pallet_insecure_randomness_collective_flip::Config for TestRuntime {} -impl pallet_credentials::Config for TestRuntime { - type RuntimeEvent = RuntimeEvent; - type AddOrigin = EnsureSigned; - type RemoveOrigin = EnsureSigned; - type SwapOrigin = EnsureSigned; - type ResetOrigin = EnsureSigned; - type PrimeOrigin = EnsureSigned; - type MembershipInitialized = (); - type MembershipChanged = (); -} - impl pallet_assets::Config for TestRuntime { - type RuntimeEvent = RuntimeEvent; - type Balance = Balance; + type ApprovalDeposit = ConstU128<1>; + type AssetAccountDeposit = ConstU128<10>; + type AssetDeposit = ConstU128<1>; type AssetId = Identifier; + type AssetIdParameter = Identifier; + type Balance = Balance; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); + type CallbackHandle = (); + type CreateOrigin = AsEnsureOriginWithArg>; type Currency = Balances; + type Extra = (); type ForceOrigin = frame_system::EnsureRoot; - type AssetDeposit = ConstU128<1>; - type AssetAccountDeposit = ConstU128<10>; + type Freezer = (); type MetadataDepositBase = ConstU128<1>; type MetadataDepositPerByte = ConstU128<1>; - type ApprovalDeposit = ConstU128<1>; + type RemoveItemsLimit = frame_support::traits::ConstU32<1000>; + type RuntimeEvent = RuntimeEvent; type StringLimit = ConstU32<50>; - type Freezer = (); type WeightInfo = (); - type Extra = (); - type AssetIdParameter = Identifier; - type CreateOrigin = AsEnsureOriginWithArg>; - type CallbackHandle = (); - type RemoveItemsLimit = frame_support::traits::ConstU32<1000>; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); } // REMARK: In the production configuration we use DAYS instead of HOURS. @@ -152,56 +144,44 @@ parameter_types! { } impl pallet_funding::Config for TestRuntime { - type RuntimeEvent = RuntimeEvent; - type StringLimit = ConstU32<64>; - type ProjectIdentifier = Identifier; - type ProjectIdParameter = Identifier; + type AuctionInitializePeriodDuration = AuctionInitializePeriodDuration; + type Balance = Balance; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); type BidId = u128; + type CandleAuctionDuration = CandleAuctionDuration; + type CommunityFundingDuration = CommunityRoundDuration; type ContributionTokenCurrency = Assets; - type EvaluationDuration = EvaluationDuration; - type AuctionInitializePeriodDuration = AuctionInitializePeriodDuration; + type ContributionVesting = ConstU32<4>; type EnglishAuctionDuration = EnglishAuctionDuration; - type CandleAuctionDuration = CandleAuctionDuration; - type RemainderFundingDuration = RemainderFundingDuration; - type PalletId = FundingPalletId; + type EvaluationDuration = EvaluationDuration; + type FundingCurrency = Balances; + type MaxContributionsPerUser = ConstU32<4>; type MaxProjectsToUpdatePerBlock = ConstU32<100>; - type CommunityFundingDuration = CommunityRoundDuration; - type Randomness = RandomnessCollectiveFlip; - type HandleMembers = Credentials; - type PreImageLimit = ConstU32<1024>; // Low value to simplify the tests type MaximumBidsPerUser = ConstU32<4>; - type MaxContributionsPerUser = ConstU32<4>; - type ContributionVesting = ConstU32<4>; - type WeightInfo = (); - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); type Multiplier = pallet_funding::types::Multiplier; - type Balance = Balance; type NativeCurrency = Balances; - type FundingCurrency = Balances; + type PalletId = FundingPalletId; + type PreImageLimit = ConstU32<1024>; + type ProjectIdParameter = Identifier; + type ProjectIdentifier = Identifier; + type Randomness = RandomnessCollectiveFlip; + type RemainderFundingDuration = RemainderFundingDuration; + type RuntimeEvent = RuntimeEvent; + type StringLimit = ConstU32<64>; + type WeightInfo = (); } // Build genesis storage according to the mock runtime. // TODO: PLMC-161. Add some mocks projects at Genesis to simplify the tests #[allow(dead_code)] pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - GenesisConfig { - balances: BalancesConfig { balances: vec![] }, - credentials: CredentialsConfig { - issuers: vec![1, 16558220937623665250], - retails: vec![2], - professionals: vec![2, 3], - institutionals: vec![4], - }, - ..Default::default() - } - .assimilate_storage(&mut t) - .unwrap(); + GenesisConfig { balances: BalancesConfig { balances: vec![] }, ..Default::default() } + .assimilate_storage(&mut t) + .unwrap(); let mut ext = sp_io::TestExternalities::new(t); // In order to emit events the block number must be more than 0 diff --git a/pallets/sandbox/src/tests.rs b/pallets/sandbox/src/tests.rs index 71fdc3562..8545884e9 100644 --- a/pallets/sandbox/src/tests.rs +++ b/pallets/sandbox/src/tests.rs @@ -19,11 +19,7 @@ fn test_buy_if_popular() { let project = default_project(0); assert_ok!(FundingModule::create(RuntimeOrigin::signed(creator), project.clone(),)); assert_ok!(FundingModule::start_evaluation(RuntimeOrigin::signed(creator), 0)); - assert_ok!(FundingModule::bond_evaluation( - RuntimeOrigin::signed(evaluator), - 0, - 120_000 * PLMC - )); + assert_ok!(FundingModule::bond_evaluation(RuntimeOrigin::signed(evaluator), 0, 120_000 * PLMC)); // advance time for _block in 0..::EvaluationDuration::get() + 10 { @@ -43,18 +39,12 @@ fn test_buy_if_popular() { >::on_initialize(System::block_number()); } - assert_ok!(FundingModule::bid( - RuntimeOrigin::signed(bidder), - 0, - 1000, - 100 * PLMC, - None - )); + assert_ok!(FundingModule::bid(RuntimeOrigin::signed(bidder), 0, 1000, 100 * PLMC, None)); // advance time - for _block in 0..(::EnglishAuctionDuration::get() - + ::CandleAuctionDuration::get() - + 5) + for _block in 0..(::EnglishAuctionDuration::get() + + ::CandleAuctionDuration::get() + + 5) { >::on_finalize(System::block_number()); >::on_idle(System::block_number(), Weight::MAX); @@ -62,21 +52,11 @@ fn test_buy_if_popular() { >::on_initialize(System::block_number()); } - assert_ok!(FundingModule::contribute( - RuntimeOrigin::signed(contributor), - 0, - 1, - None - )); + assert_ok!(FundingModule::contribute(RuntimeOrigin::signed(contributor), 0, 1, None)); assert!(Sandbox::buy_if_popular(RuntimeOrigin::signed(4), 0, 1000).is_err()); - assert_ok!(FundingModule::contribute( - RuntimeOrigin::signed(contributor), - 0, - 10000, - None - )); + assert_ok!(FundingModule::contribute(RuntimeOrigin::signed(contributor), 0, 10000, None)); assert_ok!(Sandbox::buy_if_popular(RuntimeOrigin::signed(4), 0, 1000)); }); @@ -99,45 +79,22 @@ pub fn default_project(nonce: u64) -> ProjectMetadata sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::default() - .build_storage::() - .unwrap(); + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); GenesisConfig { balances: BalancesConfig { - balances: vec![ - (1, 1_000_000 * PLMC), - (2, 1_000_000 * PLMC), - (3, 1_000_000 * PLMC), - (4, 10_000_000 * PLMC), - ], - }, - credentials: CredentialsConfig { - issuers: vec![1, 16558220937623665250], - retails: vec![2], - professionals: vec![2, 3], - institutionals: vec![4], + balances: vec![(1, 1_000_000 * PLMC), (2, 1_000_000 * PLMC), (3, 1_000_000 * PLMC), (4, 10_000_000 * PLMC)], }, ..Default::default() } diff --git a/polimec-skeleton/pallets/funding/src/mock.rs b/polimec-skeleton/pallets/funding/src/mock.rs index adb149460..23ebb3b7e 100644 --- a/polimec-skeleton/pallets/funding/src/mock.rs +++ b/polimec-skeleton/pallets/funding/src/mock.rs @@ -86,7 +86,6 @@ parameter_types! { // https://github.com/paritytech/substrate/blob/069917b/frame/assets/src/lib.rs#L257L271 pub const MetadataDepositBase: Balance = free_deposit(); pub const MetadataDepositPerByte: Balance = free_deposit(); - pub const AssetsPalletId: PalletId = PalletId(*b"assetsid"); pub const ApprovalDeposit: Balance = EXISTENTIAL_DEPOSIT; } diff --git a/primitives/xcm/Cargo.toml b/primitives/xcm/Cargo.toml deleted file mode 100644 index ab131c9e8..000000000 --- a/primitives/xcm/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "xcm-primitives" -version = "0.0.1" -edition = "2021" - -[dependencies] -sp-std.workspace = true - -xcm.workspace = true -xcm-executor.workspace = true - -[features] -default = [ "std" ] -std = [ - "sp-std/std", - "xcm/std", - "xcm-executor/std" -] diff --git a/primitives/xcm/src/lib.rs b/primitives/xcm/src/lib.rs deleted file mode 100644 index e653cdc4d..000000000 --- a/primitives/xcm/src/lib.rs +++ /dev/null @@ -1,63 +0,0 @@ -// Polimec Blockchain – https://www.polimec.org/ -// Copyright (C) Polimec 2022. All rights reserved. - -// The Polimec Blockchain 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. - -// The Polimec Blockchain 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 . - -#![cfg_attr(not(feature = "std"), no_std)] - -use sp_std::{borrow::Borrow, marker::PhantomData}; -use xcm::latest::{AssetId::Concrete, Fungibility::Fungible, MultiAsset, MultiLocation}; -use xcm_executor::traits::{Convert, Error as MatchError, MatchesFungibles}; - -pub struct AsAssetMultiLocation(PhantomData<(AssetId, AssetIdInfoGetter)>); -impl xcm_executor::traits::Convert - for AsAssetMultiLocation -where - AssetId: Clone, - AssetIdInfoGetter: AssetMultiLocationGetter, -{ - fn convert_ref(asset_multi_location: impl Borrow) -> Result { - AssetIdInfoGetter::get_asset_id(asset_multi_location.borrow().clone()).ok_or(()) - } - - fn reverse_ref(asset_id: impl Borrow) -> Result { - AssetIdInfoGetter::get_asset_multi_location(asset_id.borrow().clone()).ok_or(()) - } -} - -pub trait AssetMultiLocationGetter { - fn get_asset_multi_location(asset_id: AssetId) -> Option; - fn get_asset_id(asset_multi_location: MultiLocation) -> Option; -} - -pub struct ConvertedRegisteredAssetId( - PhantomData<(AssetId, Balance, ConvertAssetId, ConvertBalance)>, -); -impl< - AssetId: Clone, - Balance: Clone, - ConvertAssetId: Convert, - ConvertBalance: Convert, - > MatchesFungibles for ConvertedRegisteredAssetId -{ - fn matches_fungibles(a: &MultiAsset) -> Result<(AssetId, Balance), MatchError> { - let (amount, id) = match (&a.fun, &a.id) { - (Fungible(ref amount), Concrete(ref id)) => (amount, id), - _ => return Err(MatchError::AssetNotFound), - }; - let what = ConvertAssetId::convert_ref(id).map_err(|_| MatchError::AssetNotFound)?; - let amount = ConvertBalance::convert_ref(amount).map_err(|_| MatchError::AmountToBalanceConversionFailed)?; - Ok((what, amount)) - } -} diff --git a/runtime-api/credentials/Cargo.toml b/runtime-api/credentials/Cargo.toml deleted file mode 100644 index 6874844cf..000000000 --- a/runtime-api/credentials/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -name = 'polimec-runtime-api-credentials' -description = "Runtime APIs for dealing with credentials and membership." -authors.workspace = true -documentation.workspace = true -edition.workspace = true -homepage.workspace = true -license-file.workspace = true -readme.workspace = true -repository.workspace = true -version.workspace = true - - -[dependencies] -parity-scale-codec = { workspace = true, features = [ - "derive", -] } -scale-info = { workspace = true, features = ["derive"] } - -sp-runtime.workspace = true -sp-api.workspace = true -sp-std.workspace = true -polimec-traits.workspace = true - - -[features] -default = ["std"] -std = [ - "sp-api/std", - "parity-scale-codec/std", - "scale-info/std", - "sp-std/std", - "sp-runtime/std", - "polimec-traits/std", -] diff --git a/runtime-api/staking/Cargo.toml b/runtime-api/staking/Cargo.toml deleted file mode 100644 index ff0109a09..000000000 --- a/runtime-api/staking/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -version = "0.1.0" -authors = ["KILT "] -edition = "2021" -repository = 'https://github.com/polimec/polimec-node' -name = "kilt-runtime-api-staking" -description = "Runtime APIs for dealing with parachain staking." - -[dependencies] -# External dependencies -parity-scale-codec = { workspace = true, features = [ - "derive", -] } -scale-info = { workspace = true, features = ["derive"] } - -# Substrate dependencies -sp-api.workspace = true -sp-runtime.workspace = true - - -[features] -default = ["std"] -std = ["parity-scale-codec/std", "sp-api/std", "sp-runtime/std", "scale-info/std"] diff --git a/runtime-api/staking/src/lib.rs b/runtime-api/staking/src/lib.rs deleted file mode 100644 index 197ee3502..000000000 --- a/runtime-api/staking/src/lib.rs +++ /dev/null @@ -1,46 +0,0 @@ -// KILT Blockchain – https://botlabs.org -// Copyright (C) 2019-2023 BOTLabs GmbH - -// The KILT Blockchain 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. - -// The KILT Blockchain 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 . - -// If you feel like getting in touch with us, you can do so at info@botlabs.org - -#![cfg_attr(not(feature = "std"), no_std)] - -use parity_scale_codec::{Codec, Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; -use sp_runtime::Perquintill; - -#[derive(Decode, Encode, TypeInfo, MaxEncodedLen, PartialEq, Eq, Debug)] -pub struct StakingRates { - pub collator_staking_rate: Perquintill, - pub collator_reward_rate: Perquintill, - pub delegator_staking_rate: Perquintill, - pub delegator_reward_rate: Perquintill, -} - -sp_api::decl_runtime_apis! { - /// The API to query staking and reward rates. - pub trait Staking - where - AccountId: Codec, - Balance: Codec - { - /// Returns the current staking rewards for a given account address. - fn get_unclaimed_staking_rewards(account: &AccountId) -> Balance; - /// Returns the current staking and reward rates for collators and - /// delegators. - fn get_staking_rates() -> StakingRates; - } -} diff --git a/runtimes/base/Cargo.toml b/runtimes/base/Cargo.toml index 8f9a0d5d2..51e0309a4 100644 --- a/runtimes/base/Cargo.toml +++ b/runtimes/base/Cargo.toml @@ -14,7 +14,7 @@ version.workspace = true substrate-wasm-builder.workspace = true [dependencies] -parity-scale-codec = { version = "3.3.0", default-features = false, features = [ +parity-scale-codec = { version = "3.3.0", default-features = false, features = [ "derive", ] } hex-literal = { version = "0.3.4", optional = true } @@ -25,8 +25,8 @@ scale-info = { version = "2.3.1", default-features = false, features = [ smallvec = "1.10.0" # Local -runtime-common.workspace = true -parachain-staking.workspace = true +pallet-parachain-staking.workspace = true +shared-configuration.workspace = true # Substrate frame-benchmarking = { workspace = true, optional = true } @@ -45,6 +45,7 @@ pallet-sudo.workspace = true pallet-timestamp.workspace = true pallet-transaction-payment.workspace = true pallet-transaction-payment-rpc-runtime-api.workspace = true +sp-arithmetic.workspace = true sp-api.workspace = true sp-block-builder.workspace = true sp-consensus-aura.workspace = true @@ -82,7 +83,7 @@ polkadot-primitives.workspace = true [features] default = ["std"] -fast-gov = ["runtime-common/fast-gov"] +fast-gov = [] std = [ "polkadot-primitives/std", "frame-benchmarking?/std", @@ -101,6 +102,8 @@ std = [ "frame-support/std", "frame-system-rpc-runtime-api/std", "frame-system/std", + "pallet-parachain-staking/std", + "parachains-common/std", "pallet-aura/std", "pallet-authorship/std", "pallet-balances/std", @@ -110,11 +113,11 @@ std = [ "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", "pallet-treasury/std", - "parachain-staking/std", "pallet-xcm/std", "parachain-info/std", "polkadot-parachain/std", "polkadot-runtime-common/std", + "sp-arithmetic/std", "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", @@ -125,11 +128,11 @@ std = [ "sp-session/std", "sp-std/std", "sp-transaction-pool/std", + "shared-configuration/std", "sp-version/std", "xcm-builder/std", "xcm-executor/std", "xcm/std", - "runtime-common/std", ] runtime-benchmarks = [ @@ -145,7 +148,6 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "cumulus-pallet-session-benchmarking/runtime-benchmarks", "cumulus-pallet-xcmp-queue/runtime-benchmarks", - "runtime-common/runtime-benchmarks", ] try-runtime = [ @@ -166,5 +168,4 @@ try-runtime = [ "pallet-transaction-payment/try-runtime", "pallet-xcm/try-runtime", "parachain-info/try-runtime", - "runtime-common/try-runtime", ] diff --git a/runtimes/base/build.rs b/runtimes/base/build.rs index b81f7762c..657bcc0d1 100644 --- a/runtimes/base/build.rs +++ b/runtimes/base/build.rs @@ -17,9 +17,5 @@ use substrate_wasm_builder::WasmBuilder; fn main() { - WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build() + WasmBuilder::new().with_current_project().export_heap_base().import_memory().build() } diff --git a/runtimes/base/src/lib.rs b/runtimes/base/src/lib.rs index 6f2b46cf7..d4884e971 100644 --- a/runtimes/base/src/lib.rs +++ b/runtimes/base/src/lib.rs @@ -24,17 +24,11 @@ extern crate frame_benchmarking; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use frame_support::{ - construct_runtime, - dispatch::DispatchClass, - parameter_types, - traits::{ConstU32, ConstU64, Everything}, + construct_runtime, parameter_types, + traits::Everything, weights::{ConstantMultiplier, Weight}, - PalletId, -}; -use frame_system::{ - limits::{BlockLength, BlockWeights}, - EnsureRoot, }; +use frame_system::EnsureRoot; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use sp_api::impl_runtime_apis; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; @@ -52,23 +46,20 @@ use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; + // XCM Imports -use xcm::latest::prelude::BodyId; +use xcm_config::{XcmConfig, XcmOriginToTransactDispatchOrigin}; use xcm_executor::XcmExecutor; -pub use runtime_common::constants::*; -use runtime_common::{ - fees::{ToAuthor, WeightToFee}, - FeeSplit, -}; -use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; -use xcm_config::{XcmConfig, XcmOriginToTransactDispatchOrigin}; +// Polimec Shared Imports +pub use shared_configuration::{currency::*, fee::*, governance::*, staking::*, weights::*}; + +pub use pallet_parachain_staking; // Make the WASM binary available. #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -mod weights; pub mod xcm_config; /// Alias to 512-bit hash when used in the context of a transaction signature on the chain. @@ -132,11 +123,10 @@ pub type Executive = /// of data like extrinsics, allowing for them to continue syncing the network through upgrades /// to even the core data structures. pub mod opaque { - pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; - use sp_runtime::{generic, traits::BlakeTwo256}; - use super::*; + use sp_runtime::{generic, traits::BlakeTwo256}; + pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; /// Opaque block header type. pub type Header = generic::Header; /// Opaque block type. @@ -166,158 +156,114 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { /// The version information used to identify this runtime when compiled natively. #[cfg(feature = "std")] pub fn native_version() -> NativeVersion { - NativeVersion { - runtime_version: VERSION, - can_author_with: Default::default(), - } + NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } parameter_types! { pub const Version: RuntimeVersion = VERSION; - - // This part is copied from Substrate's `bin/node/runtime/src/lib.rs`. - // The `RuntimeBlockLength` and `RuntimeBlockWeights` exist here because the - // `DeletionWeightLimit` and `DeletionQueueDepth` depend on those to parameterize - // the lazy contract deletion. - pub RuntimeBlockLength: BlockLength = - BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); - pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() - .base_block(BlockExecutionWeight::get()) - .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = ExtrinsicBaseWeight::get(); - }) - .for_class(DispatchClass::Normal, |weights| { - weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); - }) - .for_class(DispatchClass::Operational, |weights| { - weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); - // Operational transactions have some extra reserved space, so that they - // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. - weights.reserved = Some( - MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT - ); - }) - .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) - .build_or_panic(); pub const SS58Prefix: u16 = 42; } // Configure FRAME pallets to include in runtime. impl frame_system::Config for Runtime { + /// The data to be stored in an account. + type AccountData = pallet_balances::AccountData; /// The identifier used to distinguish between accounts. type AccountId = AccountId; - /// The aggregated dispatch type that is available for extrinsics. - 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. - type Index = Index; + /// The basic call filter to use in dispatchable. + type BaseCallFilter = Everything; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = BlockHashCount; + /// The maximum length of a block (in bytes). + type BlockLength = RuntimeBlockLength; /// The index type for blocks. type BlockNumber = BlockNumber; + /// Block & extrinsics weights: base values and limits. + type BlockWeights = RuntimeBlockWeights; + /// The weight of database operations that the runtime can invoke. + type DbWeight = RocksDbWeight; /// The type for hashing blocks and tries. type Hash = Hash; /// The hashing algorithm used. type Hashing = BlakeTwo256; /// The header type. type Header = generic::Header; + /// The index type for storing how many extrinsics an account has signed. + type Index = Index; + /// The lookup mechanism to get account ID from whatever is passed in dispatchers. + type Lookup = AccountIdLookup; + type MaxConsumers = frame_support::traits::ConstU32<16>; + /// What to do if an account is fully reaped from the system. + type OnKilledAccount = (); + /// What to do if a new account is created. + type OnNewAccount = (); + /// The action to take on a Runtime Upgrade + type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + /// Converts a module to an index of this module in the runtime. + type PalletInfo = PalletInfo; + /// The aggregated dispatch type that is available for extrinsics. + type RuntimeCall = RuntimeCall; /// The ubiquitous event type. type RuntimeEvent = RuntimeEvent; /// The ubiquitous origin type. type RuntimeOrigin = RuntimeOrigin; - /// Maximum number of block number to block hash mappings to keep (oldest pruned first). - type BlockHashCount = BlockHashCount; - /// Runtime version. - type Version = Version; - /// Converts a module to an index of this module in the runtime. - type PalletInfo = PalletInfo; - /// The data to be stored in an account. - type AccountData = pallet_balances::AccountData; - /// What to do if a new account is created. - type OnNewAccount = (); - /// What to do if an account is fully reaped from the system. - type OnKilledAccount = (); - /// The weight of database operations that the runtime can invoke. - type DbWeight = RocksDbWeight; - /// The basic call filter to use in dispatchable. - type BaseCallFilter = Everything; - /// Weight information for the extrinsics of this pallet. - type SystemWeightInfo = (); - /// Block & extrinsics weights: base values and limits. - type BlockWeights = RuntimeBlockWeights; - /// The maximum length of a block (in bytes). - type BlockLength = RuntimeBlockLength; /// This is used as an identifier of the chain. 42 is the generic substrate prefix. type SS58Prefix = SS58Prefix; - /// The action to take on a Runtime Upgrade - type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; - type MaxConsumers = frame_support::traits::ConstU32<16>; -} -parameter_types! { - pub const UncleGenerations: u32 = 0; + /// Weight information for the extrinsics of this pallet. + type SystemWeightInfo = (); + /// Runtime version. + type Version = Version; } impl pallet_timestamp::Config for Runtime { + type MinimumPeriod = MinimumPeriod; /// A timestamp: milliseconds since the unix epoch. type Moment = u64; type OnTimestampSet = Aura; - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = (); } impl pallet_authorship::Config for Runtime { - type FindAuthor = pallet_session::FindAccountFromAuthorIndex; type EventHandler = ParachainStaking; -} - -parameter_types! { - pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; + type FindAuthor = pallet_session::FindAccountFromAuthorIndex; } impl pallet_balances::Config for Runtime { - type MaxLocks = ConstU32<50>; - /// The type for recording an account's balance. + type AccountStore = System; type Balance = Balance; - /// The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = pallet_balances::weights::SubstrateWeight; - type MaxReserves = ConstU32<50>; + type FreezeIdentifier = (); + type HoldIdentifier = (); + type MaxFreezes = MaxReserves; + type MaxHolds = MaxLocks; + type MaxLocks = MaxLocks; + type MaxReserves = MaxReserves; type ReserveIdentifier = [u8; 8]; -} - -parameter_types! { - /// Relay Chain `TransactionByteFee` / 10 - pub const TransactionByteFee: Balance = 10 * MICRO_PLMC; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); } impl pallet_transaction_payment::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = - pallet_transaction_payment::CurrencyAdapter>>; - type OperationalFeeMultiplier = runtime_common::constants::fee::OperationalFeeMultiplier; - type WeightToFee = WeightToFee; - type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; -} - -parameter_types! { - pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); - pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + type LengthToFee = ConstantMultiplier; + type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; + type OperationalFeeMultiplier = frame_support::traits::ConstU8<5>; + type RuntimeEvent = RuntimeEvent; + type WeightToFee = WeightToFee; } impl cumulus_pallet_parachain_system::Config for Runtime { - type RuntimeEvent = RuntimeEvent; + type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; + type DmpMessageHandler = DmpQueue; type OnSystemEvent = (); - type SelfParaId = parachain_info::Pallet; type OutboundXcmpMessageSource = XcmpQueue; - type DmpMessageHandler = DmpQueue; type ReservedDmpWeight = ReservedDmpWeight; - type XcmpMessageHandler = XcmpQueue; type ReservedXcmpWeight = ReservedXcmpWeight; - type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; + type RuntimeEvent = RuntimeEvent; + type SelfParaId = parachain_info::Pallet; + type XcmpMessageHandler = XcmpQueue; } impl parachain_info::Config for Runtime {} @@ -325,115 +271,69 @@ impl parachain_info::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {} impl cumulus_pallet_xcmp_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; - type VersionWrapper = (); - type ExecuteOverweightOrigin = EnsureRoot; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; - type WeightInfo = (); + type ExecuteOverweightOrigin = EnsureRoot; type PriceForSiblingDelivery = (); + type RuntimeEvent = RuntimeEvent; + type VersionWrapper = (); + type WeightInfo = (); + type XcmExecutor = XcmExecutor; } impl cumulus_pallet_dmp_queue::Config for Runtime { + type ExecuteOverweightOrigin = EnsureRoot; type RuntimeEvent = RuntimeEvent; type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = EnsureRoot; -} - -parameter_types! { - pub const Period: u32 = 6 * HOURS; - pub const Offset: u32 = 0; } impl pallet_session::Config for Runtime { + type Keys = SessionKeys; + type NextSessionRotation = ParachainStaking; type RuntimeEvent = RuntimeEvent; + type SessionHandler = ::KeyTypeIdProviders; + type SessionManager = ParachainStaking; + type ShouldEndSession = ParachainStaking; type ValidatorId = AccountId; type ValidatorIdOf = ConvertInto; - type ShouldEndSession = ParachainStaking; - type NextSessionRotation = ParachainStaking; - type SessionManager = ParachainStaking; - type SessionHandler = ::KeyTypeIdProviders; - type Keys = SessionKeys; - // type WeightInfo = weights::pallet_session::WeightInfo; type WeightInfo = (); } impl pallet_aura::Config for Runtime { type AuthorityId = AuraId; type DisabledValidators = (); - type MaxAuthorities = ConstU32<100_000>; -} - -parameter_types! { - pub const PotId: PalletId = PalletId(*b"PotStake"); - pub const MaxCandidates: u32 = 1000; - pub const MinCandidates: u32 = 5; - pub const SessionLength: BlockNumber = 6 * HOURS; - pub const MaxInvulnerables: u32 = 100; - pub const ExecutiveBody: BodyId = BodyId::Executive; + type MaxAuthorities = MaxAuthorities; } -parameter_types! { - pub const ProposalBond: Permill = Permill::from_percent(5); - pub const ProposalBondMinimum: Balance = 20 * PLMC; - pub const SpendPeriod: BlockNumber = runtime_common::constants::governance::SPEND_PERIOD; - pub const Burn: Permill = Permill::zero(); - pub const MaxApprovals: u32 = 100; - pub const TreasuryId: PalletId = PalletId(*b"plmc/tsy"); -} - -impl pallet_treasury::Config for Runtime { - type PalletId = TreasuryId; - type Currency = Balances; - type ApproveOrigin = EnsureRoot; - type RejectOrigin = EnsureRoot; +impl pallet_sudo::Config for Runtime { + type RuntimeCall = RuntimeCall; type RuntimeEvent = RuntimeEvent; - type OnSlash = Treasury; - type ProposalBond = ProposalBond; - type ProposalBondMinimum = ProposalBondMinimum; - type ProposalBondMaximum = (); - type SpendPeriod = SpendPeriod; - type SpendOrigin = frame_support::traits::NeverEnsureOrigin; - type Burn = Burn; - type BurnDestination = (); - type SpendFunds = (); - // type WeightInfo = weights::pallet_treasury::WeightInfo; - type WeightInfo = (); - type MaxApprovals = MaxApprovals; } -impl parachain_staking::Config for Runtime { - type RuntimeEvent = RuntimeEvent; +impl pallet_parachain_staking::Config for Runtime { + type CandidateBondLessDelay = CandidateBondLessDelay; type Currency = Balances; - type CurrencyBalance = Balance; - - type MinBlocksPerRound = runtime_common::constants::staking::MinBlocksPerRound; - type DefaultBlocksPerRound = runtime_common::constants::staking::DefaultBlocksPerRound; - type StakeDuration = runtime_common::constants::staking::StakeDuration; - type ExitQueueDelay = runtime_common::constants::staking::ExitQueueDelay; - type MinCollators = runtime_common::constants::staking::MinCollators; - type MinRequiredCollators = runtime_common::constants::staking::MinRequiredCollators; - type MaxDelegationsPerRound = runtime_common::constants::staking::MaxDelegationsPerRound; - type MaxDelegatorsPerCollator = runtime_common::constants::staking::MaxDelegatorsPerCollator; - type MinCollatorStake = runtime_common::constants::staking::MinCollatorStake; - type MinCollatorCandidateStake = runtime_common::constants::staking::MinCollatorStake; - type MaxTopCandidates = runtime_common::constants::staking::MaxCollatorCandidates; - type MinDelegatorStake = runtime_common::constants::staking::MinDelegatorStake; - type MaxUnstakeRequests = runtime_common::constants::staking::MaxUnstakeRequests; - type NetworkRewardRate = runtime_common::constants::staking::NetworkRewardRate; - type NetworkRewardStart = runtime_common::constants::staking::NetworkRewardStart; - type NetworkRewardBeneficiary = Treasury; - // type WeightInfo = weights::parachain_staking::WeightInfo; - type WeightInfo = (); - - const BLOCKS_PER_YEAR: Self::BlockNumber = runtime_common::constants::BLOCKS_PER_YEAR; -} - -impl pallet_sudo::Config for Runtime { - type RuntimeCall = RuntimeCall; + type DelegationBondLessDelay = DelegationBondLessDelay; + type LeaveCandidatesDelay = LeaveCandidatesDelay; + type LeaveDelegatorsDelay = LeaveDelegatorsDelay; + type MaxBottomDelegationsPerCandidate = MaxBottomDelegationsPerCandidate; + type MaxDelegationsPerDelegator = MaxDelegationsPerDelegator; + type MaxTopDelegationsPerCandidate = MaxTopDelegationsPerCandidate; + type MinBlocksPerRound = MinBlocksPerRound; + type MinCandidateStk = MinCandidateStk; + type MinDelegation = MinDelegation; + type MinDelegatorStk = MinDelegatorStk; + type MinSelectedCandidates = MinSelectedCandidates; + type MonetaryGovernanceOrigin = frame_system::EnsureRoot; + type OnCollatorPayout = (); + type OnNewRound = (); + // We use the default implementation, so we leave () here. + type PayoutCollatorReward = (); + type RevokeDelegationDelay = RevokeDelegationDelay; + type RewardPaymentDelay = RewardPaymentDelay; type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_parachain_staking::weights::SubstrateWeight; } // Create the runtime by composing the FRAME pallets that were previously configured. @@ -453,16 +353,13 @@ construct_runtime!( // Monetary stuff. Balances: pallet_balances = 10, TransactionPayment: pallet_transaction_payment = 11, - Treasury: pallet_treasury = 12, - // Consensus support. - // The following order MUST NOT be changed: Aura -> Session -> Staking -> Authorship -> AuraExt - // Dependencies: AuraExt on Aura, Authorship and Session on ParachainStaking - Aura: pallet_aura = 23, - Session: pallet_session = 22, - ParachainStaking: parachain_staking = 21, - Authorship: pallet_authorship = 20, - AuraExt: cumulus_pallet_aura_ext = 24, + // Collator support. the order of these 5 are important and shall not change. + Authorship: pallet_authorship::{Pallet, Storage} = 20, + Session: pallet_session::{Pallet, Call, Storage, Event, Config} = 22, + Aura: pallet_aura::{Pallet, Storage, Config} = 23, + AuraExt: cumulus_pallet_aura_ext::{Pallet, Storage, Config} = 24, + ParachainStaking: pallet_parachain_staking::{Pallet, Call, Storage, Event, Config} = 25, // XCM helpers. XcmpQueue: cumulus_pallet_xcmp_queue = 30, @@ -512,6 +409,13 @@ impl_runtime_apis! { fn metadata() -> OpaqueMetadata { OpaqueMetadata::new(Runtime::metadata().into()) } + fn metadata_at_version(version: u32) -> Option { + Runtime::metadata_at_version(version) + } + + fn metadata_versions() -> sp_std::vec::Vec { + Runtime::metadata_versions() + } } impl sp_block_builder::BlockBuilder for Runtime { @@ -582,7 +486,6 @@ impl_runtime_apis! { ) -> pallet_transaction_payment::FeeDetails { TransactionPayment::query_fee_details(uxt, len) } - fn query_weight_to_fee(weight: Weight) -> Balance { TransactionPayment::weight_to_fee(weight) } @@ -606,7 +509,6 @@ impl_runtime_apis! { ) -> pallet_transaction_payment::FeeDetails { TransactionPayment::query_call_fee_details(call, len) } - fn query_weight_to_fee(weight: Weight) -> Balance { TransactionPayment::weight_to_fee(weight) } @@ -634,8 +536,6 @@ impl_runtime_apis! { signature_check: bool, select: frame_try_runtime::TryStateSelect, ) -> Weight { - // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to - // have a backtrace here. Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap() } } @@ -686,11 +586,11 @@ struct CheckInherents; impl cumulus_pallet_parachain_system::CheckInherents for CheckInherents { fn check_inherents( - block: &Block, relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof, + block: &Block, + relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof, ) -> sp_inherents::CheckInherentsResult { - let relay_chain_slot = relay_state_proof - .read_slot() - .expect("Could not read the relay chain slot from the proof"); + let relay_chain_slot = + relay_state_proof.read_slot().expect("Could not read the relay chain slot from the proof"); let inherent_data = cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration( relay_chain_slot, diff --git a/runtimes/base/src/xcm_config.rs b/runtimes/base/src/xcm_config.rs index c8d6ae879..5f7ae306e 100644 --- a/runtimes/base/src/xcm_config.rs +++ b/runtimes/base/src/xcm_config.rs @@ -15,8 +15,8 @@ // along with this program. If not, see . use super::{ - AccountId, AllPalletsWithSystem, Balances, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, - RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, + AccountId, AllPalletsWithSystem, Balances, EnsureRoot, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, + RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, XcmpQueue, }; use frame_support::{ match_types, parameter_types, @@ -122,31 +122,31 @@ pub type Barrier = DenyThenTry< pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { - type RuntimeCall = RuntimeCall; - type XcmSender = XcmRouter; + type AssetClaims = PolkadotXcm; + type AssetExchanger = (); + type AssetLocker = (); // How to withdraw and deposit an asset. type AssetTransactor = LocalAssetTransactor; - type OriginConverter = XcmOriginToTransactDispatchOrigin; + type AssetTrap = PolkadotXcm; + type Barrier = Barrier; + type CallDispatcher = RuntimeCall; + type FeeManager = (); type IsReserve = NativeAsset; type IsTeleporter = (); - // Teleporting is disabled. - type UniversalLocation = UniversalLocation; - type Barrier = Barrier; - type Weigher = FixedWeightBounds; - type Trader = UsingComponents, RelayLocation, AccountId, Balances, ToAuthor>; - type ResponseHandler = PolkadotXcm; - type AssetTrap = PolkadotXcm; - type AssetClaims = PolkadotXcm; - type SubscriptionService = PolkadotXcm; - type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type AssetLocker = (); - type AssetExchanger = (); - type FeeManager = (); type MessageExporter = (); - type UniversalAliases = Nothing; - type CallDispatcher = RuntimeCall; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type PalletInstancesInfo = AllPalletsWithSystem; + type ResponseHandler = PolkadotXcm; + type RuntimeCall = RuntimeCall; type SafeCallFilter = Everything; + type SubscriptionService = PolkadotXcm; + type Trader = UsingComponents>; + type UniversalAliases = Nothing; + // Teleporting is disabled. + type UniversalLocation = UniversalLocation; + type Weigher = FixedWeightBounds; + type XcmSender = XcmRouter; } /// No local origins on this chain are allowed to dispatch XCM sends/executions. @@ -167,32 +167,33 @@ parameter_types! { } impl pallet_xcm::Config for Runtime { + type AdminOrigin = EnsureRoot; + // ^ Override for AdvertisedXcmVersion default + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type ExecuteXcmOrigin = EnsureXcmOrigin; + type MaxLockers = ConstU32<8>; + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + type RuntimeCall = RuntimeCall; type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; type SendXcmOrigin = EnsureXcmOrigin; - type XcmRouter = XcmRouter; - type ExecuteXcmOrigin = EnsureXcmOrigin; + type SovereignAccountOf = LocationToAccountId; + type TrustedLockers = (); + type UniversalLocation = UniversalLocation; + type Weigher = FixedWeightBounds; + type WeightInfo = pallet_xcm::TestWeightInfo; type XcmExecuteFilter = Nothing; // ^ Disable dispatchable execute on the XCM pallet. // Needs to be `Everything` for local testing. type XcmExecutor = XcmExecutor; - type XcmTeleportFilter = Everything; type XcmReserveTransferFilter = Nothing; - type Weigher = FixedWeightBounds; - type UniversalLocation = UniversalLocation; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; + type XcmRouter = XcmRouter; + type XcmTeleportFilter = Everything; const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; - // ^ Override for AdvertisedXcmVersion default - type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; - type Currency = Balances; - type CurrencyMatcher = (); - type TrustedLockers = (); - type SovereignAccountOf = LocationToAccountId; - type MaxLockers = ConstU32<8>; - type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/runtimes/common/Cargo.toml b/runtimes/common/Cargo.toml deleted file mode 100644 index f4ae2a40e..000000000 --- a/runtimes/common/Cargo.toml +++ /dev/null @@ -1,90 +0,0 @@ -[package] -authors.workspace = true -documentation.workspace = true -edition.workspace = true -homepage.workspace = true -license-file.workspace = true -readme.workspace = true -repository.workspace = true -version.workspace = true -name = "runtime-common" -description = "Common interfaces, types, constants and functionality for all Polimec runtimes." - -[dev-dependencies] -sp-io = { workspace = true, features = ["std"] } - -[dependencies] -# External dependencies -parity-scale-codec = { workspace = true, features = [ - "derive", -] } -log.workspace = true -scale-info = { workspace = true, features = ["derive"] } -smallvec.workspace = true - -# Internal dependencies -parachain-staking.workspace = true -did.workspace = true -dip-support.workspace = true -pallet-did-lookup = { workspace = true, optional = true } -pallet-dip-consumer.workspace = true -pallet-dip-provider.workspace = true - -# Substrate dependencies -frame-support.workspace = true -frame-system.workspace = true -pallet-authorship.workspace = true -pallet-balances.workspace = true -pallet-transaction-payment.workspace = true -sp-consensus-aura.workspace = true -sp-core.workspace = true -sp-io.workspace = true -sp-trie.workspace = true -sp-runtime.workspace = true -sp-std.workspace = true -pallet-membership.workspace = true - -# Cumulus dependencies -cumulus-primitives-core.workspace = true - -# Polkadot dependencies -polkadot-parachain.workspace = true -xcm.workspace = true -xcm-builder.workspace = true -xcm-executor.workspace = true -parachains-common.workspace = true - -[features] -default = ["std"] -fast-gov = [] -runtime-benchmarks = [ - "frame-support/runtime-benchmarks", - "parachain-staking/runtime-benchmarks", - "polkadot-parachain/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", - "xcm-builder/runtime-benchmarks", -] -std = [ - "parity-scale-codec/std", - "frame-support/std", - "frame-system/std", - "cumulus-primitives-core/std", - "pallet-authorship/std", - "pallet-balances/std", - "pallet-transaction-payment/std", - "pallet-membership/std", - "parachain-staking/std", - "polkadot-parachain/std", - "scale-info/std", - "sp-consensus-aura/std", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", - "sp-std/std", - "xcm-builder/std", - "xcm-executor/std", - "xcm/std", - "parachains-common/std", - "dip-support/std", -] -try-runtime = ["frame-support/try-runtime"] diff --git a/runtimes/common/src/constants.rs b/runtimes/common/src/constants.rs deleted file mode 100644 index 72e961558..000000000 --- a/runtimes/common/src/constants.rs +++ /dev/null @@ -1,358 +0,0 @@ -// Polimec Blockchain – https://www.polimec.org/ -// Copyright (C) Polimec 2022. All rights reserved. - -// The Polimec Blockchain 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. - -// The Polimec Blockchain 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 frame_support::{ - parameter_types, - traits::WithdrawReasons, - weights::{constants::WEIGHT_REF_TIME_PER_SECOND, Weight}, -}; -use sp_runtime::{Perbill, Percent, Perquintill}; - -pub use parachain_staking::InflationInfo; - -use crate::{Balance, BlockNumber}; - -/// This determines the average expected block time that we are targetting. -/// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`. -/// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked -/// up by `pallet_aura` to implement `fn slot_duration()`. -/// -/// Change this to adjust the block time. -pub const MILLISECS_PER_BLOCK: u64 = 12_000; - -pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; - -// Time is measured by number of blocks. -pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); -pub const HOURS: BlockNumber = MINUTES * 60; -pub const DAYS: BlockNumber = HOURS * 24; -// Julian year as Substrate handles it -pub const BLOCKS_PER_YEAR: BlockNumber = DAYS * 36525 / 100; - -pub const MAX_COLLATOR_STAKE: Balance = 200_000 * PLMC; - -/// One PLMC -pub const PLMC: Balance = 10u128.pow(10); - -/// 0.001 PLMC -pub const MILLI_PLMC: Balance = 10u128.pow(7); - -/// 0.000_001 PLMC -pub const MICRO_PLMC: Balance = 10u128.pow(4); - -pub const EXISTENTIAL_DEPOSIT: Balance = 10 * MILLI_PLMC; - -// 1 in 4 blocks (on average, not counting collisions) will be primary babe -// blocks. -pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); - -/// We assume that ~10% of the block weight is consumed by `on_initalize` -/// handlers. This is used to limit the maximal weight of a single extrinsic. -pub 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. -pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); -/// We allow for 0.5 of a second of compute with a 12 second average block time. -pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_ref_time(WEIGHT_REF_TIME_PER_SECOND) - .saturating_div(2) - .set_proof_size(cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64); - -pub const INFLATION_CONFIG: (Perquintill, Perquintill, Perquintill, Perquintill) = ( - // max collator staking rate - Perquintill::from_percent(40), - // collator reward rate - Perquintill::from_percent(10), - // max delegator staking rate - Perquintill::from_percent(10), - // delegator reward rate - Perquintill::from_percent(8), -); - -/// Inflation configuration which is used at genesis -pub fn polimec_inflation_config() -> InflationInfo { - InflationInfo::new( - BLOCKS_PER_YEAR.into(), - // max collator staking rate - Perquintill::from_percent(40), - // collator reward rate - Perquintill::from_percent(10), - // max delegator staking rate - Perquintill::from_percent(10), - // delegator reward rate - Perquintill::from_percent(8), - ) -} - -/// Calculate the storage deposit based on the number of storage items and the -/// combined byte size of those items. -pub const fn deposit(items: u32, bytes: u32) -> Balance { - items as Balance * 56 * MILLI_PLMC + (bytes as Balance) * 50 * MICRO_PLMC -} - -/// The size of an index in the index pallet. -/// The size is checked in the runtime by a test. -pub const MAX_INDICES_BYTE_LENGTH: u32 = 49; - -/// Copied from Kusama & Polkadot runtime -pub const MAX_VESTING_SCHEDULES: u32 = 28; - -parameter_types! { - /// Vesting Pallet. Copied from Kusama & Polkadot runtime - pub const MinVestedTransfer: Balance = 100 * MILLI_PLMC; - /// Deposits per byte - pub const ByteDeposit: Balance = deposit(0, 1); - /// Index Pallet. Deposit taken for an account index - pub const IndicesDeposit: Balance = deposit(1, MAX_INDICES_BYTE_LENGTH); - /// CType Pallet. Per byte fee for a ctype. - pub const CtypeFee: Balance = MILLI_PLMC; - pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons = - WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); -} - -pub mod delegation { - use super::*; - - pub const DELEGATION_DEPOSIT: Balance = PLMC; - pub const MAX_SIGNATURE_BYTE_LENGTH: u16 = 64; - pub const MAX_PARENT_CHECKS: u32 = 5; - pub const MAX_REVOCATIONS: u32 = 5; - pub const MAX_REMOVALS: u32 = MAX_REVOCATIONS; - pub const MAX_CHILDREN: u32 = 1000; - - parameter_types! { - pub const MaxSignatureByteLength: u16 = MAX_SIGNATURE_BYTE_LENGTH; - pub const MaxParentChecks: u32 = MAX_PARENT_CHECKS; - pub const MaxRevocations: u32 = MAX_REVOCATIONS; - pub const MaxRemovals: u32 = MAX_REMOVALS; - #[derive(Clone)] - pub const MaxChildren: u32 = MAX_CHILDREN; - pub const DelegationDeposit: Balance = DELEGATION_DEPOSIT; - } -} - -pub mod staking { - use super::*; - - /// Minimum round length is 1 hour (300 * 12 second block times) - #[cfg(feature = "fast-gov")] - pub const MIN_BLOCKS_PER_ROUND: BlockNumber = 10; - #[cfg(not(feature = "fast-gov"))] - pub const MIN_BLOCKS_PER_ROUND: BlockNumber = HOURS; - - #[cfg(feature = "fast-gov")] - pub const DEFAULT_BLOCKS_PER_ROUND: BlockNumber = 20; - #[cfg(not(feature = "fast-gov"))] - pub const DEFAULT_BLOCKS_PER_ROUND: BlockNumber = 2 * HOURS; - - #[cfg(feature = "fast-gov")] - pub const STAKE_DURATION: BlockNumber = 30; - #[cfg(not(feature = "fast-gov"))] - pub const STAKE_DURATION: BlockNumber = 7 * DAYS; - - #[cfg(feature = "fast-gov")] - pub const MIN_COLLATORS: u32 = 4; - #[cfg(not(feature = "fast-gov"))] - pub const MIN_COLLATORS: u32 = 16; - - #[cfg(feature = "fast-gov")] - pub const MAX_CANDIDATES: u32 = 16; - #[cfg(not(feature = "fast-gov"))] - pub const MAX_CANDIDATES: u32 = 75; - - pub const MAX_DELEGATORS_PER_COLLATOR: u32 = 35; - pub const MIN_DELEGATOR_STAKE: Balance = 20 * PLMC; - - pub const NETWORK_REWARD_RATE: Perquintill = Perquintill::from_percent(10); - - parameter_types! { - /// Minimum round length is 1 hour - pub const MinBlocksPerRound: BlockNumber = MIN_BLOCKS_PER_ROUND; - /// Default length of a round/session is 2 hours - pub const DefaultBlocksPerRound: BlockNumber = DEFAULT_BLOCKS_PER_ROUND; - /// Unstaked balance can be unlocked after 7 days - pub const StakeDuration: BlockNumber = STAKE_DURATION; - /// Collator exit requests are delayed by 4 hours (2 rounds/sessions) - pub const ExitQueueDelay: u32 = 2; - /// Minimum 16 collators selected per round, default at genesis and minimum forever after - pub const MinCollators: u32 = MIN_COLLATORS; - /// At least 4 candidates which cannot leave the network if there are no other candidates. - pub const MinRequiredCollators: u32 = 4; - /// We only allow one delegation per round. - pub const MaxDelegationsPerRound: u32 = 1; - /// Maximum 25 delegators per collator at launch, might be increased later - #[derive(Debug, Eq, PartialEq)] - pub const MaxDelegatorsPerCollator: u32 = MAX_DELEGATORS_PER_COLLATOR; - /// Minimum stake required to be reserved to be a collator is 10_000 - pub const MinCollatorStake: Balance = 10_000 * PLMC; - /// Minimum stake required to be reserved to be a delegator is 1000 - pub const MinDelegatorStake: Balance = MIN_DELEGATOR_STAKE; - /// Maximum number of collator candidates - #[derive(Debug, Eq, PartialEq)] - pub const MaxCollatorCandidates: u32 = MAX_CANDIDATES; - /// Maximum number of concurrent requests to unlock unstaked balance - pub const MaxUnstakeRequests: u32 = 10; - /// The starting block number for the network rewards - pub const NetworkRewardStart: BlockNumber = super::treasury::INITIAL_PERIOD_LENGTH; - /// The rate in percent for the network rewards - pub const NetworkRewardRate: Perquintill = NETWORK_REWARD_RATE; - } -} - -pub mod governance { - use super::*; - - pub const MIN_DEPOSIT: Balance = PLMC; - - #[cfg(feature = "fast-gov")] - pub const LAUNCH_PERIOD: BlockNumber = 7 * MINUTES; - #[cfg(not(feature = "fast-gov"))] - pub const LAUNCH_PERIOD: BlockNumber = 7 * DAYS; - - #[cfg(feature = "fast-gov")] - pub const VOTING_PERIOD: BlockNumber = 7 * MINUTES; - #[cfg(not(feature = "fast-gov"))] - pub const VOTING_PERIOD: BlockNumber = 7 * DAYS; - - #[cfg(feature = "fast-gov")] - pub const FAST_TRACK_VOTING_PERIOD: BlockNumber = 3 * MINUTES; - #[cfg(not(feature = "fast-gov"))] - pub const FAST_TRACK_VOTING_PERIOD: BlockNumber = 3 * HOURS; - - #[cfg(feature = "fast-gov")] - pub const ENACTMENT_PERIOD: BlockNumber = 8 * MINUTES; - #[cfg(not(feature = "fast-gov"))] - pub const ENACTMENT_PERIOD: BlockNumber = DAYS; - - #[cfg(feature = "fast-gov")] - pub const COOLOFF_PERIOD: BlockNumber = 7 * MINUTES; - #[cfg(not(feature = "fast-gov"))] - pub const COOLOFF_PERIOD: BlockNumber = 7 * DAYS; - - #[cfg(feature = "fast-gov")] - pub const SPEND_PERIOD: BlockNumber = 6 * MINUTES; - #[cfg(not(feature = "fast-gov"))] - pub const SPEND_PERIOD: BlockNumber = 6 * DAYS; - - #[cfg(feature = "fast-gov")] - pub const ROTATION_PERIOD: BlockNumber = 80 * MINUTES; - #[cfg(not(feature = "fast-gov"))] - pub const ROTATION_PERIOD: BlockNumber = 80 * HOURS; - - #[cfg(feature = "fast-gov")] - pub const TERM_DURATION: BlockNumber = 15 * MINUTES; - #[cfg(not(feature = "fast-gov"))] - pub const TERM_DURATION: BlockNumber = DAYS; - - #[cfg(feature = "fast-gov")] - pub const COUNCIL_MOTION_DURATION: BlockNumber = 4 * MINUTES; - #[cfg(not(feature = "fast-gov"))] - pub const COUNCIL_MOTION_DURATION: BlockNumber = 3 * DAYS; - - #[cfg(feature = "fast-gov")] - pub const TECHNICAL_MOTION_DURATION: BlockNumber = 4 * MINUTES; - #[cfg(not(feature = "fast-gov"))] - pub const TECHNICAL_MOTION_DURATION: BlockNumber = 3 * DAYS; - - parameter_types! { - // Democracy Pallet - pub const LaunchPeriod: BlockNumber = LAUNCH_PERIOD; - pub const VotingPeriod: BlockNumber = VOTING_PERIOD; - pub const FastTrackVotingPeriod: BlockNumber = FAST_TRACK_VOTING_PERIOD; - pub const MinimumDeposit: Balance = MIN_DEPOSIT; - pub const EnactmentPeriod: BlockNumber = ENACTMENT_PERIOD; - pub const CooloffPeriod: BlockNumber = COOLOFF_PERIOD; - pub const MaxProposals: u32 = 100; - // Council Pallet - pub const CouncilMotionDuration: BlockNumber = COUNCIL_MOTION_DURATION; - pub const CouncilMaxProposals: u32 = 100; - pub const CouncilMaxMembers: u32 = 100; - // Technical Committee - pub const TechnicalMotionDuration: BlockNumber = TECHNICAL_MOTION_DURATION; - pub const TechnicalMaxProposals: u32 = 100; - pub const TechnicalMaxMembers: u32 = 100; - } -} - -pub mod treasury { - use super::*; - - pub const INITIAL_PERIOD_LENGTH: BlockNumber = BLOCKS_PER_YEAR.saturating_mul(5); - const YEARLY_REWARD: Balance = 2_000_000u128 * PLMC; - pub const INITIAL_PERIOD_REWARD_PER_BLOCK: Balance = YEARLY_REWARD / (BLOCKS_PER_YEAR as Balance); - - parameter_types! { - pub const InitialPeriodLength: BlockNumber = INITIAL_PERIOD_LENGTH; - pub const InitialPeriodReward: Balance = INITIAL_PERIOD_REWARD_PER_BLOCK; - } -} - -pub mod proxy { - use super::*; - - parameter_types! { - // One storage item; key size 32, value size 8; . - pub const ProxyDepositBase: Balance = deposit(1, 8); - // Additional storage item size of 33 bytes. - pub const ProxyDepositFactor: Balance = deposit(0, 33); - pub const MaxProxies: u16 = 10; - pub const AnnouncementDepositBase: Balance = deposit(1, 8); - pub const AnnouncementDepositFactor: Balance = deposit(0, 66); - pub const MaxPending: u16 = 10; - } -} - -pub mod preimage { - use super::*; - - parameter_types! { - pub const PreimageMaxSize: u32 = 4096 * 1024; - pub const PreimageBaseDeposit: Balance = deposit(2, 64); - } -} - -pub mod tips { - use super::*; - - parameter_types! { - pub const MaximumReasonLength: u32 = 16384; - pub const TipCountdown: BlockNumber = DAYS; - pub const TipFindersFee: Percent = Percent::from_percent(20); - pub const TipReportDepositBase: Balance = deposit(1, 1); - } -} - -pub mod fee { - use super::*; - - parameter_types! { - /// This value increases the priority of `Operational` transactions by adding - /// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`. - pub const OperationalFeeMultiplier: u8 = 5; - pub const TransactionByteFee: Balance = MICRO_PLMC; - } -} - -#[cfg(test)] -mod tests { - use super::*; - - // TODO: static assert - #[allow(clippy::assertions_on_constants)] - #[test] - fn blocks_per_year_saturation() { - assert!(BLOCKS_PER_YEAR < u32::MAX); - } -} diff --git a/runtimes/common/src/fees.rs b/runtimes/common/src/fees.rs deleted file mode 100644 index 88f5ebefb..000000000 --- a/runtimes/common/src/fees.rs +++ /dev/null @@ -1,279 +0,0 @@ -// Polimec Blockchain – https://www.polimec.org/ -// Copyright (C) Polimec 2022. All rights reserved. - -// The Polimec Blockchain 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. - -// The Polimec Blockchain 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 frame_support::{ - dispatch::DispatchClass, - traits::{Currency, Get, Imbalance, OnUnbalanced}, - weights::{ - Weight, WeightToFee as WeightToFeeT, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, - }, -}; -use pallet_balances::WeightInfo; -use pallet_transaction_payment::OnChargeTransaction; -use smallvec::smallvec; -use sp_runtime::Perbill; - -use crate::{constants::MILLI_PLMC, AccountId, Balance, NegativeImbalanceOf}; - -/// Split two Imbalances between two unbalanced handlers. -/// The first Imbalance will be split according to the given ratio. The second -/// Imbalance will be handled by the second beneficiary. -/// -/// In case of transaction payment, the first Imbalance is the fee and the -/// second imbalance the tip. -pub struct SplitFeesByRatio( - sp_std::marker::PhantomData<(R, Ratio, Beneficiary1, Beneficiary2)>, -); -impl OnUnbalanced> - for SplitFeesByRatio -where - R: pallet_balances::Config, - Beneficiary1: OnUnbalanced>, - Beneficiary2: OnUnbalanced>, - Ratio: Get<(u32, u32)>, -{ - fn on_unbalanceds(mut fees_then_tips: impl Iterator>) { - let ratio = Ratio::get(); - if let Some(fees) = fees_then_tips.next() { - let mut split = fees.ration(ratio.0, ratio.1); - if let Some(tips) = fees_then_tips.next() { - // for tips, if any, 100% to author - tips.merge_into(&mut split.1); - } - Beneficiary1::on_unbalanced(split.0); - Beneficiary2::on_unbalanced(split.1); - } - } -} - -/// Logic for the author to get a portion of fees. -pub struct ToAuthor(sp_std::marker::PhantomData); - -impl OnUnbalanced> for ToAuthor -where - R: pallet_balances::Config + pallet_authorship::Config, - ::AccountId: From, - ::AccountId: Into, - ::Balance: Into, -{ - fn on_nonzero_unbalanced(amount: NegativeImbalanceOf) { - if let Some(author) = >::author() { - >::resolve_creating(&author, amount); - } - } -} - -/// Handles converting a weight scalar to a fee value, based on the scale and -/// granularity of the node's balance type. -/// -/// This should typically create a mapping between the following ranges: -/// - [0, MAXIMUM_BLOCK_WEIGHT] -/// - [Balance::min, Balance::max] -/// -/// Yet, it can be used for any other sort of change to weight-fee. Some -/// examples being: -/// - Setting it to `0` will essentially disable the weight fee. -/// - Setting it to `1` will cause the literal `#[weight = x]` values to be -/// charged. -pub struct WeightToFee(sp_std::marker::PhantomData); -impl WeightToFeePolynomial for WeightToFee -where - R: pallet_transaction_payment::Config, - R: frame_system::Config, - R: pallet_balances::Config, - u128: From<<::OnChargeTransaction as OnChargeTransaction>::Balance>, -{ - type Balance = Balance; - fn polynomial() -> WeightToFeeCoefficients { - // The should be fee - let wanted_fee: Balance = 10 * MILLI_PLMC; - - // TODO: transfer_keep_alive is 288 byte long? - let tx_len: u64 = 288; - let byte_fee: Balance = - ::LengthToFee::weight_to_fee(&Weight::from_ref_time(tx_len)) - .into(); - let base_weight: Weight = ::BlockWeights::get() - .get(DispatchClass::Normal) - .base_extrinsic; - let base_weight_fee: Balance = - ::LengthToFee::weight_to_fee(&base_weight).into(); - let tx_weight_fee: Balance = ::LengthToFee::weight_to_fee( - &::WeightInfo::transfer_keep_alive(), - ) - .into(); - let unbalanced_fee: Balance = base_weight_fee.saturating_add(tx_weight_fee); - - let wanted_weight_fee: Balance = wanted_fee.saturating_sub(byte_fee); - - smallvec![WeightToFeeCoefficient { - degree: 1, - negative: false, - coeff_frac: Perbill::from_rational(wanted_weight_fee % unbalanced_fee, unbalanced_fee), - coeff_integer: wanted_weight_fee / unbalanced_fee, - }] - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - AccountId, BlockExecutionWeight, ExtrinsicBaseWeight, AVERAGE_ON_INITIALIZE_RATIO, MAXIMUM_BLOCK_WEIGHT, - NORMAL_DISPATCH_RATIO, - }; - use frame_support::{dispatch::DispatchClass, parameter_types, traits::FindAuthor}; - use frame_system::limits; - use sp_core::H256; - use sp_runtime::{ - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - Perbill, - }; - - type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; - type Block = frame_system::mocking::MockBlock; - - frame_support::construct_runtime!( - pub enum Test where - Block = Block, - NodeBlock = Block, - UncheckedExtrinsic = UncheckedExtrinsic, - { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - Authorship: pallet_authorship::{Pallet, Storage}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - } - ); - - parameter_types! { - pub const BlockHashCount: u64 = 250; - // One to one clone of our runtimes' blockweight - pub BlockWeights: limits::BlockWeights = limits::BlockWeights::builder() - .base_block(BlockExecutionWeight::get()) - .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = ExtrinsicBaseWeight::get(); - }) - .for_class(DispatchClass::Normal, |weights| { - weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); - }) - .for_class(DispatchClass::Operational, |weights| { - weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); - // Operational transactions have some extra reserved space, so that they - // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. - weights.reserved = Some( - MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT - ); - }) - .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) - .build_or_panic(); - pub BlockLength: limits::BlockLength = limits::BlockLength::max(2 * 1024); - pub const AvailableBlockRatio: Perbill = Perbill::one(); - } - - impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type RuntimeOrigin = RuntimeOrigin; - type Index = u64; - type BlockNumber = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Header = Header; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type BlockLength = BlockLength; - type BlockWeights = BlockWeights; - type DbWeight = (); - 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_balances::Config for Test { - type Balance = u64; - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = (); - type AccountStore = System; - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type WeightInfo = (); - } - - pub const TREASURY_ACC: AccountId = crate::AccountId::new([1u8; 32]); - const AUTHOR_ACC: AccountId = AccountId::new([2; 32]); - - pub struct ToBeneficiary(); - impl OnUnbalanced> for ToBeneficiary { - fn on_nonzero_unbalanced(amount: NegativeImbalanceOf) { - // Must resolve into existing but better to be safe. - >::resolve_creating(&TREASURY_ACC, amount); - } - } - - pub struct OneAuthor; - impl FindAuthor for OneAuthor { - fn find_author<'a, I>(_: I) -> Option - where - I: 'a, - { - Some(AUTHOR_ACC) - } - } - impl pallet_authorship::Config for Test { - type FindAuthor = OneAuthor; - type EventHandler = (); - } - - pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - // We use default for brevity, but you can configure as desired if needed. - pallet_balances::GenesisConfig::::default() - .assimilate_storage(&mut t) - .unwrap(); - t.into() - } - - parameter_types! { - pub const Ratio: (u32, u32) = (50, 50); - } - - #[test] - fn test_fees_and_tip_split() { - new_test_ext().execute_with(|| { - let fee = Balances::issue(10); - let tip = Balances::issue(20); - - assert_eq!(Balances::free_balance(TREASURY_ACC), 0); - assert_eq!(Balances::free_balance(AUTHOR_ACC), 0); - - SplitFeesByRatio::>::on_unbalanceds(vec![fee, tip].into_iter()); - - assert_eq!(Balances::free_balance(TREASURY_ACC), 5); - assert_eq!(Balances::free_balance(AUTHOR_ACC), 25); - }); - } -} diff --git a/runtimes/common/src/lib.rs b/runtimes/common/src/lib.rs deleted file mode 100644 index 7a2d83e10..000000000 --- a/runtimes/common/src/lib.rs +++ /dev/null @@ -1,184 +0,0 @@ -// Polimec Blockchain – https://www.polimec.org/ -// Copyright (C) Polimec 2022. All rights reserved. - -// The Polimec Blockchain 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. - -// The Polimec Blockchain 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 . - -#![cfg_attr(not(feature = "std"), no_std)] - -use constants::{AVERAGE_ON_INITIALIZE_RATIO, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO}; -use fees::SplitFeesByRatio; - -pub use sp_consensus_aura::sr25519::AuthorityId; - -pub use opaque::*; - -pub use frame_support::weights::constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; -use frame_support::{ - dispatch::DispatchClass, - parameter_types, - traits::{Contains, ContainsLengthBound, Currency, Get, SortedMembers}, -}; -use frame_system::limits; -use pallet_transaction_payment::{Multiplier, TargetedFeeAdjustment}; -use parachains_common::{Balance, BlockNumber}; -use sp_runtime::{ - generic, - traits::{Bounded, IdentifyAccount, Verify}, - FixedPointNumber, MultiSignature, Perquintill, SaturatedConversion, -}; -use sp_std::marker::PhantomData; - -pub mod constants; -pub mod fees; -pub mod xcm_config; - -/// Opaque types. These are used by the CLI to instantiate machinery that don't -/// need to know the specifics of the runtime. They can then be made to be -/// agnostic over specific formats of data like extrinsics, allowing for them to -/// continue syncing the network through upgrades to even the core data -/// structures. -pub mod opaque { - use super::*; - use sp_runtime::{generic, traits::BlakeTwo256}; - - pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; - /// Opaque block header type. - pub type Header = generic::Header; - /// Opaque block type. - pub type Block = generic::Block; - /// Opaque block identifier type. - pub type BlockId = generic::BlockId; -} - -/// Alias to 512-bit hash when used in the context of a transaction signature on -/// the chain. -pub type Signature = MultiSignature; - -/// Alias to the public key used for this chain, actually a `MultiSigner`. Like -/// the signature, this also isn't a fixed size when encoded, as different -/// cryptos have different size public keys. -pub type AccountPublic = ::Signer; - -/// Alias to the opaque account ID type for this chain, actually a -/// `AccountId32`. This is always 32 bytes. -pub type AccountId = ::AccountId; - -/// The type for looking up accounts. We don't expect more than 4 billion of -/// them, but you never know... -pub type AccountIndex = u32; - -/// Identifier for a chain. 32-bit should be plenty. -pub type ChainId = u32; - -pub type Amount = i128; - -/// Index of a transaction in the chain. -pub type Index = u64; - -/// A hash of some data used by the chain. -pub type Hash = sp_core::H256; - -/// Digest item type. -pub type DigestItem = generic::DigestItem; - -/// A Kilt DID subject identifier. -pub type DidIdentifier = AccountId; - -pub type NegativeImbalanceOf = - as Currency<::AccountId>>::NegativeImbalance; - -// Common constants used in all runtimes. -parameter_types! { - pub const BlockHashCount: BlockNumber = 2400; - /// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less - /// than this will decrease the weight and more will increase. - pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25); - /// The adjustment variable of the runtime. Higher values will cause `TargetBlockFullness` to - /// change the fees more rapidly. - pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(3, 100_000); - /// Minimum amount of the multiplier. This value cannot be too low. A test case should ensure - /// that combined with `AdjustmentVariable`, we can recover from the minimum. - /// See `multiplier_can_grow_from_zero`. - pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128); - /// The maximum amount of the multiplier. - pub MaximumMultiplier: Multiplier = Bounded::max_value(); - /// Maximum length of block. Up to 5MB. - pub RuntimeBlockLength: limits::BlockLength = - limits::BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); - /// Block weights base values and limits. - pub RuntimeBlockWeights: limits::BlockWeights = limits::BlockWeights::builder() - .base_block(BlockExecutionWeight::get()) - .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = ExtrinsicBaseWeight::get(); - }) - .for_class(DispatchClass::Normal, |weights| { - weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); - }) - .for_class(DispatchClass::Operational, |weights| { - weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); - // Operational transactions have some extra reserved space, so that they - // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. - weights.reserved = Some( - MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT, - ); - }) - .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) - .build_or_panic(); - - /// Fee split ratio between treasury and block author (order is important). - pub const FeeSplitRatio: (u32, u32) = (50, 50); -} - -/// Split the fees using a preconfigured Ratio -/// (`runtime_common::FeeSplitRatio`). -pub type FeeSplit = SplitFeesByRatio; - -/// Parameterized slow adjusting fee updated based on -/// https://w3f-research.readthedocs.io/en/latest/polkadot/Token%20Economics.html#-2.-slow-adjusting-mechanism -pub type SlowAdjustingFeeUpdate = - TargetedFeeAdjustment; - -pub struct Tippers(PhantomData, PhantomData); -impl ContainsLengthBound for Tippers -where - R: pallet_membership::Config, -{ - fn max_len() -> usize { - >::MaxMembers::get().saturated_into() - } - - fn min_len() -> usize { - 0 - } -} - -impl SortedMembers for Tippers -where - R: pallet_membership::Config, - pallet_membership::Pallet: SortedMembers + Contains, -{ - fn sorted_members() -> sp_std::vec::Vec { - pallet_membership::Pallet::::sorted_members() - } - - #[cfg(feature = "runtime-benchmarks")] - fn add(who: &R::AccountId) { - pallet_membership::Members::::mutate(|members| match members.binary_search_by(|m| m.cmp(who)) { - Ok(_) => (), - Err(pos) => members - .try_insert(pos, who.clone()) - .expect("Should not fail to add members"), - }) - } -} diff --git a/runtimes/common/src/xcm_config.rs b/runtimes/common/src/xcm_config.rs deleted file mode 100644 index f685ddc7d..000000000 --- a/runtimes/common/src/xcm_config.rs +++ /dev/null @@ -1,160 +0,0 @@ -// Polimec Blockchain – https://www.polimec.org/ -// Copyright (C) Polimec 2022. All rights reserved. - -// The Polimec Blockchain 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. - -// The Polimec Blockchain 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 core::marker::PhantomData; - -use frame_support::{log, match_types, parameter_types}; -use polkadot_parachain::primitives::Sibling; -use xcm::{latest::prelude::*, v3::Weight}; -use xcm_builder::{ - AccountId32Aliases, AllowUnpaidExecutionFrom, CurrencyAdapter, IsConcrete, ParentIsPreset, - SiblingParachainConvertsVia, -}; -use xcm_executor::traits::ShouldExecute; - -use crate::AccountId; - -parameter_types! { - // One XCM operation is 1_000_000_000 weight, almost certainly a conservative estimate. - pub UnitWeightCost: u64 = 1_000_000_000; - pub const MaxInstructions: u32 = 100; -} - -match_types! { - // The legislative of our parent (i.e. Polkadot majority vote for Spiritnet). - pub type ParentLegislative: impl Contains = { - MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Legislative, .. }) } - }; -} - -// Note: This might move to polkadot's xcm module. -/// Deny executing the xcm message if it matches any of the Deny filter -/// regardless of anything else. If it passes the Deny and matches one of the -/// Allow cases, then it is let through. -pub struct DenyThenTry(PhantomData<(Deny, Allow)>); - -impl ShouldExecute for DenyThenTry -where - Deny: ShouldExecute, - Allow: ShouldExecute, -{ - fn should_execute( - origin: &MultiLocation, message: &mut [Instruction], max_weight: Weight, weight_credit: &mut Weight, - ) -> Result<(), ()> { - Deny::should_execute(origin, message, max_weight, weight_credit)?; - Allow::should_execute(origin, message, max_weight, weight_credit) - } -} - -/// Explicitly deny ReserveTransfer to the relay chain. Allow calls from the -/// relay chain governance. -pub type XcmBarrier = DenyThenTry< - DenyReserveTransferToRelayChain, - ( - // We don't allow anything from any sibling chain, therefore the following is not included here: - // * TakeWeightCredit - // * AllowTopLevelPaidExecutionFrom - - // We allow everything from the relay chain if it was sent by the relay chain legislative (i.e., democracy - // vote). Since the relaychain doesn't own KILTs and missing fees shouldn't prevent calls from the relaychain - // legislative, we allow unpaid execution. - AllowUnpaidExecutionFrom, - ), ->; - -/// Reserved funds to the relay chain can't return. See https://github.com/paritytech/polkadot/issues/5233 -pub struct DenyReserveTransferToRelayChain; -impl ShouldExecute for DenyReserveTransferToRelayChain { - fn should_execute( - origin: &MultiLocation, message: &mut [Instruction], _max_weight: Weight, _weight_credit: &mut Weight, - ) -> Result<(), ()> { - if message.iter().any(|inst| { - matches!( - inst, - InitiateReserveWithdraw { - reserve: MultiLocation { - parents: 1, - interior: Here - }, - .. - } | DepositReserveAsset { - dest: MultiLocation { - parents: 1, - interior: Here - }, - .. - } | TransferReserveAsset { - dest: MultiLocation { - parents: 1, - interior: Here - }, - .. - } - ) - }) { - return Err(()); // Deny - } - - // Allow reserve transfers to arrive from relay chain - if matches!( - origin, - MultiLocation { - parents: 1, - interior: Here - } - ) && message.iter().any(|inst| matches!(inst, ReserveAssetDeposited { .. })) - { - log::warn!( - target: "xcm::barriers", - "Unexpected ReserveAssetDeposited from the relay chain", - ); - } - // Permit everything else - Ok(()) - } -} - -parameter_types! { - pub const RelayLocation: MultiLocation = MultiLocation::parent(); - pub const HereLocation: MultiLocation = MultiLocation::here(); -} - -/// Type for specifying how a `MultiLocation` can be converted into an -/// `AccountId`. This is used when determining ownership of accounts for asset -/// transacting and when attempting to use XCM `Transact` in order to determine -/// the dispatch Origin. -pub type LocationToAccountId = ( - // The parent (Relay-chain) origin converts to the b"parent" `AccountId`. - ParentIsPreset, - // Sibling parachain origins convert to AccountId via the `ParaId::into`. - SiblingParachainConvertsVia, - // Straight up local `AccountId32` origins just alias directly to `AccountId`. - AccountId32Aliases, -); - -/// Means for transacting assets on this chain. -pub type LocalAssetTransactor = CurrencyAdapter< - // Use this currency: - Currency, - // Use this currency when it is a fungible asset matching the given location or name: - IsConcrete, - // Do a simple punn to convert an AccountId32 MultiLocation into a native chain account ID: - LocationToAccountId, - // Our chain's account ID type (we can't get away without mentioning it explicitly): - AccountId, - // We don't track any teleports. - (), ->; diff --git a/runtimes/shared-configuration/Cargo.toml b/runtimes/shared-configuration/Cargo.toml new file mode 100644 index 000000000..f52095e35 --- /dev/null +++ b/runtimes/shared-configuration/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "shared-configuration" +description = "Chain shared configuration Polimec" +authors.workspace = true +documentation.workspace = true +edition.workspace = true +homepage.workspace = true +license-file.workspace = true +readme.workspace = true +repository.workspace = true +version.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +smallvec.workspace = true + +# FRAME +frame-system.workspace = true +frame-support.workspace = true +sp-arithmetic.workspace = true +parachains-common.workspace = true + +[features] +default = ["std"] +fast-gov = [] +std = ["frame-support/std", "sp-arithmetic/std", "parachains-common/std"] +runtime-benchmarks = ["frame-support/runtime-benchmarks"] diff --git a/runtimes/testnet/src/weights/mod.rs b/runtimes/shared-configuration/src/assets.rs similarity index 59% rename from runtimes/testnet/src/weights/mod.rs rename to runtimes/shared-configuration/src/assets.rs index 40ae41d0a..6568a765b 100644 --- a/runtimes/testnet/src/weights/mod.rs +++ b/runtimes/shared-configuration/src/assets.rs @@ -14,15 +14,18 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Expose the auto generated weight files. +use crate::{ + currency::{deposit, PLMC}, + Balance, +}; +use frame_support::parameter_types; -pub mod block_weights; -pub mod extrinsic_weights; -pub mod pallet_funding; -pub mod paritydb_weights; -pub mod rocksdb_weights; - -pub use block_weights::constants::BlockExecutionWeight; -pub use extrinsic_weights::constants::ExtrinsicBaseWeight; -pub use paritydb_weights::constants::ParityDbWeight; -pub use rocksdb_weights::constants::RocksDbWeight; +parameter_types! { + pub const AssetDeposit: Balance = 10 * PLMC; + pub const AssetsStringLimit: u32 = 50; + /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) + // https://github.com/paritytech/substrate/blob/069917b/frame/assets/src/lib.rs#L257L271 + pub const MetadataDepositBase: Balance = deposit(1, 68); + pub const MetadataDepositPerByte: Balance = deposit(0, 1); + pub const AssetAccountDeposit: Balance = deposit(1, 18); +} diff --git a/runtimes/shared-configuration/src/currency.rs b/runtimes/shared-configuration/src/currency.rs new file mode 100644 index 000000000..bc401318a --- /dev/null +++ b/runtimes/shared-configuration/src/currency.rs @@ -0,0 +1,64 @@ +// Polimec Blockchain – https://www.polimec.org/ +// Copyright (C) Polimec 2022. All rights reserved. + +// The Polimec Blockchain 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. + +// The Polimec Blockchain 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::Balance; +use frame_support::parameter_types; + +/// One PLMC +pub const PLMC: Balance = 10u128.pow(10); +/// 0.001 PLMC +pub const MILLI_PLMC: Balance = 10u128.pow(7); +/// 0.000_001 PLMC +pub const MICRO_PLMC: Balance = 10u128.pow(4); + +pub const EXISTENTIAL_DEPOSIT: Balance = MILLI_PLMC; + +/// Deposit that must be provided for each occupied storage item. +pub const DEPOSIT_STORAGE_ITEM: Balance = 56 * MILLI_PLMC; +/// Deposit that must be provided for each occupied storage byte. +pub const DEPOSIT_STORAGE_BYTE: Balance = 100 * MICRO_PLMC; + +pub const fn deposit(items: u32, bytes: u32) -> Balance { + (items as Balance * DEPOSIT_STORAGE_ITEM + (bytes as Balance) * DEPOSIT_STORAGE_BYTE) / 100 +} + +#[inline(always)] +pub const fn free_deposit() -> Balance { + deposit(0, 0) +} + +parameter_types! { + /// Relay Chain `TransactionByteFee` / 10 + pub const TransactionByteFee: Balance = 10 * MICRO_PLMC; + pub const DepositBase: Balance = DEPOSIT_STORAGE_ITEM; + pub const DepositFactor: Balance = DEPOSIT_STORAGE_BYTE; + pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; + pub const MaxSignatories: u32 = 64; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +pub mod vesting { + use frame_support::traits::WithdrawReasons; + + use super::*; + + parameter_types! { + pub const MinVestedTransfer: Balance = 10 * PLMC; + pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons = + WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); + } +} diff --git a/runtimes/shared-configuration/src/fee.rs b/runtimes/shared-configuration/src/fee.rs new file mode 100644 index 000000000..a95a31252 --- /dev/null +++ b/runtimes/shared-configuration/src/fee.rs @@ -0,0 +1,46 @@ +// Polimec Blockchain – https://www.polimec.org/ +// Copyright (C) Polimec 2022. All rights reserved. + +// The Polimec Blockchain 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. + +// The Polimec Blockchain 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::{currency::MILLI_PLMC, Balance}; +use frame_support::{ + parameter_types, + weights::{constants::ExtrinsicBaseWeight, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial}, +}; +use parachains_common::SLOT_DURATION; +use smallvec::smallvec; +use sp_arithmetic::Perbill; + +pub struct WeightToFee; +impl WeightToFeePolynomial for WeightToFee { + type Balance = Balance; + + fn polynomial() -> WeightToFeeCoefficients { + // extrinsic base weight (smallest non-zero weight) is mapped to 1/10 CENT: + let p = 10 * MILLI_PLMC; + let q = Balance::from(ExtrinsicBaseWeight::get().ref_time()); + smallvec![WeightToFeeCoefficient { + degree: 1, + negative: false, + coeff_frac: Perbill::from_rational(p % q, q), + coeff_integer: p / q, + }] + } +} + +parameter_types! { + pub const MinimumPeriod: u64 = SLOT_DURATION / 2; + pub const MaxAuthorities: u32 = 100_000; +} diff --git a/runtimes/shared-configuration/src/funding.rs b/runtimes/shared-configuration/src/funding.rs new file mode 100644 index 000000000..a1bf85ad0 --- /dev/null +++ b/runtimes/shared-configuration/src/funding.rs @@ -0,0 +1,64 @@ +// Polimec Blockchain – https://www.polimec.org/ +// Copyright (C) Polimec 2022. All rights reserved. + +// The Polimec Blockchain 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. + +// The Polimec Blockchain 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::{BlockNumber, DAYS}; +use frame_support::{parameter_types, PalletId}; + +#[cfg(feature = "fast-gov")] +pub const EVALUATION_DURATION: BlockNumber = 28; +#[cfg(not(feature = "fast-gov"))] +pub const EVALUATION_DURATION: BlockNumber = 28 * DAYS; + +#[cfg(feature = "fast-gov")] +pub const AUCTION_INITIALIZE_PERIOD_DURATION: BlockNumber = 7; +#[cfg(not(feature = "fast-gov"))] +pub const AUCTION_INITIALIZE_PERIOD_DURATION: BlockNumber = 7 * DAYS; + +#[cfg(feature = "fast-gov")] +pub const ENGLISH_AUCTION_DURATION: BlockNumber = 10; +#[cfg(not(feature = "fast-gov"))] +pub const ENGLISH_AUCTION_DURATION: BlockNumber = 2 * DAYS; + +#[cfg(feature = "fast-gov")] +pub const CANDLE_AUCTION_DURATION: BlockNumber = 5; +#[cfg(not(feature = "fast-gov"))] +pub const CANDLE_AUCTION_DURATION: BlockNumber = 3 * DAYS; + +#[cfg(feature = "fast-gov")] +pub const COMMUNITY_FUNDING_DURATION: BlockNumber = 10; +#[cfg(not(feature = "fast-gov"))] +pub const COMMUNITY_FUNDING_DURATION: BlockNumber = 5 * DAYS; + +#[cfg(feature = "fast-gov")] +pub const REMAINDER_FUNDING_DURATION: BlockNumber = 10; +#[cfg(not(feature = "fast-gov"))] +pub const REMAINDER_FUNDING_DURATION: BlockNumber = DAYS; + +#[cfg(feature = "fast-gov")] +pub const CONTRIBUTION_VESTING_DURATION: BlockNumber = 365; +#[cfg(not(feature = "fast-gov"))] +pub const CONTRIBUTION_VESTING_DURATION: BlockNumber = 365 * DAYS; + +parameter_types! { + pub const EvaluationDuration: BlockNumber = EVALUATION_DURATION; + pub const AuctionInitializePeriodDuration: BlockNumber = AUCTION_INITIALIZE_PERIOD_DURATION; + pub const EnglishAuctionDuration: BlockNumber = ENGLISH_AUCTION_DURATION; + pub const CandleAuctionDuration: BlockNumber = CANDLE_AUCTION_DURATION; + pub const CommunityFundingDuration: BlockNumber = COMMUNITY_FUNDING_DURATION; + pub const RemainderFundingDuration: BlockNumber = REMAINDER_FUNDING_DURATION; + pub const ContributionVestingDuration: BlockNumber = CONTRIBUTION_VESTING_DURATION; + pub const FundingPalletId: PalletId = PalletId(*b"py/cfund"); +} diff --git a/runtimes/shared-configuration/src/governance.rs b/runtimes/shared-configuration/src/governance.rs new file mode 100644 index 000000000..654000553 --- /dev/null +++ b/runtimes/shared-configuration/src/governance.rs @@ -0,0 +1,105 @@ +// Polimec Blockchain – https://www.polimec.org/ +// Copyright (C) Polimec 2022. All rights reserved. + +// The Polimec Blockchain 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. + +// The Polimec Blockchain 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::{ + currency::{deposit, PLMC}, + Balance, +}; +use frame_support::{parameter_types, PalletId}; +use parachains_common::{BlockNumber, DAYS, HOURS}; +use sp_arithmetic::Permill; + +pub const MIN_DEPOSIT: Balance = PLMC; + +#[cfg(feature = "fast-gov")] +pub const LAUNCH_PERIOD: BlockNumber = 7 * MINUTES; +#[cfg(not(feature = "fast-gov"))] +pub const LAUNCH_PERIOD: BlockNumber = 7 * DAYS; + +#[cfg(feature = "fast-gov")] +pub const VOTING_PERIOD: BlockNumber = 7 * MINUTES; +#[cfg(not(feature = "fast-gov"))] +pub const VOTING_PERIOD: BlockNumber = 7 * DAYS; + +#[cfg(feature = "fast-gov")] +pub const FAST_TRACK_VOTING_PERIOD: BlockNumber = 3 * MINUTES; +#[cfg(not(feature = "fast-gov"))] +pub const FAST_TRACK_VOTING_PERIOD: BlockNumber = 3 * HOURS; + +#[cfg(feature = "fast-gov")] +pub const ENACTMENT_PERIOD: BlockNumber = 8 * MINUTES; +#[cfg(not(feature = "fast-gov"))] +pub const ENACTMENT_PERIOD: BlockNumber = DAYS; + +#[cfg(feature = "fast-gov")] +pub const COOLOFF_PERIOD: BlockNumber = 7 * MINUTES; +#[cfg(not(feature = "fast-gov"))] +pub const COOLOFF_PERIOD: BlockNumber = 7 * DAYS; + +#[cfg(feature = "fast-gov")] +pub const SPEND_PERIOD: BlockNumber = 6 * MINUTES; +#[cfg(not(feature = "fast-gov"))] +pub const SPEND_PERIOD: BlockNumber = 6 * DAYS; + +#[cfg(feature = "fast-gov")] +pub const ROTATION_PERIOD: BlockNumber = 80 * MINUTES; +#[cfg(not(feature = "fast-gov"))] +pub const ROTATION_PERIOD: BlockNumber = 80 * HOURS; + +#[cfg(feature = "fast-gov")] +pub const TERM_DURATION: BlockNumber = 15 * MINUTES; +#[cfg(not(feature = "fast-gov"))] +pub const TERM_DURATION: BlockNumber = DAYS; + +#[cfg(feature = "fast-gov")] +pub const COUNCIL_MOTION_DURATION: BlockNumber = 4 * MINUTES; +#[cfg(not(feature = "fast-gov"))] +pub const COUNCIL_MOTION_DURATION: BlockNumber = 3 * DAYS; + +#[cfg(feature = "fast-gov")] +pub const TECHNICAL_MOTION_DURATION: BlockNumber = 4 * MINUTES; +#[cfg(not(feature = "fast-gov"))] +pub const TECHNICAL_MOTION_DURATION: BlockNumber = 3 * DAYS; + +parameter_types! { + // Democracy Pallet + pub const LaunchPeriod: BlockNumber = LAUNCH_PERIOD; + pub const VotingPeriod: BlockNumber = VOTING_PERIOD; + pub const FastTrackVotingPeriod: BlockNumber = FAST_TRACK_VOTING_PERIOD; + pub const MinimumDeposit: Balance = MIN_DEPOSIT; + pub const EnactmentPeriod: BlockNumber = ENACTMENT_PERIOD; + pub const CooloffPeriod: BlockNumber = COOLOFF_PERIOD; + // Council Pallet + pub const CouncilMotionDuration: BlockNumber = COUNCIL_MOTION_DURATION; + pub const CouncilMaxProposals: u32 = 100; + pub const CouncilMaxMembers: u32 = 100; + // Technical Committee + pub const TechnicalMotionDuration: BlockNumber = TECHNICAL_MOTION_DURATION; + pub const TechnicalMaxProposals: u32 = 100; + pub const TechnicalMaxMembers: u32 = 100; + // Tipper Group + pub const TipperMaxMembers: u32 = 21; + // Extras + pub const PreimageBaseDeposit: Balance = deposit(2, 64); + pub const MaxProposals: u32 = 100; + //Treasury + pub const ProposalBond: Permill = Permill::from_percent(5); + pub const ProposalBondMinimum: Balance = 20 * PLMC; + pub const SpendPeriod: BlockNumber = SPEND_PERIOD; + pub const Burn: Permill = Permill::zero(); + pub const MaxApprovals: u32 = 100; + pub const TreasuryId: PalletId = PalletId(*b"plmc/tsy"); +} diff --git a/runtimes/base/src/weights/mod.rs b/runtimes/shared-configuration/src/lib.rs similarity index 67% rename from runtimes/base/src/weights/mod.rs rename to runtimes/shared-configuration/src/lib.rs index fb04fe6e5..01fd24175 100644 --- a/runtimes/base/src/weights/mod.rs +++ b/runtimes/shared-configuration/src/lib.rs @@ -14,14 +14,15 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Expose the auto generated weight files. +#![cfg_attr(not(feature = "std"), no_std)] -pub mod block_weights; -pub mod extrinsic_weights; -pub mod paritydb_weights; -pub mod rocksdb_weights; +pub mod assets; +pub mod currency; +pub mod fee; +pub mod funding; +pub mod governance; +pub mod staking; +pub mod weights; -pub use block_weights::constants::BlockExecutionWeight; -pub use extrinsic_weights::constants::ExtrinsicBaseWeight; -pub use paritydb_weights::constants::ParityDbWeight; -pub use rocksdb_weights::constants::RocksDbWeight; +/// Common types +pub use parachains_common::{Balance, BlockNumber, DAYS}; diff --git a/runtimes/shared-configuration/src/staking.rs b/runtimes/shared-configuration/src/staking.rs new file mode 100644 index 000000000..66292b5d4 --- /dev/null +++ b/runtimes/shared-configuration/src/staking.rs @@ -0,0 +1,38 @@ +// Polimec Blockchain – https://www.polimec.org/ +// Copyright (C) Polimec 2022. All rights reserved. + +// The Polimec Blockchain 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. + +// The Polimec Blockchain 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::currency::PLMC; +use frame_support::parameter_types; + +// Since a Round is 6 hours, one week, expresses as `RoundIndex` is 4 * 7 +const WEEK_IN_ROUNDS: u32 = 4 * 7; + +parameter_types! { + pub const MinBlocksPerRound: u32 = 10; + pub const LeaveCandidatesDelay: u32 = WEEK_IN_ROUNDS; + pub const CandidateBondLessDelay: u32 = WEEK_IN_ROUNDS; + pub const LeaveDelegatorsDelay: u32 = WEEK_IN_ROUNDS; + pub const RevokeDelegationDelay: u32 = WEEK_IN_ROUNDS; + pub const DelegationBondLessDelay: u32 = WEEK_IN_ROUNDS; + pub const RewardPaymentDelay: u32 = 2; + pub const MinSelectedCandidates: u32 = 5; + pub const MaxTopDelegationsPerCandidate: u32 = 300; + pub const MaxBottomDelegationsPerCandidate: u32 = 50; + pub const MaxDelegationsPerDelegator: u32 = 100; + pub const MinCandidateStk: u128 = 20_000 * PLMC; + pub const MinDelegatorStk: u128 = 50 * PLMC; + pub const MinDelegation: u128 = 50 * PLMC; +} diff --git a/runtimes/base/src/weights/block_weights.rs b/runtimes/shared-configuration/src/weights/block_weights.rs similarity index 87% rename from runtimes/base/src/weights/block_weights.rs rename to runtimes/shared-configuration/src/weights/block_weights.rs index 451c27f95..b17b64afc 100644 --- a/runtimes/base/src/weights/block_weights.rs +++ b/runtimes/shared-configuration/src/weights/block_weights.rs @@ -23,7 +23,7 @@ pub mod constants { parameter_types! { /// Importing a block with 0 Extrinsics. pub const BlockExecutionWeight: Weight = - Weight::from_ref_time(constants::WEIGHT_REF_TIME_PER_NANOS.saturating_mul(5_000_000)); + Weight::from_parts(constants::WEIGHT_REF_TIME_PER_NANOS.saturating_mul(5_000_000), 0); } #[cfg(test)] @@ -43,10 +43,7 @@ pub mod constants { "Weight should be at least 100 µs." ); // At most 50 ms. - assert!( - w.ref_time() <= 50u64 * constants::WEIGHT_REF_TIME_PER_MILLIS, - "Weight should be at most 50 ms." - ); + assert!(w.ref_time() <= 50u64 * constants::WEIGHT_REF_TIME_PER_MILLIS, "Weight should be at most 50 ms."); } } } diff --git a/runtimes/base/src/weights/extrinsic_weights.rs b/runtimes/shared-configuration/src/weights/extrinsic_weights.rs similarity index 80% rename from runtimes/base/src/weights/extrinsic_weights.rs rename to runtimes/shared-configuration/src/weights/extrinsic_weights.rs index 0819bab8a..5aabc4cdb 100644 --- a/runtimes/base/src/weights/extrinsic_weights.rs +++ b/runtimes/shared-configuration/src/weights/extrinsic_weights.rs @@ -23,7 +23,7 @@ pub mod constants { parameter_types! { /// Executing a NO-OP `System::remarks` Extrinsic. pub const ExtrinsicBaseWeight: Weight = - Weight::from_ref_time(constants::WEIGHT_REF_TIME_PER_NANOS.saturating_mul(125_000)); + Weight::from_parts(constants::WEIGHT_REF_TIME_PER_NANOS.saturating_mul(125_000), 0); } #[cfg(test)] @@ -38,15 +38,9 @@ pub mod constants { let w = super::constants::ExtrinsicBaseWeight::get(); // At least 10 µs. - assert!( - w.ref_time() >= 10u64 * constants::WEIGHT_REF_TIME_PER_MICROS, - "Weight should be at least 10 µs." - ); + assert!(w.ref_time() >= 10u64 * constants::WEIGHT_REF_TIME_PER_MICROS, "Weight should be at least 10 µs."); // At most 1 ms. - assert!( - w.ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Weight should be at most 1 ms." - ); + assert!(w.ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, "Weight should be at most 1 ms."); } } } diff --git a/runtimes/shared-configuration/src/weights/mod.rs b/runtimes/shared-configuration/src/weights/mod.rs new file mode 100644 index 000000000..ea1fd8720 --- /dev/null +++ b/runtimes/shared-configuration/src/weights/mod.rs @@ -0,0 +1,64 @@ +// Polimec Blockchain – https://www.polimec.org/ +// Copyright (C) Polimec 2022. All rights reserved. + +// The Polimec Blockchain 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. + +// The Polimec Blockchain 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 . + +//! Expose the auto generated weight files. + +pub mod block_weights; +pub mod extrinsic_weights; +pub mod paritydb_weights; +pub mod rocksdb_weights; + +pub use block_weights::constants::BlockExecutionWeight; +pub use extrinsic_weights::constants::ExtrinsicBaseWeight; +use frame_support::{dispatch::DispatchClass, parameter_types, weights::Weight}; +use parachains_common::{AVERAGE_ON_INITIALIZE_RATIO, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO}; +pub use paritydb_weights::constants::ParityDbWeight; +pub use rocksdb_weights::constants::RocksDbWeight; + +use frame_system::limits::{BlockLength, BlockWeights}; +use sp_arithmetic::Perbill; + +parameter_types! { + // This part is copied from Substrate's `bin/node/runtime/src/lib.rs`. + // The `RuntimeBlockLength` and `RuntimeBlockWeights` exist here because the + // `DeletionWeightLimit` and `DeletionQueueDepth` depend on those to parameterize + // the lazy contract deletion. + pub RuntimeBlockLength: BlockLength = + BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); + pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() + .base_block(BlockExecutionWeight::get()) + .for_class(DispatchClass::all(), |weights| { + weights.base_extrinsic = ExtrinsicBaseWeight::get(); + }) + .for_class(DispatchClass::Normal, |weights| { + weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); + }) + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); + // Operational transactions have some extra reserved space, so that they + // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. + weights.reserved = Some( + MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT + ); + }) + .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) + .build_or_panic(); + pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); + pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block; + pub MaxCollectivesProposalWeight: Weight = Perbill::from_percent(50) * RuntimeBlockWeights::get().max_block; + pub const MaxScheduledPerBlock: u32 = 50; +} diff --git a/runtimes/base/src/weights/paritydb_weights.rs b/runtimes/shared-configuration/src/weights/paritydb_weights.rs similarity index 100% rename from runtimes/base/src/weights/paritydb_weights.rs rename to runtimes/shared-configuration/src/weights/paritydb_weights.rs diff --git a/runtimes/base/src/weights/rocksdb_weights.rs b/runtimes/shared-configuration/src/weights/rocksdb_weights.rs similarity index 100% rename from runtimes/base/src/weights/rocksdb_weights.rs rename to runtimes/shared-configuration/src/weights/rocksdb_weights.rs diff --git a/runtimes/standalone/Cargo.toml b/runtimes/standalone/Cargo.toml index fc036bdc1..1287744a3 100644 --- a/runtimes/standalone/Cargo.toml +++ b/runtimes/standalone/Cargo.toml @@ -31,6 +31,7 @@ sp-session.workspace = true sp-std.workspace = true sp-transaction-pool.workspace = true sp-version.workspace = true +sp-consensus-grandpa.workspace = true # FRAME pallet-aura.workspace = true @@ -66,16 +67,14 @@ hex-literal = { workspace = true, optional = true } # Local Dependencies pallet-funding.workspace = true -pallet-credentials.workspace = true -polimec-traits.workspace = true -runtime-common.workspace = true +shared-configuration.workspace = true [build-dependencies] substrate-wasm-builder.workspace = true [features] default = ["std"] -fast-gov = ["runtime-common/fast-gov"] +fast-gov = [] std = [ "frame-benchmarking?/std", "parity-scale-codec/std", @@ -107,7 +106,6 @@ std = [ "sp-std/std", "sp-transaction-pool/std", "sp-version/std", - "pallet-credentials/std", "pallet-funding/std", "pallet-democracy/std", "pallet-collective/std", @@ -115,9 +113,9 @@ std = [ "pallet-session/std", "pallet-authorship/std", "pallet-insecure-randomness-collective-flip/std", - "polimec-traits/std", "pallet-vesting/std", - "runtime-common/std" + "shared-configuration/std", + "sp-consensus-grandpa/std" ] runtime-benchmarks = [ @@ -132,13 +130,10 @@ runtime-benchmarks = [ "sp-runtime/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-collective/runtime-benchmarks", - "pallet-credentials/runtime-benchmarks", "pallet-democracy/runtime-benchmarks", "pallet-funding/runtime-benchmarks", "pallet-scheduler/runtime-benchmarks", - "polimec-traits/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", - "runtime-common/runtime-benchmarks" ] try-runtime = [ "frame-executive/try-runtime", @@ -154,13 +149,10 @@ try-runtime = [ "pallet-transaction-payment/try-runtime", "pallet-authorship/try-runtime", "pallet-collective/try-runtime", - "pallet-credentials/try-runtime", "pallet-democracy/try-runtime", "pallet-funding/try-runtime", "pallet-insecure-randomness-collective-flip/try-runtime", "pallet-scheduler/try-runtime", "pallet-session/try-runtime", - "polimec-traits/try-runtime", "pallet-vesting/try-runtime", - "runtime-common/try-runtime" ] diff --git a/runtimes/standalone/build.rs b/runtimes/standalone/build.rs index b81f7762c..657bcc0d1 100644 --- a/runtimes/standalone/build.rs +++ b/runtimes/standalone/build.rs @@ -17,9 +17,5 @@ use substrate_wasm_builder::WasmBuilder; fn main() { - WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build() + WasmBuilder::new().with_current_project().export_heap_base().import_memory().build() } diff --git a/runtimes/standalone/src/lib.rs b/runtimes/standalone/src/lib.rs index 9975c2faa..a419de698 100644 --- a/runtimes/standalone/src/lib.rs +++ b/runtimes/standalone/src/lib.rs @@ -26,7 +26,7 @@ pub use frame_support::{ construct_runtime, parameter_types, traits::{ ConstU128, ConstU32, ConstU64, ConstU8, Contains, EitherOfDiverse, EqualPrivilegeOnly, KeyOwnerProofSystem, - Randomness, StorageInfo, + Randomness, StorageInfo, WithdrawReasons, }, weights::{ constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND}, @@ -40,7 +40,7 @@ use frame_system::EnsureSigned; pub use frame_system::{Call as SystemCall, EnsureRoot}; pub use pallet_balances::Call as BalancesCall; use pallet_funding::{BondType, Multiplier as FundingMultiplier}; -use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; +use pallet_grandpa::AuthorityId as GrandpaId; pub use pallet_timestamp::Call as TimestampCall; use pallet_transaction_payment::{ConstFeeMultiplier, CurrencyAdapter, Multiplier}; use sp_api::impl_runtime_apis; @@ -62,6 +62,16 @@ use sp_std::prelude::*; use sp_version::NativeVersion; use sp_version::RuntimeVersion; +pub use shared_configuration::{ + assets::*, + currency::{vesting::*, *}, + fee::*, + funding::*, + governance::*, + staking::*, + weights::*, +}; + // Make the WASM binary available. #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); @@ -167,10 +177,7 @@ pub const MICRO_PLMC: Balance = 10u128.pow(4); /// The version information used to identify this runtime when compiled natively. #[cfg(feature = "std")] pub fn native_version() -> NativeVersion { - NativeVersion { - runtime_version: VERSION, - can_author_with: Default::default(), - } + NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); @@ -192,55 +199,55 @@ parameter_types! { // Configure FRAME pallets to include in runtime. impl frame_system::Config for Runtime { + /// The data to be stored in an account. + type AccountData = pallet_balances::AccountData; + /// The identifier used to distinguish between accounts. + type AccountId = AccountId; /// The basic call filter to use in dispatchable. type BaseCallFilter = frame_support::traits::Everything; - /// Block & extrinsics weights: base values and limits. - type BlockWeights = BlockWeights; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = BlockHashCount; /// The maximum length of a block (in bytes). type BlockLength = BlockLength; - /// The identifier used to distinguish between accounts. - type AccountId = AccountId; - /// The aggregated dispatch type that is available for extrinsics. - 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. - type Index = Index; /// The index type for blocks. type BlockNumber = BlockNumber; + /// Block & extrinsics weights: base values and limits. + type BlockWeights = BlockWeights; + /// The weight of database operations that the runtime can invoke. + type DbWeight = RocksDbWeight; /// The type for hashing blocks and tries. type Hash = Hash; /// The hashing algorithm used. type Hashing = BlakeTwo256; /// The header type. type Header = generic::Header; - /// The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; - /// The ubiquitous origin type. - 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. - type DbWeight = RocksDbWeight; - /// Version of the runtime. - type Version = Version; + /// The index type for storing how many extrinsics an account has signed. + type Index = Index; + /// The lookup mechanism to get account ID from whatever is passed in dispatchers. + type Lookup = AccountIdLookup; + type MaxConsumers = frame_support::traits::ConstU32<16>; + /// What to do if an account is fully reaped from the system. + type OnKilledAccount = (); + /// What to do if a new account is created. + type OnNewAccount = (); + /// The set code logic, just the default since we're not a parachain. + type OnSetCode = (); /// Converts a module to the index of the module in `construct_runtime!`. /// /// This type is being generated by `construct_runtime!`. type PalletInfo = PalletInfo; - /// What to do if a new account is created. - type OnNewAccount = (); - /// What to do if an account is fully reaped from the system. - type OnKilledAccount = (); - /// The data to be stored in an account. - type AccountData = pallet_balances::AccountData; - /// Weight information for the extrinsics of this pallet. - type SystemWeightInfo = (); + /// The aggregated dispatch type that is available for extrinsics. + type RuntimeCall = RuntimeCall; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + /// The ubiquitous origin type. + type RuntimeOrigin = RuntimeOrigin; /// This is used as an identifier of the chain. 42 is the generic substrate prefix. type SS58Prefix = SS58Prefix; - /// The set code logic, just the default since we're not a parachain. - type OnSetCode = (); - type MaxConsumers = frame_support::traits::ConstU32<16>; + /// Weight information for the extrinsics of this pallet. + type SystemWeightInfo = (); + /// Version of the runtime. + type Version = Version; } impl pallet_insecure_randomness_collective_flip::Config for Runtime {} @@ -252,45 +259,35 @@ impl pallet_aura::Config for Runtime { } impl pallet_grandpa::Config for Runtime { + type EquivocationReportSystem = (); + type KeyOwnerProof = sp_core::Void; + type MaxAuthorities = ConstU32<32>; + type MaxSetIdSessionEntries = ConstU64<0>; type RuntimeEvent = RuntimeEvent; - - type KeyOwnerProofSystem = (); - - type KeyOwnerProof = >::Proof; - - type KeyOwnerIdentification = - >::IdentificationTuple; - - type HandleEquivocation = (); - type WeightInfo = (); - type MaxAuthorities = ConstU32<32>; - type MaxSetIdSessionEntries = (); } impl pallet_timestamp::Config for Runtime { - /// A timestamp: milliseconds since the unix epoch. + type MinimumPeriod = MinimumPeriod; type Moment = u64; type OnTimestampSet = Aura; - type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>; type WeightInfo = (); } -/// Existential deposit. -pub const EXISTENTIAL_DEPOSIT: u128 = 500; - impl pallet_balances::Config for Runtime { - type MaxLocks = ConstU32<50>; - type MaxReserves = ConstU32<50>; - type ReserveIdentifier = BondType; - /// The type for recording an account's balance. + type AccountStore = System; type Balance = Balance; - /// The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; type DustRemoval = (); - type ExistentialDeposit = ConstU128; - type AccountStore = System; - type WeightInfo = pallet_balances::weights::SubstrateWeight; + type ExistentialDeposit = ExistentialDeposit; + type FreezeIdentifier = (); + type HoldIdentifier = (); + type MaxFreezes = MaxReserves; + type MaxHolds = MaxLocks; + type MaxLocks = MaxLocks; + type MaxReserves = MaxReserves; + type ReserveIdentifier = BondType; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); } parameter_types! { @@ -298,59 +295,40 @@ parameter_types! { } impl pallet_transaction_payment::Config for Runtime { - type RuntimeEvent = RuntimeEvent; + type FeeMultiplierUpdate = ConstFeeMultiplier; + type LengthToFee = IdentityFee; type OnChargeTransaction = CurrencyAdapter; type OperationalFeeMultiplier = ConstU8<5>; + type RuntimeEvent = RuntimeEvent; type WeightToFee = IdentityFee; - type LengthToFee = IdentityFee; - type FeeMultiplierUpdate = ConstFeeMultiplier; } impl pallet_sudo::Config for Runtime { - type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; -} - -pub const fn deposit(items: u32, bytes: u32) -> Balance { - items as Balance * 15 * MICRO_PLMC + (bytes as Balance) * 6 * MICRO_PLMC -} - -pub const fn free_deposit() -> Balance { - 0 * MICRO_PLMC -} - -parameter_types! { - pub const AssetDeposit: Balance = PLMC; // 1 UNIT deposit to create asset - pub const ApprovalDeposit: Balance = EXISTENTIAL_DEPOSIT; - pub const AssetAccountDeposit: Balance = deposit(1, 16); - pub const AssetsStringLimit: u32 = 50; - /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) - // https://github.com/paritytech/substrate/blob/069917b/frame/assets/src/lib.rs#L257L271 - pub const MetadataDepositBase: Balance = free_deposit(); - pub const MetadataDepositPerByte: Balance = free_deposit(); + type RuntimeEvent = RuntimeEvent; } impl pallet_assets::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Balance = Balance; + type ApprovalDeposit = ExistentialDeposit; + type AssetAccountDeposit = AssetAccountDeposit; + type AssetDeposit = AssetDeposit; type AssetId = u32; type AssetIdParameter = parity_scale_codec::Compact; - type Currency = Balances; + type Balance = Balance; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); + type CallbackHandle = (); type CreateOrigin = AsEnsureOriginWithArg>; + type Currency = Balances; + type Extra = (); type ForceOrigin = EnsureRoot; - type AssetDeposit = AssetDeposit; + type Freezer = (); type MetadataDepositBase = MetadataDepositBase; type MetadataDepositPerByte = MetadataDepositPerByte; - type ApprovalDeposit = ApprovalDeposit; + type RemoveItemsLimit = frame_support::traits::ConstU32<1000>; + type RuntimeEvent = RuntimeEvent; type StringLimit = AssetsStringLimit; - type Freezer = (); - type Extra = (); type WeightInfo = (); - type CallbackHandle = (); - type AssetAccountDeposit = AssetAccountDeposit; - type RemoveItemsLimit = frame_support::traits::ConstU32<1000>; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); } parameter_types! { @@ -365,57 +343,45 @@ parameter_types! { } impl pallet_funding::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ProjectIdentifier = u32; - type ProjectIdParameter = parity_scale_codec::Compact; - type Multiplier = FundingMultiplier; + type AuctionInitializePeriodDuration = AuctionInitializePeriodDuration; type Balance = Balance; - type NativeCurrency = Balances; - type FundingCurrency = Balances; - type ContributionTokenCurrency = Assets; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); type BidId = u128; - type Randomness = Random; - type HandleMembers = Credentials; - type StringLimit = ConstU32<64>; - type PreImageLimit = ConstU32<1024>; - type EvaluationDuration = EvaluationDuration; - type AuctionInitializePeriodDuration = AuctionInitializePeriodDuration; - type EnglishAuctionDuration = EnglishAuctionDuration; type CandleAuctionDuration = CandleAuctionDuration; type CommunityFundingDuration = CommunityRoundDuration; - type RemainderFundingDuration = RemainderFundingDuration; - type PalletId = FundingPalletId; + type ContributionTokenCurrency = Assets; + type ContributionVesting = ContributionVestingDuration; + type EnglishAuctionDuration = EnglishAuctionDuration; + type EvaluationDuration = EvaluationDuration; + type FundingCurrency = Balances; + type MaxContributionsPerUser = ConstU32<64>; type MaxProjectsToUpdatePerBlock = ConstU32<100>; type MaximumBidsPerUser = ConstU32<256>; - type MaxContributionsPerUser = ConstU32<64>; - type ContributionVesting = ContributionVestingDuration; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); - type WeightInfo = (); -} - -impl pallet_credentials::Config for Runtime { + type Multiplier = FundingMultiplier; + type NativeCurrency = Balances; + type PalletId = FundingPalletId; + type PreImageLimit = ConstU32<1024>; + type ProjectIdParameter = parity_scale_codec::Compact; + type ProjectIdentifier = u32; + type Randomness = Random; + type RemainderFundingDuration = RemainderFundingDuration; type RuntimeEvent = RuntimeEvent; - type AddOrigin = EnsureRoot; - type RemoveOrigin = EnsureRoot; - type SwapOrigin = EnsureRoot; - type ResetOrigin = EnsureRoot; - type PrimeOrigin = EnsureRoot; - type MembershipInitialized = (); - type MembershipChanged = (); + type StringLimit = ConstU32<64>; + type WeightInfo = (); } impl pallet_scheduler::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeOrigin = RuntimeOrigin; + type MaxScheduledPerBlock = (); + type MaximumWeight = (); + type OriginPrivilegeCmp = EqualPrivilegeOnly; type PalletsOrigin = OriginCaller; + type Preimages = (); type RuntimeCall = RuntimeCall; - type MaximumWeight = (); + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; type ScheduleOrigin = EnsureRoot; - type MaxScheduledPerBlock = (); type WeightInfo = (); - type OriginPrivilegeCmp = EqualPrivilegeOnly; - type Preimages = (); } parameter_types! { @@ -426,15 +392,16 @@ parameter_types! { type CouncilCollective = pallet_collective::Instance1; impl pallet_collective::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; + type DefaultVote = pallet_collective::PrimeDefaultVote; + type MaxMembers = CouncilMaxMembers; + type MaxProposalWeight = MaxCollectivesProposalWeight; + type MaxProposals = CouncilMaxProposals; + type MotionDuration = CouncilMotionDuration; type Proposal = RuntimeCall; type RuntimeEvent = RuntimeEvent; - type MotionDuration = CouncilMotionDuration; - type MaxProposals = CouncilMaxProposals; - type MaxMembers = CouncilMaxMembers; - type DefaultVote = pallet_collective::PrimeDefaultVote; - type WeightInfo = pallet_collective::weights::SubstrateWeight; + type RuntimeOrigin = RuntimeOrigin; type SetMembersOrigin = EnsureRoot; + type WeightInfo = pallet_collective::weights::SubstrateWeight; } parameter_types! { @@ -445,15 +412,16 @@ parameter_types! { type TechnicalCollective = pallet_collective::Instance2; impl pallet_collective::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; + type DefaultVote = pallet_collective::PrimeDefaultVote; + type MaxMembers = TechnicalMaxMembers; + type MaxProposalWeight = MaxCollectivesProposalWeight; + type MaxProposals = TechnicalMaxProposals; + type MotionDuration = TechnicalMotionDuration; type Proposal = RuntimeCall; type RuntimeEvent = RuntimeEvent; - type MotionDuration = TechnicalMotionDuration; - type MaxProposals = TechnicalMaxProposals; - type MaxMembers = TechnicalMaxMembers; - type DefaultVote = pallet_collective::PrimeDefaultVote; - type WeightInfo = pallet_collective::weights::SubstrateWeight; + type RuntimeOrigin = RuntimeOrigin; type SetMembersOrigin = EnsureRoot; + type WeightInfo = pallet_collective::weights::SubstrateWeight; } parameter_types! { @@ -470,49 +438,50 @@ parameter_types! { } impl pallet_democracy::Config for Runtime { - type RuntimeEvent = RuntimeEvent; + type BlacklistOrigin = EnsureRoot; + // To cancel a proposal before it has been passed, the technical committee must be unanimous or + // Root must agree. + type CancelProposalOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, + >; + // To cancel a proposal which has been passed, 2/3 of the council must agree to it. + type CancellationOrigin = pallet_collective::EnsureProportionAtLeast; + type CooloffPeriod = CooloffPeriod; type Currency = Balances; type EnactmentPeriod = EnactmentPeriod; - type LaunchPeriod = LaunchPeriod; - type VotingPeriod = VotingPeriod; - type VoteLockingPeriod = EnactmentPeriod; // Same as EnactmentPeriod - type MinimumDeposit = MinimumDeposit; - /// A straight majority of the council can decide what their next motion is. - type ExternalOrigin = pallet_collective::EnsureProportionAtLeast; - /// A super-majority can have the next scheduled referendum be a straight majority-carries vote. - type ExternalMajorityOrigin = pallet_collective::EnsureProportionAtLeast; /// A unanimous council can have the next scheduled referendum be a straight default-carries /// (NTB) vote. type ExternalDefaultOrigin = pallet_collective::EnsureProportionAtLeast; + /// A super-majority can have the next scheduled referendum be a straight majority-carries vote. + type ExternalMajorityOrigin = pallet_collective::EnsureProportionAtLeast; + /// A straight majority of the council can decide what their next motion is. + type ExternalOrigin = pallet_collective::EnsureProportionAtLeast; /// Two thirds of the technical committee can have an ExternalMajority/ExternalDefault vote /// be tabled immediately and with a shorter voting/enactment period. type FastTrackOrigin = pallet_collective::EnsureProportionAtLeast; - type InstantOrigin = pallet_collective::EnsureProportionAtLeast; - type InstantAllowed = frame_support::traits::ConstBool; type FastTrackVotingPeriod = FastTrackVotingPeriod; - // To cancel a proposal which has been passed, 2/3 of the council must agree to it. - type CancellationOrigin = pallet_collective::EnsureProportionAtLeast; - // To cancel a proposal before it has been passed, the technical committee must be unanimous or - // Root must agree. - type CancelProposalOrigin = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, - >; - type BlacklistOrigin = EnsureRoot; + type InstantAllowed = frame_support::traits::ConstBool; + type InstantOrigin = pallet_collective::EnsureProportionAtLeast; + type LaunchPeriod = LaunchPeriod; + type MaxBlacklisted = (); + type MaxDeposits = (); + type MaxProposals = MaxProposals; + type MaxVotes = ConstU32<100>; + // Same as EnactmentPeriod + type MinimumDeposit = MinimumDeposit; + type PalletsOrigin = OriginCaller; + type Preimages = (); + type RuntimeEvent = RuntimeEvent; + type Scheduler = Scheduler; + type Slash = (); + type SubmitOrigin = EnsureSigned; // Any single technical committee member may veto a coming council proposal, however they can // only do it once and it lasts only for the cool-off period. type VetoOrigin = pallet_collective::EnsureMember; - type CooloffPeriod = CooloffPeriod; - type Slash = (); - type Scheduler = Scheduler; - type PalletsOrigin = OriginCaller; - type MaxVotes = ConstU32<100>; + type VoteLockingPeriod = EnactmentPeriod; + type VotingPeriod = VotingPeriod; type WeightInfo = pallet_democracy::weights::SubstrateWeight; - type MaxProposals = MaxProposals; - type Preimages = (); - type MaxDeposits = (); - type MaxBlacklisted = (); - type SubmitOrigin = EnsureSigned; } parameter_types! { @@ -521,14 +490,14 @@ parameter_types! { } impl pallet_session::Config for Runtime { + type Keys = opaque::SessionKeys; + type NextSessionRotation = (); type RuntimeEvent = RuntimeEvent; + type SessionHandler = ::KeyTypeIdProviders; + type SessionManager = (); + type ShouldEndSession = pallet_session::PeriodicSessions; type ValidatorId = AccountId; type ValidatorIdOf = (); - type ShouldEndSession = pallet_session::PeriodicSessions; - type NextSessionRotation = (); - type SessionManager = (); - type SessionHandler = ::KeyTypeIdProviders; - type Keys = opaque::SessionKeys; type WeightInfo = (); } @@ -537,8 +506,8 @@ parameter_types! { } impl pallet_authorship::Config for Runtime { - type FindAuthor = pallet_session::FindAccountFromAuthorIndex; type EventHandler = (); + type FindAuthor = pallet_session::FindAccountFromAuthorIndex; } parameter_types! { @@ -550,29 +519,37 @@ parameter_types! { } impl pallet_multisig::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; type Currency = Balances; type DepositBase = DepositBase; type DepositFactor = DepositFactor; type MaxSignatories = MaxSignatories; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } impl pallet_utility::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } +parameter_types! { + /// Vesting Pallet. Copied from Kusama & Polkadot runtime + pub const MinVestedTransfer: Balance = 100 * MILLI_PLMC; + pub UnvestedFundsAllowedWithdrawReasons: WithdrawReasons = + WithdrawReasons::except(WithdrawReasons::TRANSFER | WithdrawReasons::RESERVE); +} + impl pallet_vesting::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; type BlockNumberToBalance = ConvertInto; - type MinVestedTransfer = runtime_common::constants::MinVestedTransfer; + type Currency = Balances; + type MinVestedTransfer = MinVestedTransfer; + type RuntimeEvent = RuntimeEvent; + type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; type WeightInfo = pallet_vesting::weights::SubstrateWeight; - type UnvestedFundsAllowedWithdrawReasons = runtime_common::constants::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; @@ -613,7 +590,6 @@ construct_runtime!( // Include the custom logic PolimecFunding: pallet_funding, - Credentials: pallet_credentials, } ); @@ -672,6 +648,14 @@ impl_runtime_apis! { fn metadata() -> OpaqueMetadata { OpaqueMetadata::new(Runtime::metadata().into()) } + + fn metadata_at_version(version: u32) -> Option { + Runtime::metadata_at_version(version) + } + + fn metadata_versions() -> sp_std::vec::Vec { + Runtime::metadata_versions() + } } impl sp_block_builder::BlockBuilder for Runtime { @@ -733,29 +717,29 @@ impl_runtime_apis! { } } - impl fg_primitives::GrandpaApi for Runtime { - fn grandpa_authorities() -> GrandpaAuthorityList { + impl sp_consensus_grandpa::GrandpaApi for Runtime { + fn grandpa_authorities() -> sp_consensus_grandpa::AuthorityList { Grandpa::grandpa_authorities() } - fn current_set_id() -> fg_primitives::SetId { + fn current_set_id() -> sp_consensus_grandpa::SetId { Grandpa::current_set_id() } fn submit_report_equivocation_unsigned_extrinsic( - _equivocation_proof: fg_primitives::EquivocationProof< + _equivocation_proof: sp_consensus_grandpa::EquivocationProof< ::Hash, NumberFor, >, - _key_owner_proof: fg_primitives::OpaqueKeyOwnershipProof, + _key_owner_proof: sp_consensus_grandpa::OpaqueKeyOwnershipProof, ) -> Option<()> { None } fn generate_key_ownership_proof( - _set_id: fg_primitives::SetId, + _set_id: sp_consensus_grandpa::SetId, _authority_id: GrandpaId, - ) -> Option { + ) -> Option { // NOTE: this is the only implementation possible since we've // defined our key owner proof type as a bottom type (i.e. a type // with no values). @@ -819,9 +803,10 @@ impl_runtime_apis! { Vec, Vec, ) { - use frame_benchmarking::{Benchmarking, BenchmarkList}; + use frame_benchmarking::{baseline, Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use baseline::Pallet as BaselineBench; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -837,6 +822,7 @@ impl_runtime_apis! { use frame_benchmarking::{baseline, Benchmarking, BenchmarkBatch, TrackedStorageKey}; use frame_system_benchmarking::Pallet as SystemBench; + use baseline::Pallet as BaselineBench; impl frame_system_benchmarking::Config for Runtime {} impl baseline::Config for Runtime {} @@ -852,37 +838,35 @@ impl_runtime_apis! { } } - #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade() -> (Weight, Weight) { + fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to // have a backtrace here. If any of the pre/post migration checks fail, we shall stop // right here and right now. - let weight = Executive::try_runtime_upgrade().unwrap(); + let weight = Executive::try_runtime_upgrade(checks).unwrap(); (weight, BlockWeights::get().max_block) } fn execute_block( block: Block, state_root_check: bool, + signature_check: bool, select: frame_try_runtime::TryStateSelect ) -> Weight { // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to // have a backtrace here. - Executive::try_execute_block(block, state_root_check, select).expect("execute-block failed") + Executive::try_execute_block(block, state_root_check, signature_check, select).expect("execute-block failed") } } } #[cfg(test)] mod tests { - use std::collections::HashSet; - + use super::*; use frame_support::traits::WhitelistedStorageKeys; use sp_core::hexdisplay::HexDisplay; - - use super::*; + use std::collections::HashSet; #[test] fn check_whitelist() { diff --git a/runtimes/testnet/Cargo.toml b/runtimes/testnet/Cargo.toml index e526e248d..42a17d71f 100644 --- a/runtimes/testnet/Cargo.toml +++ b/runtimes/testnet/Cargo.toml @@ -25,20 +25,7 @@ smallvec.workspace = true # Polimec specific pallet-funding.workspace = true -parachain-staking.workspace = true -pallet-credentials.workspace = true -pallet-asset-registry.workspace = true -polimec-traits.workspace = true -runtime-common.workspace = true - -# KILT specific -pallet-dip-consumer.workspace = true -did.workspace = true -pallet-did-lookup.workspace = true -kilt-dip-support.workspace = true - -# Primitives -xcm-primitives.workspace = true +shared-configuration.workspace = true # FRAME frame-benchmarking = { workspace = true, optional = true } @@ -67,6 +54,7 @@ pallet-multisig.workspace = true pallet-preimage.workspace = true pallet-insecure-randomness-collective-flip.workspace = true pallet-vesting.workspace = true +pallet-parachain-staking.workspace = true # Substrate sp-api.workspace = true @@ -107,7 +95,7 @@ polkadot-primitives.workspace = true [features] default = ["std"] -fast-gov = ["runtime-common/fast-gov"] +fast-gov = [] std = [ "pallet-asset-tx-payment/std", "pallet-assets/std", @@ -131,12 +119,10 @@ std = [ "frame-system/std", "pallet-assets/std", "pallet-asset-tx-payment/std", - "pallet-asset-registry/std", "pallet-aura/std", "pallet-authorship/std", "pallet-balances/std", "pallet-collective/std", - "pallet-credentials/std", "pallet-democracy/std", "pallet-scheduler/std", "pallet-session/std", @@ -153,12 +139,9 @@ std = [ "pallet-preimage/std", "pallet-insecure-randomness-collective-flip/std", "parachains-common/std", - "parachain-staking/std", "parachain-info/std", "polkadot-parachain/std", "polkadot-runtime-common/std", - "polimec-traits/std", - "runtime-common/std", "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", @@ -174,9 +157,8 @@ std = [ "xcm-builder/std", "xcm-executor/std", "xcm/std", - "did/std", - "pallet-dip-consumer/std", - "pallet-did-lookup/std", + "shared-configuration/std", + "pallet-parachain-staking/std" ] runtime-benchmarks = [ @@ -195,11 +177,10 @@ runtime-benchmarks = [ "cumulus-pallet-xcmp-queue/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", - "runtime-common/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-collective/runtime-benchmarks", ] -# + try-runtime = [ "cumulus-pallet-aura-ext/try-runtime", "cumulus-pallet-dmp-queue/try-runtime", @@ -219,7 +200,6 @@ try-runtime = [ "pallet-xcm/try-runtime", "parachain-info/try-runtime", "pallet-vesting/try-runtime", - "runtime-common/try-runtime", "pallet-assets/try-runtime", "pallet-asset-tx-payment/try-runtime", ] diff --git a/runtimes/testnet/build.rs b/runtimes/testnet/build.rs index b81f7762c..657bcc0d1 100644 --- a/runtimes/testnet/build.rs +++ b/runtimes/testnet/build.rs @@ -17,9 +17,5 @@ use substrate_wasm_builder::WasmBuilder; fn main() { - WasmBuilder::new() - .with_current_project() - .export_heap_base() - .import_memory() - .build() + WasmBuilder::new().with_current_project().export_heap_base().import_memory().build() } diff --git a/runtimes/testnet/src/dip.rs b/runtimes/testnet/src/dip.rs deleted file mode 100644 index 6e9b41ecb..000000000 --- a/runtimes/testnet/src/dip.rs +++ /dev/null @@ -1,169 +0,0 @@ -// Polimec Blockchain – https://www.polimec.org/ -// Copyright (C) Polimec 2022. All rights reserved. - -// The Polimec Blockchain 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. - -// The Polimec Blockchain 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 did::{did_details::DidVerificationKey, DidVerificationKeyRelationship, KeyIdOf}; -use frame_support::traits::Contains; -use kilt_dip_support::{ - did::{DidSignatureAndCallVerifier, MerkleEntriesAndDidSignature, MerkleRevealedDidSignatureVerifier}, - merkle::{DidMerkleProofVerifier, MerkleProof, ProofLeaf}, - traits::{BlockNumberProvider, DidDipOriginFilter, GenesisProvider}, - MerkleProofAndDidSignatureVerifier, -}; -use pallet_dip_consumer::traits::IdentityProofVerifier; -use sp_std::vec::Vec; - -use crate::{AccountId, BlockNumber, Hash, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin}; -use runtime_common::DidIdentifier; -use sp_runtime::traits::BlakeTwo256; -pub type Hasher = BlakeTwo256; - -pub type MerkleProofVerifier = DidMerkleProofVerifier, BlockNumber, u128, 10>; -pub type MerkleProofVerifierOutputOf = - >::VerificationResult; - -pub type MerkleDidSignatureVerifierOf = MerkleRevealedDidSignatureVerifier< - BlockNumber, - Hash, - u128, - AccountId, - MerkleProofVerifierOutputOf, - BlockNumberProvider, - // Signatures are valid for 50 blocks - 50, - GenesisProvider, - Hash, ->; - -impl pallet_dip_consumer::Config for Runtime { - type DipCallOriginFilter = PreliminaryDipOriginFilter; - type Identifier = DidIdentifier; - type IdentityDetails = u128; - type Proof = MerkleEntriesAndDidSignature>, ProofLeaf>, BlockNumber>; - type ProofDigest = Hash; - type ProofVerifier = MerkleProofAndDidSignatureVerifier< - BlockNumber, - MerkleProofVerifier, - DidSignatureAndCallVerifier, DipCallFilter>, - >; - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type RuntimeOrigin = RuntimeOrigin; -} - -pub struct PreliminaryDipOriginFilter; - -impl Contains for PreliminaryDipOriginFilter { - fn contains(t: &RuntimeCall) -> bool { - matches!( - t, - RuntimeCall::DidLookup { .. } - | RuntimeCall::Utility(pallet_utility::Call::batch { .. }) - | RuntimeCall::Utility(pallet_utility::Call::batch_all { .. }) - | RuntimeCall::Utility(pallet_utility::Call::force_batch { .. }) - ) - } -} - -fn derive_verification_key_relationship(call: &RuntimeCall) -> Option { - match call { - RuntimeCall::DidLookup { .. } => Some(DidVerificationKeyRelationship::Authentication), - RuntimeCall::Utility(pallet_utility::Call::batch { calls }) => single_key_relationship(calls.iter()).ok(), - RuntimeCall::Utility(pallet_utility::Call::batch_all { calls }) => single_key_relationship(calls.iter()).ok(), - RuntimeCall::Utility(pallet_utility::Call::force_batch { calls }) => single_key_relationship(calls.iter()).ok(), - _ => None, - } -} - -// Taken and adapted from `impl -// did::DeriveDidCallAuthorizationVerificationKeyRelationship for RuntimeCall` -// in Spiritnet/Peregrine runtime. -fn single_key_relationship<'a>( - calls: impl Iterator, -) -> Result { - let mut calls = calls.peekable(); - let first_call_relationship = calls - .peek() - .and_then(|k| derive_verification_key_relationship(k)) - .ok_or(())?; - calls - .map(derive_verification_key_relationship) - .try_fold(first_call_relationship, |acc, next| { - if next == Some(acc) { - Ok(acc) - } else { - Err(()) - } - }) -} - -pub struct DipCallFilter; - -impl DidDipOriginFilter for DipCallFilter { - type Error = (); - type OriginInfo = (DidVerificationKey, DidVerificationKeyRelationship); - type Success = (); - - // Accepts only a DipOrigin for the DidLookup pallet calls. - fn check_call_origin_info(call: &RuntimeCall, info: &Self::OriginInfo) -> Result { - let key_relationship = single_key_relationship([call].into_iter())?; - if info.1 == key_relationship { - Ok(()) - } else { - Err(()) - } - } -} - -#[cfg(test)] -mod dip_call_origin_filter_tests { - use super::*; - - use frame_support::assert_err; - - #[test] - fn test_key_relationship_derivation() { - // Can call DidLookup functions with an authentication key - let did_lookup_call = RuntimeCall::DidLookup(pallet_did_lookup::Call::associate_sender {}); - assert_eq!( - single_key_relationship(vec![did_lookup_call].iter()), - Ok(DidVerificationKeyRelationship::Authentication) - ); - // Can't call System functions with a DID key (hence a DIP origin) - let system_call = RuntimeCall::System(frame_system::Call::remark { remark: vec![] }); - assert_err!(single_key_relationship(vec![system_call].iter()), ()); - // Can't call empty batch with a DID key - let empty_batch_call = RuntimeCall::Utility(pallet_utility::Call::batch_all { calls: vec![] }); - assert_err!(single_key_relationship(vec![empty_batch_call].iter()), ()); - // Can call batch with a DipLookup with an authentication key - let did_lookup_batch_call = RuntimeCall::Utility(pallet_utility::Call::batch_all { - calls: vec![pallet_did_lookup::Call::associate_sender {}.into()], - }); - assert_eq!( - single_key_relationship(vec![did_lookup_batch_call].iter()), - Ok(DidVerificationKeyRelationship::Authentication) - ); - // Can't call a batch with different required keys - let did_lookup_batch_call = RuntimeCall::Utility(pallet_utility::Call::batch_all { - calls: vec![ - // Authentication key - pallet_did_lookup::Call::associate_sender {}.into(), - // No key - frame_system::Call::remark { remark: vec![] }.into(), - ], - }); - assert_err!(single_key_relationship(vec![did_lookup_batch_call].iter()), ()); - } -} diff --git a/runtimes/testnet/src/lib.rs b/runtimes/testnet/src/lib.rs index a36c0bdb3..5455833ef 100644 --- a/runtimes/testnet/src/lib.rs +++ b/runtimes/testnet/src/lib.rs @@ -24,15 +24,9 @@ extern crate frame_benchmarking; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; use frame_support::{ - construct_runtime, - pallet_prelude::Get, - parameter_types, - traits::{ - AsEnsureOriginWithArg, ConstU32, Currency, EitherOfDiverse, EqualPrivilegeOnly, Everything, Imbalance, - OnUnbalanced, - }, + construct_runtime, parameter_types, + traits::{AsEnsureOriginWithArg, ConstU32, Currency, EitherOfDiverse, EqualPrivilegeOnly, Everything}, weights::{ConstantMultiplier, Weight}, - PalletId, }; use frame_system::{EnsureRoot, EnsureSigned}; pub use parachains_common::{ @@ -40,6 +34,7 @@ pub use parachains_common::{ Header, Index, Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, MINUTES, NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; + // Polkadot imports use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use sp_api::impl_runtime_apis; @@ -50,39 +45,36 @@ use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto, OpaqueKeys}, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, Perquintill, + ApplyExtrinsicResult, }; pub use sp_runtime::{MultiAddress, Perbill, Permill}; use sp_std::prelude::*; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -// XCM Imports -use pallet_funding::{BondType, Multiplier as FundingMultiplier}; -use xcm_executor::XcmExecutor; -use kilt_dip_support::merkle::VerificationResult; -use pallet_dip_consumer::{DipOrigin, EnsureDipOrigin}; -use runtime_common::constants::staking::*; -pub use runtime_common::{ - constants::{ - governance::*, polimec_inflation_config, preimage::PreimageBaseDeposit, treasury::INITIAL_PERIOD_LENGTH, - InflationInfo, BLOCKS_PER_YEAR, EXISTENTIAL_DEPOSIT, MAX_COLLATOR_STAKE, MICRO_PLMC, PLMC, - }, - fees::WeightToFee, - DidIdentifier, RuntimeBlockLength, RuntimeBlockWeights, -}; -use weights::RocksDbWeight; +// XCM Imports use xcm_config::XcmConfig; +use xcm_executor::XcmExecutor; +mod xcm_config; +pub use crate::xcm_config::*; // Make the WASM binary available. #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); -mod dip; -mod weights; -mod xcm_config; -pub use crate::{dip::*, xcm_config::*}; +// Polimec Shared Imports +use pallet_funding::{BondType, Multiplier as FundingMultiplier}; +pub use pallet_parachain_staking; +pub use shared_configuration::{ + assets::*, + currency::{vesting::*, *}, + fee::*, + funding::*, + governance::*, + staking::*, + weights::*, +}; pub type NegativeImbalanceOf = as Currency<::AccountId>>::NegativeImbalance; @@ -108,7 +100,6 @@ pub type SignedExtra = ( frame_system::CheckEra, frame_system::CheckNonce, frame_system::CheckWeight, - // pallet_asset_tx_payment::ChargeAssetTxPayment, pallet_transaction_payment::ChargeTransactionPayment, ); @@ -143,10 +134,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { /// The version information used to identify this runtime when compiled natively. #[cfg(feature = "std")] pub fn native_version() -> NativeVersion { - NativeVersion { - runtime_version: VERSION, - can_author_with: Default::default(), - } + NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } } parameter_types! { @@ -157,196 +145,118 @@ parameter_types! { // Configure FRAME pallets to include in runtime. impl frame_system::Config for Runtime { + /// The data to be stored in an account. + type AccountData = pallet_balances::AccountData; + /// The identifier used to distinguish between accounts. + type AccountId = AccountId; /// The basic call filter to use in dispatchable. type BaseCallFilter = Everything; - /// Block & extrinsics weights: base values and limits. - type BlockWeights = RuntimeBlockWeights; + /// Maximum number of block number to block hash mappings to keep (oldest pruned first). + type BlockHashCount = BlockHashCount; /// The maximum length of a block (in bytes). type BlockLength = RuntimeBlockLength; - /// The ubiquitous origin type. - type RuntimeOrigin = RuntimeOrigin; - /// The aggregated dispatch type that is available for extrinsics. - type RuntimeCall = RuntimeCall; - /// The index type for storing how many extrinsics an account has signed. - type Index = Index; /// The index type for blocks. type BlockNumber = BlockNumber; + /// Block & extrinsics weights: base values and limits. + type BlockWeights = RuntimeBlockWeights; + /// The weight of database operations that the runtime can invoke. + type DbWeight = RocksDbWeight; /// The type for hashing blocks and tries. type Hash = Hash; /// The hashing algorithm used. type Hashing = BlakeTwo256; - /// The identifier used to distinguish between accounts. - type AccountId = AccountId; + /// The header type. + type Header = Header; + /// The index type for storing how many extrinsics an account has signed. + type Index = Index; /// The lookup mechanism to get account ID from whatever is passed in dispatchers. type Lookup = AccountIdLookup; - /// The header type. - type Header = runtime_common::Header; - /// The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; - /// 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. - type DbWeight = RocksDbWeight; - /// Runtime version. - type Version = Version; - /// Converts a module to an index of this module in the runtime. - type PalletInfo = PalletInfo; - /// The data to be stored in an account. - type AccountData = pallet_balances::AccountData; - /// What to do if a new account is created. - type OnNewAccount = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; /// What to do if an account is fully reaped from the system. type OnKilledAccount = (); + /// What to do if a new account is created. + type OnNewAccount = (); + /// The action to take on a Runtime Upgrade + type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + /// Converts a module to an index of this module in the runtime. + type PalletInfo = PalletInfo; + /// The aggregated dispatch type that is available for extrinsics. + type RuntimeCall = RuntimeCall; + /// The ubiquitous event type. + type RuntimeEvent = RuntimeEvent; + /// The ubiquitous origin type. + type RuntimeOrigin = RuntimeOrigin; + /// This is used as an identifier of the chain. 42 is the generic substrate prefix. + type SS58Prefix = SS58Prefix; /// Weight information for the extrinsics of this pallet. /// weights::frame_system::WeightInfo; type SystemWeightInfo = (); - /// This is used as an identifier of the chain. 42 is the generic substrate prefix. - type SS58Prefix = SS58Prefix; - /// The action to take on a Runtime Upgrade - type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -parameter_types! { - pub const MinimumPeriod: u64 = SLOT_DURATION / 2; + /// Runtime version. + type Version = Version; } impl pallet_timestamp::Config for Runtime { + type MinimumPeriod = MinimumPeriod; /// A timestamp: milliseconds since the unix epoch. type Moment = u64; type OnTimestampSet = Aura; - type MinimumPeriod = MinimumPeriod; type WeightInfo = (); } -parameter_types! { - pub const UncleGenerations: u32 = 0; -} - impl pallet_authorship::Config for Runtime { + type EventHandler = (ParachainStaking,); type FindAuthor = pallet_session::FindAccountFromAuthorIndex; - type EventHandler = ParachainStaking; -} - -parameter_types! { - pub const MaxLocks: u32 = 50; - pub const MaxReserves: u32 = 50; - pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT; - } impl pallet_balances::Config for Runtime { - /// The type for recording an account's balance. + type AccountStore = System; type Balance = Balance; - type DustRemoval = Treasury; - /// The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; + type DustRemoval = (); type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = pallet_balances::weights::SubstrateWeight; + type FreezeIdentifier = (); + type HoldIdentifier = (); + type MaxFreezes = MaxReserves; + type MaxHolds = MaxLocks; type MaxLocks = MaxLocks; type MaxReserves = MaxReserves; type ReserveIdentifier = BondType; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); } -/// Logic for the author to get a portion of fees. -pub struct ToAuthor(sp_std::marker::PhantomData); - -impl OnUnbalanced> for ToAuthor -where - R: pallet_balances::Config + pallet_authorship::Config, - ::AccountId: From, - ::AccountId: Into, - ::Balance: Into, -{ - fn on_nonzero_unbalanced(amount: NegativeImbalanceOf) { - if let Some(author) = >::author() { - >::resolve_creating(&author, amount); - } - } -} - -/// Split two Imbalances between two unbalanced handlers. -/// The first Imbalance will be split according to the given ratio. The second -/// Imbalance will be handled by the second beneficiary. -/// -/// In case of transaction payment, the first Imbalance is the fee and the -/// second imbalance the tip. -pub struct SplitFeesByRatio( - sp_std::marker::PhantomData<(R, Ratio, Beneficiary1, Beneficiary2)>, -); -impl OnUnbalanced> - for SplitFeesByRatio -where - R: pallet_balances::Config, - Beneficiary1: OnUnbalanced>, - Beneficiary2: OnUnbalanced>, - Ratio: Get<(u32, u32)>, -{ - fn on_unbalanceds(mut fees_then_tips: impl Iterator>) { - let ratio = Ratio::get(); - if let Some(fees) = fees_then_tips.next() { - let mut split = fees.ration(ratio.0, ratio.1); - if let Some(tips) = fees_then_tips.next() { - // for tips, if any, 100% to author - tips.merge_into(&mut split.1); - } - Beneficiary1::on_unbalanced(split.0); - Beneficiary2::on_unbalanced(split.1); - } - } -} - -parameter_types! { - /// Relay Chain `TransactionByteFee` / 10 - pub const TransactionByteFee: Balance = 10 * MICRO_PLMC; - pub const OperationalFeeMultiplier: u8 = 5; - pub const FeeSplitRatio: (u32, u32) = (50, 50); -} - -/// Split the fees using a preconfigured Ratio -pub type FeeSplit = SplitFeesByRatio; - impl pallet_transaction_payment::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = - pallet_transaction_payment::CurrencyAdapter>>; - type WeightToFee = WeightToFee; - type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; - type OperationalFeeMultiplier = OperationalFeeMultiplier; + type LengthToFee = ConstantMultiplier; + type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; + type OperationalFeeMultiplier = frame_support::traits::ConstU8<5>; + type RuntimeEvent = RuntimeEvent; + type WeightToFee = WeightToFee; } impl pallet_asset_tx_payment::Config for Runtime { - type RuntimeEvent = RuntimeEvent; type Fungibles = StatemintAssets; type OnChargeAssetTransaction = pallet_asset_tx_payment::FungiblesAdapter< pallet_assets::BalanceToAssetBalance, xcm_config::AssetsToBlockAuthor, >; + type RuntimeEvent = RuntimeEvent; } -parameter_types! { - pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); - pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); -} - -// TODO: On Testnet only impl pallet_sudo::Config for Runtime { type RuntimeCall = RuntimeCall; type RuntimeEvent = RuntimeEvent; } impl cumulus_pallet_parachain_system::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type OnSystemEvent = (); - type SelfParaId = ParachainInfo; + type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; type DmpMessageHandler = DmpQueue; - type ReservedDmpWeight = ReservedDmpWeight; + type OnSystemEvent = (); type OutboundXcmpMessageSource = XcmpQueue; - type XcmpMessageHandler = XcmpQueue; + type ReservedDmpWeight = ReservedDmpWeight; type ReservedXcmpWeight = ReservedXcmpWeight; - type CheckAssociatedRelayNumber = RelayNumberStrictlyIncreases; + type RuntimeEvent = RuntimeEvent; + type SelfParaId = ParachainInfo; + type XcmpMessageHandler = XcmpQueue; } impl parachain_info::Config for Runtime {} @@ -354,464 +264,292 @@ impl parachain_info::Config for Runtime {} impl cumulus_pallet_aura_ext::Config for Runtime {} impl cumulus_pallet_xcmp_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; type ChannelInfo = ParachainSystem; - type VersionWrapper = PolkadotXcm; - type ExecuteOverweightOrigin = EnsureRoot; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = xcm_config::XcmOriginToTransactDispatchOrigin; + type ExecuteOverweightOrigin = EnsureRoot; type PriceForSiblingDelivery = (); + type RuntimeEvent = RuntimeEvent; + type VersionWrapper = PolkadotXcm; type WeightInfo = (); + type XcmExecutor = XcmExecutor; } impl cumulus_pallet_dmp_queue::Config for Runtime { + type ExecuteOverweightOrigin = EnsureRoot; type RuntimeEvent = RuntimeEvent; type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = EnsureRoot; -} - -parameter_types! { - pub const Period: BlockNumber = 6 * HOURS; - pub const Offset: BlockNumber = 0; - pub const MaxAuthorities: u32 = 100_000; } impl pallet_session::Config for Runtime { + type Keys = SessionKeys; + type NextSessionRotation = ParachainStaking; type RuntimeEvent = RuntimeEvent; + type SessionHandler = ::KeyTypeIdProviders; + type SessionManager = ParachainStaking; + type ShouldEndSession = ParachainStaking; type ValidatorId = ::AccountId; type ValidatorIdOf = ConvertInto; - type ShouldEndSession = ParachainStaking; - type NextSessionRotation = ParachainStaking; - type SessionManager = ParachainStaking; - type SessionHandler = ::KeyTypeIdProviders; - type Keys = SessionKeys; type WeightInfo = (); } impl pallet_aura::Config for Runtime { type AuthorityId = AuraId; - // TODO: handle disabled validators type DisabledValidators = (); type MaxAuthorities = MaxAuthorities; } -parameter_types! { - /// Minimum round length is 1 hour - pub const MinBlocksPerRound: BlockNumber = MIN_BLOCKS_PER_ROUND; - /// Default length of a round/session is 2 hours - pub const DefaultBlocksPerRound: BlockNumber = DEFAULT_BLOCKS_PER_ROUND; - /// Unstaked balance can be unlocked after 7 days - pub const StakeDuration: BlockNumber = STAKE_DURATION; - /// Collator exit requests are delayed by 4 hours (2 rounds/sessions) - pub const ExitQueueDelay: u32 = 2; - /// Minimum 16 collators selected per round, default at genesis and minimum forever after - pub const MinCollators: u32 = MIN_COLLATORS; - /// At least 4 candidates which cannot leave the network if there are no other candidates. - pub const MinRequiredCollators: u32 = 4; - /// We only allow one delegation per round. - pub const MaxDelegationsPerRound: u32 = 1; - /// Maximum 25 delegators per collator at launch, might be increased later - #[derive(Debug, Eq, PartialEq)] - pub const MaxDelegatorsPerCollator: u32 = MAX_DELEGATORS_PER_COLLATOR; - /// Minimum stake required to be reserved to be a collator is 10_000 - pub const MinCollatorStake: Balance = 10_000 * PLMC; - /// Minimum stake required to be reserved to be a delegator is 1000 - pub const MinDelegatorStake: Balance = MIN_DELEGATOR_STAKE; - /// Maximum number of collator candidates - #[derive(Debug, Eq, PartialEq)] - pub const MaxCollatorCandidates: u32 = MAX_CANDIDATES; - /// Maximum number of concurrent requests to unlock unstaked balance - pub const MaxUnstakeRequests: u32 = 10; - /// The starting block number for the network rewards - pub const NetworkRewardStart: BlockNumber = INITIAL_PERIOD_LENGTH; - /// The rate in percent for the network rewards - pub const NetworkRewardRate: Perquintill = NETWORK_REWARD_RATE; -} - -impl parachain_staking::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; - type CurrencyBalance = Balance; - type MinBlocksPerRound = MinBlocksPerRound; - type DefaultBlocksPerRound = DefaultBlocksPerRound; - type StakeDuration = StakeDuration; - type ExitQueueDelay = ExitQueueDelay; - type MinCollators = MinCollators; - type MinRequiredCollators = MinRequiredCollators; - type MaxDelegationsPerRound = MaxDelegationsPerRound; - type MaxDelegatorsPerCollator = MaxDelegatorsPerCollator; - type MinCollatorStake = MinCollatorStake; - type MinCollatorCandidateStake = MinCollatorStake; - type MaxTopCandidates = MaxCollatorCandidates; - type MinDelegatorStake = MinDelegatorStake; - type MaxUnstakeRequests = MaxUnstakeRequests; - type NetworkRewardRate = NetworkRewardRate; - type NetworkRewardStart = NetworkRewardStart; - type NetworkRewardBeneficiary = Treasury; - type WeightInfo = (); - - const BLOCKS_PER_YEAR: Self::BlockNumber = BLOCKS_PER_YEAR; -} - impl pallet_insecure_randomness_collective_flip::Config for Runtime {} -#[cfg(feature = "fast-gov")] -pub const EVALUATION_DURATION: BlockNumber = 28; -#[cfg(not(feature = "fast-gov"))] -pub const EVALUATION_DURATION: BlockNumber = 28 * DAYS; - -#[cfg(feature = "fast-gov")] -pub const AUCTION_INITIALIZE_PERIOD_DURATION: BlockNumber = 7; -#[cfg(not(feature = "fast-gov"))] -pub const AUCTION_INITIALIZE_PERIOD_DURATION: BlockNumber = 7 * DAYS; - -#[cfg(feature = "fast-gov")] -pub const ENGLISH_AUCTION_DURATION: BlockNumber = 10; -#[cfg(not(feature = "fast-gov"))] -pub const ENGLISH_AUCTION_DURATION: BlockNumber = 2 * DAYS; - -#[cfg(feature = "fast-gov")] -pub const CANDLE_AUCTION_DURATION: BlockNumber = 5; -#[cfg(not(feature = "fast-gov"))] -pub const CANDLE_AUCTION_DURATION: BlockNumber = 3 * DAYS; - -#[cfg(feature = "fast-gov")] -pub const COMMUNITY_FUNDING_DURATION: BlockNumber = 10; -#[cfg(not(feature = "fast-gov"))] -pub const COMMUNITY_FUNDING_DURATION: BlockNumber = 5 * DAYS; - -#[cfg(feature = "fast-gov")] -pub const REMAINDER_FUNDING_DURATION: BlockNumber = 10; -#[cfg(not(feature = "fast-gov"))] -pub const REMAINDER_FUNDING_DURATION: BlockNumber = 1 * DAYS; - -#[cfg(feature = "fast-gov")] -pub const CONTRIBUTION_VESTING_DURATION: BlockNumber = 365; -#[cfg(not(feature = "fast-gov"))] -pub const CONTRIBUTION_VESTING_DURATION: BlockNumber = 365 * DAYS; - -parameter_types! { - pub const EvaluationDuration: BlockNumber = EVALUATION_DURATION; - pub const AuctionInitializePeriodDuration: BlockNumber = AUCTION_INITIALIZE_PERIOD_DURATION; - pub const EnglishAuctionDuration: BlockNumber = ENGLISH_AUCTION_DURATION; - pub const CandleAuctionDuration: BlockNumber = CANDLE_AUCTION_DURATION; - pub const CommunityFundingDuration: BlockNumber = COMMUNITY_FUNDING_DURATION; - pub const RemainderFundingDuration: BlockNumber = REMAINDER_FUNDING_DURATION; - pub const ContributionVestingDuration: BlockNumber = CONTRIBUTION_VESTING_DURATION; - pub const FundingPalletId: PalletId = PalletId(*b"py/cfund"); -} - impl pallet_funding::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type ProjectIdentifier = u32; - type ProjectIdParameter = parity_scale_codec::Compact; - type Multiplier = FundingMultiplier; + type AuctionInitializePeriodDuration = AuctionInitializePeriodDuration; type Balance = Balance; - type NativeCurrency = Balances; - type FundingCurrency = Balances; - type ContributionTokenCurrency = LocalAssets; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); type BidId = u128; - type Randomness = Random; - type HandleMembers = Credentials; - type StringLimit = ConstU32<64>; - type PreImageLimit = ConstU32<1024>; - type EvaluationDuration = EvaluationDuration; - type AuctionInitializePeriodDuration = AuctionInitializePeriodDuration; - type EnglishAuctionDuration = EnglishAuctionDuration; type CandleAuctionDuration = CandleAuctionDuration; type CommunityFundingDuration = CommunityFundingDuration; - type RemainderFundingDuration = RemainderFundingDuration; - type PalletId = FundingPalletId; + type ContributionTokenCurrency = LocalAssets; + type ContributionVesting = ContributionVestingDuration; + type EnglishAuctionDuration = EnglishAuctionDuration; + type EvaluationDuration = EvaluationDuration; + type FundingCurrency = Balances; + type MaxContributionsPerUser = ConstU32<256>; type MaxProjectsToUpdatePerBlock = ConstU32<100>; type MaximumBidsPerUser = ConstU32<256>; - - type MaxContributionsPerUser = ConstU32<256>; - type ContributionVesting = ContributionVestingDuration; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); - type WeightInfo = weights::pallet_funding::WeightInfo; -} - -impl pallet_credentials::Config for Runtime { + type Multiplier = FundingMultiplier; + type NativeCurrency = Balances; + type PalletId = FundingPalletId; + type PreImageLimit = ConstU32<1024>; + type ProjectIdParameter = parity_scale_codec::Compact; + type ProjectIdentifier = u32; + type Randomness = Random; + type RemainderFundingDuration = RemainderFundingDuration; type RuntimeEvent = RuntimeEvent; - type AddOrigin = EnsureRoot; - type RemoveOrigin = EnsureRoot; - type SwapOrigin = EnsureRoot; - type ResetOrigin = EnsureRoot; - type PrimeOrigin = EnsureRoot; - type MembershipInitialized = (); - type MembershipChanged = (); -} - -#[cfg(feature = "fast-gov")] -pub const SPEND_PERIOD: BlockNumber = 6 * MINUTES; -#[cfg(not(feature = "fast-gov"))] -pub const SPEND_PERIOD: BlockNumber = 6 * DAYS; - -parameter_types! { - pub const ProposalBond: Permill = Permill::from_percent(5); - pub const ProposalBondMinimum: Balance = 20 * PLMC; - pub const SpendPeriod: BlockNumber = SPEND_PERIOD; - pub const Burn: Permill = Permill::zero(); - pub const MaxApprovals: u32 = 100; - pub const TreasuryPalletId: PalletId = PalletId(*b"politrea"); + type StringLimit = ConstU32<64>; + type WeightInfo = (); } impl pallet_treasury::Config for Runtime { - type Currency = Balances; // TODO: Use the Council instead of Root! type ApproveOrigin = EnsureRoot; - type RejectOrigin = EnsureRoot; - type RuntimeEvent = RuntimeEvent; + type Burn = Burn; + type BurnDestination = (); + type Currency = Balances; + type MaxApprovals = MaxApprovals; type OnSlash = Treasury; + type PalletId = TreasuryId; type ProposalBond = ProposalBond; - type ProposalBondMinimum = ProposalBondMinimum; type ProposalBondMaximum = (); - type SpendPeriod = SpendPeriod; - type Burn = Burn; - type PalletId = TreasuryPalletId; - type BurnDestination = (); - type WeightInfo = (); + type ProposalBondMinimum = ProposalBondMinimum; + type RejectOrigin = EnsureRoot; + type RuntimeEvent = RuntimeEvent; type SpendFunds = (); - type MaxApprovals = MaxApprovals; type SpendOrigin = frame_support::traits::NeverEnsureOrigin; -} - -parameter_types! { - pub const CouncilMotionDuration: BlockNumber = 5 * DAYS; - pub const CouncilMaxProposals: u32 = 100; - pub const CouncilMaxMembers: u32 = 100; + type SpendPeriod = SpendPeriod; + type WeightInfo = (); } // TODO: VERY BASIC implementation, more work needed type CouncilCollective = pallet_collective::Instance1; impl pallet_collective::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; + type DefaultVote = pallet_collective::PrimeDefaultVote; + type MaxMembers = CouncilMaxMembers; + type MaxProposalWeight = MaxCollectivesProposalWeight; + type MaxProposals = CouncilMaxProposals; + type MotionDuration = CouncilMotionDuration; type Proposal = RuntimeCall; type RuntimeEvent = RuntimeEvent; - type MotionDuration = CouncilMotionDuration; - type MaxProposals = CouncilMaxProposals; - type MaxMembers = CouncilMaxMembers; - type DefaultVote = pallet_collective::PrimeDefaultVote; - type WeightInfo = pallet_collective::weights::SubstrateWeight; + type RuntimeOrigin = RuntimeOrigin; type SetMembersOrigin = EnsureRoot; -} - -parameter_types! { - pub const TechnicalMotionDuration: BlockNumber = 5 * DAYS; - pub const TechnicalMaxProposals: u32 = 100; - pub const TechnicalMaxMembers: u32 = 100; + type WeightInfo = pallet_collective::weights::SubstrateWeight; } type TechnicalCollective = pallet_collective::Instance2; impl pallet_collective::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; + type DefaultVote = pallet_collective::PrimeDefaultVote; + type MaxMembers = TechnicalMaxMembers; + type MaxProposalWeight = MaxCollectivesProposalWeight; + type MaxProposals = TechnicalMaxProposals; + type MotionDuration = TechnicalMotionDuration; type Proposal = RuntimeCall; type RuntimeEvent = RuntimeEvent; - type MotionDuration = TechnicalMotionDuration; - type MaxProposals = TechnicalMaxProposals; - type MaxMembers = TechnicalMaxMembers; - type DefaultVote = pallet_collective::PrimeDefaultVote; - type WeightInfo = pallet_collective::weights::SubstrateWeight; + type RuntimeOrigin = RuntimeOrigin; type SetMembersOrigin = EnsureRoot; + type WeightInfo = pallet_collective::weights::SubstrateWeight; } impl pallet_democracy::Config for Runtime { - type WeightInfo = pallet_democracy::weights::SubstrateWeight; - type RuntimeEvent = RuntimeEvent; - type Scheduler = Scheduler; - type Preimages = Preimage; + type BlacklistOrigin = EnsureRoot; + // To cancel a proposal before it has been passed, the technical committee must be unanimous or + // Root must agree. + type CancelProposalOrigin = EitherOfDiverse< + EnsureRoot, + pallet_collective::EnsureProportionAtLeast, + >; + // To cancel a proposal which has been passed, 2/3 of the council must agree to it. + type CancellationOrigin = pallet_collective::EnsureProportionAtLeast; + type CooloffPeriod = CooloffPeriod; type Currency = Balances; type EnactmentPeriod = EnactmentPeriod; - type LaunchPeriod = LaunchPeriod; - type VotingPeriod = VotingPeriod; - type VoteLockingPeriod = EnactmentPeriod; - // Same as EnactmentPeriod - type MinimumDeposit = MinimumDeposit; - type InstantAllowed = frame_support::traits::ConstBool; - type FastTrackVotingPeriod = FastTrackVotingPeriod; - type CooloffPeriod = CooloffPeriod; - type MaxVotes = ConstU32<128>; - type MaxProposals = MaxProposals; - type MaxDeposits = (); - type MaxBlacklisted = (); - /// A straight majority of the council can decide what their next motion is. - type ExternalOrigin = pallet_collective::EnsureProportionAtLeast; - /// A super-majority can have the next scheduled referendum be a straight majority-carries vote. - type ExternalMajorityOrigin = pallet_collective::EnsureProportionAtLeast; /// A unanimous council can have the next scheduled referendum be a straight default-carries /// (NTB) vote. type ExternalDefaultOrigin = pallet_collective::EnsureProportionAtLeast; + /// A super-majority can have the next scheduled referendum be a straight majority-carries vote. + type ExternalMajorityOrigin = pallet_collective::EnsureProportionAtLeast; + /// A straight majority of the council can decide what their next motion is. + type ExternalOrigin = pallet_collective::EnsureProportionAtLeast; /// Two thirds of the technical committee can have an ExternalMajority/ExternalDefault vote /// be tabled immediately and with a shorter voting/enactment period. type FastTrackOrigin = pallet_collective::EnsureProportionAtLeast; + type FastTrackVotingPeriod = FastTrackVotingPeriod; + type InstantAllowed = frame_support::traits::ConstBool; type InstantOrigin = pallet_collective::EnsureProportionAtLeast; - // To cancel a proposal which has been passed, 2/3 of the council must agree to it. - type CancellationOrigin = pallet_collective::EnsureProportionAtLeast; - type BlacklistOrigin = EnsureRoot; - // To cancel a proposal before it has been passed, the technical committee must be unanimous or - // Root must agree. - type CancelProposalOrigin = EitherOfDiverse< - EnsureRoot, - pallet_collective::EnsureProportionAtLeast, - >; - // Any single technical committee member may veto a coming council proposal, however they can - // only do it once and it lasts only for the cool-off period. - type VetoOrigin = pallet_collective::EnsureMember; + type LaunchPeriod = LaunchPeriod; + type MaxBlacklisted = (); + type MaxDeposits = (); + type MaxProposals = MaxProposals; + type MaxVotes = ConstU32<128>; + // Same as EnactmentPeriod + type MinimumDeposit = MinimumDeposit; type PalletsOrigin = OriginCaller; + type Preimages = Preimage; + type RuntimeEvent = RuntimeEvent; + type Scheduler = Scheduler; type Slash = (); type SubmitOrigin = EnsureSigned; -} - -parameter_types! { - pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block; - pub const MaxScheduledPerBlock: u32 = 50; + // Any single technical committee member may veto a coming council proposal, however they can + // only do it once and it lasts only for the cool-off period. + type VetoOrigin = pallet_collective::EnsureMember; + type VoteLockingPeriod = EnactmentPeriod; + type VotingPeriod = VotingPeriod; + type WeightInfo = pallet_democracy::weights::SubstrateWeight; } impl pallet_scheduler::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeOrigin = RuntimeOrigin; + type MaxScheduledPerBlock = MaxScheduledPerBlock; + type MaximumWeight = MaximumSchedulerWeight; + type OriginPrivilegeCmp = EqualPrivilegeOnly; type PalletsOrigin = OriginCaller; + type Preimages = Preimage; type RuntimeCall = RuntimeCall; - type MaximumWeight = MaximumSchedulerWeight; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; type ScheduleOrigin = EnsureRoot; - type OriginPrivilegeCmp = EqualPrivilegeOnly; - type MaxScheduledPerBlock = MaxScheduledPerBlock; type WeightInfo = (); - type Preimages = Preimage; } impl pallet_utility::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } -pub const fn deposit(items: u32, bytes: u32) -> Balance { - items as Balance * 15 * MICRO_PLMC + (bytes as Balance) * 6 * MICRO_PLMC -} - -pub const fn free_deposit() -> Balance { - 0 * MICRO_PLMC -} - -parameter_types! { - // One storage item; key size is 32; value is size 4+4+16+32 bytes = 56 bytes. - pub const DepositBase: Balance = deposit(1, 88); - // Additional storage item size of 32 bytes. - pub const DepositFactor: Balance = deposit(0, 32); - pub const MaxSignatories: u16 = 100; -} - impl pallet_multisig::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; type Currency = Balances; type DepositBase = DepositBase; type DepositFactor = DepositFactor; type MaxSignatories = MaxSignatories; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } impl pallet_preimage::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - type Currency = Balances; - type ManagerOrigin = EnsureRoot; type BaseDeposit = PreimageBaseDeposit; type ByteDeposit = (); -} - -parameter_types! { - pub const AssetDeposit: Balance = PLMC; // 1 UNIT deposit to create asset - pub const ApprovalDeposit: Balance = EXISTENTIAL_DEPOSIT; - pub const AssetAccountDeposit: Balance = deposit(1, 16); - pub const AssetsStringLimit: u32 = 50; - /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) - // https://github.com/paritytech/substrate/blob/069917b/frame/assets/src/lib.rs#L257L271 - pub const MetadataDepositBase: Balance = free_deposit(); - pub const MetadataDepositPerByte: Balance = free_deposit(); - pub const AssetsPalletId: PalletId = PalletId(*b"assetsid"); + type Currency = Balances; + type ManagerOrigin = EnsureRoot; + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); } pub type LocalAssetsInstance = pallet_assets::Instance1; pub type StatemintAssetsInstance = pallet_assets::Instance2; impl pallet_assets::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Balance = Balance; - type RemoveItemsLimit = frame_support::traits::ConstU32<1000>; + type ApprovalDeposit = ExistentialDeposit; + type AssetAccountDeposit = AssetAccountDeposit; + type AssetDeposit = AssetDeposit; type AssetId = AssetId; type AssetIdParameter = parity_scale_codec::Compact; - type Currency = Balances; + type Balance = Balance; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); + type CallbackHandle = (); type CreateOrigin = AsEnsureOriginWithArg>; + type Currency = Balances; + type Extra = (); type ForceOrigin = EnsureRoot; - type AssetDeposit = AssetDeposit; - type AssetAccountDeposit = AssetAccountDeposit; + type Freezer = (); type MetadataDepositBase = MetadataDepositBase; type MetadataDepositPerByte = MetadataDepositPerByte; - type ApprovalDeposit = ApprovalDeposit; + type RemoveItemsLimit = frame_support::traits::ConstU32<1000>; + type RuntimeEvent = RuntimeEvent; type StringLimit = AssetsStringLimit; - type Freezer = (); - type Extra = (); - type CallbackHandle = (); type WeightInfo = (); - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); } impl pallet_assets::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Balance = Balance; - type RemoveItemsLimit = frame_support::traits::ConstU32<1000>; + type ApprovalDeposit = ExistentialDeposit; + type AssetAccountDeposit = AssetAccountDeposit; + type AssetDeposit = AssetDeposit; type AssetId = AssetId; type AssetIdParameter = parity_scale_codec::Compact; - type Currency = Balances; + type Balance = Balance; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); + type CallbackHandle = (); type CreateOrigin = AsEnsureOriginWithArg>; + type Currency = Balances; + type Extra = (); type ForceOrigin = EnsureRoot; - type AssetDeposit = AssetDeposit; - type AssetAccountDeposit = AssetAccountDeposit; + type Freezer = (); type MetadataDepositBase = MetadataDepositBase; type MetadataDepositPerByte = MetadataDepositPerByte; - type ApprovalDeposit = ApprovalDeposit; - type StringLimit = AssetsStringLimit; - type Freezer = (); - type Extra = (); - type CallbackHandle = (); - type WeightInfo = (); - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); -} - -impl pallet_asset_registry::Config for Runtime { + type RemoveItemsLimit = frame_support::traits::ConstU32<1000>; type RuntimeEvent = RuntimeEvent; - type ReserveAssetModifierOrigin = frame_system::EnsureRoot; - type Assets = StatemintAssets; + type StringLimit = AssetsStringLimit; type WeightInfo = (); } impl pallet_vesting::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Currency = Balances; type BlockNumberToBalance = ConvertInto; - type MinVestedTransfer = runtime_common::constants::MinVestedTransfer; + type Currency = Balances; + type MinVestedTransfer = MinVestedTransfer; + type RuntimeEvent = RuntimeEvent; + type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; type WeightInfo = pallet_vesting::weights::SubstrateWeight; - type UnvestedFundsAllowedWithdrawReasons = runtime_common::constants::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; } -impl pallet_did_lookup::Config for Runtime { +impl pallet_parachain_staking::Config for Runtime { + type CandidateBondLessDelay = CandidateBondLessDelay; type Currency = Balances; - type Deposit = DepositBase; - type DidIdentifier = DidIdentifier; - type EnsureOrigin = EnsureDipOrigin>; - type OriginSuccess = DipOrigin>; + type DelegationBondLessDelay = DelegationBondLessDelay; + type LeaveCandidatesDelay = LeaveCandidatesDelay; + type LeaveDelegatorsDelay = LeaveDelegatorsDelay; + type MaxBottomDelegationsPerCandidate = MaxBottomDelegationsPerCandidate; + type MaxDelegationsPerDelegator = MaxDelegationsPerDelegator; + type MaxTopDelegationsPerCandidate = MaxTopDelegationsPerCandidate; + type MinBlocksPerRound = MinBlocksPerRound; + type MinCandidateStk = MinCandidateStk; + type MinDelegation = MinDelegation; + type MinDelegatorStk = MinDelegatorStk; + type MinSelectedCandidates = MinSelectedCandidates; + type MonetaryGovernanceOrigin = frame_system::EnsureRoot; + type OnCollatorPayout = (); + type OnNewRound = (); + // We use the default implementation, so we leave () here. + type PayoutCollatorReward = (); + type RevokeDelegationDelay = RevokeDelegationDelay; + type RewardPaymentDelay = RewardPaymentDelay; type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); + type WeightInfo = pallet_parachain_staking::weights::SubstrateWeight; } // Create the runtime by composing the FRAME pallets that were previously configured. @@ -834,17 +572,15 @@ construct_runtime!( AssetTxPayment: pallet_asset_tx_payment::{Pallet, Storage, Event} = 12, LocalAssets: pallet_assets::::{Pallet, Call, Storage, Event} = 13, StatemintAssets: pallet_assets::::{Pallet, Call, Storage, Event} = 14, - AssetRegistry: pallet_asset_registry::{Pallet, Call, Storage, Event} = 15, Vesting: pallet_vesting::{Pallet, Call, Storage, Event, Config} = 16, - // Consensus support. - // The following order MUST NOT be changed: Aura -> Session -> Staking -> Authorship -> AuraExt - // Dependencies: AuraExt on Aura, Authorship and Session on ParachainStaking - Aura: pallet_aura = 23, - Session: pallet_session = 22, - ParachainStaking: parachain_staking = 21, + // Collator support. the order of these 5 are important and shall not change. Authorship: pallet_authorship::{Pallet, Storage} = 20, - AuraExt: cumulus_pallet_aura_ext = 24, + Session: pallet_session::{Pallet, Call, Storage, Event, Config} = 22, + Aura: pallet_aura::{Pallet, Storage, Config} = 23, + AuraExt: cumulus_pallet_aura_ext::{Pallet, Storage, Config} = 24, + ParachainStaking: pallet_parachain_staking::{Pallet, Call, Storage, Event, Config} = 25, + // Governance Treasury: pallet_treasury = 40, @@ -854,10 +590,7 @@ construct_runtime!( Preimage: pallet_preimage::{Pallet, Call, Storage, Event} = 44, // Polimec Core - DipConsumer: pallet_dip_consumer = 50, - DidLookup: pallet_did_lookup = 51, PolimecFunding: pallet_funding::{Pallet, Call, Storage, Event} = 52, - Credentials: pallet_credentials = 53, // Utilities Scheduler: pallet_scheduler::{Pallet, Call, Storage, Event} = 61, @@ -918,6 +651,13 @@ impl_runtime_apis! { fn metadata() -> OpaqueMetadata { OpaqueMetadata::new(Runtime::metadata().into()) } + fn metadata_at_version(version: u32) -> Option { + Runtime::metadata_at_version(version) + } + + fn metadata_versions() -> sp_std::vec::Vec { + Runtime::metadata_versions() + } } impl sp_block_builder::BlockBuilder for Runtime { @@ -988,11 +728,9 @@ impl_runtime_apis! { ) -> pallet_transaction_payment::FeeDetails { TransactionPayment::query_fee_details(uxt, len) } - fn query_weight_to_fee(weight: Weight) -> Balance { TransactionPayment::weight_to_fee(weight) } - fn query_length_to_fee(length: u32) -> Balance { TransactionPayment::length_to_fee(length) } @@ -1013,15 +751,12 @@ impl_runtime_apis! { ) -> pallet_transaction_payment::FeeDetails { TransactionPayment::query_call_fee_details(call, len) } - fn query_weight_to_fee(weight: Weight) -> Balance { TransactionPayment::weight_to_fee(weight) } - fn query_length_to_fee(length: u32) -> Balance { TransactionPayment::length_to_fee(length) } - } impl cumulus_primitives_core::CollectCollationInfo for Runtime { @@ -1032,21 +767,18 @@ impl_runtime_apis! { #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade() -> (Weight, Weight) { - log::info!("try-runtime::on_runtime_upgrade statemine."); - let weight = Executive::try_runtime_upgrade().unwrap(); + fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { + let weight = Executive::try_runtime_upgrade(checks).unwrap(); (weight, RuntimeBlockWeights::get().max_block) } - fn execute_block(block: Block, state_root_check: bool, select: frame_try_runtime::TryStateSelect) -> Weight { - log::info!( - target: "runtime::statemine", "try-runtime: executing block #{} ({:?}) / root checks: {:?} / sanity-checks: {:?}", - block.header.number, - block.header.hash(), - state_root_check, - select, - ); - Executive::try_execute_block(block, state_root_check, select).expect("try_execute_block failed") + fn execute_block( + block: Block, + state_root_check: bool, + signature_check: bool, + select: frame_try_runtime::TryStateSelect, + ) -> Weight { + Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap() } } @@ -1056,7 +788,6 @@ impl_runtime_apis! { Vec, Vec, ) { - use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; @@ -1072,7 +803,7 @@ impl_runtime_apis! { fn dispatch_benchmark( config: frame_benchmarking::BenchmarkConfig ) -> Result, sp_runtime::RuntimeString> { - use frame_benchmarking::{Benchmarking, BenchmarkBatch, TrackedStorageKey}; + use frame_benchmarking::{Benchmarking, BenchmarkBatch}; use frame_system_benchmarking::Pallet as SystemBench; impl frame_system_benchmarking::Config for Runtime {} @@ -1080,25 +811,14 @@ impl_runtime_apis! { use cumulus_pallet_session_benchmarking::Pallet as SessionBench; impl cumulus_pallet_session_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(), - //TODO: use from relay_well_known_keys::ACTIVE_CONFIG - hex_literal::hex!("06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385").to_vec().into(), - ]; + use frame_support::traits::WhitelistedStorageKeys; + let whitelist = AllPalletsWithSystem::whitelisted_storage_keys(); let mut batches = Vec::::new(); let params = (&config, &whitelist); add_benchmarks!(params, batches); + if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches) } } @@ -1108,11 +828,11 @@ struct CheckInherents; impl cumulus_pallet_parachain_system::CheckInherents for CheckInherents { fn check_inherents( - block: &Block, relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof, + block: &Block, + relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof, ) -> sp_inherents::CheckInherentsResult { - let relay_chain_slot = relay_state_proof - .read_slot() - .expect("Could not read the relay chain slot from the proof"); + let relay_chain_slot = + relay_state_proof.read_slot().expect("Could not read the relay chain slot from the proof"); let inherent_data = cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration( relay_chain_slot, diff --git a/runtimes/testnet/src/weights/block_weights.rs b/runtimes/testnet/src/weights/block_weights.rs deleted file mode 100644 index f5dcc6ac2..000000000 --- a/runtimes/testnet/src/weights/block_weights.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Polimec Blockchain – https://www.polimec.org/ -// Copyright (C) Polimec 2022. All rights reserved. - -// The Polimec Blockchain 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. - -// The Polimec Blockchain 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 .erning permissions and -// limitations under the License. - -pub mod constants { - use frame_support::{ - parameter_types, - weights::{constants, Weight}, - }; - - parameter_types! { - /// Importing a block with 0 Extrinsics. - pub const BlockExecutionWeight: Weight = - Weight::from_ref_time(constants::WEIGHT_REF_TIME_PER_NANOS.saturating_mul(5_000_000)); - } - - #[cfg(test)] - mod test_weights { - use frame_support::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, - // you can delete it. - #[test] - fn sane() { - let w = super::constants::BlockExecutionWeight::get(); - - // At least 100 µs. - assert!( - w.ref_time() >= 100u64 * constants::WEIGHT_REF_TIME_PER_MICROS, - "Weight should be at least 100 µs." - ); - // At most 50 ms. - assert!( - w.ref_time() <= 50u64 * constants::WEIGHT_REF_TIME_PER_MILLIS, - "Weight should be at most 50 ms." - ); - } - } -} diff --git a/runtimes/testnet/src/weights/extrinsic_weights.rs b/runtimes/testnet/src/weights/extrinsic_weights.rs deleted file mode 100644 index 0819bab8a..000000000 --- a/runtimes/testnet/src/weights/extrinsic_weights.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Polimec Blockchain – https://www.polimec.org/ -// Copyright (C) Polimec 2022. All rights reserved. - -// The Polimec Blockchain 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. - -// The Polimec Blockchain 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 . - -pub mod constants { - use frame_support::{ - parameter_types, - weights::{constants, Weight}, - }; - - parameter_types! { - /// Executing a NO-OP `System::remarks` Extrinsic. - pub const ExtrinsicBaseWeight: Weight = - Weight::from_ref_time(constants::WEIGHT_REF_TIME_PER_NANOS.saturating_mul(125_000)); - } - - #[cfg(test)] - mod test_weights { - use frame_support::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, - // you can delete it. - #[test] - fn sane() { - let w = super::constants::ExtrinsicBaseWeight::get(); - - // At least 10 µs. - assert!( - w.ref_time() >= 10u64 * constants::WEIGHT_REF_TIME_PER_MICROS, - "Weight should be at least 10 µs." - ); - // At most 1 ms. - assert!( - w.ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Weight should be at most 1 ms." - ); - } - } -} diff --git a/runtimes/testnet/src/weights/pallet_funding.rs b/runtimes/testnet/src/weights/pallet_funding.rs deleted file mode 100644 index 50c79d7b7..000000000 --- a/runtimes/testnet/src/weights/pallet_funding.rs +++ /dev/null @@ -1,202 +0,0 @@ - -//! Autogenerated weights for `pallet_funding` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-03-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `pop-os`, CPU: `13th Gen Intel(R) Core(TM) i9-13900K` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 - -// Executed Command: -// target/release/polimec-standalone-node -// benchmark -// pallet -// --chain=dev -// --steps=50 -// --repeat=20 -// --pallet=pallet_funding -// --extrinsic -// * -// --execution=wasm -// --wasm-execution=compiled -// --heap-pages=4096 -// --output=runtimes/testnet/src/weights/pallet_funding.rs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] - -use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; - -/// Weight functions for `pallet_funding`. -pub struct WeightInfo(PhantomData); -impl pallet_funding::WeightInfo for WeightInfo { - /// Storage: PolimecFunding Images (r:0 w:1) - /// Proof Skipped: PolimecFunding Images (max_values: None, max_size: None, mode: Measured) - fn note_image() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 5_860 nanoseconds. - Weight::from_ref_time(6_343_000) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: PolimecFunding Images (r:1 w:0) - /// Proof Skipped: PolimecFunding Images (max_values: None, max_size: None, mode: Measured) - /// Storage: PolimecFunding NextProjectId (r:1 w:1) - /// Proof Skipped: PolimecFunding NextProjectId (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolimecFunding Projects (r:0 w:1) - /// Proof Skipped: PolimecFunding Projects (max_values: None, max_size: None, mode: Measured) - /// Storage: PolimecFunding ProjectsInfo (r:0 w:1) - /// Proof Skipped: PolimecFunding ProjectsInfo (max_values: None, max_size: None, mode: Measured) - /// Storage: PolimecFunding ProjectsIssuers (r:0 w:1) - /// Proof Skipped: PolimecFunding ProjectsIssuers (max_values: None, max_size: None, mode: Measured) - fn create() -> Weight { - // Proof Size summary in bytes: - // Measured: `111` - // Estimated: `3525` - // Minimum execution time: 13_134 nanoseconds. - Weight::from_parts(13_798_000, 3525) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: PolimecFunding ProjectsIssuers (r:1 w:0) - /// Proof Skipped: PolimecFunding ProjectsIssuers (max_values: None, max_size: None, mode: Measured) - /// Storage: PolimecFunding ProjectsInfo (r:1 w:1) - /// Proof Skipped: PolimecFunding ProjectsInfo (max_values: None, max_size: None, mode: Measured) - /// Storage: PolimecFunding ProjectsActive (r:1 w:1) - /// Proof Skipped: PolimecFunding ProjectsActive (max_values: Some(1), max_size: None, mode: Measured) - fn start_evaluation() -> Weight { - // Proof Size summary in bytes: - // Measured: `207` - // Estimated: `6066` - // Minimum execution time: 12_306 nanoseconds. - Weight::from_parts(12_756_000, 6066) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: PolimecFunding ProjectsIssuers (r:1 w:0) - /// Proof Skipped: PolimecFunding ProjectsIssuers (max_values: None, max_size: None, mode: Measured) - /// Storage: PolimecFunding ProjectsInfo (r:1 w:0) - /// Proof Skipped: PolimecFunding ProjectsInfo (max_values: None, max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: PolimecFunding Bonds (r:1 w:1) - /// Proof Skipped: PolimecFunding Bonds (max_values: None, max_size: None, mode: Measured) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - fn bond() -> Weight { - // Proof Size summary in bytes: - // Measured: `370` - // Estimated: `14912` - // Minimum execution time: 19_568 nanoseconds. - Weight::from_parts(19_897_000, 14912) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: PolimecFunding ProjectsIssuers (r:1 w:0) - /// Proof Skipped: PolimecFunding ProjectsIssuers (max_values: None, max_size: None, mode: Measured) - /// Storage: PolimecFunding Images (r:1 w:0) - /// Proof Skipped: PolimecFunding Images (max_values: None, max_size: None, mode: Measured) - /// Storage: PolimecFunding ProjectsInfo (r:1 w:0) - /// Proof Skipped: PolimecFunding ProjectsInfo (max_values: None, max_size: None, mode: Measured) - /// Storage: PolimecFunding Projects (r:1 w:1) - /// Proof Skipped: PolimecFunding Projects (max_values: None, max_size: None, mode: Measured) - fn edit_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `454` - // Estimated: `11716` - // Minimum execution time: 14_476 nanoseconds. - Weight::from_parts(15_071_000, 11716) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: PolimecFunding ProjectsIssuers (r:1 w:0) - /// Proof Skipped: PolimecFunding ProjectsIssuers (max_values: None, max_size: None, mode: Measured) - /// Storage: PolimecFunding ProjectsInfo (r:1 w:1) - /// Proof Skipped: PolimecFunding ProjectsInfo (max_values: None, max_size: None, mode: Measured) - fn start_auction() -> Weight { - // Proof Size summary in bytes: - // Measured: `268` - // Estimated: `5486` - // Minimum execution time: 13_427 nanoseconds. - Weight::from_parts(13_815_000, 5486) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: PolimecFunding ProjectsIssuers (r:1 w:0) - /// Proof Skipped: PolimecFunding ProjectsIssuers (max_values: None, max_size: None, mode: Measured) - /// Storage: PolimecFunding ProjectsInfo (r:1 w:0) - /// Proof Skipped: PolimecFunding ProjectsInfo (max_values: None, max_size: None, mode: Measured) - /// Storage: PolimecFunding Projects (r:1 w:0) - /// Proof Skipped: PolimecFunding Projects (max_values: None, max_size: None, mode: Measured) - /// Storage: PolimecFunding AuctionsInfo (r:1 w:1) - /// Proof Skipped: PolimecFunding AuctionsInfo (max_values: None, max_size: None, mode: Measured) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn bid() -> Weight { - // Proof Size summary in bytes: - // Measured: `633` - // Estimated: `15035` - // Minimum execution time: 25_578 nanoseconds. - Weight::from_parts(26_100_000, 15035) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: PolimecFunding ProjectsIssuers (r:1 w:0) - /// Proof Skipped: PolimecFunding ProjectsIssuers (max_values: None, max_size: None, mode: Measured) - /// Storage: PolimecFunding ProjectsInfo (r:1 w:0) - /// Proof Skipped: PolimecFunding ProjectsInfo (max_values: None, max_size: None, mode: Measured) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: PolimecFunding Contributions (r:1 w:1) - /// Proof Skipped: PolimecFunding Contributions (max_values: None, max_size: None, mode: Measured) - fn contribute() -> Weight { - // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `14053` - // Minimum execution time: 30_643 nanoseconds. - Weight::from_parts(31_201_000, 14053) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: PolimecFunding ProjectsInfo (r:1 w:0) - /// Proof Skipped: PolimecFunding ProjectsInfo (max_values: None, max_size: None, mode: Measured) - /// Storage: PolimecFunding Contributions (r:1 w:1) - /// Proof Skipped: PolimecFunding Contributions (max_values: None, max_size: None, mode: Measured) - /// Storage: Assets Asset (r:1 w:1) - /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) - /// Storage: Assets Account (r:1 w:1) - /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn claim_contribution_tokens() -> Weight { - // Proof Size summary in bytes: - // Measured: `877` - // Estimated: `14569` - // Minimum execution time: 26_228 nanoseconds. - Weight::from_parts(27_498_000, 14569) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: PolimecFunding ProjectsActive (r:1 w:0) - /// Proof Skipped: PolimecFunding ProjectsActive (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: PolimecFunding ProjectsInfo (r:100 w:100) - /// Proof Skipped: PolimecFunding ProjectsInfo (max_values: None, max_size: None, mode: Measured) - /// Storage: PolimecFunding Bonds (r:200 w:0) - /// Proof Skipped: PolimecFunding Bonds (max_values: None, max_size: None, mode: Measured) - fn on_initialize() -> Weight { - // Proof Size summary in bytes: - // Measured: `15727` - // Estimated: `790176` - // Minimum execution time: 1_279_152 nanoseconds. - Weight::from_parts(1_286_826_000, 790176) - .saturating_add(T::DbWeight::get().reads(301)) - .saturating_add(T::DbWeight::get().writes(100)) - } - - fn failed_evaluation_unbond_for() -> Weight { - Weight::from_ref_time(1_000_000) - } -} diff --git a/runtimes/testnet/src/weights/paritydb_weights.rs b/runtimes/testnet/src/weights/paritydb_weights.rs deleted file mode 100644 index 8f380e07a..000000000 --- a/runtimes/testnet/src/weights/paritydb_weights.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Polimec Blockchain – https://www.polimec.org/ -// Copyright (C) Polimec 2022. All rights reserved. - -// The Polimec Blockchain 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. - -// The Polimec Blockchain 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 . - -pub mod constants { - use frame_support::{ - parameter_types, - weights::{constants, RuntimeDbWeight}, - }; - - parameter_types! { - /// `ParityDB` can be enabled with a feature flag, but is still experimental. These weights - /// are available for brave runtime engineers who may want to try this out as default. - pub const ParityDbWeight: RuntimeDbWeight = RuntimeDbWeight { - read: 8_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - write: 50_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - }; - } - - #[cfg(test)] - mod test_db_weights { - use super::constants::ParityDbWeight as W; - use frame_support::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, - // you can delete it. - #[test] - fn sane() { - // At least 1 µs. - assert!( - W::get().reads(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, - "Read weight should be at least 1 µs." - ); - assert!( - W::get().writes(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, - "Write weight should be at least 1 µs." - ); - // At most 1 ms. - assert!( - W::get().reads(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Read weight should be at most 1 ms." - ); - assert!( - W::get().writes(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Write weight should be at most 1 ms." - ); - } - } -} diff --git a/runtimes/testnet/src/weights/rocksdb_weights.rs b/runtimes/testnet/src/weights/rocksdb_weights.rs deleted file mode 100644 index d7e720f64..000000000 --- a/runtimes/testnet/src/weights/rocksdb_weights.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Polimec Blockchain – https://www.polimec.org/ -// Copyright (C) Polimec 2022. All rights reserved. - -// The Polimec Blockchain 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. - -// The Polimec Blockchain 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 . - -pub mod constants { - use frame_support::{ - parameter_types, - weights::{constants, RuntimeDbWeight}, - }; - - parameter_types! { - /// By default, Substrate uses `RocksDB`, so this will be the weight used throughout - /// the runtime. - pub const RocksDbWeight: RuntimeDbWeight = RuntimeDbWeight { - read: 25_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - write: 100_000 * constants::WEIGHT_REF_TIME_PER_NANOS, - }; - } - - #[cfg(test)] - mod test_db_weights { - use super::constants::RocksDbWeight as W; - use frame_support::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, - // you can delete it. - #[test] - fn sane() { - // At least 1 µs. - assert!( - W::get().reads(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, - "Read weight should be at least 1 µs." - ); - assert!( - W::get().writes(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS, - "Write weight should be at least 1 µs." - ); - // At most 1 ms. - assert!( - W::get().reads(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Read weight should be at most 1 ms." - ); - assert!( - W::get().writes(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS, - "Write weight should be at most 1 ms." - ); - } - } -} diff --git a/runtimes/testnet/src/xcm_config.rs b/runtimes/testnet/src/xcm_config.rs index 5aa13b359..1c43b34db 100644 --- a/runtimes/testnet/src/xcm_config.rs +++ b/runtimes/testnet/src/xcm_config.rs @@ -26,7 +26,7 @@ use core::marker::PhantomData; use frame_support::{ match_types, parameter_types, traits::{ - fungibles::{self, Balanced, CreditOf}, + fungibles::{self, Balanced, Credit}, ConstU32, Contains, ContainsPair, Everything, Get, Nothing, }, weights::Weight, @@ -51,8 +51,9 @@ use xcm_executor::{ }; use super::{ - AccountId, AllPalletsWithSystem, AssetId as AssetIdPalletAssets, Balance, Balances, ParachainInfo, ParachainSystem, - PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, StatemintAssets, WeightToFee, XcmpQueue, + AccountId, AllPalletsWithSystem, AssetId as AssetIdPalletAssets, Balance, Balances, EnsureRoot, ParachainInfo, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, StatemintAssets, WeightToFee, + XcmpQueue, }; const DOT_ASSET_ID: AssetId = Concrete(RelayLocation::get()); @@ -121,19 +122,14 @@ pub struct NativeToFungible; impl Convert for NativeToFungible { fn convert(asset: MultiLocation) -> Result { match asset { - MultiLocation { - parents: 1, - interior: Here, - } => Ok(AssetIdPalletAssets::from(0u32)), + MultiLocation { parents: 1, interior: Here } => Ok(AssetIdPalletAssets::from(0u32)), _ => Err(asset), } } + fn reverse(value: AssetIdPalletAssets) -> Result { if value == AssetIdPalletAssets::from(0u32) { - Ok(MultiLocation { - parents: 1, - interior: Here, - }) + Ok(MultiLocation { parents: 1, interior: Here }) } else { Err(value) } @@ -155,7 +151,7 @@ impl< { fn matches_fungibles(a: &MultiAsset) -> Result<(AssetId, Balance), Error> { ConvertedConcreteId::::matches_fungibles(a) - .map_err(|_| Error::AssetNotFound) + .map_err(|_| Error::AssetNotHandled) } } @@ -250,23 +246,13 @@ impl ContainsPair for StatemintAssetsFilter { // location must be the statemint parachain let loc = MultiLocation::new(1, X1(Parachain(1000))); // asset must be either a fungible asset from `pallet_assets` or the native token of the relay chain - &loc == origin - && match asset { - MultiAsset { - id: - Concrete(MultiLocation { - parents: 0, - interior: X2(PalletInstance(50), GeneralIndex(_)), - }), - .. - } => true, + &loc == origin && + match asset { MultiAsset { - id: Concrete(MultiLocation { - parents: 1, - interior: Here, - }), + id: Concrete(MultiLocation { parents: 0, interior: X2(PalletInstance(50), GeneralIndex(_)) }), .. } => true, + MultiAsset { id: Concrete(MultiLocation { parents: 1, interior: Here }), .. } => true, _ => false, } @@ -276,8 +262,8 @@ impl ContainsPair for StatemintAssetsFilter { impl> ContainsPair for AssetsFrom { fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { let loc = T::get(); - &loc == origin - && matches!(asset, MultiAsset { id: AssetId::Concrete(asset_loc), fun: Fungible(_a) } + &loc == origin && + matches!(asset, MultiAsset { id: AssetId::Concrete(asset_loc), fun: Fungible(_a) } if asset_loc.match_and_split(&loc).is_some()) } } @@ -304,7 +290,7 @@ where R: pallet_authorship::Config + pallet_assets::Config, AccountIdOf: From + Into, { - fn handle_credit(credit: CreditOf, pallet_assets::Pallet>) { + fn handle_credit(credit: Credit, pallet_assets::Pallet>) { if let Some(author) = pallet_authorship::Pallet::::author() { // In case of error: Will drop the result triggering the `OnDrop` of the imbalance. let _ = pallet_assets::Pallet::::resolve(&author, credit); @@ -343,7 +329,7 @@ impl ContainsPair for MultiNativeAsset { fn contains(asset: &MultiAsset, origin: &MultiLocation) -> bool { if let Some(ref reserve) = asset.reserve() { if reserve == origin { - return true; + return true } } false @@ -364,35 +350,35 @@ pub type Reserves = (NativeAsset, StatemintAssetsFilter); pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { - type RuntimeCall = RuntimeCall; - type XcmSender = XcmRouter; + type AssetClaims = PolkadotXcm; + type AssetExchanger = (); + type AssetLocker = (); // How to withdraw and deposit an asset. type AssetTransactor = AssetTransactors; - type OriginConverter = XcmOriginToTransactDispatchOrigin; + type AssetTrap = PolkadotXcm; + type Barrier = Barrier; + type CallDispatcher = RuntimeCall; + type FeeManager = (); type IsReserve = Reserves; type IsTeleporter = NativeAsset; - type UniversalLocation = UniversalLocation; - type Barrier = Barrier; - type Weigher = FixedWeightBounds; + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type MessageExporter = (); + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type PalletInstancesInfo = AllPalletsWithSystem; + type ResponseHandler = PolkadotXcm; + type RuntimeCall = RuntimeCall; + // TODO: Restrict this to a subset of allowed `RuntimeCall`. + type SafeCallFilter = Everything; + type SubscriptionService = PolkadotXcm; type Trader = ( // TODO: weight to fee has to be carefully considered. For now use default - UsingComponents, HereLocation, AccountId, Balances, ToAuthor>, + UsingComponents>, FixedRateOfFungible, ); - type ResponseHandler = PolkadotXcm; - type AssetTrap = PolkadotXcm; - type AssetClaims = PolkadotXcm; - type SubscriptionService = PolkadotXcm; - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type AssetLocker = (); - type AssetExchanger = (); - type FeeManager = (); - type MessageExporter = (); type UniversalAliases = Nothing; - type CallDispatcher = RuntimeCall; - // TODO: Restrict this to a subset of allowed `RuntimeCall`. - type SafeCallFilter = Everything; + type UniversalLocation = UniversalLocation; + type Weigher = FixedWeightBounds; + type XcmSender = XcmRouter; } /// No local origins on this chain are allowed to dispatch XCM sends/executions. @@ -413,33 +399,34 @@ parameter_types! { } impl pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; + type AdminOrigin = EnsureRoot; + // ^ Override for AdvertisedXcmVersion default + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; type Currency = Balances; type CurrencyMatcher = (); - type SendXcmOrigin = EnsureXcmOrigin; - type XcmRouter = XcmRouter; type ExecuteXcmOrigin = EnsureXcmOrigin; + type MaxLockers = ConstU32<8>; + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type SendXcmOrigin = EnsureXcmOrigin; + type SovereignAccountOf = LocationToAccountId; + type TrustedLockers = (); + type UniversalLocation = UniversalLocation; + type Weigher = FixedWeightBounds; + type WeightInfo = pallet_xcm::TestWeightInfo; // TODO: change back to `Nothing` once we add the xcm functionalities into a pallet type XcmExecuteFilter = Everything; // ^ Disable dispatchable execute on the XCM pallet. // Needs to be `Everything` for local testing. type XcmExecutor = XcmExecutor; - type XcmTeleportFilter = Everything; type XcmReserveTransferFilter = Everything; - type Weigher = FixedWeightBounds; - type UniversalLocation = UniversalLocation; + type XcmRouter = XcmRouter; + type XcmTeleportFilter = Everything; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; - // ^ Override for AdvertisedXcmVersion default - type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; - type TrustedLockers = (); - type SovereignAccountOf = LocationToAccountId; - type MaxLockers = ConstU32<8>; - type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; } impl cumulus_pallet_xcm::Config for Runtime { diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 6f5d27ec8..084fd8d11 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "stable" +channel = "1.69.0" components = [ "rustfmt", "clippy" ] targets = [ "wasm32-unknown-unknown" ] \ No newline at end of file diff --git a/rustfmt.toml b/rustfmt.toml index 402b58e25..a7034e8d6 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,8 +1,19 @@ -edition = "2021" -fn_params_layout = "Compressed" -use_field_init_shorthand = true +# Basic +hard_tabs = true max_width = 120 -use_small_heuristics = "Default" # This modifies `fn_call_width`, `attr_fn_like_width`, `struct_lit_width`, `struct_variant_width`, `array_width`, `chain_width`, `single_line_if_else_max_width` according to the value of `max_width` -use_try_shorthand = true +use_small_heuristics = "Max" +# Imports +imports_granularity = "Crate" +reorder_imports = true +# Consistency newline_style = "Unix" -hard_tabs = true \ No newline at end of file +# Misc +spaces_around_ranges = false +binop_separator = "Back" +reorder_impl_items = true +match_arm_leading_pipes = "Preserve" +match_arm_blocks = false +match_block_trailing_comma = true +trailing_semicolon = false +use_field_init_shorthand = true +edition = "2021" \ No newline at end of file diff --git a/shell.nix b/shell.nix deleted file mode 100644 index c08005c16..000000000 --- a/shell.nix +++ /dev/null @@ -1,35 +0,0 @@ -let - mozillaOverlay = - import (builtins.fetchGit { - url = "https://github.com/mozilla/nixpkgs-mozilla.git"; - rev = "57c8084c7ef41366993909c20491e359bbb90f54"; - }); - pinned = builtins.fetchGit { - # Descriptive name to make the store path easier to identify - url = "https://github.com/nixos/nixpkgs/"; - # Commit hash for nixos-unstable as of 2020-04-26 - # `git ls-remote https://github.com/nixos/nixpkgs nixos-unstable` - ref = "refs/heads/nixos-unstable"; - rev = "1fe6ed37fd9beb92afe90671c0c2a662a03463dd"; - }; - nixpkgs = import pinned { overlays = [ mozillaOverlay ]; }; - toolchain = with nixpkgs; (rustChannelOf { date = "2021-09-14"; channel = "nightly"; }); - rust-wasm = toolchain.rust.override { - targets = [ "wasm32-unknown-unknown" ]; - }; -in -with nixpkgs; pkgs.mkShell { - buildInputs = [ - clang - pkg-config - rust-wasm - ] ++ stdenv.lib.optionals stdenv.isDarwin [ - darwin.apple_sdk.frameworks.Security - ]; - - LIBCLANG_PATH = "${llvmPackages.libclang}/lib"; - PROTOC = "${protobuf}/bin/protoc"; - RUST_SRC_PATH = "${toolchain.rust-src}/lib/rustlib/src/rust/library/"; - ROCKSDB_LIB_DIR = "${rocksdb}/lib"; - -} diff --git a/traits/Cargo.toml b/traits/Cargo.toml deleted file mode 100644 index aa5411b7a..000000000 --- a/traits/Cargo.toml +++ /dev/null @@ -1,42 +0,0 @@ -[package] -name = 'polimec-traits' -description = 'Common traits for Polimec pallets' -authors.workspace = true -documentation.workspace = true -edition.workspace = true -homepage.workspace = true -license-file.workspace = true -readme.workspace = true -repository.workspace = true -version.workspace = true - -[dependencies] -parity-scale-codec = { workspace = true, features = [ - "derive", -] } -scale-info = { workspace = true, features = ["derive"] } -serde = { workspace = true, features = ["derive"], default-features = false } -frame-benchmarking = { workspace = true, optional = true } -frame-support.workspace = true -frame-system.workspace = true -sp-std.workspace = true -sp-runtime.workspace = true - -[dev-dependencies] -sp-core.workspace = true -sp-io.workspace = true - -[features] -default = ["std"] -std = [ - "frame-benchmarking?/std", - "parity-scale-codec/std", - "sp-std/std", - "sp-runtime/std", - "frame-support/std", - "frame-system/std", - "scale-info/std", - "serde/std", -] -runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] -try-runtime = ["frame-support/try-runtime"] diff --git a/traits/src/lib.rs b/traits/src/lib.rs deleted file mode 100644 index ab2269e92..000000000 --- a/traits/src/lib.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Polimec Blockchain – https://www.polimec.org/ -// Copyright (C) Polimec 2022. All rights reserved. - -// The Polimec Blockchain 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. - -// The Polimec Blockchain 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 . - -#![cfg_attr(not(feature = "std"), no_std)] - -use core::slice::Iter; -use frame_support::{ - pallet_prelude::{Decode, DispatchError, Encode, MaxEncodedLen, TypeInfo}, - BoundedVec, RuntimeDebug, -}; -use serde::{Deserialize, Serialize}; -use sp_std::vec::Vec; - -/// The various roles that a member can hold. -#[derive(Copy, Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen, Serialize, Deserialize)] -pub enum MemberRole { - Issuer, - Retail, - Professional, - Institutional, -} - -impl MemberRole { - pub fn iterator() -> Iter<'static, MemberRole> { - static ROLES: [MemberRole; 4] = [ - MemberRole::Issuer, - MemberRole::Retail, - MemberRole::Professional, - MemberRole::Institutional, - ]; - ROLES.iter() - } -} - -/// The various attesters on KILT. -#[derive(Copy, Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] -pub enum Issuers { - IssuerOne, - IssuerTwo, - IssuerThree, - IssuerFour, -} - -#[derive(Copy, Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] -pub enum Country { - Switzerland, - UnitedStates, -} - -// TODO: Set this at runtime -type MaxDomicile = frame_support::traits::ConstU32<255>; - -/// A basic "credential" representation -#[derive(Clone, PartialEq, Eq, RuntimeDebug, Encode, Decode, TypeInfo, MaxEncodedLen)] -pub struct Credential { - pub issuer: Issuers, - pub role: MemberRole, - pub domicile: BoundedVec, - pub country: Country, - // TODO: Find a way to handle the date of birth - pub date_of_birth: u32, -} - -pub trait PolimecMembers { - fn is_in(role: &MemberRole, who: &AccountId) -> bool; - fn add_member(role: &MemberRole, who: &AccountId) -> Result<(), DispatchError>; - fn initialize_members(role: &MemberRole, members: &[AccountId]); - fn get_members_of(role: &MemberRole) -> Vec; - fn get_roles_of(who: &AccountId) -> Vec; -}