diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index b36e54aba7..2dc0e193bd 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -1263,6 +1263,181 @@ dependencies = [ "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "frame-executive" +version = "2.0.0" +dependencies = [ + "frame-support 2.0.0", + "frame-system 2.0.0", + "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pallet-balances 2.0.0", + "pallet-indices 2.0.0", + "pallet-transaction-payment 2.0.0", + "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 2.0.0", + "sr-primitives 2.0.0", + "sr-std 2.0.0", + "substrate-primitives 2.0.0", +] + +[[package]] +name = "frame-metadata" +version = "2.0.0" +dependencies = [ + "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-std 2.0.0", + "substrate-primitives 2.0.0", +] + +[[package]] +name = "frame-support" +version = "2.0.0" +dependencies = [ + "bitmask 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "frame-metadata 2.0.0", + "frame-support-procedural 2.0.0", + "frame-system 2.0.0", + "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "once_cell 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-arithmetic 2.0.0", + "sr-io 2.0.0", + "sr-primitives 2.0.0", + "sr-std 2.0.0", + "substrate-inherents 2.0.0", + "substrate-primitives 2.0.0", + "substrate-state-machine 2.0.0", + "tracing 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "frame-support-procedural" +version = "2.0.0" +dependencies = [ + "frame-support-procedural-tools 2.0.0", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "frame-support-procedural-tools" +version = "2.0.0" +dependencies = [ + "frame-support-procedural-tools-derive 2.0.0", + "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "frame-support-procedural-tools-derive" +version = "2.0.0" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "frame-support-rpc" +version = "2.0.0" +dependencies = [ + "frame-support 2.0.0", + "frame-system 2.0.0", + "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-client-transports 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "substrate-primitives-storage 2.0.0", + "substrate-rpc-api 2.0.0", + "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "frame-support-test" +version = "2.0.0" +dependencies = [ + "frame-support 2.0.0", + "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 2.0.0", + "sr-primitives 2.0.0", + "substrate-inherents 2.0.0", + "substrate-primitives 2.0.0", + "substrate-state-machine 2.0.0", + "trybuild 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "frame-system" +version = "2.0.0" +dependencies = [ + "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "frame-support 2.0.0", + "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 2.0.0", + "sr-primitives 2.0.0", + "sr-std 2.0.0", + "sr-version 2.0.0", + "substrate-primitives 2.0.0", +] + +[[package]] +name = "frame-system-rpc" +version = "2.0.0" +dependencies = [ + "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "frame-system-rpc-runtime-api 2.0.0", + "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-derive 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 2.0.0", + "substrate-client 2.0.0", + "substrate-primitives 2.0.0", + "substrate-test-runtime-client 2.0.0", + "substrate-transaction-pool 2.0.0", +] + +[[package]] +name = "frame-system-rpc-runtime-api" +version = "2.0.0" +dependencies = [ + "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-api 2.0.0", +] + +[[package]] +name = "frame-utility" +version = "2.0.0" +dependencies = [ + "frame-support 2.0.0", + "frame-system 2.0.0", + "pallet-balances 2.0.0", + "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 2.0.0", + "sr-primitives 2.0.0", + "sr-std 2.0.0", + "substrate-primitives 2.0.0", +] + [[package]] name = "fs-swap" version = "0.2.4" @@ -2851,6 +3026,8 @@ dependencies = [ "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "console_log 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "frame-support 2.0.0", + "frame-system 2.0.0", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2863,8 +3040,6 @@ dependencies = [ "node-primitives 2.0.0", "node-rpc 2.0.0", "node-runtime 2.0.0", - "frame-support 2.0.0", - "frame-system 2.0.0", "pallet-authority-discovery 0.1.0", "pallet-balances 2.0.0", "pallet-contracts 2.0.0", @@ -2919,11 +3094,11 @@ name = "node-executor" version = "2.0.0" dependencies = [ "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "frame-support 2.0.0", + "frame-system 2.0.0", "node-primitives 2.0.0", "node-runtime 2.0.0", "node-testing 2.0.0", - "frame-support 2.0.0", - "frame-system 2.0.0", "pallet-balances 2.0.0", "pallet-contracts 2.0.0", "pallet-grandpa 2.0.0", @@ -2958,10 +3133,10 @@ dependencies = [ name = "node-rpc" version = "2.0.0" dependencies = [ + "frame-system-rpc 2.0.0", "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 2.0.0", "node-runtime 2.0.0", - "frame-system-rpc 2.0.0", "pallet-contracts-rpc 2.0.0", "pallet-transaction-payment-rpc 2.0.0", "sr-primitives 2.0.0", @@ -2986,13 +3161,13 @@ dependencies = [ name = "node-runtime" version = "2.0.0" dependencies = [ - "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "node-primitives 2.0.0", "frame-executive 2.0.0", "frame-support 2.0.0", "frame-system 2.0.0", "frame-system-rpc-runtime-api 2.0.0", "frame-utility 2.0.0", + "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "node-primitives 2.0.0", "pallet-authority-discovery 0.1.0", "pallet-authorship 0.1.0", "pallet-babe 2.0.0", @@ -3110,11 +3285,11 @@ dependencies = [ name = "node-testing" version = "2.0.0" dependencies = [ + "frame-support 2.0.0", + "frame-system 2.0.0", "node-executor 2.0.0", "node-primitives 2.0.0", "node-runtime 2.0.0", - "frame-support 2.0.0", - "frame-system 2.0.0", "pallet-balances 2.0.0", "pallet-contracts 2.0.0", "pallet-grandpa 2.0.0", @@ -3279,181 +3454,6 @@ dependencies = [ "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "frame-executive" -version = "2.0.0" -dependencies = [ - "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "frame-support 2.0.0", - "frame-system 2.0.0", - "pallet-balances 2.0.0", - "pallet-indices 2.0.0", - "pallet-transaction-payment 2.0.0", - "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "frame-metadata" -version = "2.0.0" -dependencies = [ - "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "frame-support" -version = "2.0.0" -dependencies = [ - "bitmask 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "once_cell 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "frame-metadata 2.0.0", - "frame-support-procedural 2.0.0", - "frame-system 2.0.0", - "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-arithmetic 2.0.0", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "substrate-inherents 2.0.0", - "substrate-primitives 2.0.0", - "substrate-state-machine 2.0.0", - "tracing 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "frame-support-procedural" -version = "2.0.0" -dependencies = [ - "frame-support-procedural-tools 2.0.0", - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "frame-support-procedural-tools" -version = "2.0.0" -dependencies = [ - "frame-support-procedural-tools-derive 2.0.0", - "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "frame-support-procedural-tools-derive" -version = "2.0.0" -dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "frame-support-rpc" -version = "2.0.0" -dependencies = [ - "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-client-transports 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "frame-support 2.0.0", - "frame-system 2.0.0", - "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "substrate-primitives-storage 2.0.0", - "substrate-rpc-api 2.0.0", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "frame-support-test" -version = "2.0.0" -dependencies = [ - "frame-support 2.0.0", - "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "substrate-inherents 2.0.0", - "substrate-primitives 2.0.0", - "substrate-state-machine 2.0.0", - "trybuild 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "frame-system" -version = "2.0.0" -dependencies = [ - "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "frame-support 2.0.0", - "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "sr-version 2.0.0", - "substrate-primitives 2.0.0", -] - -[[package]] -name = "frame-system-rpc" -version = "2.0.0" -dependencies = [ - "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core-client 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-derive 14.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "frame-system-rpc-runtime-api 2.0.0", - "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-primitives 2.0.0", - "substrate-client 2.0.0", - "substrate-primitives 2.0.0", - "substrate-test-runtime-client 2.0.0", - "substrate-transaction-pool 2.0.0", -] - -[[package]] -name = "frame-system-rpc-runtime-api" -version = "2.0.0" -dependencies = [ - "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-api 2.0.0", -] - -[[package]] -name = "frame-utility" -version = "2.0.0" -dependencies = [ - "frame-support 2.0.0", - "frame-system 2.0.0", - "pallet-balances 2.0.0", - "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", - "sr-io 2.0.0", - "sr-primitives 2.0.0", - "sr-std 2.0.0", - "substrate-primitives 2.0.0", -] - [[package]] name = "pallet-assets" version = "2.0.0" @@ -3472,9 +3472,9 @@ dependencies = [ name = "pallet-aura" version = "2.0.0" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "frame-support 2.0.0", "frame-system 2.0.0", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "pallet-session 2.0.0", "pallet-timestamp 2.0.0", "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3512,9 +3512,9 @@ dependencies = [ name = "pallet-authorship" version = "0.1.0" dependencies = [ - "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "frame-support 2.0.0", "frame-system 2.0.0", + "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "sp-authorship 2.0.0", "sr-io 2.0.0", @@ -3528,10 +3528,10 @@ dependencies = [ name = "pallet-babe" version = "2.0.0" dependencies = [ - "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "frame-support 2.0.0", "frame-system 2.0.0", + "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "pallet-session 2.0.0", "pallet-timestamp 2.0.0", "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3569,9 +3569,9 @@ dependencies = [ name = "pallet-collective" version = "2.0.0" dependencies = [ - "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "frame-support 2.0.0", "frame-system 2.0.0", + "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "pallet-balances 2.0.0", "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3587,10 +3587,10 @@ name = "pallet-contracts" version = "2.0.0" dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "frame-support 2.0.0", "frame-system 2.0.0", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "pallet-balances 2.0.0", "pallet-randomness-collective-flip 2.0.0", "pallet-timestamp 2.0.0", @@ -3654,9 +3654,9 @@ dependencies = [ name = "pallet-elections" version = "2.0.0" dependencies = [ - "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "frame-support 2.0.0", "frame-system 2.0.0", + "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "pallet-balances 2.0.0", "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3671,9 +3671,9 @@ dependencies = [ name = "pallet-elections-phragmen" version = "2.0.0" dependencies = [ - "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "frame-support 2.0.0", "frame-system 2.0.0", + "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "pallet-balances 2.0.0", "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3723,9 +3723,9 @@ dependencies = [ name = "pallet-finality-tracker" version = "2.0.0" dependencies = [ - "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "frame-support 2.0.0", "frame-system 2.0.0", + "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "sp-finality-tracker 2.0.0", @@ -3881,10 +3881,10 @@ dependencies = [ name = "pallet-session" version = "2.0.0" dependencies = [ - "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "frame-support 2.0.0", "frame-system 2.0.0", + "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "pallet-timestamp 2.0.0", "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3950,9 +3950,9 @@ dependencies = [ name = "pallet-timestamp" version = "2.0.0" dependencies = [ - "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "frame-support 2.0.0", "frame-system 2.0.0", + "impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "sp-timestamp 2.0.0", @@ -5474,11 +5474,11 @@ name = "subkey" version = "2.0.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "frame-system 2.0.0", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 2.0.0", "node-runtime 2.0.0", - "frame-system 2.0.0", "pallet-balances 2.0.0", "pallet-transaction-payment 2.0.0", "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -6589,12 +6589,12 @@ name = "substrate-test-runtime" version = "2.0.0" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "memory-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "frame-executive 2.0.0", "frame-support 2.0.0", "frame-system 2.0.0", "frame-system-rpc-runtime-api 2.0.0", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "memory-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", "pallet-babe 2.0.0", "pallet-timestamp 2.0.0", "parity-scale-codec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/substrate/frame/elections-phragmen/src/lib.rs b/substrate/frame/elections-phragmen/src/lib.rs index 978a2be0d7..c9d515423e 100644 --- a/substrate/frame/elections-phragmen/src/lib.rs +++ b/substrate/frame/elections-phragmen/src/lib.rs @@ -52,15 +52,21 @@ //! //! Candidates also reserve a bond as they submit candidacy. A candidate cannot take their candidacy //! back. A candidate can end up in one of the below situations: -//! - **Winner**: A winner is kept as a _member_. They must still have a bond in reserve and they -//! are automatically counted as a candidate for the next election. -//! - **Loser**: Any of the candidate who are not a winner are left as losers. A loser might be an -//! _outgoing member_, meaning that they are an active member who failed to keep their spot. In -//! this case, the outgoing member will get their bond back. Otherwise, the bond is slashed from -//! the loser candidate. +//! - **Winner**: A winner is kept as a _member_. They must still have a bond in reserve and they +//! are automatically counted as a candidate for the next election. //! - **Runner-up**: Runners-up are the best candidates immediately after the winners. The number -//! of runners_up to keep is configurable. Runners-up are used, in order that they are elected, -//! as replacements when a candidate is kicked by `remove_member()`. +//! of runners_up to keep is configurable. Runners-up are used, in order that they are elected, +//! as replacements when a candidate is kicked by `[remove_member]`, or when an active member +//! renounces their candidacy. Runners are automatically counted as a candidate for the next +//! election. +//! - **Loser**: Any of the candidate who are not a winner are left as losers. A loser might be an +//! _outgoing member or runner_, meaning that they are an active member who failed to keep their +//! spot. An outgoing will always lose their bond. +//! +//! ##### Renouncing candidacy. +//! +//! All candidates, elected or not, can renounce their candidacy. A call to [`renounce_candidacy`] +//! will always cause the candidacy bond to be refunded. //! //! Note that with the members being the default candidates for the next round and votes persisting //! in storage, the election system is entirely stable given no further input. This means that if @@ -77,12 +83,10 @@ #![cfg_attr(not(feature = "std"), no_std)] use rstd::prelude::*; -use codec::Decode; use sr_primitives::{print, traits::{Zero, StaticLookup, Bounded, Convert}}; use support::weights::SimpleDispatchInfo; use support::{ decl_storage, decl_event, ensure, decl_module, dispatch, - storage::unhashed, traits::{ Currency, Get, LockableCurrency, LockIdentifier, ReservableCurrency, WithdrawReasons, ChangeMembers, OnUnbalanced, WithdrawReason @@ -161,11 +165,6 @@ decl_storage! { /// The present candidate list. Sorted based on account id. A current member can never enter /// this vector and is always implicitly assumed to be a candidate. pub Candidates get(fn candidates): Vec; - - /// Has the storage format been updated? - /// NOTE: Only use and set to false if you have used an early version of this module. Should - /// be set to true otherwise. - DidMigrate: bool; } } @@ -315,6 +314,7 @@ decl_module! { let index = is_candidate.unwrap_err(); ensure!(!Self::is_member(&who), "member cannot re-submit candidacy"); + ensure!(!Self::is_runner(&who), "runner cannot re-submit candidacy"); T::Currency::reserve(&who, T::CandidacyBond::get()) .map_err(|_| "candidate does not have enough funds")?; @@ -322,7 +322,63 @@ decl_module! { >::mutate(|c| c.insert(index, who)); } - /// Remove a particular member from the set. This is effective immediately. + /// Renounce one's intention to be a candidate for the next election round. 3 potential + /// outcomes exist: + /// - `origin` is a candidate and not elected in any set. In this case, the bond is + /// unreserved, returned and origin is removed as a candidate. + /// - `origin` is a current runner up. In this case, the bond is unreserved, returned and + /// origin is removed as a runner. + /// - `origin` is a current member. In this case, the bond is unreserved and origin is + /// removed as a member, consequently not being a candidate for the next round anymore. + /// Similar to [`remove_voter`], if replacement runners exists, they are immediately used. + #[weight = SimpleDispatchInfo::FixedOperational(2_000_000)] + fn renounce_candidacy(origin) { + let who = ensure_signed(origin)?; + + // NOTE: this function attempts the 3 conditions (being a candidate, member, runner) and + // fails if none are matched. Unlike other Palette functions and modules where checks + // happen first and then execution happens, this function is written the other way + // around. The main intention is that reading all of the candidates, members and runners + // from storage is expensive. Furthermore, we know (soft proof) that they are always + // mutually exclusive. Hence, we try one, and only then decode more storage. + + if let Ok(_replacement) = Self::remove_and_replace_member(&who) { + T::Currency::unreserve(&who, T::CandidacyBond::get()); + Self::deposit_event(RawEvent::MemberRenounced(who.clone())); + + // safety guard to make sure we do only one arm. Better to read runners later. + return Ok(()); + } + + let mut runners_with_stake = Self::runners_up(); + if let Ok(index) = runners_with_stake + .binary_search_by(|(ref r, ref _s)| r.cmp(&who)) + { + runners_with_stake.remove(index); + // unreserve the bond + T::Currency::unreserve(&who, T::CandidacyBond::get()); + // update storage. + >::put(runners_with_stake); + // safety guard to make sure we do only one arm. Better to read runners later. + return Ok(()); + } + + let mut candidates = Self::candidates(); + if let Ok(index) = candidates.binary_search(&who) { + candidates.remove(index); + // unreserve the bond + T::Currency::unreserve(&who, T::CandidacyBond::get()); + // update storage. + >::put(candidates); + // safety guard to make sure we do only one arm. Better to read runners later. + return Ok(()); + } + + return Err("origin is not a candidate, member or a runner."); + } + + /// Remove a particular member from the set. This is effective immediately and the bond of + /// the outgoing member is slashed. /// /// If a runner-up is available, then the best runner-up will be removed and replaces the /// outgoing member. Otherwise, a new phragmen round is started. @@ -339,51 +395,21 @@ decl_module! { ensure_root(origin)?; let who = T::Lookup::lookup(who)?; - let mut members_with_stake = Self::members(); - if let Ok(index) = members_with_stake.binary_search_by(|(ref m, ref _s)| m.cmp(&who)) { - // remove, slash, emit event. - members_with_stake.remove(index); + return Self::remove_and_replace_member(&who).map(|had_replacement| { let (imbalance, _) = T::Currency::slash_reserved(&who, T::CandidacyBond::get()); T::KickedMember::on_unbalanced(imbalance); Self::deposit_event(RawEvent::MemberKicked(who.clone())); - let mut runners_up = Self::runners_up(); - if let Some((replacement, stake)) = runners_up.pop() { - // replace the outgoing with the best runner up. - if let Err(index) = members_with_stake - .binary_search_by(|(ref m, ref _s)| m.cmp(&replacement)) - { - members_with_stake.insert(index, (replacement.clone(), stake)); - ElectionRounds::mutate(|v| *v += 1); - T::ChangeMembers::change_members_sorted( - &[replacement], - &[who], - &members_with_stake - .iter() - .map(|(m, _)| m.clone()) - .collect::>(), - ); - } - // else it would mean that the runner up was already a member. This cannot - // happen. If it does, not much that we can do about it. - - >::put(members_with_stake); - >::put(runners_up); - } else { - // update `Members` storage -- `do_phragmen` adds this to the candidate list. - >::put(members_with_stake); - // trigger a new phragmen. grab a cup of coffee. This might take a while. + if !had_replacement { Self::do_phragmen(); } - } + + () + }) } /// What to do at the end of each block. Checks if an election needs to happen or not. fn on_initialize(n: T::BlockNumber) { - if !DidMigrate::exists() { - DidMigrate::put(true); - Self::do_migrate(); - } if let Err(e) = Self::end_block(n) { print("Guru meditation"); print(e); @@ -405,6 +431,8 @@ decl_event!( /// A member has been removed. This should always be followed by either `NewTerm` ot /// `EmptyTerm`. MemberKicked(AccountId), + /// A member has renounced their candidacy. + MemberRenounced(AccountId), /// A voter (first element) was reported (byt the second element) with the the report being /// successful or not (third element). VoterReported(AccountId, AccountId, bool), @@ -412,6 +440,54 @@ decl_event!( ); impl Module { + /// Attempts to remove a member `who`. If a runner up exists, it is used as the replacement. + /// Otherwise, `Ok(false)` is returned to signal the caller. + /// + /// In both cases, [`Members`], [`ElectionRounds`] and [`RunnersUp`] storage are updated + /// accordingly. Furthermore, the membership change is reported. + /// + /// O(phragmen) in the worse case. + fn remove_and_replace_member(who: &T::AccountId) -> Result { + let mut members_with_stake = Self::members(); + if let Ok(index) = members_with_stake.binary_search_by(|(ref m, ref _s)| m.cmp(who)) { + members_with_stake.remove(index); + + let mut runners_up = Self::runners_up(); + if let Some((replacement, stake)) = runners_up.pop() { + // replace the outgoing with the best runner up. + if let Err(index) = members_with_stake + .binary_search_by(|(ref m, ref _s)| m.cmp(&replacement)) + { + members_with_stake.insert(index, (replacement.clone(), stake)); + ElectionRounds::mutate(|v| *v += 1); + T::ChangeMembers::change_members_sorted( + &[replacement], + &[who.clone()], + &members_with_stake + .iter() + .map(|(m, _)| m.clone()) + .collect::>(), + ); + } + // else it would mean that the runner up was already a member. This cannot + // happen. If it does, not much that we can do about it. + + >::put(members_with_stake); + >::put(runners_up); + + Ok(true) + } else { + // update `Members` storage -- `do_phragmen` adds this to the candidate list. + >::put(members_with_stake); + + // signal caller that no replacement has been found. + Ok(false) + } + } else { + Err("not a member") + } + } + /// Check if `who` is a candidate. It returns the insert index if the element does not exists as /// an error. /// @@ -434,6 +510,13 @@ impl Module { Self::members_ids().binary_search(who).is_ok() } + /// Check if `who` is currently an active runner. + /// + /// Limited number of runners-up. Binary search. Constant time factor. O(1) + fn is_runner(who: &T::AccountId) -> bool { + Self::runners_up_ids().binary_search(who).is_ok() + } + /// Returns number of desired members. fn desired_members() -> u32 { T::DesiredMembers::get() @@ -524,14 +607,12 @@ impl Module { let mut candidates = Self::candidates(); // candidates who explicitly called `submit_candidacy`. Only these folks are at the risk of // losing their bond. - let mut exposed_candidates = candidates.clone(); + let exposed_candidates = candidates.clone(); // current members are always a candidate for the next round as well. // this is guaranteed to not create any duplicates. candidates.append(&mut Self::members_ids()); // previous runners_up are also always candidates for the next round. candidates.append(&mut Self::runners_up_ids()); - // and exposed to being an outgoing in case they are no longer elected. - exposed_candidates.append(&mut Self::runners_up_ids()); let voters_and_votes = >::enumerate() .map(|(v, i)| (v, i)) @@ -544,9 +625,10 @@ impl Module { Self::locked_stake_of, ); - let mut to_release_bond: Vec = Vec::with_capacity(desired_seats); - let old_members = >::take(); if let Some(phragmen_result) = maybe_phragmen_result { + let old_members = >::take(); + let old_runners = >::take(); + // filter out those who had literally no votes at all. // AUDIT/NOTE: the need to do this is because all candidates, even those who have no // vote are still considered by phragmen and when good candidates are scarce, then these @@ -581,22 +663,28 @@ impl Module { // split new set into winners and runner ups. let split_point = desired_seats.min(new_set_with_stake.len()); let mut new_members = (&new_set_with_stake[..split_point]).to_vec(); - let runners_up = &new_set_with_stake[split_point..] + let new_members_ids = new_members + .iter() + .map(|(m, _)| m.clone()) + .collect::>(); + let new_runners_up = &new_set_with_stake[split_point..] .into_iter() .cloned() .rev() .collect::)>>(); + let new_runners_up_ids = new_runners_up + .iter() + .map(|(r, _)| r.clone()) + .collect::>(); + + // save the runners as-is. They are sorted based on desirability. // sort and save the members. new_members.sort(); - >::put(&new_members); - - // save the runners as-is - >::put(runners_up); // report member changes. We compute diff because we need the outgoing list. let (incoming, outgoing) = T::ChangeMembers::compute_members_diff( - &Self::members_ids(), + &new_members_ids, &old_members.into_iter().map(|(m, _)| m).collect::>(), ); T::ChangeMembers::change_members_sorted( @@ -605,62 +693,50 @@ impl Module { &Self::members_ids(), ); - // unlike exposed_candidates, these are members who were in the list and no longer - // exist. They must get their bond back. - to_release_bond = outgoing.to_vec(); + // outgoing candidates lose their bond. + let mut to_burn_bond = outgoing.to_vec(); + + // compute the outgoing of runners up as well and append them to the `to_burn_bond` + { + let (_, outgoing) = T::ChangeMembers::compute_members_diff( + &new_runners_up_ids, + &old_runners.into_iter().map(|(r, _)| r).collect::>(), + ); + to_burn_bond.extend(outgoing); + } // Burn loser bond. members list is sorted. O(NLogM) (N candidates, M members) // runner up list is not sorted. O(K*N) given K runner ups. Overall: O(NLogM + N*K) + // both the member and runner counts are bounded. exposed_candidates.into_iter().for_each(|c| { // any candidate who is not a member and not a runner up. if new_members.binary_search_by_key(&c, |(m, _)| m.clone()).is_err() - && !Self::runners_up_ids().contains(&c) + && !new_runners_up_ids.contains(&c) { let (imbalance, _) = T::Currency::slash_reserved(&c, T::CandidacyBond::get()); T::LoserCandidate::on_unbalanced(imbalance); } }); - Self::deposit_event(RawEvent::NewTerm(new_members.to_vec())); + + // Burn outgoing bonds + to_burn_bond.into_iter().for_each(|x| { + let (imbalance, _) = T::Currency::slash_reserved(&x, T::CandidacyBond::get()); + T::LoserCandidate::on_unbalanced(imbalance); + }); + + >::put(&new_members); + >::put(new_runners_up); + + Self::deposit_event(RawEvent::NewTerm(new_members.clone().to_vec())); } else { Self::deposit_event(RawEvent::EmptyTerm); } - // unreserve the bond of all the outgoings. - to_release_bond.iter().for_each(|m| { - T::Currency::unreserve(&m, T::CandidacyBond::get()); - }); - // clean candidates. >::kill(); ElectionRounds::mutate(|v| *v += 1); } - - /// Perform the storage update needed to migrate the module from the initial version of the - /// storage. - /// - /// If decoding the old storage fails in any way, the consequence is that we start with an empty - /// set. - fn do_migrate() { - // old storage format. - let old_members: Vec = unhashed::get_raw(&>::hashed_key()) - .and_then(|bytes| Decode::decode(&mut &*bytes).ok()).unwrap_or_default(); - let old_runners: Vec = unhashed::get_raw(&>::hashed_key()) - .and_then(|bytes| Decode::decode(&mut &*bytes).ok()).unwrap_or_default(); - - // new storage format. - let new_runners: Vec<(T::AccountId, BalanceOf)> = old_runners - .into_iter() - .map(|r| (r, Zero::zero())) - .collect(); - let new_members: Vec<(T::AccountId, BalanceOf)> = old_members - .into_iter() - .map(|r| (r, Zero::zero())) - .collect(); - - >::put(new_members); - >::put(new_runners); - } } #[cfg(test)] @@ -671,7 +747,7 @@ mod tests { use primitives::H256; use sr_primitives::{ Perbill, testing::Header, BuildStorage, - traits::{OnInitialize, BlakeTwo256, IdentityLookup, Block as BlockT}, + traits::{BlakeTwo256, IdentityLookup, Block as BlockT}, }; use crate as elections; @@ -860,30 +936,6 @@ mod tests { lock.amount } - #[test] - fn temp_migration_works() { - ExtBuilder::default().build().execute_with(|| { - use support::storage::unhashed; - use codec::Encode; - - let old_members = vec![1u64, 2]; - let old_runners = vec![3u64]; - - let members_key = >::hashed_key(); - let runners_key = >::hashed_key(); - - unhashed::put_raw(&members_key, &old_members.encode()[..]); - unhashed::put_raw(&runners_key, &old_runners.encode()[..]); - - assert_eq!(DidMigrate::get(), false); - >::on_initialize(1); - assert_eq!(DidMigrate::get(), true); - - assert_eq!(Elections::members(), vec![(1, 0), (2, 0)]); - assert_eq!(Elections::runners_up(), vec![(3, 0)]); - }); - } - #[test] fn params_should_work() { ExtBuilder::default().build().execute_with(|| { @@ -1017,13 +1069,36 @@ mod tests { }); } + #[test] + fn runner_candidate_submission_should_not_work() { + ExtBuilder::default().desired_runners_up(2).build().execute_with(|| { + assert_ok!(Elections::submit_candidacy(Origin::signed(5))); + assert_ok!(Elections::submit_candidacy(Origin::signed(4))); + assert_ok!(Elections::submit_candidacy(Origin::signed(3))); + + assert_ok!(Elections::vote(Origin::signed(2), vec![5, 4], 20)); + assert_ok!(Elections::vote(Origin::signed(1), vec![3], 10)); + + System::set_block_number(5); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members_ids(), vec![4, 5]); + assert_eq!(Elections::runners_up_ids(), vec![3]); + + assert_noop!( + Elections::submit_candidacy(Origin::signed(3)), + "runner cannot re-submit candidacy", + ); + }); + } + #[test] fn poor_candidate_submission_should_not_work() { ExtBuilder::default().build().execute_with(|| { assert_eq!(Elections::candidates(), Vec::::new()); assert_noop!( Elections::submit_candidacy(Origin::signed(7)), - "candidate does not have enough funds" + "candidate does not have enough funds", ); }); } @@ -1089,7 +1164,6 @@ mod tests { #[test] fn can_vote_for_old_members_even_when_no_new_candidates() { - // let allowed_votes = candidates_count as usize + Self::members().len() ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1114,7 +1188,7 @@ mod tests { assert_noop!( Elections::vote(Origin::signed(2), vec![10, 20, 30], 20), - "cannot vote more than candidates" + "cannot vote more than candidates", ); }); } @@ -1127,7 +1201,7 @@ mod tests { assert_noop!( Elections::vote(Origin::signed(2), vec![4], 1), - "cannot vote with stake less than minimum balance" + "cannot vote with stake less than minimum balance", ); }) } @@ -1484,7 +1558,6 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); assert_eq!(Elections::members_ids(), vec![4, 5]); - assert_eq!(Elections::runners_up_ids(), vec![2]); assert_eq!(balances(&2), (15, 5)); @@ -1493,16 +1566,63 @@ mod tests { System::set_block_number(10); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members_ids(), vec![4, 5]); assert_eq!(Elections::runners_up_ids(), vec![3]); - assert_eq!(balances(&3), (25, 5)); assert_eq!(balances(&2), (15, 2)); }); } #[test] - fn current_members_are_always_implicitly_next_candidate() { + fn members_lose_bond_once_outgoing() { + ExtBuilder::default().build().execute_with(|| { + assert_eq!(balances(&5), (50, 0)); + + assert_ok!(Elections::submit_candidacy(Origin::signed(5))); + assert_eq!(balances(&5), (47, 3)); + + assert_ok!(Elections::vote(Origin::signed(5), vec![5], 50)); + assert_eq!(balances(&5), (45, 5)); + + System::set_block_number(5); + assert_ok!(Elections::end_block(System::block_number())); + assert_eq!(Elections::members_ids(), vec![5]); + + assert_ok!(Elections::remove_voter(Origin::signed(5))); + assert_eq!(balances(&5), (47, 3)); + + System::set_block_number(10); + assert_ok!(Elections::end_block(System::block_number())); + assert_eq!(Elections::members_ids(), vec![]); + + assert_eq!(balances(&5), (47, 0)); + }); + } + + #[test] + fn losers_will_lose_the_bond() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(Elections::submit_candidacy(Origin::signed(5))); + assert_ok!(Elections::submit_candidacy(Origin::signed(3))); + + assert_ok!(Elections::vote(Origin::signed(4), vec![5], 40)); + + assert_eq!(balances(&5), (47, 3)); + assert_eq!(balances(&3), (27, 3)); + + System::set_block_number(5); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members_ids(), vec![5]); + + // winner + assert_eq!(balances(&5), (47, 3)); + // loser + assert_eq!(balances(&3), (27, 0)); + }); + } + + #[test] + fn current_members_are_always_next_candidate() { ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1630,55 +1750,6 @@ mod tests { }); } - #[test] - fn outgoing_will_get_the_bond_back() { - ExtBuilder::default().build().execute_with(|| { - assert_eq!(balances(&5), (50, 0)); - - assert_ok!(Elections::submit_candidacy(Origin::signed(5))); - assert_eq!(balances(&5), (47, 3)); - - assert_ok!(Elections::vote(Origin::signed(5), vec![5], 50)); - assert_eq!(balances(&5), (45, 5)); - - System::set_block_number(5); - assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members_ids(), vec![5]); - - assert_ok!(Elections::remove_voter(Origin::signed(5))); - assert_eq!(balances(&5), (47, 3)); - - System::set_block_number(10); - assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members_ids(), vec![]); - - assert_eq!(balances(&5), (50, 0)); - }); - } - - #[test] - fn losers_will_lose_the_bond() { - ExtBuilder::default().build().execute_with(|| { - assert_ok!(Elections::submit_candidacy(Origin::signed(5))); - assert_ok!(Elections::submit_candidacy(Origin::signed(3))); - - assert_ok!(Elections::vote(Origin::signed(4), vec![5], 40)); - - assert_eq!(balances(&5), (47, 3)); - assert_eq!(balances(&3), (27, 3)); - - System::set_block_number(5); - assert_ok!(Elections::end_block(System::block_number())); - - assert_eq!(Elections::members_ids(), vec![5]); - - // winner - assert_eq!(balances(&5), (47, 3)); - // loser - assert_eq!(balances(&3), (27, 0)); - }); - } - #[test] fn incoming_outgoing_are_reported() { ExtBuilder::default().build().execute_with(|| { @@ -1717,8 +1788,8 @@ mod tests { // 1 is a loser, slashed by 3. assert_eq!(balances(&1), (5, 2)); - // 5 is an outgoing loser, it will get their bond back. - assert_eq!(balances(&5), (48, 2)); + // 5 is an outgoing loser. will also get slashed. + assert_eq!(balances(&5), (45, 2)); assert_eq!( System::events()[0].event, @@ -1766,4 +1837,149 @@ mod tests { assert_eq!(Elections::runners_up(), vec![(3, 20), (2, 30)]); }); } + + #[test] + fn candidates_are_sorted() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(Elections::submit_candidacy(Origin::signed(5))); + assert_ok!(Elections::submit_candidacy(Origin::signed(3))); + + assert_eq!(Elections::candidates(), vec![3, 5]); + + assert_ok!(Elections::submit_candidacy(Origin::signed(2))); + assert_ok!(Elections::submit_candidacy(Origin::signed(4))); + assert_ok!(Elections::renounce_candidacy(Origin::signed(3))); + + assert_eq!(Elections::candidates(), vec![2, 4, 5]); + }) + } + + #[test] + fn runner_up_replacement_maintains_members_order() { + ExtBuilder::default().desired_runners_up(2).build().execute_with(|| { + assert_ok!(Elections::submit_candidacy(Origin::signed(5))); + assert_ok!(Elections::submit_candidacy(Origin::signed(4))); + assert_ok!(Elections::submit_candidacy(Origin::signed(2))); + + assert_ok!(Elections::vote(Origin::signed(2), vec![5], 20)); + assert_ok!(Elections::vote(Origin::signed(4), vec![4], 40)); + assert_ok!(Elections::vote(Origin::signed(5), vec![2], 50)); + + System::set_block_number(5); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members_ids(), vec![2, 4]); + assert_ok!(Elections::remove_member(Origin::ROOT, 2)); + assert_eq!(Elections::members_ids(), vec![4, 5]); + }); + } + + #[test] + fn can_renounce_candidacy_member_with_runners_bond_is_refunded() { + ExtBuilder::default().desired_runners_up(2).build().execute_with(|| { + assert_ok!(Elections::submit_candidacy(Origin::signed(5))); + assert_ok!(Elections::submit_candidacy(Origin::signed(4))); + assert_ok!(Elections::submit_candidacy(Origin::signed(3))); + assert_ok!(Elections::submit_candidacy(Origin::signed(2))); + + assert_ok!(Elections::vote(Origin::signed(5), vec![5], 50)); + assert_ok!(Elections::vote(Origin::signed(4), vec![4], 40)); + assert_ok!(Elections::vote(Origin::signed(3), vec![3], 30)); + assert_ok!(Elections::vote(Origin::signed(2), vec![2], 20)); + + System::set_block_number(5); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members_ids(), vec![4, 5]); + assert_eq!(Elections::runners_up_ids(), vec![2, 3]); + + assert_ok!(Elections::renounce_candidacy(Origin::signed(4))); + assert_eq!(balances(&4), (38, 2)); // 2 is voting bond. + + assert_eq!(Elections::members_ids(), vec![3, 5]); + assert_eq!(Elections::runners_up_ids(), vec![2]); + }) + } + + #[test] + fn can_renounce_candidacy_member_without_runners_bond_is_refunded() { + ExtBuilder::default().desired_runners_up(2).build().execute_with(|| { + assert_ok!(Elections::submit_candidacy(Origin::signed(5))); + assert_ok!(Elections::submit_candidacy(Origin::signed(4))); + + assert_ok!(Elections::vote(Origin::signed(5), vec![5], 50)); + assert_ok!(Elections::vote(Origin::signed(4), vec![4], 40)); + + System::set_block_number(5); + assert_ok!(Elections::end_block(System::block_number())); + + assert_ok!(Elections::submit_candidacy(Origin::signed(3))); + assert_ok!(Elections::submit_candidacy(Origin::signed(2))); + assert_ok!(Elections::vote(Origin::signed(3), vec![3], 30)); + assert_ok!(Elections::vote(Origin::signed(2), vec![2], 20)); + + assert_eq!(Elections::members_ids(), vec![4, 5]); + assert_eq!(Elections::runners_up_ids(), vec![]); + assert_eq!(Elections::candidates(), vec![2, 3]); + + assert_ok!(Elections::renounce_candidacy(Origin::signed(4))); + assert_eq!(balances(&4), (38, 2)); // 2 is voting bond. + + // no replacement + assert_eq!(Elections::members_ids(), vec![5]); + assert_eq!(Elections::runners_up_ids(), vec![]); + // still candidate + assert_eq!(Elections::candidates(), vec![2, 3]); + }) + } + + #[test] + fn can_renounce_candidacy_runner() { + ExtBuilder::default().desired_runners_up(2).build().execute_with(|| { + assert_ok!(Elections::submit_candidacy(Origin::signed(5))); + assert_ok!(Elections::submit_candidacy(Origin::signed(4))); + assert_ok!(Elections::submit_candidacy(Origin::signed(3))); + assert_ok!(Elections::submit_candidacy(Origin::signed(2))); + + assert_ok!(Elections::vote(Origin::signed(5), vec![4], 50)); + assert_ok!(Elections::vote(Origin::signed(4), vec![5], 40)); + assert_ok!(Elections::vote(Origin::signed(3), vec![3], 30)); + assert_ok!(Elections::vote(Origin::signed(2), vec![2], 20)); + + System::set_block_number(5); + assert_ok!(Elections::end_block(System::block_number())); + + assert_eq!(Elections::members_ids(), vec![4, 5]); + assert_eq!(Elections::runners_up_ids(), vec![2, 3]); + + assert_ok!(Elections::renounce_candidacy(Origin::signed(3))); + assert_eq!(balances(&3), (28, 2)); // 2 is voting bond. + + assert_eq!(Elections::members_ids(), vec![4, 5]); + assert_eq!(Elections::runners_up_ids(), vec![2]); + }) + } + + #[test] + fn can_renounce_candidacy_candidate() { + ExtBuilder::default().build().execute_with(|| { + assert_ok!(Elections::submit_candidacy(Origin::signed(5))); + assert_eq!(balances(&5), (47, 3)); + assert_eq!(Elections::candidates(), vec![5]); + + assert_ok!(Elections::renounce_candidacy(Origin::signed(5))); + assert_eq!(balances(&5), (50, 0)); + assert_eq!(Elections::candidates(), vec![]); + }) + } + + #[test] + fn wrong_renounce_candidacy_should_fail() { + ExtBuilder::default().build().execute_with(|| { + assert_noop!( + Elections::renounce_candidacy(Origin::signed(5)), + "origin is not a candidate, member or a runner.", + ); + }) + } }