diff --git a/Cargo.lock b/Cargo.lock index cc38c9c9bd250..6ad0cff53bdc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -124,7 +124,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -781,7 +781,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1035,9 +1035,9 @@ name = "failure_derive" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1633,9 +1633,9 @@ name = "impl-trait-for-tuples" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2592,7 +2592,6 @@ dependencies = [ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", "sr-primitives 2.0.0", - "srml-authority-discovery 0.1.0", "srml-balances 2.0.0", "srml-contracts 2.0.0", "srml-finality-tracker 2.0.0", @@ -2603,7 +2602,6 @@ dependencies = [ "srml-timestamp 2.0.0", "srml-transaction-payment 2.0.0", "structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "substrate-authority-discovery 2.0.0", "substrate-basic-authorship 2.0.0", "substrate-chain-spec 2.0.0", "substrate-cli 2.0.0", @@ -2676,9 +2674,11 @@ version = "2.0.0" dependencies = [ "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "node-primitives 2.0.0", + "node-runtime 2.0.0", "sr-primitives 2.0.0", "srml-contracts-rpc 2.0.0", "srml-system-rpc 2.0.0", + "srml-transaction-payment-rpc 2.0.0", "substrate-client 2.0.0", "substrate-transaction-pool 2.0.0", ] @@ -2711,7 +2711,6 @@ dependencies = [ "sr-staking-primitives 2.0.0", "sr-std 2.0.0", "sr-version 2.0.0", - "srml-authority-discovery 0.1.0", "srml-authorship 0.1.0", "srml-babe 2.0.0", "srml-balances 2.0.0", @@ -2726,6 +2725,7 @@ dependencies = [ "srml-im-online 0.1.0", "srml-indices 2.0.0", "srml-membership 2.0.0", + "srml-nicks 2.0.0", "srml-offences 1.0.0", "srml-randomness-collective-flip 2.0.0", "srml-session 2.0.0", @@ -2737,9 +2737,9 @@ dependencies = [ "srml-system-rpc-runtime-api 2.0.0", "srml-timestamp 2.0.0", "srml-transaction-payment 2.0.0", + "srml-transaction-payment-rpc-runtime-api 2.0.0", "srml-treasury 2.0.0", "srml-utility 2.0.0", - "substrate-authority-discovery-primitives 2.0.0", "substrate-client 2.0.0", "substrate-consensus-babe-primitives 2.0.0", "substrate-keyring 2.0.0", @@ -2762,6 +2762,7 @@ dependencies = [ "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 2.0.0", + "sr-primitives 2.0.0", "substrate-basic-authorship 2.0.0", "substrate-cli 2.0.0", "substrate-client 2.0.0", @@ -3170,9 +3171,9 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3277,9 +3278,9 @@ name = "proc-macro-error" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3287,9 +3288,9 @@ name = "proc-macro-hack" version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3302,7 +3303,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3405,7 +3406,7 @@ name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3789,12 +3790,12 @@ dependencies = [ [[package]] name = "rustversion" -version = "0.1.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3955,9 +3956,9 @@ name = "serde_derive" version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4142,12 +4143,12 @@ name = "sr-api-macros" version = "2.0.0" dependencies = [ "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "rustversion 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rustversion 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 2.0.0", "sr-version 2.0.0", "substrate-client 2.0.0", @@ -4617,6 +4618,21 @@ dependencies = [ "substrate-primitives 2.0.0", ] +[[package]] +name = "srml-nicks" +version = "2.0.0" +dependencies = [ + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-io 2.0.0", + "sr-primitives 2.0.0", + "sr-std 2.0.0", + "srml-balances 2.0.0", + "srml-support 2.0.0", + "srml-system 2.0.0", + "substrate-primitives 2.0.0", +] + [[package]] name = "srml-offences" version = "1.0.0" @@ -4711,10 +4727,10 @@ name = "srml-staking-reward-curve" version = "2.0.0" dependencies = [ "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (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)", "sr-primitives 2.0.0", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4871,9 +4887,37 @@ dependencies = [ "srml-balances 2.0.0", "srml-support 2.0.0", "srml-system 2.0.0", + "srml-transaction-payment-rpc-runtime-api 2.0.0", "substrate-primitives 2.0.0", ] +[[package]] +name = "srml-transaction-payment-rpc" +version = "2.0.0" +dependencies = [ + "jsonrpc-core 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core-client 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-derive 13.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 2.0.0", + "srml-transaction-payment-rpc-runtime-api 2.0.0", + "substrate-client 2.0.0", + "substrate-primitives 2.0.0", + "substrate-rpc-primitives 2.0.0", +] + +[[package]] +name = "srml-transaction-payment-rpc-runtime-api" +version = "2.0.0" +dependencies = [ + "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "sr-primitives 2.0.0", + "sr-std 2.0.0", + "substrate-client 2.0.0", +] + [[package]] name = "srml-treasury" version = "2.0.0" @@ -4964,9 +5008,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5111,9 +5155,9 @@ name = "substrate-chain-spec-derive" version = "2.0.0" dependencies = [ "proc-macro-crate 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5422,9 +5466,9 @@ dependencies = [ name = "substrate-debug-derive" version = "2.0.0" dependencies = [ - "proc-macro2 1.0.5 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -5854,8 +5898,6 @@ dependencies = [ "sr-io 2.0.0", "sr-primitives 2.0.0", "substrate-application-crypto 2.0.0", - "substrate-authority-discovery 2.0.0", - "substrate-authority-discovery-primitives 2.0.0", "substrate-chain-spec 2.0.0", "substrate-client 2.0.0", "substrate-client-db 2.0.0", @@ -6030,6 +6072,7 @@ name = "substrate-transaction-graph" version = "2.0.0" dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -6128,10 +6171,10 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (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)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -6152,9 +6195,9 @@ name = "synstructure" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -6821,9 +6864,9 @@ dependencies = [ "bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-shared 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -6853,9 +6896,9 @@ name = "wasm-bindgen-macro-support" version = "0.2.51" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.5 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-backend 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-shared 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -6873,9 +6916,9 @@ dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.5 (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.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "wasm-bindgen-backend 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -7557,7 +7600,7 @@ dependencies = [ "checksum proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097" "checksum proc-macro-hack 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "114cdf1f426eb7f550f01af5f53a33c0946156f6814aec939b3bd77e844f9a9d" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90cf5f418035b98e655e9cdb225047638296b862b42411c4e45bb88d700f7fc0" +"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum prost 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96d14b1c185652833d24aaad41c5832b0be5616a590227c1fbff57c616754b23" "checksum prost-build 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eb788126ea840817128183f8f603dce02cb7aea25c2a0b764359d8e20010702e" "checksum prost-derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e7dc378b94ac374644181a2247cebf59a6ec1c88b49ac77f3a94b86b79d0e11" @@ -7610,7 +7653,7 @@ dependencies = [ "checksum rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "403bb3a286107a04825a5f82e1270acc1e14028d3d554d7a1e08914549575ab8" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustls 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f271e3552cd835fa28c541c34a7e8fdd8cdff09d77fe4eb8f6c42e87a11b096e" -"checksum rustversion 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b48139cfc215c6cc70d43c6c555a59e723c3b5adb26a4cfa09f815a5ae5871e8" +"checksum rustversion 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c48f91977f4ef3be5358c15d131d3f663f6b4d7a112555bf3bf52ad23b6659e5" "checksum rw-stream-sink 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9cbe61c20455d3015b2bb7be39e1872310283b8e5a52f5b242b0ac7581fe78" "checksum ryu 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "19d2271fa48eaf61e53cc88b4ad9adcbafa2d512c531e7fadb6dc11a4d3656c5" "checksum safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7bf422d23a88c16d5090d455f182bc99c60af4df6a345c63428acf5129e347" @@ -7665,7 +7708,7 @@ dependencies = [ "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" "checksum subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab3af2eb31c42e8f0ccf43548232556c42737e01a96db6e1777b0be108e79799" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" +"checksum syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7bedb3320d0f3035594b0b723c8a28d7d336a3eda3881db79e61d676fb644c" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum sysinfo 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d5bd3b813d94552a8033c650691645f8dd5a63d614dddd62428a95d3931ef7b6" diff --git a/Cargo.toml b/Cargo.toml index 8d3d04c4d0595..2d68511b2e003 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,6 +82,7 @@ members = [ "srml/aura", "srml/balances", "srml/contracts", + "srml/contracts/rpc", "srml/collective", "srml/democracy", "srml/elections", @@ -96,6 +97,7 @@ members = [ "srml/indices", "srml/membership", "srml/metadata", + "srml/nicks", "srml/offences", "srml/randomness-collective-flip", "srml/scored-pool", @@ -108,6 +110,7 @@ members = [ "srml/timestamp", "srml/treasury", "srml/transaction-payment", + "srml/transaction-payment/rpc", "srml/utility", "node/cli", "node/executor", diff --git a/core/client/src/runtime_api.rs b/core/client/src/runtime_api.rs index a5700951e9c4c..68b49e5910b45 100644 --- a/core/client/src/runtime_api.rs +++ b/core/client/src/runtime_api.rs @@ -23,6 +23,9 @@ pub use state_machine::OverlayedChanges; #[cfg(feature = "std")] pub use primitives::NativeOrEncoded; #[doc(hidden)] +#[cfg(not(feature = "std"))] +pub use primitives::to_substrate_wasm_fn_return_value; +#[doc(hidden)] pub use sr_primitives::{ traits::{ Block as BlockT, GetNodeBlockType, GetRuntimeBlockType, diff --git a/core/finality-grandpa/src/communication/mod.rs b/core/finality-grandpa/src/communication/mod.rs index 6f43b1106a54e..9a6a40fb8d26b 100644 --- a/core/finality-grandpa/src/communication/mod.rs +++ b/core/finality-grandpa/src/communication/mod.rs @@ -683,7 +683,7 @@ impl> Clone for NetworkBridge { } } -fn localized_payload(round: RoundNumber, set_id: SetIdNumber, message: &E) -> Vec { +pub(crate) fn localized_payload(round: RoundNumber, set_id: SetIdNumber, message: &E) -> Vec { (message, round, set_id).encode() } diff --git a/core/finality-grandpa/src/import.rs b/core/finality-grandpa/src/import.rs index 758f6f18dbb01..8fbe0791e8c05 100644 --- a/core/finality-grandpa/src/import.rs +++ b/core/finality-grandpa/src/import.rs @@ -465,17 +465,15 @@ impl, RA, SC> BlockImport _ => {}, } - if !needs_justification && !enacts_consensus_change { - return Ok(ImportResult::Imported(imported_aux)); - } - match justification { Some(justification) => { self.import_justification(hash, number, justification, needs_justification).unwrap_or_else(|err| { - debug!(target: "finality", "Imported block #{} that enacts authority set change with \ - invalid justification: {:?}, requesting justification from peers.", number, err); - imported_aux.bad_justification = true; - imported_aux.needs_justification = true; + if needs_justification || enacts_consensus_change { + debug!(target: "finality", "Imported block #{} that enacts authority set change with \ + invalid justification: {:?}, requesting justification from peers.", number, err); + imported_aux.bad_justification = true; + imported_aux.needs_justification = true; + } }); }, None => { diff --git a/core/finality-grandpa/src/justification.rs b/core/finality-grandpa/src/justification.rs index b4de8ff058684..f5965df3e1228 100644 --- a/core/finality-grandpa/src/justification.rs +++ b/core/finality-grandpa/src/justification.rs @@ -39,7 +39,7 @@ use crate::communication; /// This is meant to be stored in the db and passed around the network to other /// nodes, and are used by syncing nodes to prove authority set handoffs. #[derive(Encode, Decode)] -pub(crate) struct GrandpaJustification { +pub struct GrandpaJustification { round: u64, pub(crate) commit: Commit, votes_ancestries: Vec, diff --git a/core/finality-grandpa/src/lib.rs b/core/finality-grandpa/src/lib.rs index 63eddfd3f33fb..68019dc8eb21b 100644 --- a/core/finality-grandpa/src/lib.rs +++ b/core/finality-grandpa/src/lib.rs @@ -96,6 +96,7 @@ mod voting_rule; pub use communication::Network; pub use finality_proof::FinalityProofProvider; +pub use justification::GrandpaJustification; pub use light_import::light_block_import; pub use observer::run_grandpa_observer; pub use voting_rule::{ diff --git a/core/finality-grandpa/src/tests.rs b/core/finality-grandpa/src/tests.rs index 8c0047e38bdbf..2767c14b27431 100644 --- a/core/finality-grandpa/src/tests.rs +++ b/core/finality-grandpa/src/tests.rs @@ -1627,3 +1627,84 @@ fn grandpa_environment_respects_voting_rules() { 19, ); } + +#[test] +fn imports_justification_for_regular_blocks_on_import() { + // NOTE: this is a regression test since initially we would only import + // justifications for authority change blocks, and would discard any + // existing justification otherwise. + let peers = &[Ed25519Keyring::Alice]; + let voters = make_ids(peers); + let api = TestApi::new(voters); + let mut net = GrandpaTestNet::new(api.clone(), 1); + + let client = net.peer(0).client().clone(); + let (mut block_import, ..) = net.make_block_import(client.clone()); + + let full_client = client.as_full().expect("only full clients are used in test"); + let builder = full_client.new_block_at(&BlockId::Number(0), Default::default()).unwrap(); + let block = builder.bake().unwrap(); + + let block_hash = block.hash(); + + // create a valid justification, with one precommit targeting the block + let justification = { + let round = 1; + let set_id = 0; + + let precommit = grandpa::Precommit { + target_hash: block_hash, + target_number: *block.header.number(), + }; + + let msg = grandpa::Message::Precommit(precommit.clone()); + let encoded = communication::localized_payload(round, set_id, &msg); + let signature = peers[0].sign(&encoded[..]).into(); + + let precommit = grandpa::SignedPrecommit { + precommit, + signature, + id: peers[0].public().into(), + }; + + let commit = grandpa::Commit { + target_hash: block_hash, + target_number: *block.header.number(), + precommits: vec![precommit], + }; + + GrandpaJustification::from_commit( + &full_client, + round, + commit, + ).unwrap() + }; + + // we import the block with justification attached + let block = BlockImportParams { + origin: BlockOrigin::File, + header: block.header, + justification: Some(justification.encode()), + post_digests: Vec::new(), + body: Some(block.extrinsics), + finalized: false, + auxiliary: Vec::new(), + fork_choice: ForkChoiceStrategy::LongestChain, + }; + + assert_eq!( + block_import.import_block(block, HashMap::new()).unwrap(), + ImportResult::Imported(ImportedAux { + needs_justification: false, + clear_justification_requests: false, + bad_justification: false, + is_new_best: true, + ..Default::default() + }), + ); + + // the justification should be imported and available from the client + assert!( + client.justification(&BlockId::Hash(block_hash)).unwrap().is_some(), + ); +} diff --git a/core/network/src/behaviour.rs b/core/network/src/behaviour.rs index 2471cbcaaf26a..28830b326eaee 100644 --- a/core/network/src/behaviour.rs +++ b/core/network/src/behaviour.rs @@ -26,7 +26,7 @@ use libp2p::core::{Multiaddr, PeerId, PublicKey}; use libp2p::kad::record; use libp2p::swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess}; use libp2p::core::{nodes::Substream, muxing::StreamMuxerBox}; -use log::warn; +use log::{debug, warn}; use sr_primitives::traits::Block as BlockT; use std::iter; use void; @@ -133,7 +133,7 @@ impl, H: ExHashT> NetworkBehaviourEventPr warn!(target: "sub-libp2p", "Connected to a non-Substrate node: {:?}", info); } if info.listen_addrs.len() > 30 { - warn!(target: "sub-libp2p", "Node {:?} has reported more than 30 addresses; \ + debug!(target: "sub-libp2p", "Node {:?} has reported more than 30 addresses; \ it is identified by {:?} and {:?}", peer_id, info.protocol_version, info.agent_version ); diff --git a/core/phragmen/src/lib.rs b/core/phragmen/src/lib.rs index 7377bac2f802a..8c8401bed6511 100644 --- a/core/phragmen/src/lib.rs +++ b/core/phragmen/src/lib.rs @@ -290,7 +290,9 @@ pub fn elect( let mut assignment = (n.who.clone(), vec![]); for e in &mut n.edges { if let Some(c) = elected_candidates.iter().cloned().find(|(c, _)| *c == e.who) { - if c.0 != n.who { + // if self_vote == false, this branch should always be executed as we want to + // collect all nominations + if c.0 != n.who || !self_vote { let per_bill_parts = { if n.load == e.load { @@ -360,6 +362,47 @@ pub fn elect( }) } +/// Build the support map from the given phragmen result. +pub fn build_support_map( + elected_stashes: &Vec, + assignments: &Vec<(AccountId, Vec>)>, + stake_of: FS, + assume_self_vote: bool, +) -> SupportMap where + AccountId: Default + Ord + Member, + Balance: Default + Copy + SimpleArithmetic, + C: Convert + Convert, + for<'r> FS: Fn(&'r AccountId) -> Balance, +{ + let to_votes = |b: Balance| >::convert(b) as ExtendedBalance; + // Initialize the support of each candidate. + let mut supports = >::new(); + elected_stashes + .iter() + .map(|e| (e, if assume_self_vote { to_votes(stake_of(e)) } else { Zero::zero() } )) + .for_each(|(e, s)| { + let item = Support { own: s, total: s, ..Default::default() }; + supports.insert(e.clone(), item); + }); + + // build support struct. + for (n, assignment) in assignments.iter() { + for (c, per_thing) in assignment.iter() { + let nominator_stake = to_votes(stake_of(n)); + // AUDIT: it is crucially important for the `Mul` implementation of all + // per-things to be sound. + let other_stake = *per_thing * nominator_stake; + if let Some(support) = supports.get_mut(c) { + // For an astronomically rich validator with more astronomically rich + // set of nominators, this might saturate. + support.total = support.total.saturating_add(other_stake); + support.others.push((n.clone(), other_stake)); + } + } + } + supports +} + /// Performs equalize post-processing to the output of the election algorithm. This happens in /// rounds. The number of rounds and the maximum diff-per-round tolerance can be tuned through input /// parameters. diff --git a/core/primitives/src/lib.rs b/core/primitives/src/lib.rs index d1b42766a08f0..02f28c797c002 100644 --- a/core/primitives/src/lib.rs +++ b/core/primitives/src/lib.rs @@ -287,3 +287,25 @@ impl From for log::Level { } } } + +/// Encodes the given value into a buffer and returns the pointer and the length as a single `u64`. +/// +/// When Substrate calls into Wasm it expects a fixed signature for functions exported +/// from the Wasm blob. The return value of this signature is always a `u64`. +/// This `u64` stores the pointer to the encoded return value and the length of this encoded value. +/// The low `32bits` are reserved for the pointer, followed by `32bit` for the length. +#[cfg(not(feature = "std"))] +pub fn to_substrate_wasm_fn_return_value(value: &impl Encode) -> u64 { + let encoded = value.encode(); + + let ptr = encoded.as_ptr() as u64; + let length = encoded.len() as u64; + let res = ptr | (length << 32); + + // Leak the output vector to avoid it being freed. + // This is fine in a WASM context since the heap + // will be discarded after the call. + rstd::mem::forget(encoded); + + res +} diff --git a/core/primitives/src/sr25519.rs b/core/primitives/src/sr25519.rs index bb319b8221828..ba7f480128081 100644 --- a/core/primitives/src/sr25519.rs +++ b/core/primitives/src/sr25519.rs @@ -129,9 +129,6 @@ impl std::fmt::Display for Public { } } -#[cfg(not(feature = "std"))] -use core as std; - impl rstd::fmt::Debug for Public { #[cfg(feature = "std")] fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result { diff --git a/core/primitives/src/testing.rs b/core/primitives/src/testing.rs index 92a09ff044f77..e5d301008e3d4 100644 --- a/core/primitives/src/testing.rs +++ b/core/primitives/src/testing.rs @@ -196,15 +196,7 @@ macro_rules! wasm_export_functions { $( $fn_impl )* } - // We need to return *something* - let output = Vec::::new(); - let res = output.as_ptr() as u64 + ((output.len() as u64) << 32); - - // Leak the output vector to avoid it being freed. - // This is fine in a WASM context since the heap - // will be discarded after the call. - $crate::rstd::mem::forget(output); - res + $crate::to_substrate_wasm_fn_return_value(&()) } }; (@IMPL @@ -232,14 +224,7 @@ macro_rules! wasm_export_functions { $( $fn_impl )* }; - let output = $crate::Encode::encode(&output); - let res = output.as_ptr() as u64 + ((output.len() as u64) << 32); - - // Leak the output vector to avoid it being freed. - // This is fine in a WASM context since the heap - // will be discarded after the call. - $crate::rstd::mem::forget(output); - res + $crate::to_substrate_wasm_fn_return_value(&output) } }; } diff --git a/core/rpc-servers/src/lib.rs b/core/rpc-servers/src/lib.rs index 3f408f6684a03..8d39386f93c4a 100644 --- a/core/rpc-servers/src/lib.rs +++ b/core/rpc-servers/src/lib.rs @@ -60,7 +60,9 @@ pub fn rpc_handler( mod inner { use super::*; + /// Type alias for http server pub type HttpServer = http::Server; + /// Type alias for ws server pub type WsServer = ws::Server; /// Start HTTP server listening on given address. diff --git a/core/service/Cargo.toml b/core/service/Cargo.toml index 04371087eff2e..0d6f27936244f 100644 --- a/core/service/Cargo.toml +++ b/core/service/Cargo.toml @@ -32,14 +32,12 @@ client = { package = "substrate-client", path = "../../core/client" } client_db = { package = "substrate-client-db", path = "../../core/client/db", features = ["kvdb-rocksdb"] } codec = { package = "parity-scale-codec", version = "1.0.0" } substrate-executor = { path = "../../core/executor" } -substrate-authority-discovery = { path = "../../core/authority-discovery"} transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" } rpc-servers = { package = "substrate-rpc-servers", path = "../../core/rpc-servers" } rpc = { package = "substrate-rpc", path = "../../core/rpc" } tel = { package = "substrate-telemetry", path = "../../core/telemetry" } offchain = { package = "substrate-offchain", path = "../../core/offchain" } parity-multiaddr = { package = "parity-multiaddr", version = "0.5.0" } -authority-discovery-primitives = { package = "substrate-authority-discovery-primitives", path = "../authority-discovery/primitives", default-features = false } [dev-dependencies] substrate-test-runtime-client = { path = "../test-runtime/client" } diff --git a/core/sr-api-macros/Cargo.toml b/core/sr-api-macros/Cargo.toml index 6f02e3040986f..022536136b80e 100644 --- a/core/sr-api-macros/Cargo.toml +++ b/core/sr-api-macros/Cargo.toml @@ -21,12 +21,17 @@ state_machine = { package = "substrate-state-machine", path = "../state-machine" sr-primitives = { path = "../sr-primitives" } sr-version = { path = "../sr-version" } primitives = { package = "substrate-primitives", path = "../primitives" } -criterion = "0.2.11" +criterion = "0.3.0" consensus_common = { package = "substrate-consensus-common", path = "../consensus/common" } codec = { package = "parity-scale-codec", version = "1.0.0" } -trybuild = "1.0.14" -rustversion = "0.1.4" +trybuild = "1.0.17" +rustversion = "1.0.0" [[bench]] name = "bench" harness = false + +# We actually don't need the `std` feature in this crate, but the tests require it. +[features] +default = [ "std" ] +std = [] diff --git a/core/sr-api-macros/src/impl_runtime_apis.rs b/core/sr-api-macros/src/impl_runtime_apis.rs index fb154aa112358..28eb5c60729ed 100644 --- a/core/sr-api-macros/src/impl_runtime_apis.rs +++ b/core/sr-api-macros/src/impl_runtime_apis.rs @@ -83,8 +83,7 @@ fn generate_impl_call( )* #[allow(deprecated)] - let output = <#runtime as #impl_trait>::#fn_name(#( #pborrow #pnames2 ),*); - #c::runtime_api::Encode::encode(&output) + <#runtime as #impl_trait>::#fn_name(#( #pborrow #pnames2 ),*) ) ) } @@ -175,11 +174,12 @@ fn generate_impl_calls( /// Generate the dispatch function that is used in native to call into the runtime. fn generate_dispatch_function(impls: &[ItemImpl]) -> Result { let data = Ident::new("data", Span::call_site()); + let c = generate_crate_access(HIDDEN_INCLUDES_ID); let impl_calls = generate_impl_calls(impls, &data)? .into_iter() .map(|(trait_, fn_name, impl_)| { let name = prefix_function_with_trait(&trait_, &fn_name); - quote!( #name => Some({ #impl_ }), ) + quote!( #name => Some(#c::runtime_api::Encode::encode(&{ #impl_ })), ) }); Ok(quote!( @@ -218,13 +218,7 @@ fn generate_wasm_interface(impls: &[ItemImpl]) -> Result { }; let output = { #impl_ }; - let res = output.as_ptr() as u64 + ((output.len() as u64) << 32); - - // Leak the output vector to avoid it being freed. - // This is fine in a WASM context since the heap - // will be discarded after the call. - #c::runtime_api::mem::forget(output); - res + #c::runtime_api::to_substrate_wasm_fn_return_value(&output) } ) }); diff --git a/core/sr-api-macros/tests/decl_and_impl.rs b/core/sr-api-macros/tests/decl_and_impl.rs index 36091d1f85062..a539d838221be 100644 --- a/core/sr-api-macros/tests/decl_and_impl.rs +++ b/core/sr-api-macros/tests/decl_and_impl.rs @@ -93,13 +93,6 @@ fn test_client_side_function_signature() { RuntimeApiImpl::::same_name_before_version_2; } -#[test] -fn test_runtime_side_function_signature() { - let _api_same_name: fn(input_data: *mut u8, input_len: usize) -> u64 = api::Api_same_name; - let _api_with_version_same_name: fn(input_data: *mut u8, input_len: usize) -> u64 = - api::ApiWithCustomVersion_same_name; -} - #[test] fn check_runtime_api_info() { assert_eq!(&Api::::ID, &runtime_decl_for_Api::ID); diff --git a/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.rs b/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.rs index 774d017c190e9..b85431f3ba049 100644 --- a/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.rs +++ b/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.rs @@ -1,6 +1,6 @@ -use sr_primitives::traits::GetNodeBlockType; +use sr_primitives::traits::{GetNodeBlockType, Block as BlockT}; use test_client::runtime::Block; -use client::{decl_runtime_apis, impl_runtime_apis}; +use client::{decl_runtime_apis, impl_runtime_apis, runtime_api}; /// The declaration of the `Runtime` type and the implementation of the `GetNodeBlockType` /// trait are done by the `construct_runtime!` macro in a real runtime. @@ -19,6 +19,18 @@ impl_runtime_apis! { impl self::Api for Runtime { fn test(data: String) {} } + + impl runtime_api::Core for Runtime { + fn version() -> runtime_api::RuntimeVersion { + unimplemented!() + } + fn execute_block(_: Block) { + unimplemented!() + } + fn initialize_block(_: &::Header) { + unimplemented!() + } + } } fn main() {} diff --git a/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.stderr b/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.stderr index 15434a52ba8b7..025ca60c48095 100644 --- a/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.stderr +++ b/core/sr-api-macros/tests/ui/impl_incorrect_method_signature.stderr @@ -10,6 +10,37 @@ error[E0053]: method `test` has an incompatible type for trait = note: expected type `fn(u64)` found type `fn(std::string::String)` +error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for trait + --> $DIR/impl_incorrect_method_signature.rs:18:1 + | +12 | / decl_runtime_apis! { +13 | | pub trait Api { +14 | | fn test(data: u64); +15 | | } +16 | | } + | |_- type in trait +17 | +18 | impl_runtime_apis! { + | ^^^^^^^^^^^^^^^^^^ expected u64, found struct `std::string::String` + | + = note: expected type `fn(&RuntimeApiImpl, &sr_primitives::generic::block::BlockId, substrate_test_runtime::Extrinsic>>, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::ExecutionContext, std::option::Option, std::vec::Vec) -> std::result::Result, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::error::Error>` + found type `fn(&RuntimeApiImpl, &sr_primitives::generic::block::BlockId, substrate_test_runtime::Extrinsic>>, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::ExecutionContext, std::option::Option, std::vec::Vec) -> std::result::Result, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::error::Error>` + +error[E0308]: mismatched types + --> $DIR/impl_incorrect_method_signature.rs:18:1 + | +18 | / impl_runtime_apis! { +19 | | impl self::Api for Runtime { +20 | | fn test(data: String) {} +21 | | } +... | +33 | | } +34 | | } + | |_^ expected u64, found struct `std::string::String` + | + = note: expected type `u64` + found type `std::string::String` + error[E0308]: mismatched types --> $DIR/impl_incorrect_method_signature.rs:20:11 | @@ -18,6 +49,3 @@ error[E0308]: mismatched types | = note: expected type `u64` found type `std::string::String` - -Some errors have detailed explanations: E0053, E0308. -For more information about an error, try `rustc --explain E0053`. diff --git a/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.rs b/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.rs index acca97a73df5b..1664bec577b57 100644 --- a/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.rs +++ b/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.rs @@ -16,6 +16,8 @@ decl_runtime_apis! { } mod second { + use super::*; + decl_runtime_apis! { pub trait Api { fn test2(data: u64); diff --git a/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.stderr b/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.stderr index 355db2864bb78..4c37b6b716a0a 100644 --- a/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.stderr +++ b/core/sr-api-macros/tests/ui/impl_two_traits_with_same_name.stderr @@ -1,25 +1,17 @@ error: Two traits with the same name detected! The trait name is used to generate its ID. Please rename one trait at the declaration! - --> $DIR/impl_two_traits_with_same_name.rs:31:15 + --> $DIR/impl_two_traits_with_same_name.rs:33:15 | -31 | impl second::Api for Runtime { +33 | impl second::Api for Runtime { | ^^^ -error: cannot find macro `decl_runtime_apis!` in this scope - --> $DIR/impl_two_traits_with_same_name.rs:19:2 +error[E0277]: the trait bound `RuntimeApiImpl: sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::Core, substrate_test_runtime::Extrinsic>>` is not satisfied + --> $DIR/impl_two_traits_with_same_name.rs:29:7 | -19 | decl_runtime_apis! { - | ^^^^^^^^^^^^^^^^^ +29 | impl self::Api for Runtime { + | ^^^^^^^^^^^^^^^^ the trait `sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::Core, substrate_test_runtime::Extrinsic>>` is not implemented for `RuntimeApiImpl` -error[E0433]: failed to resolve: could not find `runtime_decl_for_Api` in `second` - --> $DIR/impl_two_traits_with_same_name.rs:26:1 +error[E0277]: the trait bound `RuntimeApiImpl: sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::Core, substrate_test_runtime::Extrinsic>>` is not satisfied + --> $DIR/impl_two_traits_with_same_name.rs:33:7 | -26 | / impl_runtime_apis! { -27 | | impl self::Api for Runtime { -28 | | fn test(data: u64) {} -29 | | } -... | -33 | | } -34 | | } - | |_^ could not find `runtime_decl_for_Api` in `second` - -For more information about this error, try `rustc --explain E0433`. +33 | impl second::Api for Runtime { + | ^^^^^^^^^^^^^^^^^^ the trait `sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::Core, substrate_test_runtime::Extrinsic>>` is not implemented for `RuntimeApiImpl` diff --git a/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.rs b/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.rs index 0e7dc56951647..20f114c6bb29e 100644 --- a/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.rs +++ b/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.rs @@ -1,6 +1,6 @@ -use sr_primitives::traits::GetNodeBlockType; +use sr_primitives::traits::{GetNodeBlockType, Block as BlockT}; use test_client::runtime::Block; -use client::{decl_runtime_apis, impl_runtime_apis}; +use client::{decl_runtime_apis, impl_runtime_apis, runtime_api}; /// The declaration of the `Runtime` type and the implementation of the `GetNodeBlockType` /// trait are done by the `construct_runtime!` macro in a real runtime. @@ -21,6 +21,18 @@ impl_runtime_apis! { unimplemented!() } } + + impl runtime_api::Core for Runtime { + fn version() -> runtime_api::RuntimeVersion { + unimplemented!() + } + fn execute_block(_: Block) { + unimplemented!() + } + fn initialize_block(_: &::Header) { + unimplemented!() + } + } } fn main() {} diff --git a/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.stderr b/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.stderr index 9bfc04c8db046..f3abaddd6ea9d 100644 --- a/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.stderr +++ b/core/sr-api-macros/tests/ui/type_reference_in_impl_runtime_apis_call.stderr @@ -10,6 +10,22 @@ error[E0053]: method `test` has an incompatible type for trait = note: expected type `fn(u64)` found type `fn(&u64)` +error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for trait + --> $DIR/type_reference_in_impl_runtime_apis_call.rs:18:1 + | +12 | / decl_runtime_apis! { +13 | | pub trait Api { +14 | | fn test(data: u64); +15 | | } +16 | | } + | |_- type in trait +17 | +18 | impl_runtime_apis! { + | ^^^^^^^^^^^^^^^^^^ expected u64, found &u64 + | + = note: expected type `fn(&RuntimeApiImpl, &sr_primitives::generic::block::BlockId, substrate_test_runtime::Extrinsic>>, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::ExecutionContext, std::option::Option, std::vec::Vec) -> std::result::Result, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::error::Error>` + found type `fn(&RuntimeApiImpl, &sr_primitives::generic::block::BlockId, substrate_test_runtime::Extrinsic>>, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::runtime_api::ExecutionContext, std::option::Option<&u64>, std::vec::Vec) -> std::result::Result, sr_api_hidden_includes_DECL_RUNTIME_APIS::sr_api_client::error::Error>` + error[E0308]: mismatched types --> $DIR/type_reference_in_impl_runtime_apis_call.rs:18:1 | @@ -17,13 +33,10 @@ error[E0308]: mismatched types 19 | | impl self::Api for Runtime { 20 | | fn test(data: &u64) { 21 | | unimplemented!() -22 | | } -23 | | } -24 | | } +... | +35 | | } +36 | | } | |_^ expected u64, found &u64 | = note: expected type `u64` found type `&u64` - -Some errors have detailed explanations: E0053, E0308. -For more information about an error, try `rustc --explain E0053`. diff --git a/core/sr-primitives/src/generic/unchecked_extrinsic.rs b/core/sr-primitives/src/generic/unchecked_extrinsic.rs index c7bff1f4c8b36..befa857dffd64 100644 --- a/core/sr-primitives/src/generic/unchecked_extrinsic.rs +++ b/core/sr-primitives/src/generic/unchecked_extrinsic.rs @@ -23,6 +23,7 @@ use codec::{Decode, Encode, EncodeLike, Input, Error}; use crate::{ traits::{self, Member, MaybeDisplay, SignedExtension, Checkable, Extrinsic, IdentifyAccount}, generic::CheckedExtrinsic, transaction_validity::{TransactionValidityError, InvalidTransaction}, + weights::{GetDispatchInfo, DispatchInfo}, }; const TRANSACTION_VERSION: u8 = 4; @@ -280,6 +281,17 @@ where } } +impl GetDispatchInfo + for UncheckedExtrinsic +where + Call: GetDispatchInfo, + Extra: SignedExtension, +{ + fn get_dispatch_info(&self) -> DispatchInfo { + self.function.get_dispatch_info() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/core/sr-primitives/src/weights.rs b/core/sr-primitives/src/weights.rs index b245f902474ec..088f13244eb31 100644 --- a/core/sr-primitives/src/weights.rs +++ b/core/sr-primitives/src/weights.rs @@ -14,26 +14,58 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -//! Primitives for transaction weighting. +//! # Primitives for transaction weighting. //! -//! Each dispatch function within `decl_module!` can have an optional `#[weight = $x]` attribute. -//! `$x` can be any type that implements the `ClassifyDispatch` and `WeighData` traits. By -//! default, All transactions are annotated with `#[weight = SimpleDispatchInfo::default()]`. +//! All dispatchable functions defined in `decl_module!` must provide two trait implementations: +//! - [`WeightData`]: To determine the weight of the dispatch. +//! - [`ClassifyDispatch`]: To determine the class of the dispatch. See the enum definition for +//! more information on dispatch classes. +//! +//! Every dispatchable function is responsible for providing this data via an optional `#[weight = +//! $x]` attribute. In this snipped, `$x` can be any user provided struct that implements the +//! two aforementioned traits. +//! +//! Substrate then bundles then output information of the two traits into [`DispatchInfo`] struct +//! and provides it by implementing the [`GetDispatchInfo`] for all `Call` variants, and opaque +//! extrinsic types. +//! +//! If no `#[weight]` is defined, the macro automatically injects the `Default` implementation of +//! the [`SimpleDispatchInfo`]. //! //! Note that the decl_module macro _cannot_ enforce this and will simply fail if an invalid struct //! (something that does not implement `Weighable`) is passed in. +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; +use codec::{Encode, Decode}; use arithmetic::traits::Bounded; use crate::RuntimeDebug; +/// Re-export priority as type pub use crate::transaction_validity::TransactionPriority; /// Numeric range of a transaction weight. pub type Weight = u32; +/// Means of weighing some particular kind of data (`T`). +pub trait WeighData { + /// Weigh the data `T` given by `target`. When implementing this for a dispatchable, `T` will be + /// a tuple of all arguments given to the function (except origin). + fn weigh_data(&self, target: T) -> Weight; +} + +/// Means of classifying a dispatchable function. +pub trait ClassifyDispatch { + /// Classify the dispatch function based on input data `target` of type `T`. When implementing + /// this for a dispatchable, `T` will be a tuple of all arguments given to the function (except + /// origin). + fn classify_dispatch(&self, target: T) -> DispatchClass; +} + /// A generalized group of dispatch types. This is only distinguishing normal, user-triggered transactions /// (`Normal`) and anything beyond which serves a higher purpose to the system (`Operational`). -#[derive(PartialEq, Eq, Clone, Copy, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +#[derive(PartialEq, Eq, Clone, Copy, Encode, Decode, RuntimeDebug)] pub enum DispatchClass { /// A normal dispatch. Normal, @@ -82,8 +114,8 @@ impl DispatchInfo { } } -/// A `Dispatchable` function (aka transaction) that can carry some static information along with it, using the -/// `#[weight]` attribute. +/// A `Dispatchable` function (aka transaction) that can carry some static information along with +/// it, using the `#[weight]` attribute. pub trait GetDispatchInfo { /// Return a `DispatchInfo`, containing relevant information of this dispatch. /// @@ -91,18 +123,6 @@ pub trait GetDispatchInfo { fn get_dispatch_info(&self) -> DispatchInfo; } -/// Means of weighing some particular kind of data (`T`). -pub trait WeighData { - /// Weigh the data `T` given by `target`. - fn weigh_data(&self, target: T) -> Weight; -} - -/// Means of classifying a dispatchable function. -pub trait ClassifyDispatch { - /// Classify the dispatch function based on input data `target` of type `T`. - fn classify_dispatch(&self, target: T) -> DispatchClass; -} - /// Default type used with the `#[weight = x]` attribute in a substrate chain. /// /// A user may pass in any other type that implements the correct traits. If not, the `Default` @@ -114,13 +134,9 @@ pub trait ClassifyDispatch { /// - A `Free` variant is equal to `::Fixed(0)`. Note that this does not guarantee inclusion. /// - A `Max` variant is equal to `::Fixed(Weight::max_value())`. /// -/// Based on the final weight value, based on the above variants: -/// - A _weight-fee_ is deducted. -/// - The block weight is consumed proportionally. -/// /// As for the generalized groups themselves: /// - `Normal` variants will be assigned a priority proportional to their weight. They can only -/// consume a portion (1/4) of the maximum block resource limits. +/// consume a portion (defined in the system module) of the maximum block resource limits. /// - `Operational` variants will be assigned the maximum priority. They can potentially consume /// the entire block resource limit. #[derive(Clone, Copy)] diff --git a/core/telemetry/src/worker/node.rs b/core/telemetry/src/worker/node.rs index 11b1f2a81e699..0f606e4063802 100644 --- a/core/telemetry/src/worker/node.rs +++ b/core/telemetry/src/worker/node.rs @@ -58,6 +58,8 @@ struct NodeSocketConnected { pending: VecDeque, /// If true, we need to flush the sink. need_flush: bool, + /// A timeout for the socket to write data. + timeout: Option, } /// Event that can happen with this node. @@ -66,7 +68,16 @@ pub enum NodeEvent { /// We are now connected to this node. Connected, /// We are now disconnected from this node. - Disconnected(TSinkErr), + Disconnected(ConnectionError), +} + +/// Reason for disconnecting from a node. +#[derive(Debug)] +pub enum ConnectionError { + /// The connection timed-out. + Timeout, + /// The sink errored. + Sink(TSinkErr), } impl Node { @@ -116,10 +127,12 @@ where TTrans: Clone + Unpin, TTrans::Dial: Unpin, let mut socket = mem::replace(&mut self.socket, NodeSocket::Poisoned); self.socket = loop { match socket { - NodeSocket::Connected(mut conn) => + NodeSocket::Connected(mut conn) => { match NodeSocketConnected::poll(Pin::new(&mut conn), cx, &self.addr) { - Poll::Ready(Ok(v)) => match v {} - Poll::Pending => break NodeSocket::Connected(conn), + Poll::Ready(Ok(v)) => match v {}, + Poll::Pending => { + break NodeSocket::Connected(conn) + }, Poll::Ready(Err(err)) => { warn!(target: "telemetry", "Disconnected from {}: {:?}", self.addr, err); let timeout = gen_rand_reconnect_delay(); @@ -127,10 +140,16 @@ where TTrans: Clone + Unpin, TTrans::Dial: Unpin, return Poll::Ready(NodeEvent::Disconnected(err)) } } + } NodeSocket::Dialing(mut s) => match Future::poll(Pin::new(&mut s), cx) { Poll::Ready(Ok(sink)) => { debug!(target: "telemetry", "Connected to {}", self.addr); - let conn = NodeSocketConnected { sink, pending: VecDeque::new(), need_flush: false }; + let conn = NodeSocketConnected { + sink, + pending: VecDeque::new(), + need_flush: false, + timeout: None, + }; self.socket = NodeSocket::Connected(conn); return Poll::Ready(NodeEvent::Connected) }, @@ -189,18 +208,15 @@ where TTrans::Output: Sink fn poll( mut self: Pin<&mut Self>, cx: &mut Context, - my_addr: &Multiaddr - ) -> Poll> { - loop { - if let Some(item) = self.pending.pop_front() { - if let Poll::Pending = Sink::poll_ready(Pin::new(&mut self.sink), cx) { - self.pending.push_front(item); - return Poll::Pending - } + my_addr: &Multiaddr, + ) -> Poll>> { + while let Some(item) = self.pending.pop_front() { + if let Poll::Ready(_) = Sink::poll_ready(Pin::new(&mut self.sink), cx) { let item_len = item.len(); if let Err(err) = Sink::start_send(Pin::new(&mut self.sink), item) { - return Poll::Ready(Err(err)) + self.timeout = None; + return Poll::Ready(Err(ConnectionError::Sink(err))) } trace!( target: "telemetry", "Successfully sent {:?} bytes message to {}", @@ -208,28 +224,59 @@ where TTrans::Output: Sink ); self.need_flush = true; - } else if self.need_flush { - match Sink::poll_flush(Pin::new(&mut self.sink), cx) { - Poll::Pending => return Poll::Pending, - Poll::Ready(Err(err)) => return Poll::Ready(Err(err)), - Poll::Ready(Ok(())) => self.need_flush = false, + } else { + self.pending.push_front(item); + if self.timeout.is_none() { + self.timeout = Some(Delay::new(Duration::from_secs(10))); } + break; + } + } - } else { - match Stream::poll_next(Pin::new(&mut self.sink), cx) { - Poll::Ready(Some(Ok(_))) => { - // We poll the telemetry `Stream` because the underlying implementation relies on - // this in order to answer PINGs. - // We don't do anything with incoming messages, however. - }, - Poll::Ready(Some(Err(err))) => { - return Poll::Ready(Err(err)) - }, - Poll::Pending | Poll::Ready(None) => break, + if self.need_flush { + match Sink::poll_flush(Pin::new(&mut self.sink), cx) { + Poll::Pending => { + if self.timeout.is_none() { + self.timeout = Some(Delay::new(Duration::from_secs(10))); + } + }, + Poll::Ready(Err(err)) => { + self.timeout = None; + return Poll::Ready(Err(ConnectionError::Sink(err))) + }, + Poll::Ready(Ok(())) => { + self.timeout = None; + self.need_flush = false; + }, + } + } + + if let Some(timeout) = self.timeout.as_mut() { + match Future::poll(Pin::new(timeout), cx) { + Poll::Pending => {}, + Poll::Ready(Err(err)) => { + self.timeout = None; + warn!(target: "telemetry", "Connection timeout error for {} {:?}", my_addr, err); + } + Poll::Ready(Ok(_)) => { + self.timeout = None; + return Poll::Ready(Err(ConnectionError::Timeout)) } } } + match Stream::poll_next(Pin::new(&mut self.sink), cx) { + Poll::Ready(Some(Ok(_))) => { + // We poll the telemetry `Stream` because the underlying implementation relies on + // this in order to answer PINGs. + // We don't do anything with incoming messages, however. + }, + Poll::Ready(Some(Err(err))) => { + return Poll::Ready(Err(ConnectionError::Sink(err))) + }, + Poll::Pending | Poll::Ready(None) => {}, + } + Poll::Pending } } diff --git a/core/transaction-pool/graph/Cargo.toml b/core/transaction-pool/graph/Cargo.toml index fa0d6f14b6f32..4b628079cd3ce 100644 --- a/core/transaction-pool/graph/Cargo.toml +++ b/core/transaction-pool/graph/Cargo.toml @@ -18,3 +18,8 @@ assert_matches = "1.3.0" env_logger = "0.7.0" codec = { package = "parity-scale-codec", version = "1.0.0" } test_runtime = { package = "substrate-test-runtime", path = "../../test-runtime" } +criterion = "0.3" + +[[bench]] +name = "basics" +harness = false diff --git a/core/transaction-pool/graph/benches/basics.rs b/core/transaction-pool/graph/benches/basics.rs new file mode 100644 index 0000000000000..dcd725ce465f4 --- /dev/null +++ b/core/transaction-pool/graph/benches/basics.rs @@ -0,0 +1,165 @@ +// Copyright 2018-2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +use criterion::{criterion_group, criterion_main, Criterion}; + +use futures::executor::block_on; +use substrate_transaction_graph::*; +use sr_primitives::transaction_validity::{ValidTransaction, InvalidTransaction}; +use codec::Encode; +use test_runtime::{Block, Extrinsic, Transfer, H256, AccountId}; +use sr_primitives::{ + generic::BlockId, + transaction_validity::{TransactionValidity, TransactionTag as Tag}, +}; +use primitives::blake2_256; + +#[derive(Clone, Debug, Default)] +struct TestApi { + nonce_dependant: bool, +} + +impl TestApi { + fn new_dependant() -> Self { + TestApi { nonce_dependant: true } + } +} + +fn to_tag(nonce: u64, from: AccountId) -> Tag { + let mut data = [0u8; 40]; + data[..8].copy_from_slice(&nonce.to_le_bytes()[..]); + data[8..].copy_from_slice(&from.0[..]); + data.to_vec() +} + +impl ChainApi for TestApi { + type Block = Block; + type Hash = H256; + type Error = error::Error; + type ValidationFuture = futures::future::Ready>; + + fn validate_transaction( + &self, + at: &BlockId, + uxt: ExtrinsicFor, + ) -> Self::ValidationFuture { + let nonce = uxt.transfer().nonce; + let from = uxt.transfer().from.clone(); + + match self.block_id_to_number(at) { + Ok(Some(num)) if num > 5 => { + return futures::future::ready( + Ok(Err(InvalidTransaction::Stale.into())) + ) + }, + _ => {}, + } + + futures::future::ready( + Ok(Ok(ValidTransaction { + priority: 4, + requires: if nonce > 1 && self.nonce_dependant { + vec![to_tag(nonce-1, from.clone())] + } else { vec![] }, + provides: vec![to_tag(nonce, from)], + longevity: 10, + propagate: true, + })) + ) + } + + fn block_id_to_number( + &self, + at: &BlockId, + ) -> Result>, Self::Error> { + Ok(match at { + BlockId::Number(num) => Some(*num), + BlockId::Hash(_) => None, + }) + } + + fn block_id_to_hash( + &self, + at: &BlockId, + ) -> Result>, Self::Error> { + Ok(match at { + BlockId::Number(num) => Some(H256::from_low_u64_be(*num)).into(), + BlockId::Hash(_) => None, + }) + } + + fn hash_and_length(&self, uxt: &ExtrinsicFor) -> (Self::Hash, usize) { + let encoded = uxt.encode(); + (blake2_256(&encoded).into(), encoded.len()) + } +} + +fn uxt(transfer: Transfer) -> Extrinsic { + Extrinsic::Transfer(transfer, Default::default()) +} + +fn bench_configured(pool: Pool, number: u64) { + let mut futures = Vec::new(); + let mut tags = Vec::new(); + + for nonce in 1..=number { + let xt = uxt(Transfer { + from: AccountId::from_h256(H256::from_low_u64_be(1)), + to: AccountId::from_h256(H256::from_low_u64_be(2)), + amount: 5, + nonce, + }); + + tags.push(to_tag(nonce, AccountId::from_h256(H256::from_low_u64_be(1)))); + futures.push(pool.submit_one(&BlockId::Number(1), xt)); + } + + let res = block_on(futures::future::join_all(futures.into_iter())); + assert!(res.iter().all(Result::is_ok)); + + assert_eq!(pool.status().future, 0); + assert_eq!(pool.status().ready, number as usize); + + // Prune all transactions. + let block_num = 6; + block_on(pool.prune_tags( + &BlockId::Number(block_num), + tags, + vec![], + )).expect("Prune failed"); + + // pool is empty + assert_eq!(pool.status().ready, 0); + assert_eq!(pool.status().future, 0); +} + +fn benchmark_main(c: &mut Criterion) { + + c.bench_function("sequential 50 tx", |b| { + b.iter(|| { + bench_configured(Pool::new(Default::default(), TestApi::new_dependant()), 50); + }); + }); + + c.bench_function("random 100 tx", |b| { + b.iter(|| { + bench_configured(Pool::new(Default::default(), TestApi::default()), 100); + }); + }); +} + +criterion_group!(benches, benchmark_main); +criterion_main!(benches); diff --git a/core/transaction-pool/graph/src/pool.rs b/core/transaction-pool/graph/src/pool.rs index 621aeabda8ee9..dcb54f710f175 100644 --- a/core/transaction-pool/graph/src/pool.rs +++ b/core/transaction-pool/graph/src/pool.rs @@ -240,6 +240,7 @@ impl Pool { tags: impl IntoIterator, known_imported_hashes: impl IntoIterator> + Clone, ) -> impl Future> { + log::trace!(target: "txpool", "Pruning at {:?}", at); // Prune all transactions that provide given tags let prune_status = match self.validated_pool.prune_tags(tags) { Ok(prune_status) => prune_status, @@ -257,6 +258,7 @@ impl Pool { let pruned_transactions = prune_status.pruned.into_iter().map(|tx| tx.data.clone()); let reverify_future = self.verify(at, pruned_transactions, false); + log::trace!(target: "txpool", "Prunning at {:?}. Resubmitting transactions.", at); // And finally - submit reverified transactions back to the pool let at = at.clone(); let validated_pool = self.validated_pool.clone(); @@ -475,7 +477,6 @@ mod tests { Pool::new(Default::default(), TestApi::default()) } - #[test] fn should_validate_and_import_transaction() { // given @@ -909,3 +910,4 @@ mod tests { } } } + diff --git a/core/transaction-pool/graph/src/ready.rs b/core/transaction-pool/graph/src/ready.rs index 85bb4dd783c42..3698bf447eeaa 100644 --- a/core/transaction-pool/graph/src/ready.rs +++ b/core/transaction-pool/graph/src/ready.rs @@ -338,7 +338,20 @@ impl ReadyTransactions { } } - debug!(target: "txpool", "[{:?}] Pruned.", tx.hash); + // we also need to remove all other tags that this transaction provides, + // but since all the hard work is done, we only clear the provided_tag -> hash + // mapping. + let current_tag = &tag; + for tag in &tx.provides { + let removed = self.provided_tags.remove(tag); + assert_eq!( + removed.as_ref(), + if current_tag == tag { None } else { Some(&tx.hash) }, + "The pool contains exactly one transaction providing given tag; the removed transaction + claims to provide that tag, so it has to be mapped to it's hash; qed" + ); + } + removed.push(tx); } } diff --git a/core/transaction-pool/src/tests.rs b/core/transaction-pool/src/tests.rs index d1ad27dd260f0..60a9e0562fce3 100644 --- a/core/transaction-pool/src/tests.rs +++ b/core/transaction-pool/src/tests.rs @@ -27,11 +27,15 @@ use sr_primitives::{ transaction_validity::{TransactionValidity, ValidTransaction}, }; -struct TestApi; +struct TestApi { + pub modifier: Box, +} impl TestApi { fn default() -> Self { - TestApi + TestApi { + modifier: Box::new(|_| {}), + } } } @@ -54,14 +58,18 @@ impl txpool::ChainApi for TestApi { }; let provides = vec![vec![uxt.transfer().nonce as u8]]; + let mut validity = ValidTransaction { + priority: 1, + requires, + provides, + longevity: 64, + propagate: true, + }; + + (self.modifier)(&mut validity); + futures::future::ready(Ok( - Ok(ValidTransaction { - priority: 1, - requires, - provides, - longevity: 64, - propagate: true, - }) + Ok(validity) )) } @@ -181,3 +189,34 @@ fn should_ban_invalid_transactions() { // then block_on(pool.submit_one(&BlockId::number(0), uxt.clone())).unwrap_err(); } + +#[test] +fn should_correctly_prune_transactions_providing_more_than_one_tag() { + let mut api = TestApi::default(); + api.modifier = Box::new(|v: &mut ValidTransaction| { + v.provides.push(vec![155]); + }); + let pool = Pool::new(Default::default(), api); + let xt = uxt(Alice, 209); + block_on(pool.submit_one(&BlockId::number(0), xt.clone())).expect("1. Imported"); + assert_eq!(pool.status().ready, 1); + + // remove the transaction that just got imported. + block_on(pool.prune_tags(&BlockId::number(1), vec![vec![209]], vec![])).expect("1. Pruned"); + assert_eq!(pool.status().ready, 0); + // it's re-imported to future + assert_eq!(pool.status().future, 1); + + // so now let's insert another transaction that also provides the 155 + let xt = uxt(Alice, 211); + block_on(pool.submit_one(&BlockId::number(2), xt.clone())).expect("2. Imported"); + assert_eq!(pool.status().ready, 1); + assert_eq!(pool.status().future, 1); + let pending: Vec<_> = pool.ready().map(|a| a.data.transfer().nonce).collect(); + assert_eq!(pending, vec![211]); + + // prune it and make sure the pool is empty + block_on(pool.prune_tags(&BlockId::number(3), vec![vec![155]], vec![])).expect("2. Pruned"); + assert_eq!(pool.status().ready, 0); + assert_eq!(pool.status().future, 2); +} diff --git a/node-template/Cargo.toml b/node-template/Cargo.toml index bb61c2c2ca7d8..ba8c4caaf8562 100644 --- a/node-template/Cargo.toml +++ b/node-template/Cargo.toml @@ -34,6 +34,7 @@ grandpa-primitives = { package = "substrate-finality-grandpa-primitives", path = substrate-client = { path = "../core/client" } basic-authorship = { package = "substrate-basic-authorship", path = "../core/basic-authorship" } runtime = { package = "node-template-runtime", path = "runtime" } +sr-primitives = { path = "../core/sr-primitives" } [build-dependencies] vergen = "3.0.4" diff --git a/node-template/runtime/src/lib.rs b/node-template/runtime/src/lib.rs index acc5143ffe5d2..b803e184174b2 100644 --- a/node-template/runtime/src/lib.rs +++ b/node-template/runtime/src/lib.rs @@ -12,9 +12,11 @@ use rstd::prelude::*; use primitives::{OpaqueMetadata, crypto::key_types}; use sr_primitives::{ ApplyResult, transaction_validity::TransactionValidity, generic, create_runtime_str, - impl_opaque_keys, AnySignature + impl_opaque_keys, MultiSignature +}; +use sr_primitives::traits::{ + NumberFor, BlakeTwo256, Block as BlockT, StaticLookup, Verify, ConvertInto, IdentifyAccount }; -use sr_primitives::traits::{NumberFor, BlakeTwo256, Block as BlockT, StaticLookup, Verify, ConvertInto}; use sr_primitives::weights::Weight; use client::{ block_builder::api::{CheckInherentsResult, InherentData, self as block_builder_api}, @@ -39,11 +41,11 @@ pub use support::{StorageValue, construct_runtime, parameter_types, traits::Rand pub type BlockNumber = u32; /// Alias to 512-bit hash when used in the context of a transaction signature on the chain. -pub type Signature = AnySignature; +pub type Signature = MultiSignature; /// Some way of identifying an account on the chain. We intentionally make it equivalent /// to the public key of our transaction signing scheme. -pub type AccountId = ::Signer; +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; /// The type for looking up accounts. We don't expect more than 4 billion of them, but you /// never know... @@ -94,9 +96,9 @@ pub mod opaque { pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("node-template"), impl_name: create_runtime_str!("node-template"), - authoring_version: 3, - spec_version: 4, - impl_version: 4, + authoring_version: 1, + spec_version: 1, + impl_version: 1, apis: RUNTIME_API_VERSIONS, }; @@ -104,16 +106,11 @@ pub const MILLISECS_PER_BLOCK: u64 = 6000; pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; -pub const EPOCH_DURATION_IN_BLOCKS: u32 = 10 * MINUTES; - // These time units are defined in 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; -// 1 in 4 blocks (on average, not counting collisions) will be primary babe blocks. -pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); - /// The version infromation used to identify this runtime when compiled natively. #[cfg(feature = "std")] pub fn native_version() -> NativeVersion { @@ -175,7 +172,7 @@ impl grandpa::Trait for Runtime { impl indices::Trait for Runtime { /// The type for recording indexing into the account enumeration. If this ever overflows, there /// will be problems! - type AccountIndex = u32; + type AccountIndex = AccountIndex; /// Use the standard means of resolving an index hint from an id. type ResolveHint = indices::SimpleResolveHint; /// Determine whether an account is dead. @@ -346,7 +343,7 @@ impl_runtime_apis! { fn slot_duration() -> u64 { Aura::slot_duration() } - + fn authorities() -> Vec { Aura::authorities() } diff --git a/node-template/src/chain_spec.rs b/node-template/src/chain_spec.rs index b8f7fef35e86a..8d43e67304c79 100644 --- a/node-template/src/chain_spec.rs +++ b/node-template/src/chain_spec.rs @@ -1,11 +1,12 @@ -use primitives::{Pair, Public}; +use primitives::{Pair, Public, sr25519}; use runtime::{ AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, - SudoConfig, IndicesConfig, SystemConfig, WASM_BINARY, + SudoConfig, IndicesConfig, SystemConfig, WASM_BINARY, Signature }; use aura_primitives::sr25519::{AuthorityId as AuraId}; use grandpa_primitives::{AuthorityId as GrandpaId}; use substrate_service; +use sr_primitives::traits::{Verify, IdentifyAccount}; // Note this is the URL for the telemetry server //const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; @@ -31,8 +32,17 @@ pub fn get_from_seed(seed: &str) -> ::Pu .public() } +type AccountPublic = ::Signer; + +/// Helper function to generate an account ID from seed +pub fn get_account_id_from_seed(seed: &str) -> AccountId where + AccountPublic: From<::Public> +{ + AccountPublic::from(get_from_seed::(seed)).into_account() +} + /// Helper function to generate an authority key for Aura -pub fn get_authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) { +pub fn get_authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) { ( get_from_seed::(s), get_from_seed::(s), @@ -49,12 +59,12 @@ impl Alternative { || testnet_genesis(vec![ get_authority_keys_from_seed("Alice"), ], - get_from_seed::("Alice"), + get_account_id_from_seed::("Alice"), vec![ - get_from_seed::("Alice"), - get_from_seed::("Bob"), - get_from_seed::("Alice//stash"), - get_from_seed::("Bob//stash"), + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), ], true), vec![], @@ -69,21 +79,21 @@ impl Alternative { || testnet_genesis(vec![ get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob"), - ], - get_from_seed::("Alice"), + ], + get_account_id_from_seed::("Alice"), vec![ - get_from_seed::("Alice"), - get_from_seed::("Bob"), - get_from_seed::("Charlie"), - get_from_seed::("Dave"), - get_from_seed::("Eve"), - get_from_seed::("Ferdie"), - get_from_seed::("Alice//stash"), - get_from_seed::("Bob//stash"), - get_from_seed::("Charlie//stash"), - get_from_seed::("Dave//stash"), - get_from_seed::("Eve//stash"), - get_from_seed::("Ferdie//stash"), + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), ], true), vec![], @@ -105,7 +115,7 @@ impl Alternative { } fn testnet_genesis(initial_authorities: Vec<(AuraId, GrandpaId)>, - root_key: AccountId, + root_key: AccountId, endowed_accounts: Vec, _enable_println: bool) -> GenesisConfig { GenesisConfig { diff --git a/node-template/src/service.rs b/node-template/src/service.rs index 203e311df9df9..8972cffa96eb6 100644 --- a/node-template/src/service.rs +++ b/node-template/src/service.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use std::time::Duration; use substrate_client::LongestChain; -use futures::prelude::*; use runtime::{self, GenesisConfig, opaque::Block, RuntimeApi}; use substrate_service::{error::{Error as ServiceError}, AbstractService, Configuration, ServiceBuilder}; use transaction_pool::{self, txpool::{Pool as TransactionPool}}; diff --git a/node/cli/Cargo.toml b/node/cli/Cargo.toml index 5fa92360d62cf..7e011d9de8687 100644 --- a/node/cli/Cargo.toml +++ b/node/cli/Cargo.toml @@ -48,8 +48,6 @@ balances = { package = "srml-balances", path = "../../srml/balances" } transaction-payment = { package = "srml-transaction-payment", path = "../../srml/transaction-payment" } support = { package = "srml-support", path = "../../srml/support", default-features = false } im_online = { package = "srml-im-online", path = "../../srml/im-online", default-features = false } -sr-authority-discovery = { package = "srml-authority-discovery", path = "../../srml/authority-discovery", default-features = false } -authority-discovery = { package = "substrate-authority-discovery", path = "../../core/authority-discovery"} serde = { version = "1.0.101", features = [ "derive" ] } client_db = { package = "substrate-client-db", path = "../../core/client/db", features = ["kvdb-rocksdb"] } offchain = { package = "substrate-offchain", path = "../../core/offchain" } diff --git a/node/cli/src/chain_spec.rs b/node/cli/src/chain_spec.rs index 721fdbaf99576..04fb41c211009 100644 --- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -20,23 +20,22 @@ use chain_spec::ChainSpecExtension; use primitives::{Pair, Public, crypto::UncheckedInto, sr25519}; use serde::{Serialize, Deserialize}; use node_runtime::{ - AuthorityDiscoveryConfig, BabeConfig, BalancesConfig, ContractsConfig, CouncilConfig, DemocracyConfig, - ElectionsConfig, GrandpaConfig, ImOnlineConfig, IndicesConfig, SessionConfig, SessionKeys, StakerStatus, - StakingConfig, SudoConfig, SystemConfig, TechnicalCommitteeConfig, WASM_BINARY, + BabeConfig, BalancesConfig, ContractsConfig, CouncilConfig, DemocracyConfig, GrandpaConfig, + ImOnlineConfig, IndicesConfig, SessionConfig, SessionKeys, StakerStatus, StakingConfig, + SudoConfig, SystemConfig, TechnicalCommitteeConfig, WASM_BINARY, }; use node_runtime::Block; -use node_runtime::constants::{time::*, currency::*}; +use node_runtime::constants::currency::*; use substrate_service; use hex_literal::hex; use substrate_telemetry::TelemetryEndpoints; use grandpa_primitives::{AuthorityId as GrandpaId}; use babe_primitives::{AuthorityId as BabeId}; use im_online::sr25519::{AuthorityId as ImOnlineId}; -use sr_primitives::{traits::Verify, Perbill}; +use sr_primitives::{Perbill, traits::{Verify, IdentifyAccount}}; pub use node_primitives::{AccountId, Balance, Signature}; pub use node_runtime::GenesisConfig; -use sr_primitives::traits::IdentifyAccount; type AccountPublic = ::Signer; @@ -244,12 +243,6 @@ pub fn testnet_genesis( members: vec![], phantom: Default::default(), }), - elections_phragmen: Some(ElectionsConfig { - members: endowed_accounts.iter().take(2).cloned().collect(), - term_duration: 28 * DAYS, - desired_members: 4, - desired_runners_up: 1, - }), contracts: Some(ContractsConfig { current_schedule: contracts::Schedule { enable_println, // this should only be enabled on development chains @@ -266,9 +259,6 @@ pub fn testnet_genesis( im_online: Some(ImOnlineConfig { keys: vec![], }), - authority_discovery: Some(AuthorityDiscoveryConfig{ - keys: vec![], - }), grandpa: Some(GrandpaConfig { authorities: vec![], }), diff --git a/node/cli/src/service.rs b/node/cli/src/service.rs index 78b978b72b7ac..ef1fd8ad9f386 100644 --- a/node/cli/src/service.rs +++ b/node/cli/src/service.rs @@ -130,8 +130,8 @@ macro_rules! new_full { // back-pressure. Authority discovery is triggering one event per authority within the current authority set. // This estimates the authority set size to be somewhere below 10 000 thereby setting the channel buffer size to // 10 000. - let (dht_event_tx, dht_event_rx) = - mpsc::channel::(10000); + let (dht_event_tx, _dht_event_rx) = + mpsc::channel::(10_000); let service = builder.with_network_protocol(|_| Ok(crate::service::NodeProtocol::new()))? .with_finality_proof_provider(|client, backend| @@ -169,14 +169,6 @@ macro_rules! new_full { let babe = babe::start_babe(babe_config)?; service.spawn_essential_task(babe); - - let authority_discovery = authority_discovery::AuthorityDiscovery::new( - service.client(), - service.network(), - dht_event_rx, - ); - - service.spawn_task(authority_discovery); } let config = grandpa::Config { diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index 5d2ca81e0ff84..5e8b7614892ba 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -8,7 +8,9 @@ edition = "2018" client = { package = "substrate-client", path = "../../core/client" } jsonrpc-core = "13.2.0" node-primitives = { path = "../primitives" } +node-runtime = { path = "../runtime" } sr-primitives = { path = "../../core/sr-primitives" } srml-contracts-rpc = { path = "../../srml/contracts/rpc/" } +srml-transaction-payment-rpc = { path = "../../srml/transaction-payment/rpc/" } srml-system-rpc = { path = "../../srml/system/rpc/" } transaction_pool = { package = "substrate-transaction-pool", path = "../../core/transaction-pool" } diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index 398d458e63a20..99321373f8f8c 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -32,6 +32,7 @@ use std::sync::Arc; use node_primitives::{Block, AccountId, Index, Balance}; +use node_runtime::UncheckedExtrinsic; use sr_primitives::traits::ProvideRuntimeApi; use transaction_pool::txpool::{ChainApi, Pool}; @@ -42,18 +43,23 @@ pub fn create(client: Arc, pool: Arc>) -> jsonrpc_core::IoHa C: Send + Sync + 'static, C::Api: srml_system_rpc::AccountNonceApi, C::Api: srml_contracts_rpc::ContractsRuntimeApi, + C::Api: srml_transaction_payment_rpc::TransactionPaymentRuntimeApi, P: ChainApi + Sync + Send + 'static, M: jsonrpc_core::Metadata + Default, { use srml_system_rpc::{System, SystemApi}; use srml_contracts_rpc::{Contracts, ContractsApi}; + use srml_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; let mut io = jsonrpc_core::IoHandler::default(); io.extend_with( SystemApi::to_delegate(System::new(client.clone(), pool)) ); io.extend_with( - ContractsApi::to_delegate(Contracts::new(client)) + ContractsApi::to_delegate(Contracts::new(client.clone())) + ); + io.extend_with( + TransactionPaymentApi::to_delegate(TransactionPayment::new(client)) ); io } diff --git a/node/runtime/Cargo.toml b/node/runtime/Cargo.toml index 5a6a2b6772c1e..0aa2dc551ef3a 100644 --- a/node/runtime/Cargo.toml +++ b/node/runtime/Cargo.toml @@ -12,7 +12,6 @@ rustc-hex = { version = "2.0", optional = true } safe-mix = { version = "1.0", default-features = false } serde = { version = "1.0.101", optional = true } -authority-discovery-primitives = { package = "substrate-authority-discovery-primitives", path = "../../core/authority-discovery/primitives", default-features = false } babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../../core/consensus/babe/primitives", default-features = false } client = { package = "substrate-client", path = "../../core/client", default-features = false } node-primitives = { path = "../primitives", default-features = false } @@ -25,7 +24,6 @@ substrate-keyring = { path = "../../core/keyring", optional = true } substrate-session = { path = "../../core/session", default-features = false } version = { package = "sr-version", path = "../../core/sr-version", default-features = false } -authority-discovery = { package = "srml-authority-discovery", path = "../../srml/authority-discovery", default-features = false } authorship = { package = "srml-authorship", path = "../../srml/authorship", default-features = false } babe = { package = "srml-babe", path = "../../srml/babe", default-features = false } balances = { package = "srml-balances", path = "../../srml/balances", default-features = false } @@ -40,6 +38,7 @@ grandpa = { package = "srml-grandpa", path = "../../srml/grandpa", default-featu im-online = { package = "srml-im-online", path = "../../srml/im-online", default-features = false } indices = { package = "srml-indices", path = "../../srml/indices", default-features = false } membership = { package = "srml-membership", path = "../../srml/membership", default-features = false } +nicks = { package = "srml-nicks", path = "../../srml/nicks", default-features = false } offences = { package = "srml-offences", path = "../../srml/offences", default-features = false } randomness-collective-flip = { package = "srml-randomness-collective-flip", path = "../../srml/randomness-collective-flip", default-features = false } session = { package = "srml-session", path = "../../srml/session", default-features = false, features = ["historical"] } @@ -53,6 +52,7 @@ timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default treasury = { package = "srml-treasury", path = "../../srml/treasury", default-features = false } utility = { package = "srml-utility", path = "../../srml/utility", default-features = false } transaction-payment = { package = "srml-transaction-payment", path = "../../srml/transaction-payment", default-features = false } +transaction-payment-rpc-runtime-api = { package = "srml-transaction-payment-rpc-runtime-api", path = "../../srml/transaction-payment/rpc/runtime-api/", default-features = false } [build-dependencies] wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "1.0.4", path = "../../core/utils/wasm-builder-runner" } @@ -63,8 +63,6 @@ runtime_io = { package = "sr-io", path = "../../core/sr-io" } [features] default = ["std"] std = [ - "authority-discovery-primitives/std", - "authority-discovery/std", "authorship/std", "babe-primitives/std", "babe/std", @@ -82,6 +80,7 @@ std = [ "im-online/std", "indices/std", "membership/std", + "nicks/std", "node-primitives/std", "offchain-primitives/std", "offences/std", @@ -105,5 +104,6 @@ std = [ "treasury/std", "utility/std", "transaction-payment/std", + "transaction-payment-rpc-runtime-api/std", "version/std", ] diff --git a/node/runtime/src/lib.rs b/node/runtime/src/lib.rs index 3b72ff40faafc..3dba79d27ba9b 100644 --- a/node/runtime/src/lib.rs +++ b/node/runtime/src/lib.rs @@ -29,7 +29,7 @@ use node_primitives::{ AccountId, AccountIndex, Balance, BlockNumber, Hash, Index, Moment, Signature, }; -use babe_primitives::{AuthorityId as BabeId, AuthoritySignature as BabeSignature}; +use babe_primitives::AuthorityId as BabeId; use grandpa::fg_primitives; use client::{ block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult}, @@ -50,8 +50,8 @@ use version::NativeVersion; use primitives::OpaqueMetadata; use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight}; use im_online::sr25519::{AuthorityId as ImOnlineId}; -use authority_discovery_primitives::{AuthorityId as EncodedAuthorityId, Signature as EncodedSignature}; -use codec::{Encode, Decode}; +use transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; +use contracts_rpc_runtime_api::ContractExecResult; use system::offchain::TransactionSubmitter; #[cfg(any(feature = "std", test))] @@ -83,8 +83,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to equal spec_version. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 184, - impl_version: 185, + spec_version: 189, + impl_version: 190, apis: RUNTIME_API_VERSIONS, }; @@ -211,7 +211,10 @@ impl authorship::Trait for Runtime { type EventHandler = Staking; } -type SessionHandlers = (Grandpa, Babe, ImOnline, AuthorityDiscovery); +// !!!!!!!!!!!!! +// WARNING!!!!!! SEE NOTE BELOW BEFORE TOUCHING THIS CODE +// !!!!!!!!!!!!! +type SessionHandlers = (Grandpa, Babe, ImOnline); impl_opaque_keys! { pub struct SessionKeys { @@ -327,6 +330,9 @@ impl collective::Trait for Runtime { parameter_types! { pub const CandidacyBond: Balance = 10 * DOLLARS; pub const VotingBond: Balance = 1 * DOLLARS; + pub const TermDuration: BlockNumber = 7 * DAYS; + pub const DesiredMembers: u32 = 13; + pub const DesiredRunnersUp: u32 = 7; } impl elections_phragmen::Trait for Runtime { @@ -335,6 +341,9 @@ impl elections_phragmen::Trait for Runtime { type CurrencyToVote = CurrencyToVoteHandler; type CandidacyBond = CandidacyBond; type VotingBond = VotingBond; + type TermDuration = TermDuration; + type DesiredMembers = DesiredMembers; + type DesiredRunnersUp = DesiredRunnersUp; type LoserCandidate = (); type BadReport = (); type KickedMember = (); @@ -370,7 +379,6 @@ impl treasury::Trait for Runtime { type ApproveOrigin = collective::EnsureMembers<_4, AccountId, CouncilCollective>; type RejectOrigin = collective::EnsureMembers<_2, AccountId, CouncilCollective>; type Event = Event; - type MintedForSpending = (); type ProposalRejection = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ProposalBondMinimum; @@ -440,10 +448,6 @@ impl offences::Trait for Runtime { type OnOffenceHandler = Staking; } -impl authority_discovery::Trait for Runtime { - type AuthorityId = BabeId; -} - impl grandpa::Trait for Runtime { type Event = Event; } @@ -459,6 +463,22 @@ impl finality_tracker::Trait for Runtime { type ReportLatency = ReportLatency; } +parameter_types! { + pub const ReservationFee: Balance = 1 * DOLLARS; + pub const MinLength: usize = 3; + pub const MaxLength: usize = 16; +} + +impl nicks::Trait for Runtime { + type Event = Event; + type Currency = Balances; + type ReservationFee = ReservationFee; + type Slashed = Treasury; + type ForceOrigin = collective::EnsureMember; + type MinLength = MinLength; + type MaxLength = MaxLength; +} + impl system::offchain::CreateTransaction for Runtime { type Public = ::Signer; type Signature = Signature; @@ -508,7 +528,7 @@ construct_runtime!( Democracy: democracy::{Module, Call, Storage, Config, Event}, Council: collective::::{Module, Call, Storage, Origin, Event, Config}, TechnicalCommittee: collective::::{Module, Call, Storage, Origin, Event, Config}, - Elections: elections_phragmen::{Module, Call, Storage, Event, Config}, + Elections: elections_phragmen::{Module, Call, Storage, Event}, TechnicalMembership: membership::::{Module, Call, Storage, Event, Config}, FinalityTracker: finality_tracker::{Module, Call, Inherent}, Grandpa: grandpa::{Module, Call, Storage, Config, Event}, @@ -516,9 +536,9 @@ construct_runtime!( Contracts: contracts, Sudo: sudo, ImOnline: im_online::{Module, Call, Storage, Event, ValidateUnsigned, Config}, - AuthorityDiscovery: authority_discovery::{Module, Call, Config}, Offences: offences::{Module, Call, Storage, Event}, RandomnessCollectiveFlip: randomness_collective_flip::{Module, Call, Storage}, + Nicks: nicks::{Module, Call, Storage, Event}, } ); @@ -630,35 +650,6 @@ impl_runtime_apis! { } } - impl authority_discovery_primitives::AuthorityDiscoveryApi for Runtime { - fn authorities() -> Vec { - AuthorityDiscovery::authorities().into_iter() - .map(|id| id.encode()) - .map(EncodedAuthorityId) - .collect() - } - - fn sign(payload: &Vec) -> Option<(EncodedSignature, EncodedAuthorityId)> { - AuthorityDiscovery::sign(payload).map(|(sig, id)| { - (EncodedSignature(sig.encode()), EncodedAuthorityId(id.encode())) - }) - } - - fn verify(payload: &Vec, signature: &EncodedSignature, authority_id: &EncodedAuthorityId) -> bool { - let signature = match BabeSignature::decode(&mut &signature.0[..]) { - Ok(s) => s, - _ => return false, - }; - - let authority_id = match BabeId::decode(&mut &authority_id.0[..]) { - Ok(id) => id, - _ => return false, - }; - - AuthorityDiscovery::verify(payload, signature, authority_id) - } - } - impl system_rpc_runtime_api::AccountNonceApi for Runtime { fn account_nonce(account: AccountId) -> Index { System::account_nonce(account) @@ -672,9 +663,7 @@ impl_runtime_apis! { value: Balance, gas_limit: u64, input_data: Vec, - ) -> contracts_rpc_runtime_api::ContractExecResult { - use contracts_rpc_runtime_api::ContractExecResult; - + ) -> ContractExecResult { let exec_result = Contracts::bare_call( origin, dest.into(), @@ -692,9 +681,20 @@ impl_runtime_apis! { } } + impl transaction_payment_rpc_runtime_api::TransactionPaymentApi< + Block, + Balance, + UncheckedExtrinsic, + > for Runtime { + fn query_info(uxt: UncheckedExtrinsic, len: u32) -> RuntimeDispatchInfo { + TransactionPayment::query_info(uxt, len) + } + } + impl substrate_session::SessionKeys for Runtime { fn generate_session_keys(seed: Option>) -> Vec { - let seed = seed.as_ref().map(|s| rstd::str::from_utf8(&s).expect("Seed is an utf8 string")); + let seed = seed.as_ref().map(|s| rstd::str::from_utf8(&s) + .expect("Seed is an utf8 string")); SessionKeys::generate(seed) } } diff --git a/node/testing/src/genesis.rs b/node/testing/src/genesis.rs index 5220d1774be89..0b99052f25026 100644 --- a/node/testing/src/genesis.rs +++ b/node/testing/src/genesis.rs @@ -89,12 +89,10 @@ pub fn config(support_changes_trie: bool, code: Option<&[u8]>) -> GenesisConfig authorities: vec![], }), im_online: Some(Default::default()), - authority_discovery: Some(Default::default()), democracy: Some(Default::default()), collective_Instance1: Some(Default::default()), collective_Instance2: Some(Default::default()), membership_Instance1: Some(Default::default()), - elections_phragmen: Some(Default::default()), sudo: Some(Default::default()), treasury: Some(Default::default()), } diff --git a/srml/assets/src/lib.rs b/srml/assets/src/lib.rs index 528428000eb58..5c8b1bbd610a3 100644 --- a/srml/assets/src/lib.rs +++ b/srml/assets/src/lib.rs @@ -328,7 +328,7 @@ mod tests { } #[test] - fn transferring_amount_less_than_available_balance_should_not_work() { + fn transferring_amount_more_than_available_balance_should_not_work() { new_test_ext().execute_with(|| { assert_ok!(Assets::issue(Origin::signed(1), 100)); assert_eq!(Assets::balance(0, 1), 100); diff --git a/srml/balances/src/lib.rs b/srml/balances/src/lib.rs index 3c354da50881b..71f37cb8f8193 100644 --- a/srml/balances/src/lib.rs +++ b/srml/balances/src/lib.rs @@ -824,13 +824,13 @@ where fn ensure_can_withdraw( who: &T::AccountId, _amount: T::Balance, - reason: WithdrawReason, + reasons: WithdrawReasons, new_balance: T::Balance, ) -> Result { - match reason { - WithdrawReason::Reserve | WithdrawReason::Transfer if Self::vesting_balance(who) > new_balance => - return Err("vesting balance too high to send value"), - _ => {} + if reasons.intersects(WithdrawReason::Reserve | WithdrawReason::Transfer) + && Self::vesting_balance(who) > new_balance + { + return Err("vesting balance too high to send value"); } let locks = Self::locks(who); if locks.is_empty() { @@ -842,7 +842,7 @@ where .all(|l| now >= l.until || new_balance >= l.amount - || !l.reasons.contains(reason) + || !l.reasons.intersects(reasons) ) { Ok(()) @@ -868,7 +868,7 @@ where if would_create && value < T::ExistentialDeposit::get() { return Err("value too low to create account"); } - Self::ensure_can_withdraw(transactor, value, WithdrawReason::Transfer, new_from_balance)?; + Self::ensure_can_withdraw(transactor, value, WithdrawReason::Transfer.into(), new_from_balance)?; // NOTE: total stake being stored in the same type means that this could never overflow // but better to be safe than sorry. @@ -893,7 +893,7 @@ where fn withdraw( who: &T::AccountId, value: Self::Balance, - reason: WithdrawReason, + reasons: WithdrawReasons, liveness: ExistenceRequirement, ) -> result::Result { let old_balance = Self::free_balance(who); @@ -907,7 +907,7 @@ where { return Err("payment would kill account") } - Self::ensure_can_withdraw(who, value, reason, new_balance)?; + Self::ensure_can_withdraw(who, value, reasons, new_balance)?; Self::set_free_balance(who, new_balance); Ok(NegativeImbalance::new(value)) } else { @@ -1014,7 +1014,7 @@ where Self::free_balance(who) .checked_sub(&value) .map_or(false, |new_balance| - Self::ensure_can_withdraw(who, value, WithdrawReason::Reserve, new_balance).is_ok() + Self::ensure_can_withdraw(who, value, WithdrawReason::Reserve.into(), new_balance).is_ok() ) } @@ -1028,7 +1028,7 @@ where return Err("not enough free funds") } let new_balance = b - value; - Self::ensure_can_withdraw(who, value, WithdrawReason::Reserve, new_balance)?; + Self::ensure_can_withdraw(who, value, WithdrawReason::Reserve.into(), new_balance)?; Self::set_reserved_balance(who, Self::reserved_balance(who) + value); Self::set_free_balance(who, new_balance); Ok(()) diff --git a/srml/contracts/src/exec.rs b/srml/contracts/src/exec.rs index af79c6c818131..686b173ec7e21 100644 --- a/srml/contracts/src/exec.rs +++ b/srml/contracts/src/exec.rs @@ -642,7 +642,7 @@ fn transfer<'a, T: Trait, V: Vm, L: Loader>( if would_create && value < ctx.config.existential_deposit { return Err("value too low to create account"); } - T::Currency::ensure_can_withdraw(transactor, value, WithdrawReason::Transfer, new_from_balance)?; + T::Currency::ensure_can_withdraw(transactor, value, WithdrawReason::Transfer.into(), new_from_balance)?; let new_to_balance = match to_balance.checked_add(&value) { Some(b) => b, diff --git a/srml/contracts/src/gas.rs b/srml/contracts/src/gas.rs index 08070916fbf29..64997fbe81fdf 100644 --- a/srml/contracts/src/gas.rs +++ b/srml/contracts/src/gas.rs @@ -215,7 +215,7 @@ pub fn buy_gas( let imbalance = T::Currency::withdraw( transactor, cost, - WithdrawReason::Fee, + WithdrawReason::Fee.into(), ExistenceRequirement::KeepAlive )?; diff --git a/srml/contracts/src/rent.rs b/srml/contracts/src/rent.rs index ecc5f610313c0..6647f8963165d 100644 --- a/srml/contracts/src/rent.rs +++ b/srml/contracts/src/rent.rs @@ -119,7 +119,7 @@ fn try_evict_or_and_pay_rent( let can_withdraw_rent = T::Currency::ensure_can_withdraw( account, dues_limited, - WithdrawReason::Fee, + WithdrawReason::Fee.into(), balance.saturating_sub(dues_limited), ) .is_ok(); @@ -129,7 +129,7 @@ fn try_evict_or_and_pay_rent( let imbalance = T::Currency::withdraw( account, dues_limited, - WithdrawReason::Fee, + WithdrawReason::Fee.into(), ExistenceRequirement::KeepAlive, ) .expect( diff --git a/srml/democracy/src/lib.rs b/srml/democracy/src/lib.rs index f1f10a7319ea7..545666e493026 100644 --- a/srml/democracy/src/lib.rs +++ b/srml/democracy/src/lib.rs @@ -486,9 +486,10 @@ decl_module! { /// but it is not a majority-carries referendum then it fails. /// /// - `proposal_hash`: The hash of the current external proposal. - /// - `voting_period`: The period that is allowed for voting on this proposal. + /// - `voting_period`: The period that is allowed for voting on this proposal. Increased to + /// `EmergencyVotingPeriod` if too low. /// - `delay`: The number of block after voting has ended in approval and this should be - /// enacted. Increased to `EmergencyVotingPeriod` if too low. + /// enacted. This doesn't have a minimum amount. #[weight = SimpleDispatchInfo::FixedNormal(200_000)] fn fast_track(origin, proposal_hash: T::Hash, diff --git a/srml/elections-phragmen/src/lib.rs b/srml/elections-phragmen/src/lib.rs index f56c5a4ec3cb5..f22c05ca45cda 100644 --- a/srml/elections-phragmen/src/lib.rs +++ b/srml/elections-phragmen/src/lib.rs @@ -83,9 +83,10 @@ use srml_support::{ decl_storage, decl_event, ensure, decl_module, dispatch, traits::{ Currency, Get, LockableCurrency, LockIdentifier, ReservableCurrency, WithdrawReasons, - ChangeMembers, OnUnbalanced, + ChangeMembers, OnUnbalanced, WithdrawReason } }; +use phragmen::ExtendedBalance; use system::{self, ensure_signed, ensure_root}; const MODULE_ID: LockIdentifier = *b"phrelect"; @@ -127,25 +128,26 @@ pub trait Trait: system::Trait { /// Handler for the unbalanced reduction when a member has been kicked. type KickedMember: OnUnbalanced>; + + /// Number of members to elect. + type DesiredMembers: Get; + + /// Number of runners_up to keep. + type DesiredRunnersUp: Get; + + /// How long each seat is kept. This defines the next block number at which an election + /// round will happen. If set to zero, no elections are ever triggered and the module will + /// be in passive mode. + type TermDuration: Get; } decl_storage! { trait Store for Module as PhragmenElection { - // ---- parameters - /// Number of members to elect. - pub DesiredMembers get(fn desired_members) config(): u32; - /// Number of runners_up to keep. - pub DesiredRunnersUp get(fn desired_runners_up) config(): u32; - /// How long each seat is kept. This defines the next block number at which an election - /// round will happen. If set to zero, no elections are ever triggered and the module will - /// be in passive mode. In that case only a member set defined in at genesis can exist. - pub TermDuration get(fn term_duration) config(): T::BlockNumber; - // ---- State /// The current elected membership. Sorted based on account id. - pub Members get(fn members) config(): Vec; + pub Members get(fn members): Vec<(T::AccountId, BalanceOf)>; /// The current runners_up. Sorted based on low to high merit (worse to best runner). - pub RunnersUp get(fn runners_up): Vec; + pub RunnersUp get(fn runners_up): Vec<(T::AccountId, BalanceOf)>; /// The total number of vote rounds that have happened, excluding the upcoming one. pub ElectionRounds get(fn election_rounds): u32 = Zero::zero(); @@ -166,6 +168,9 @@ decl_module! { const CandidacyBond: BalanceOf = T::CandidacyBond::get(); const VotingBond: BalanceOf = T::VotingBond::get(); + const DesiredMembers: u32 = T::DesiredMembers::get(); + const DesiredRunnersUp: u32 = T::DesiredRunnersUp::get(); + const TermDuration: T::BlockNumber = T::TermDuration::get(); /// Vote for a set of candidates for the upcoming round of election. /// @@ -194,8 +199,8 @@ decl_module! { ensure!(!allowed_votes.is_zero(), "cannot vote when no candidates or members exist"); ensure!(votes.len() <= allowed_votes, "cannot vote more than candidates"); ensure!(votes.len() <= MAXIMUM_VOTE, "cannot vote more than maximum allowed"); - ensure!(!votes.is_empty(), "must vote for at least one candidate."); + ensure!( value > T::Currency::minimum_balance(), "cannot vote with stake less than minimum balance" @@ -215,7 +220,7 @@ decl_module! { &who, locked_balance, T::BlockNumber::max_value(), - WithdrawReasons::all(), + WithdrawReasons::except(WithdrawReason::TransactionPayment), ); >::insert(&who, locked_balance); >::insert(&who, votes); @@ -310,19 +315,6 @@ decl_module! { >::mutate(|c| c.insert(index, who)); } - /// Set the desired member count. Changes will be effective at the beginning of next round. - /// - /// # - /// #### State - /// Reads: O(1) - /// Writes: O(1) - /// # - #[weight = SimpleDispatchInfo::FixedOperational(10_000)] - fn set_desired_member_count(origin, #[compact] count: u32) { - ensure_root(origin)?; - DesiredMembers::put(count); - } - /// Remove a particular member from the set. This is effective immediately. /// /// If a runner-up is available, then the best runner-up will be removed and replaces the @@ -340,49 +332,45 @@ decl_module! { ensure_root(origin)?; let who = T::Lookup::lookup(who)?; - let mut members = Self::members(); - if let Ok(index) = members.binary_search(&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.remove(index); + members_with_stake.remove(index); 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) = runners_up.pop() { + if let Some((replacement, stake)) = runners_up.pop() { // replace the outgoing with the best runner up. - if let Err(index) = members.binary_search(&replacement) { - members.insert(index, replacement.clone()); + 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); + 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); + >::put(members_with_stake); >::put(runners_up); } else { // update `Members` storage -- `do_phragmen` adds this to the candidate list. - >::put(members); + >::put(members_with_stake); // trigger a new phragmen. grab a cup of coffee. This might take a while. Self::do_phragmen(); } } } - /// Set the duration of each term. This will affect the next election's block number. - /// - /// # - /// #### State - /// Reads: O(1) - /// Writes: O(1) - /// # - #[weight = SimpleDispatchInfo::FixedOperational(10_000)] - fn set_term_duration(origin, #[compact] count: T::BlockNumber) { - ensure_root(origin)?; - >::put(count); - } - /// 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 let Err(e) = Self::end_block(n) { @@ -394,10 +382,13 @@ decl_module! { } decl_event!( - pub enum Event where ::AccountId { + pub enum Event where + Balance = BalanceOf, + ::AccountId, + { /// A new term with new members. This indicates that enough candidates existed, not that /// enough have has been elected. The inner value must be examined for this purpose. - NewTerm(Vec), + NewTerm(Vec<(AccountId, Balance)>), /// No (or not enough) candidates existed for this round. EmptyTerm, /// A member has been removed. This should always be followed by either `NewTerm` ot @@ -429,7 +420,32 @@ impl Module { /// /// Limited number of members. Binary search. Constant time factor. O(1) fn is_member(who: &T::AccountId) -> bool { - Self::members().binary_search(who).is_ok() + Self::members_ids().binary_search(who).is_ok() + } + + /// Returns number of desired members. + fn desired_members() -> u32 { + T::DesiredMembers::get() + } + + /// Returns number of desired runners up. + fn desired_runners_up() -> u32 { + T::DesiredRunnersUp::get() + } + + /// Returns the term duration + fn term_duration() -> T::BlockNumber { + T::TermDuration::get() + } + + /// Get the members' account ids. + fn members_ids() -> Vec { + Self::members().into_iter().map(|(m, _)| m).collect::>() + } + + /// The the runners' up account ids. + fn runners_up_ids() -> Vec { + Self::runners_up().into_iter().map(|(r, _)| r).collect::>() } /// Check if `who` is a defunct voter. @@ -500,11 +516,11 @@ impl Module { let mut 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()); + candidates.append(&mut Self::members_ids()); // previous runners_up are also always candidates for the next round. - candidates.append(&mut Self::runners_up()); + 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()); + exposed_candidates.append(&mut Self::runners_up_ids()); let voters_and_votes = >::enumerate() .map(|(v, i)| (v, i)) @@ -532,14 +548,35 @@ impl Module { .filter_map(|(m, a)| if a.is_zero() { None } else { Some(m) } ) .collect::>(); + let support_map = phragmen::build_support_map::<_, _, _, T::CurrencyToVote>( + &new_set, + &phragmen_result.assignments, + Self::locked_stake_of, + false, + ); + + let to_balance = |e: ExtendedBalance| + >>::convert(e); + let new_set_with_stake = new_set + .into_iter() + .map(|ref m| { + let support = support_map.get(m) + .expect( + "entire new_set was given to build_support_map; en entry must be \ + created for each item; qed" + ); + (m.clone(), to_balance(support.total)) + }) + .collect::)>>(); + // split new set into winners and runner ups. - let split_point = desired_seats.min(new_set.len()); - let mut new_members = (&new_set[..split_point]).to_vec(); - let runners_up = &new_set[split_point..] + 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..] .into_iter() .cloned() .rev() - .collect::>(); + .collect::)>>(); // sort and save the members. new_members.sort(); @@ -550,13 +587,13 @@ impl Module { // report member changes. We compute diff because we need the outgoing list. let (incoming, outgoing) = T::ChangeMembers::compute_members_diff( - &new_members, - &old_members + &Self::members_ids(), + &old_members.into_iter().map(|(m, _)| m).collect::>(), ); T::ChangeMembers::change_members_sorted( &incoming, &outgoing.clone(), - &new_members + &Self::members_ids(), ); // unlike exposed_candidates, these are members who were in the list and no longer @@ -567,7 +604,8 @@ impl Module { // runner up list is not sorted. O(K*N) given K runner ups. Overall: O(NLogM + N*K) exposed_candidates.into_iter().for_each(|c| { // any candidate who is not a member and not a runner up. - if new_members.binary_search(&c).is_err() && !runners_up.contains(&c) + if new_members.binary_search_by_key(&c, |(m, _)| m.clone()).is_err() + && !Self::runners_up_ids().contains(&c) { let (imbalance, _) = T::Currency::slash_reserved(&c, T::CandidacyBond::get()); T::LoserCandidate::on_unbalanced(imbalance); @@ -651,7 +689,9 @@ mod tests { thread_local! { static VOTING_BOND: RefCell = RefCell::new(2); - static MEMBERS: RefCell> = RefCell::new(vec![]); + static DESIRED_MEMBERS: RefCell = RefCell::new(2); + static DESIRED_RUNNERS_UP: RefCell = RefCell::new(2); + static TERM_DURATION: RefCell = RefCell::new(5); } pub struct VotingBond; @@ -659,6 +699,21 @@ mod tests { fn get() -> u64 { VOTING_BOND.with(|v| *v.borrow()) } } + pub struct DesiredMembers; + impl Get for DesiredMembers { + fn get() -> u32 { DESIRED_MEMBERS.with(|v| *v.borrow()) } + } + + pub struct DesiredRunnersUp; + impl Get for DesiredRunnersUp { + fn get() -> u32 { DESIRED_RUNNERS_UP.with(|v| *v.borrow()) } + } + + pub struct TermDuration; + impl Get for TermDuration { + fn get() -> u64 { TERM_DURATION.with(|v| *v.borrow()) } + } + pub struct TestChangeMembers; impl ChangeMembers for TestChangeMembers { fn change_members_sorted(_: &[u64], _: &[u64], _: &[u64]) {} @@ -682,6 +737,9 @@ mod tests { type ChangeMembers = TestChangeMembers; type CandidacyBond = CandidacyBond; type VotingBond = VotingBond; + type TermDuration = TermDuration; + type DesiredMembers = DesiredMembers; + type DesiredRunnersUp = DesiredRunnersUp; type LoserCandidate = (); type KickedMember = (); type BadReport = (); @@ -698,7 +756,7 @@ mod tests { { System: system::{Module, Call, Event}, Balances: balances::{Module, Call, Event, Config}, - Elections: elections::{Module, Call, Event, Config}, + Elections: elections::{Module, Call, Event}, } ); @@ -707,7 +765,6 @@ mod tests { voter_bond: u64, term_duration: u64, desired_runners_up: u32, - members: Vec, } impl Default for ExtBuilder { @@ -717,7 +774,6 @@ mod tests { voter_bond: 2, desired_runners_up: 0, term_duration: 5, - members: vec![], } } } @@ -735,12 +791,10 @@ mod tests { self.term_duration = duration; self } - pub fn members(mut self, members: Vec) -> Self { - self.members = members; - self - } pub fn build(self) -> runtime_io::TestExternalities { VOTING_BOND.with(|v| *v.borrow_mut() = self.voter_bond); + TERM_DURATION.with(|v| *v.borrow_mut() = self.term_duration); + DESIRED_RUNNERS_UP.with(|v| *v.borrow_mut() = self.desired_runners_up); GenesisConfig { balances: Some(balances::GenesisConfig::{ balances: vec![ @@ -753,12 +807,6 @@ mod tests { ], vesting: vec![], }), - elections: Some(elections::GenesisConfig::{ - members: self.members, - desired_members: 2, - desired_runners_up: self.desired_runners_up, - term_duration: self.term_duration, - }), }.build_storage().unwrap().into() } } @@ -798,10 +846,9 @@ mod tests { } #[test] - fn passive_module_should_work() { + fn term_duration_zero_is_passive() { ExtBuilder::default() .term_duration(0) - .members(vec![1, 2, 3]) .build() .execute_with(|| { @@ -810,17 +857,16 @@ mod tests { assert_eq!(Elections::desired_members(), 2); assert_eq!(Elections::election_rounds(), 0); - assert_eq!(Elections::members(), vec![1, 2, 3]); + assert_eq!(Elections::members_ids(), vec![]); assert_eq!(Elections::runners_up(), vec![]); - assert_eq!(Elections::candidates(), vec![]); - assert_eq!(all_voters(), vec![]); System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![1, 2, 3]); + assert_eq!(Elections::members_ids(), vec![]); assert_eq!(Elections::runners_up(), vec![]); + assert_eq!(Elections::candidates(), vec![]); }); } @@ -863,7 +909,7 @@ mod tests { assert!(Elections::is_candidate(&2).is_ok()); assert_eq!(Elections::candidates(), vec![1, 2]); - assert_eq!(Elections::members(), vec![]); + assert_eq!(Elections::members_ids(), vec![]); assert_eq!(Elections::runners_up(), vec![]); System::set_block_number(5); @@ -873,7 +919,7 @@ mod tests { assert!(Elections::is_candidate(&2).is_err()); assert_eq!(Elections::candidates(), vec![]); - assert_eq!(Elections::members(), vec![]); + assert_eq!(Elections::members_ids(), vec![]); assert_eq!(Elections::runners_up(), vec![]); }); } @@ -901,7 +947,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![5]); + assert_eq!(Elections::members_ids(), vec![5]); assert_eq!(Elections::runners_up(), vec![]); assert_eq!(Elections::candidates(), vec![]); @@ -994,7 +1040,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); assert_eq!(Elections::candidates(), vec![]); assert_ok!(Elections::vote(Origin::signed(3), vec![4, 5], 10)); @@ -1016,7 +1062,7 @@ mod tests { #[test] fn cannot_vote_for_less_than_ed() { - ExtBuilder::default().voter_bond(8).build().execute_with(|| { + ExtBuilder::default().build().execute_with(|| { assert_ok!(Elections::submit_candidacy(Origin::signed(5))); assert_ok!(Elections::submit_candidacy(Origin::signed(4))); @@ -1101,7 +1147,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![3, 5]); + assert_eq!(Elections::members_ids(), vec![3, 5]); }); } @@ -1130,7 +1176,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); assert_eq!(Elections::candidates(), vec![]); // all of them have a member that they voted for. @@ -1165,7 +1211,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); assert_eq!(Elections::candidates(), vec![]); assert_eq!(balances(&3), (28, 2)); @@ -1194,7 +1240,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); assert_eq!(Elections::candidates(), vec![]); assert_eq!(balances(&4), (35, 5)); @@ -1237,7 +1283,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![3, 5]); + assert_eq!(Elections::members(), vec![(3, 30), (5, 20)]); assert_eq!(Elections::runners_up(), vec![]); assert_eq_uvec!(all_voters(), vec![2, 3, 4]); assert_eq!(Elections::candidates(), vec![]); @@ -1259,7 +1305,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![5]); + assert_eq!(Elections::members(), vec![(5, 50)]); assert_eq!(Elections::election_rounds(), 1); // but now it has a valid target. @@ -1269,7 +1315,7 @@ mod tests { assert_ok!(Elections::end_block(System::block_number())); // candidate 4 is affected by an old vote. - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members(), vec![(4, 30), (5, 50)]); assert_eq!(Elections::election_rounds(), 2); assert_eq_uvec!(all_voters(), vec![3, 5]); }); @@ -1292,7 +1338,7 @@ mod tests { assert_ok!(Elections::end_block(System::block_number())); assert_eq!(Elections::election_rounds(), 1); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); }); } @@ -1307,7 +1353,7 @@ mod tests { assert_eq!(Elections::candidates(), vec![]); assert_eq!(Elections::election_rounds(), 1); - assert_eq!(Elections::members(), vec![]); + assert_eq!(Elections::members_ids(), vec![]); }); } @@ -1327,9 +1373,9 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); // sorted based on account id. - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); // sorted based on merit (least -> most) - assert_eq!(Elections::runners_up(), vec![3, 2]); + assert_eq!(Elections::runners_up_ids(), vec![3, 2]); // runner ups are still locked. assert_eq!(balances(&4), (35, 5)); @@ -1353,15 +1399,15 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); - assert_eq!(Elections::runners_up(), vec![2, 3]); + assert_eq!(Elections::members(), vec![(4, 40), (5, 50)]); + assert_eq!(Elections::runners_up(), vec![(2, 20), (3, 30)]); assert_ok!(Elections::vote(Origin::signed(5), vec![5], 15)); System::set_block_number(10); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![3, 4]); - assert_eq!(Elections::runners_up(), vec![5, 2]); + assert_eq!(Elections::members(), vec![(3, 30), (4, 40)]); + assert_eq!(Elections::runners_up(), vec![(5, 15), (2, 20)]); }); } @@ -1378,9 +1424,9 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); - assert_eq!(Elections::runners_up(), vec![2]); + assert_eq!(Elections::runners_up_ids(), vec![2]); assert_eq!(balances(&2), (15, 5)); assert_ok!(Elections::submit_candidacy(Origin::signed(3))); @@ -1388,9 +1434,9 @@ mod tests { System::set_block_number(10); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); - assert_eq!(Elections::runners_up(), vec![3]); + assert_eq!(Elections::runners_up_ids(), vec![3]); assert_eq!(balances(&3), (25, 5)); assert_eq!(balances(&2), (15, 2)); }); @@ -1408,7 +1454,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); assert_eq!(Elections::election_rounds(), 1); assert_ok!(Elections::submit_candidacy(Origin::signed(2))); @@ -1426,7 +1472,7 @@ mod tests { assert_ok!(Elections::end_block(System::block_number())); // 4 removed; 5 and 3 are the new best. - assert_eq!(Elections::members(), vec![3, 5]); + assert_eq!(Elections::members_ids(), vec![3, 5]); }); } @@ -1449,8 +1495,8 @@ mod tests { System::set_block_number(b.into()); assert_ok!(Elections::end_block(System::block_number())); // we keep re-electing the same folks. - assert_eq!(Elections::members(), vec![4, 5]); - assert_eq!(Elections::runners_up(), vec![2, 3]); + assert_eq!(Elections::members(), vec![(4, 40), (5, 50)]); + assert_eq!(Elections::runners_up(), vec![(2, 20), (3, 30)]); // no new candidates but old members and runners-up are always added. assert_eq!(Elections::candidates(), vec![]); assert_eq!(Elections::election_rounds(), b / 5); @@ -1476,7 +1522,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); assert_eq!(Elections::election_rounds(), 1); // a new candidate @@ -1487,7 +1533,7 @@ mod tests { assert_eq!(balances(&4), (35, 2)); // slashed assert_eq!(Elections::election_rounds(), 2); // new election round - assert_eq!(Elections::members(), vec![3, 5]); // new members + assert_eq!(Elections::members_ids(), vec![3, 5]); // new members }); } @@ -1509,7 +1555,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![3, 5]); + assert_eq!(Elections::members_ids(), vec![3, 5]); assert_eq!(Elections::election_rounds(), 1); assert_ok!(Elections::remove_voter(Origin::signed(2))); @@ -1520,7 +1566,7 @@ mod tests { // meanwhile, no one cares to become a candidate again. System::set_block_number(10); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![]); + assert_eq!(Elections::members_ids(), vec![]); assert_eq!(Elections::election_rounds(), 2); }); } @@ -1538,14 +1584,14 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![5]); + 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(), vec![]); + assert_eq!(Elections::members_ids(), vec![]); assert_eq!(balances(&5), (50, 0)); }); @@ -1565,7 +1611,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![5]); + assert_eq!(Elections::members_ids(), vec![5]); // winner assert_eq!(balances(&5), (47, 3)); @@ -1585,7 +1631,7 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq!(Elections::members(), vec![4, 5]); + assert_eq!(Elections::members_ids(), vec![4, 5]); assert_ok!(Elections::submit_candidacy(Origin::signed(1))); assert_ok!(Elections::submit_candidacy(Origin::signed(2))); @@ -1605,7 +1651,7 @@ mod tests { assert_ok!(Elections::end_block(System::block_number())); // 3, 4 are new members, must still be bonded, nothing slashed. - assert_eq!(Elections::members(), vec![3, 4]); + assert_eq!(Elections::members(), vec![(3, 30), (4, 48)]); assert_eq!(balances(&3), (25, 5)); assert_eq!(balances(&4), (35, 5)); @@ -1615,7 +1661,10 @@ mod tests { // 5 is an outgoing loser, it will get their bond back. assert_eq!(balances(&5), (48, 2)); - assert_eq!(System::events()[0].event, Event::elections(RawEvent::NewTerm(vec![4, 5]))); + assert_eq!( + System::events()[0].event, + Event::elections(RawEvent::NewTerm(vec![(4, 40), (5, 50)])), + ); }) } @@ -1632,8 +1681,30 @@ mod tests { System::set_block_number(5); assert_ok!(Elections::end_block(System::block_number())); - assert_eq_uvec!(Elections::members(), vec![3, 4]); + assert_eq_uvec!(Elections::members_ids(), vec![3, 4]); assert_eq!(Elections::election_rounds(), 1); }); } + + #[test] + fn members_are_sorted_based_on_id_runners_on_merit() { + 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(2), vec![3], 20)); + assert_ok!(Elections::vote(Origin::signed(3), vec![2], 30)); + assert_ok!(Elections::vote(Origin::signed(4), vec![5], 40)); + assert_ok!(Elections::vote(Origin::signed(5), vec![4], 50)); + + System::set_block_number(5); + assert_ok!(Elections::end_block(System::block_number())); + // id: low -> high. + assert_eq!(Elections::members(), vec![(4, 50), (5, 40)]); + // merit: low -> high. + assert_eq!(Elections::runners_up(), vec![(3, 20), (2, 30)]); + }); + } } diff --git a/srml/elections/src/lib.rs b/srml/elections/src/lib.rs index 87e29f3b14498..1e2349440f168 100644 --- a/srml/elections/src/lib.rs +++ b/srml/elections/src/lib.rs @@ -807,7 +807,7 @@ impl Module { let imbalance = T::Currency::withdraw( &who, T::VotingFee::get(), - WithdrawReason::Fee, + WithdrawReason::Fee.into(), ExistenceRequirement::KeepAlive, )?; T::BadVoterIndex::on_unbalanced(imbalance); diff --git a/srml/example/src/lib.rs b/srml/example/src/lib.rs index c9d9d93cc7334..fb05e731bdd4d 100644 --- a/srml/example/src/lib.rs +++ b/srml/example/src/lib.rs @@ -269,13 +269,13 @@ use sr_primitives::{ // the arguments and makes a decision based upon them. // // The `WeightData` trait has access to the arguments of the dispatch that it wants to assign a -// weight to. Nonetheless, the trait itself can not make any assumptions about what that type -// generic type of the arguments, `T`, is. Based on our needs, we could replace `T` with a more -// concrete type while implementing the trait. The `decl_module!` expects whatever implements -// `WeighData` to replace `T` with a tuple of the dispatch arguments. This is exactly how we will -// craft the implementation below. +// weight to. Nonetheless, the trait itself can not make any assumptions about what the generic type +// of the arguments (`T`) is. Based on our needs, we could replace `T` with a more concrete type +// while implementing the trait. The `decl_module!` expects whatever implements `WeighData` to +// replace `T` with a tuple of the dispatch arguments. This is exactly how we will craft the +// implementation below. // -// The rules of `WeightForSetDummy` is as follows: +// The rules of `WeightForSetDummy` are as follows: // - The final weight of each dispatch is calculated as the argument of the call multiplied by the // parameter given to the `WeightForSetDummy`'s constructor. // - assigns a dispatch class `operational` if the argument of the call is more than 1000. @@ -449,9 +449,8 @@ decl_module! { // The _right-hand-side_ value of the `#[weight]` attribute can be any type that implements // a set of traits, namely [`WeighData`] and [`ClassifyDispatch`]. The former conveys the // weight (a numeric representation of pure execution time and difficulty) of the - // transaction and the latter demonstrates the `DispatchClass` of the call. A higher weight - // means a larger transaction (less of which can be placed in a single block). See the - // `CheckWeight` signed extension struct in the `system` module for more information. + // transaction and the latter demonstrates the [`DispatchClass`] of the call. A higher + // weight means a larger transaction (less of which can be placed in a single block). #[weight = SimpleDispatchInfo::FixedNormal(10_000)] fn accumulate_dummy(origin, increase_by: T::Balance) -> Result { // This is a public call, so we ensure that the origin is some signed account. diff --git a/srml/executive/src/lib.rs b/srml/executive/src/lib.rs index 401f07d2069e9..927a7fef25581 100644 --- a/srml/executive/src/lib.rs +++ b/srml/executive/src/lib.rs @@ -571,7 +571,7 @@ mod tests { assert!(Executive::apply_extrinsic(x2.clone()).unwrap().is_ok()); // default weight for `TestXt` == encoded length. - assert_eq!(>::all_extrinsics_weight(), (3 * len).into()); + assert_eq!(>::all_extrinsics_weight(), (3 * len) as u32); assert_eq!(>::all_extrinsics_len(), 3 * len); let _ = >::finalize(); diff --git a/srml/generic-asset/src/lib.rs b/srml/generic-asset/src/lib.rs index fdbb57f56fc99..38bff08e12d0b 100644 --- a/srml/generic-asset/src/lib.rs +++ b/srml/generic-asset/src/lib.rs @@ -128,7 +128,7 @@ //! T::Currency::withdraw( //! transactor, //! amount, -//! WithdrawReason::TransactionPayment, +//! WithdrawReason::TransactionPayment.into(), //! ExistenceRequirement::KeepAlive, //! )?; //! // ... @@ -563,11 +563,16 @@ impl Module { /// Transfer some liquid free balance from one account to another. /// This will not emit the `Transferred` event. - pub fn make_transfer(asset_id: &T::AssetId, from: &T::AccountId, to: &T::AccountId, amount: T::Balance) -> Result { + pub fn make_transfer( + asset_id: &T::AssetId, + from: &T::AccountId, + to: &T::AccountId, + amount: T::Balance + ) -> Result { let new_balance = Self::free_balance(asset_id, from) .checked_sub(&amount) .ok_or_else(|| "balance too low to send amount")?; - Self::ensure_can_withdraw(asset_id, from, amount, WithdrawReason::Transfer, new_balance)?; + Self::ensure_can_withdraw(asset_id, from, amount, WithdrawReason::Transfer.into(), new_balance)?; if from != to { >::mutate(asset_id, from, |balance| *balance -= amount); @@ -734,7 +739,7 @@ impl Module { asset_id: &T::AssetId, who: &T::AccountId, _amount: T::Balance, - reason: WithdrawReason, + reasons: WithdrawReasons, new_balance: T::Balance, ) -> Result { if asset_id != &Self::staking_asset_id() { @@ -748,7 +753,7 @@ impl Module { let now = >::block_number(); if Self::locks(who) .into_iter() - .all(|l| now >= l.until || new_balance >= l.amount || !l.reasons.contains(reason)) + .all(|l| now >= l.until || new_balance >= l.amount || !l.reasons.intersects(reasons)) { Ok(()) } else { @@ -1098,22 +1103,22 @@ where fn ensure_can_withdraw( who: &T::AccountId, amount: Self::Balance, - reason: WithdrawReason, + reasons: WithdrawReasons, new_balance: Self::Balance, ) -> Result { - >::ensure_can_withdraw(&U::asset_id(), who, amount, reason, new_balance) + >::ensure_can_withdraw(&U::asset_id(), who, amount, reasons, new_balance) } fn withdraw( who: &T::AccountId, value: Self::Balance, - reason: WithdrawReason, + reasons: WithdrawReasons, _: ExistenceRequirement, // no existential deposit policy for generic asset ) -> result::Result { let new_balance = Self::free_balance(who) .checked_sub(&value) .ok_or_else(|| "account has too few funds")?; - Self::ensure_can_withdraw(who, value, reason, new_balance)?; + Self::ensure_can_withdraw(who, value, reasons, new_balance)?; >::set_free_balance(&U::asset_id(), who, new_balance); Ok(NegativeImbalance::new(value)) } @@ -1197,7 +1202,7 @@ where .checked_sub(&value) .map_or(false, |new_balance| >::ensure_can_withdraw( - &U::asset_id(), who, value, WithdrawReason::Reserve, new_balance + &U::asset_id(), who, value, WithdrawReason::Reserve.into(), new_balance ).is_ok() ) } diff --git a/srml/nicks/Cargo.toml b/srml/nicks/Cargo.toml new file mode 100644 index 0000000000000..4b8fabe9effe5 --- /dev/null +++ b/srml/nicks/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "srml-nicks" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +serde = { version = "1.0.101", optional = true } +codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } +rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } +runtime-io = { package = "sr-io", path = "../../core/sr-io", default-features = false } +sr-primitives = { path = "../../core/sr-primitives", default-features = false } +support = { package = "srml-support", path = "../support", default-features = false } +system = { package = "srml-system", path = "../system", default-features = false } + +[dev-dependencies] +primitives = { package = "substrate-primitives", path = "../../core/primitives" } +balances = { package = "srml-balances", path = "../balances", default-features = false } + +[features] +default = ["std"] +std = [ + "serde", + "codec/std", + "rstd/std", + "runtime-io/std", + "sr-primitives/std", + "support/std", + "system/std", +] diff --git a/srml/nicks/src/lib.rs b/srml/nicks/src/lib.rs new file mode 100644 index 0000000000000..6b914ca5dc220 --- /dev/null +++ b/srml/nicks/src/lib.rs @@ -0,0 +1,385 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! # Nicks Module +//! +//! - [`nicks::Trait`](./trait.Trait.html) +//! - [`Call`](./enum.Call.html) +//! +//! ## Overview +//! +//! Nicks is a trivial module for keeping track of account names on-chain. It makes no effort to +//! create a name hierarchy, be a DNS replacement or provide reverse lookups. +//! +//! ## Interface +//! +//! ### Dispatchable Functions +//! +//! * `set_name` - Set the associated name of an account; a small deposit is reserved if not already +//! taken. +//! * `clear_name` - Remove an account's associated name; the deposit is returned. +//! * `kill_name` - Forcibly remove the associated name; the deposit is lost. +//! +//! [`Call`]: ./enum.Call.html +//! [`Trait`]: ./trait.Trait.html + +#![cfg_attr(not(feature = "std"), no_std)] + +use rstd::prelude::*; +use sr_primitives::{ + traits::{StaticLookup, EnsureOrigin, Zero}, weights::SimpleDispatchInfo +}; +use support::{ + decl_module, decl_event, decl_storage, ensure, traits::{ + Currency, ReservableCurrency, OnUnbalanced, Get + }, +}; +use system::{ensure_signed, ensure_root}; + +type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +type NegativeImbalanceOf = <::Currency as Currency<::AccountId>>::NegativeImbalance; + +pub trait Trait: system::Trait { + /// The overarching event type. + type Event: From> + Into<::Event>; + + /// The currency trait. + type Currency: ReservableCurrency; + + /// Reservation fee. + type ReservationFee: Get>; + + /// What to do with slashed funds. + type Slashed: OnUnbalanced>; + + /// The origin which may forcibly set or remove a name. Root can always do this. + type ForceOrigin: EnsureOrigin; + + /// The minimum length a name may be. + type MinLength: Get; + + /// The maximum length a name may be. + type MaxLength: Get; +} + +decl_storage! { + trait Store for Module as Sudo { + /// The lookup table for names. + NameOf: map T::AccountId => Option<(Vec, BalanceOf)>; + } +} + +decl_event!( + pub enum Event where AccountId = ::AccountId, Balance = BalanceOf { + /// A name was set. + NameSet(AccountId), + /// A name was forcibly set. + NameForced(AccountId), + /// A name was changed. + NameChanged(AccountId), + /// A name was cleared, and the given balance returned. + NameCleared(AccountId, Balance), + /// A name was removed and the given balance slashed. + NameKilled(AccountId, Balance), + } +); + +decl_module! { + // Simple declaration of the `Module` type. Lets the macro know what it's working on. + pub struct Module for enum Call where origin: T::Origin { + fn deposit_event() = default; + + /// Reservation fee. + const ReservationFee: BalanceOf = T::ReservationFee::get(); + + /// The minimum length a name may be. + const MinLength: u32 = T::MinLength::get() as u32; + + /// The maximum length a name may be. + const MaxLength: u32 = T::MaxLength::get() as u32; + + /// Set an account's name. The name should be a UTF-8-encoded string by convention, though + /// we don't check it. + /// + /// The name may not be more than `T::MaxLength` bytes, nor less than `T::MinLength` bytes. + /// + /// If the account doesn't already have a name, then a fee of `ReservationFee` is reserved + /// in the account. + /// + /// The dispatch origin for this call must be _Signed_. + /// + /// # + /// - O(1). + /// - At most one balance operation. + /// - One storage read/write. + /// - One event. + /// # + #[weight = SimpleDispatchInfo::FixedNormal(50_000)] + fn set_name(origin, name: Vec) { + let sender = ensure_signed(origin)?; + + ensure!(name.len() >= T::MinLength::get(), "Name too short"); + ensure!(name.len() <= T::MaxLength::get(), "Name too long"); + + let deposit = if let Some((_, deposit)) = >::get(&sender) { + Self::deposit_event(RawEvent::NameSet(sender.clone())); + deposit + } else { + let deposit = T::ReservationFee::get(); + T::Currency::reserve(&sender, deposit.clone())?; + Self::deposit_event(RawEvent::NameChanged(sender.clone())); + deposit + }; + + >::insert(&sender, (name, deposit)); + } + + /// Clear an account's name and return the deposit. Fails if the account was not named. + /// + /// The dispatch origin for this call must be _Signed_. + /// + /// # + /// - O(1). + /// - One balance operation. + /// - One storage read/write. + /// - One event. + /// # + fn clear_name(origin) { + let sender = ensure_signed(origin)?; + + let deposit = >::take(&sender).ok_or("Not named")?.1; + + let _ = T::Currency::unreserve(&sender, deposit.clone()); + + Self::deposit_event(RawEvent::NameCleared(sender, deposit)); + } + + /// Remove an account's name and take charge of the deposit. + /// + /// Fails if `who` has not been named. The deposit is dealt with through `T::Slashed` + /// imbalance handler. + /// + /// The dispatch origin for this call must be _Root_ or match `T::ForceOrigin`. + /// + /// # + /// - O(1). + /// - One unbalanced handler (probably a balance transfer) + /// - One storage read/write. + /// - One event. + /// # + #[weight = SimpleDispatchInfo::FreeOperational] + fn kill_name(origin, target: ::Source) { + T::ForceOrigin::try_origin(origin) + .map(|_| ()) + .or_else(ensure_root) + .map_err(|_| "bad origin")?; + + // Figure out who we're meant to be clearing. + let target = T::Lookup::lookup(target)?; + // Grab their deposit (and check that they have one). + let deposit = >::take(&target).ok_or("Not named")?.1; + // Slash their deposit from them. + T::Slashed::on_unbalanced(T::Currency::slash_reserved(&target, deposit.clone()).0); + + Self::deposit_event(RawEvent::NameKilled(target, deposit)); + } + + /// Set a third-party account's name with no deposit. + /// + /// No length checking is done on the name. + /// + /// The dispatch origin for this call must be _Root_ or match `T::ForceOrigin`. + /// + /// # + /// - O(1). + /// - At most one balance operation. + /// - One storage read/write. + /// - One event. + /// # + #[weight = SimpleDispatchInfo::FreeOperational] + fn force_name(origin, target: ::Source, name: Vec) { + T::ForceOrigin::try_origin(origin) + .map(|_| ()) + .or_else(ensure_root) + .map_err(|_| "bad origin")?; + + let target = T::Lookup::lookup(target)?; + let deposit = >::get(&target).map(|x| x.1).unwrap_or_else(Zero::zero); + >::insert(&target, (name, deposit)); + + Self::deposit_event(RawEvent::NameForced(target)); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use support::{assert_ok, assert_noop, impl_outer_origin, parameter_types}; + use primitives::H256; + use system::EnsureSignedBy; + // The testing primitives are very useful for avoiding having to work with signatures + // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. + use sr_primitives::{ + Perbill, testing::Header, traits::{BlakeTwo256, IdentityLookup}, + }; + + impl_outer_origin! { + pub enum Origin for Test {} + } + + // For testing the module, we construct most of a mock runtime. This means + // first constructing a configuration type (`Test`) which `impl`s each of the + // configuration traits of modules we want to use. + #[derive(Clone, Eq, PartialEq)] + pub struct Test; + parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockWeight: u32 = 1024; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); + } + impl system::Trait for Test { + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Call = (); + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type BlockHashCount = BlockHashCount; + type MaximumBlockWeight = MaximumBlockWeight; + type MaximumBlockLength = MaximumBlockLength; + type AvailableBlockRatio = AvailableBlockRatio; + type Version = (); + } + parameter_types! { + pub const ExistentialDeposit: u64 = 0; + pub const TransferFee: u64 = 0; + pub const CreationFee: u64 = 0; + } + impl balances::Trait for Test { + type Balance = u64; + type OnFreeBalanceZero = (); + type OnNewAccount = (); + type Event = (); + type TransferPayment = (); + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type TransferFee = TransferFee; + type CreationFee = CreationFee; + } + parameter_types! { + pub const ReservationFee: u64 = 2; + pub const MinLength: usize = 3; + pub const MaxLength: usize = 16; + pub const One: u64 = 1; + } + impl Trait for Test { + type Event = (); + type Currency = Balances; + type ReservationFee = ReservationFee; + type Slashed = (); + type ForceOrigin = EnsureSignedBy; + type MinLength = MinLength; + type MaxLength = MaxLength; + } + type Balances = balances::Module; + type Nicks = Module; + + // This function basically just builds a genesis storage key/value store according to + // our desired mockup. + fn new_test_ext() -> runtime_io::TestExternalities { + let mut t = system::GenesisConfig::default().build_storage::().unwrap(); + // We use default for brevity, but you can configure as desired if needed. + balances::GenesisConfig:: { + balances: vec![ + (1, 10), + (2, 10), + ], + vesting: vec![], + }.assimilate_storage(&mut t).unwrap(); + t.into() + } + + #[test] + fn kill_name_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Nicks::set_name(Origin::signed(2), b"Dave".to_vec())); + assert_eq!(Balances::total_balance(&2), 10); + assert_ok!(Nicks::kill_name(Origin::signed(1), 2)); + assert_eq!(Balances::total_balance(&2), 8); + assert_eq!(>::get(2), None); + }); + } + + #[test] + fn force_name_should_work() { + new_test_ext().execute_with(|| { + assert_noop!( + Nicks::set_name(Origin::signed(2), b"Dr. David Brubeck, III".to_vec()), + "Name too long" + ); + + assert_ok!(Nicks::set_name(Origin::signed(2), b"Dave".to_vec())); + assert_eq!(Balances::reserved_balance(&2), 2); + assert_ok!(Nicks::force_name(Origin::signed(1), 2, b"Dr. David Brubeck, III".to_vec())); + assert_eq!(Balances::reserved_balance(&2), 2); + assert_eq!(>::get(2).unwrap(), (b"Dr. David Brubeck, III".to_vec(), 2)); + }); + } + + #[test] + fn normal_operation_should_work() { + new_test_ext().execute_with(|| { + assert_ok!(Nicks::set_name(Origin::signed(1), b"Gav".to_vec())); + assert_eq!(Balances::reserved_balance(&1), 2); + assert_eq!(Balances::free_balance(&1), 8); + assert_eq!(>::get(1).unwrap().0, b"Gav".to_vec()); + + assert_ok!(Nicks::set_name(Origin::signed(1), b"Gavin".to_vec())); + assert_eq!(Balances::reserved_balance(&1), 2); + assert_eq!(Balances::free_balance(&1), 8); + assert_eq!(>::get(1).unwrap().0, b"Gavin".to_vec()); + + assert_ok!(Nicks::clear_name(Origin::signed(1))); + assert_eq!(Balances::reserved_balance(&1), 0); + assert_eq!(Balances::free_balance(&1), 10); + }); + } + + #[test] + fn error_catching_should_work() { + new_test_ext().execute_with(|| { + assert_noop!(Nicks::clear_name(Origin::signed(1)), "Not named"); + + assert_noop!(Nicks::set_name(Origin::signed(3), b"Dave".to_vec()), "not enough free funds"); + + assert_noop!(Nicks::set_name(Origin::signed(1), b"Ga".to_vec()), "Name too short"); + assert_noop!( + Nicks::set_name(Origin::signed(1), b"Gavin James Wood, Esquire".to_vec()), + "Name too long" + ); + assert_ok!(Nicks::set_name(Origin::signed(1), b"Dave".to_vec())); + assert_noop!(Nicks::kill_name(Origin::signed(2), 1), "bad origin"); + assert_noop!(Nicks::force_name(Origin::signed(2), 1, b"Whatever".to_vec()), "bad origin"); + }); + } +} diff --git a/srml/staking/src/lib.rs b/srml/staking/src/lib.rs index e7d7c073a1584..edbf7c245fea7 100644 --- a/srml/staking/src/lib.rs +++ b/srml/staking/src/lib.rs @@ -278,7 +278,7 @@ use sr_staking_primitives::{ use sr_primitives::{Serialize, Deserialize}; use system::{ensure_signed, ensure_root}; -use phragmen::{elect, equalize, ExtendedBalance, Support, SupportMap, PhragmenStakedAssignment}; +use phragmen::{elect, equalize, build_support_map, ExtendedBalance, PhragmenStakedAssignment}; const DEFAULT_MINIMUM_VALIDATOR_COUNT: u32 = 4; const MAX_NOMINATIONS: usize = 16; @@ -993,6 +993,17 @@ decl_module! { ensure_root(origin)?; >::put(validators); } + + /// Force a current staker to become completely unstaked, immediately. + #[weight = SimpleDispatchInfo::FreeOperational] + fn force_unstake(origin, stash: T::AccountId) { + ensure_root(origin)?; + + // remove the lock. + T::Currency::remove_lock(STAKING_ID, &stash); + // remove all staking-related information. + Self::kill_stash(&stash); + } } } @@ -1257,31 +1268,12 @@ impl Module { let to_balance = |e: ExtendedBalance| >>::convert(e); - // Initialize the support of each candidate. - let mut supports = >::new(); - elected_stashes - .iter() - .map(|e| (e, to_votes(Self::slashable_balance_of(e)))) - .for_each(|(e, s)| { - let item = Support { own: s, total: s, ..Default::default() }; - supports.insert(e.clone(), item); - }); - - // build support struct. - for (n, assignment) in assignments.iter() { - for (c, per_thing) in assignment.iter() { - let nominator_stake = to_votes(Self::slashable_balance_of(n)); - // AUDIT: it is crucially important for the `Mul` implementation of all - // per-things to be sound. - let other_stake = *per_thing * nominator_stake; - if let Some(support) = supports.get_mut(c) { - // For an astronomically rich validator with more astronomically rich - // set of nominators, this might saturate. - support.total = support.total.saturating_add(other_stake); - support.others.push((n.clone(), other_stake)); - } - } - } + let mut supports = build_support_map::<_, _, _, T::CurrencyToVote>( + &elected_stashes, + &assignments, + Self::slashable_balance_of, + true, + ); if cfg!(feature = "equalize") { let mut staked_assignments diff --git a/srml/staking/src/tests.rs b/srml/staking/src/tests.rs index 2cb798115403b..2b821764579d4 100644 --- a/srml/staking/src/tests.rs +++ b/srml/staking/src/tests.rs @@ -22,6 +22,28 @@ use sr_primitives::{assert_eq_error_rate, traits::OnInitialize}; use sr_staking_primitives::offence::{OffenceDetails, OnOffenceHandler}; use support::{assert_ok, assert_noop, assert_eq_uvec, traits::{Currency, ReservableCurrency}}; +#[test] +fn force_unstake_works() { + // Verifies initial conditions of mock + ExtBuilder::default().build().execute_with(|| { + // Account 11 is stashed and locked, and account 10 is the controller + assert_eq!(Staking::bonded(&11), Some(10)); + // Cant transfer + assert_noop!( + Balances::transfer(Origin::signed(11), 1, 10), + "account liquidity restrictions prevent withdrawal" + ); + // Force unstake requires root. + assert_noop!(Staking::force_unstake(Origin::signed(11), 11), "RequireRootOrigin"); + // We now force them to unstake + assert_ok!(Staking::force_unstake(Origin::ROOT, 11)); + // No longer bonded. + assert_eq!(Staking::bonded(&11), None); + // Transfer works. + assert_ok!(Balances::transfer(Origin::signed(11), 1, 10)); + }); +} + #[test] fn basic_setup_works() { // Verifies initial conditions of mock diff --git a/srml/support/procedural/src/storage/parse.rs b/srml/support/procedural/src/storage/parse.rs index 53da5ae33e92f..e428fbe24f295 100644 --- a/srml/support/procedural/src/storage/parse.rs +++ b/srml/support/procedural/src/storage/parse.rs @@ -17,7 +17,7 @@ //! Parsing of decl_storage input. use srml_support_procedural_tools::{ToTokens, Parse, syn_ext as ext}; -use syn::{Ident, Token}; +use syn::{Ident, Token, spanned::Spanned}; mod keyword { syn::custom_keyword!(hiddencrate); @@ -265,7 +265,6 @@ fn get_module_instance( pub fn parse(input: syn::parse::ParseStream) -> syn::Result { use syn::parse::Parse; - use syn::spanned::Spanned; let def = StorageDefinition::parse(input)?; @@ -303,9 +302,31 @@ pub fn parse(input: syn::parse::ParseStream) -> syn::Result, +) -> syn::Result> { + let mut storage_lines = Vec::::new(); + + for line in defs { let getter = line.getter.inner.map(|o| o.getfn.content.ident); let config = if let Some(config) = line.config.inner { if let Some(ident) = config.expr.content { @@ -315,14 +336,28 @@ pub fn parse(input: syn::parse::ParseStream) -> syn::Result super::StorageLineTypeDef::Map( super::MapDef { @@ -365,18 +400,5 @@ pub fn parse(input: syn::parse::ParseStream) -> syn::Result { fn ensure_can_withdraw( who: &AccountId, _amount: Self::Balance, - reason: WithdrawReason, + reasons: WithdrawReasons, new_balance: Self::Balance, ) -> result::Result<(), &'static str>; @@ -459,7 +459,7 @@ pub trait Currency { fn withdraw( who: &AccountId, value: Self::Balance, - reason: WithdrawReason, + reasons: WithdrawReasons, liveness: ExistenceRequirement, ) -> result::Result; @@ -467,11 +467,11 @@ pub trait Currency { fn settle( who: &AccountId, value: Self::PositiveImbalance, - reason: WithdrawReason, + reasons: WithdrawReasons, liveness: ExistenceRequirement, ) -> result::Result<(), Self::PositiveImbalance> { let v = value.peek(); - match Self::withdraw(who, v, reason, liveness) { + match Self::withdraw(who, v, reasons, liveness) { Ok(opposite) => Ok(drop(value.offset(opposite))), _ => Err(value), } @@ -614,6 +614,8 @@ bitmask! { Reserve = 0b00000100, /// In order to pay some other (higher-level) fees. Fee = 0b00001000, + /// In order to tip a validator for transaction inclusion. + Tip = 0b00010000, } } @@ -630,7 +632,7 @@ impl WithdrawReasons { /// # use srml_support::traits::{WithdrawReason, WithdrawReasons}; /// # fn main() { /// assert_eq!( - /// WithdrawReason::Fee | WithdrawReason::Transfer | WithdrawReason::Reserve, + /// WithdrawReason::Fee | WithdrawReason::Transfer | WithdrawReason::Reserve | WithdrawReason::Tip, /// WithdrawReasons::except(WithdrawReason::TransactionPayment), /// ); /// # } diff --git a/srml/support/test/Cargo.toml b/srml/support/test/Cargo.toml index f40fef9eade60..a5e375b5c6b93 100644 --- a/srml/support/test/Cargo.toml +++ b/srml/support/test/Cargo.toml @@ -12,7 +12,7 @@ support = { package = "srml-support", version = "2", path = "../", default-featu inherents = { package = "substrate-inherents", path = "../../../core/inherents", default-features = false } sr-primitives = { package = "sr-primitives", path = "../../../core/sr-primitives", default-features = false } primitives = { package = "substrate-primitives", path = "../../../core/primitives", default-features = false } -trybuild = "1.0.14" +trybuild = "1.0.17" pretty_assertions = "0.6.1" [features] diff --git a/srml/support/test/src/lib.rs b/srml/support/test/src/lib.rs index 0e4ab93629141..b65bc43cbb5a8 100644 --- a/srml/support/test/src/lib.rs +++ b/srml/support/test/src/lib.rs @@ -16,9 +16,3 @@ //! Test crate for srml_support. Allow to make use of `support::decl_storage`. //! See tests directory. - -#[test] -fn reserved_keyword() { - let t = trybuild::TestCases::new(); - t.compile_fail("tests/reserved_keyword/*.rs"); -} diff --git a/srml/support/test/tests/decl_storage_ui.rs b/srml/support/test/tests/decl_storage_ui.rs new file mode 100644 index 0000000000000..32c15eb390f8b --- /dev/null +++ b/srml/support/test/tests/decl_storage_ui.rs @@ -0,0 +1,24 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +#[test] +fn decl_storage_ui() { + // As trybuild is using `cargo check`, we don't need the real WASM binaries. + std::env::set_var("BUILD_DUMMY_WASM_BINARY", "1"); + + let t = trybuild::TestCases::new(); + t.compile_fail("tests/decl_storage_ui/*.rs"); +} diff --git a/srml/support/test/tests/decl_storage_ui/config_duplicate.rs b/srml/support/test/tests/decl_storage_ui/config_duplicate.rs new file mode 100644 index 0000000000000..bdd7da7449aa8 --- /dev/null +++ b/srml/support/test/tests/decl_storage_ui/config_duplicate.rs @@ -0,0 +1,33 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +pub trait Trait { + type Origin; + type BlockNumber: codec::Codec + codec::EncodeLike + Default + Clone; +} + +support::decl_module! { + pub struct Module for enum Call where origin: T::Origin {} +} + +support::decl_storage!{ + trait Store for Module as FinalKeysNone { + pub Value config(value): u32; + pub Value2 config(value): u32; + } +} + +fn main() {} diff --git a/srml/support/test/tests/decl_storage_ui/config_duplicate.stderr b/srml/support/test/tests/decl_storage_ui/config_duplicate.stderr new file mode 100644 index 0000000000000..761e3f3b79824 --- /dev/null +++ b/srml/support/test/tests/decl_storage_ui/config_duplicate.stderr @@ -0,0 +1,5 @@ +error: `config()`/`get()` with the same name already defined. + --> $DIR/config_duplicate.rs:29:21 + | +29 | pub Value2 config(value): u32; + | ^^^^^ diff --git a/srml/support/test/tests/decl_storage_ui/config_get_duplicate.rs b/srml/support/test/tests/decl_storage_ui/config_get_duplicate.rs new file mode 100644 index 0000000000000..2bf8df45322cc --- /dev/null +++ b/srml/support/test/tests/decl_storage_ui/config_get_duplicate.rs @@ -0,0 +1,33 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +pub trait Trait { + type Origin; + type BlockNumber: codec::Codec + codec::EncodeLike + Default + Clone; +} + +support::decl_module! { + pub struct Module for enum Call where origin: T::Origin {} +} + +support::decl_storage!{ + trait Store for Module as FinalKeysNone { + pub Value get(fn value) config(): u32; + pub Value2 config(value): u32; + } +} + +fn main() {} diff --git a/srml/support/test/tests/decl_storage_ui/config_get_duplicate.stderr b/srml/support/test/tests/decl_storage_ui/config_get_duplicate.stderr new file mode 100644 index 0000000000000..34d040f4e14f1 --- /dev/null +++ b/srml/support/test/tests/decl_storage_ui/config_get_duplicate.stderr @@ -0,0 +1,5 @@ +error: `config()`/`get()` with the same name already defined. + --> $DIR/config_get_duplicate.rs:29:21 + | +29 | pub Value2 config(value): u32; + | ^^^^^ diff --git a/srml/support/test/tests/decl_storage_ui/get_duplicate.rs b/srml/support/test/tests/decl_storage_ui/get_duplicate.rs new file mode 100644 index 0000000000000..41ca708352e8b --- /dev/null +++ b/srml/support/test/tests/decl_storage_ui/get_duplicate.rs @@ -0,0 +1,33 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +pub trait Trait { + type Origin; + type BlockNumber: codec::Codec + codec::EncodeLike + Default + Clone; +} + +support::decl_module! { + pub struct Module for enum Call where origin: T::Origin {} +} + +support::decl_storage!{ + trait Store for Module as FinalKeysNone { + pub Value get(fn value) config(): u32; + pub Value2 get(fn value) config(): u32; + } +} + +fn main() {} diff --git a/srml/support/test/tests/decl_storage_ui/get_duplicate.stderr b/srml/support/test/tests/decl_storage_ui/get_duplicate.stderr new file mode 100644 index 0000000000000..130244196f67e --- /dev/null +++ b/srml/support/test/tests/decl_storage_ui/get_duplicate.stderr @@ -0,0 +1,5 @@ +error: `config()`/`get()` with the same name already defined. + --> $DIR/get_duplicate.rs:29:21 + | +29 | pub Value2 get(fn value) config(): u32; + | ^^^^^ diff --git a/srml/support/test/tests/instance.rs b/srml/support/test/tests/instance.rs index dd05cb1d8c6e3..282fb9a6e299f 100644 --- a/srml/support/test/tests/instance.rs +++ b/srml/support/test/tests/instance.rs @@ -13,6 +13,7 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . + #![recursion_limit="128"] use sr_primitives::{generic, BuildStorage, traits::{BlakeTwo256, Block as _, Verify}}; diff --git a/srml/support/test/tests/reserved_keyword.rs b/srml/support/test/tests/reserved_keyword.rs new file mode 100644 index 0000000000000..898d61b8279e9 --- /dev/null +++ b/srml/support/test/tests/reserved_keyword.rs @@ -0,0 +1,24 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +#[test] +fn reserved_keyword() { + // As trybuild is using `cargo check`, we don't need the real WASM binaries. + std::env::set_var("BUILD_DUMMY_WASM_BINARY", "1"); + + let t = trybuild::TestCases::new(); + t.compile_fail("tests/reserved_keyword/*.rs"); +} diff --git a/srml/system/src/lib.rs b/srml/system/src/lib.rs index 87c38096ab934..e07b937751267 100644 --- a/srml/system/src/lib.rs +++ b/srml/system/src/lib.rs @@ -772,7 +772,6 @@ impl CheckWeight { fn get_dispatch_limit_ratio(class: DispatchClass) -> Perbill { match class { DispatchClass::Operational => Perbill::one(), - // TODO: this must be some sort of a constant. DispatchClass::Normal => T::AvailableBlockRatio::get(), } } diff --git a/srml/transaction-payment/Cargo.toml b/srml/transaction-payment/Cargo.toml index 7f8eddab19d98..cbce1e945e69b 100644 --- a/srml/transaction-payment/Cargo.toml +++ b/srml/transaction-payment/Cargo.toml @@ -10,6 +10,7 @@ rstd = { package = "sr-std", path = "../../core/sr-std", default-features = fals sr-primitives = { path = "../../core/sr-primitives", default-features = false } support = { package = "srml-support", path = "../support", default-features = false } system = { package = "srml-system", path = "../system", default-features = false } +transaction-payment-rpc-runtime-api = { package = "srml-transaction-payment-rpc-runtime-api", path = "./rpc/runtime-api", default-features = false } [dev-dependencies] runtime-io = { package = "sr-io", path = "../../core/sr-io" } @@ -24,4 +25,5 @@ std = [ "sr-primitives/std", "support/std", "system/std", + "transaction-payment-rpc-runtime-api/std" ] diff --git a/srml/transaction-payment/rpc/Cargo.toml b/srml/transaction-payment/rpc/Cargo.toml new file mode 100644 index 0000000000000..e3dc6f553fc0c --- /dev/null +++ b/srml/transaction-payment/rpc/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "srml-transaction-payment-rpc" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +client = { package = "substrate-client", path = "../../../core/client" } +codec = { package = "parity-scale-codec", version = "1.0.0" } +jsonrpc-core = "13.2.0" +jsonrpc-core-client = "13.2.0" +jsonrpc-derive = "13.2.0" +primitives = { package = "substrate-primitives", path = "../../../core/primitives" } +rpc-primitives = { package = "substrate-rpc-primitives", path = "../../../core/rpc/primitives" } +serde = { version = "1.0.101", features = ["derive"] } +sr-primitives = { path = "../../../core/sr-primitives" } +srml-transaction-payment-rpc-runtime-api = { path = "./runtime-api" } diff --git a/srml/transaction-payment/rpc/runtime-api/Cargo.toml b/srml/transaction-payment/rpc/runtime-api/Cargo.toml new file mode 100644 index 0000000000000..c26f295f4bec3 --- /dev/null +++ b/srml/transaction-payment/rpc/runtime-api/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "srml-transaction-payment-rpc-runtime-api" +version = "2.0.0" +authors = ["Parity Technologies "] +edition = "2018" + +[dependencies] +serde = { version = "1.0.101", optional = true, features = ["derive"] } +client = { package = "substrate-client", path = "../../../../core/client", default-features = false } +codec = { package = "parity-scale-codec", version = "1.0.6", default-features = false, features = ["derive"] } +rstd = { package = "sr-std", path = "../../../../core/sr-std", default-features = false } +sr-primitives = { path = "../../../../core/sr-primitives", default-features = false } + +[features] +default = ["std"] +std = [ + "serde", + "client/std", + "codec/std", + "rstd/std", + "sr-primitives/std", +] diff --git a/srml/transaction-payment/rpc/runtime-api/src/lib.rs b/srml/transaction-payment/rpc/runtime-api/src/lib.rs new file mode 100644 index 0000000000000..dc6360ca88d76 --- /dev/null +++ b/srml/transaction-payment/rpc/runtime-api/src/lib.rs @@ -0,0 +1,47 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! Runtime API definition for transaction payment module. + +#![cfg_attr(not(feature = "std"), no_std)] + +use rstd::prelude::*; +use sr_primitives::weights::{Weight, DispatchClass}; +use codec::{Encode, Codec, Decode}; +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +/// Some information related to a dispatchable that can be queried from the runtime. +#[derive(Eq, PartialEq, Encode, Decode, Default)] +#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))] +pub struct RuntimeDispatchInfo { + /// Weight of this dispatch. + pub weight: Weight, + /// Class of this dispatch. + pub class: DispatchClass, + /// The partial inclusion fee of this dispatch. This does not include tip or anything else which + /// is dependent on the signature (aka. depends on a `SignedExtension`). + pub partial_fee: Balance, +} + +client::decl_runtime_apis! { + pub trait TransactionPaymentApi where + Balance: Codec, + Extrinsic: Codec, + { + fn query_info(uxt: Extrinsic, len: u32) -> RuntimeDispatchInfo; + } +} diff --git a/srml/transaction-payment/rpc/src/lib.rs b/srml/transaction-payment/rpc/src/lib.rs new file mode 100644 index 0000000000000..6ee3c7eddbc55 --- /dev/null +++ b/srml/transaction-payment/rpc/src/lib.rs @@ -0,0 +1,108 @@ +// Copyright 2019 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see . + +//! RPC interface for the transaction payment module. + +use std::sync::Arc; +use codec::{Codec, Decode}; +use client::blockchain::HeaderBackend; +use jsonrpc_core::{Error as RpcError, ErrorCode, Result}; +use jsonrpc_derive::rpc; +use sr_primitives::{ + generic::BlockId, + traits::{Block as BlockT, ProvideRuntimeApi}, +}; +use primitives::Bytes; +use srml_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; +pub use srml_transaction_payment_rpc_runtime_api::TransactionPaymentApi as TransactionPaymentRuntimeApi; +pub use self::gen_client::Client as TransactionPaymentClient; + +#[rpc] +pub trait TransactionPaymentApi { + #[rpc(name = "payment_queryInfo")] + fn query_info( + &self, + encoded_xt: Bytes, + at: Option + ) -> Result>; +} + +/// A struct that implements the [`TransactionPaymentApi`]. +pub struct TransactionPayment { + client: Arc, + _marker: std::marker::PhantomData

, +} + +impl TransactionPayment { + /// Create new `TransactionPayment` with the given reference to the client. + pub fn new(client: Arc) -> Self { + TransactionPayment { client, _marker: Default::default() } + } +} + +/// Error type of this RPC api. +pub enum Error { + /// The transaction was not decodable. + DecodeError, + /// The call to runtime failed. + RuntimeError, +} + +impl From for i64 { + fn from(e: Error) -> i64 { + match e { + Error::RuntimeError => 1, + Error::DecodeError => 2, + } + } +} + +impl TransactionPaymentApi<::Hash, Balance> + for TransactionPayment +where + Block: BlockT, + C: Send + Sync + 'static, + C: ProvideRuntimeApi, + C: HeaderBackend, + C::Api: TransactionPaymentRuntimeApi, + Balance: Codec, + Extrinsic: Codec + Send + Sync + 'static, +{ + fn query_info( + &self, + encoded_xt: Bytes, + at: Option<::Hash> + ) -> Result> { + let api = self.client.runtime_api(); + let at = BlockId::hash(at.unwrap_or_else(|| + // If the block hash is not supplied assume the best block. + self.client.info().best_hash + )); + + let encoded_len = encoded_xt.len() as u32; + + let uxt: Extrinsic = Decode::decode(&mut &*encoded_xt).map_err(|e| RpcError { + code: ErrorCode::ServerError(Error::DecodeError.into()), + message: "Unable to query dispatch info.".into(), + data: Some(format!("{:?}", e).into()), + })?; + api.query_info(&at, uxt, encoded_len).map_err(|e| RpcError { + code: ErrorCode::ServerError(Error::RuntimeError.into()), + message: "Unable to query dispatch info.".into(), + data: Some(format!("{:?}", e).into()), + }) + } +} diff --git a/srml/transaction-payment/src/lib.rs b/srml/transaction-payment/src/lib.rs index 5ad5c650af8a0..2314edf053958 100644 --- a/srml/transaction-payment/src/lib.rs +++ b/srml/transaction-payment/src/lib.rs @@ -44,8 +44,9 @@ use sr_primitives::{ TransactionValidity, }, traits::{Zero, Saturating, SignedExtension, SaturatedConversion, Convert}, - weights::{Weight, DispatchInfo}, + weights::{Weight, DispatchInfo, GetDispatchInfo}, }; +use transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; type Multiplier = Fixed64; type BalanceOf = @@ -95,7 +96,33 @@ decl_module! { } } -impl Module {} +impl Module { + /// Query the data that we know about the fee of a given `call`. + /// + /// As this module is not and cannot be aware of the internals of a signed extension, it only + /// interprets them as some encoded value and takes their length into account. + /// + /// All dispatchables must be annotated with weight and will have some fee info. This function + /// always returns. + // NOTE: we can actually make it understand `ChargeTransactionPayment`, but would be some hassle + // for sure. We have to make it aware of the index of `ChargeTransactionPayment` in `Extra`. + // Alternatively, we could actually execute the tx's per-dispatch and record the balance of the + // sender before and after the pipeline.. but this is way too much hassle for a very very little + // potential gain in the future. + pub fn query_info( + unchecked_extrinsic: Extrinsic, + len: u32, + ) -> RuntimeDispatchInfo> + where T: Send + Sync, + { + let dispatch_info = ::get_dispatch_info(&unchecked_extrinsic); + + let partial_fee = >::compute_fee(len, dispatch_info, 0u32.into()); + let DispatchInfo { weight, class } = dispatch_info; + + RuntimeDispatchInfo { weight, class, partial_fee } + } +} /// Require the transactor pay for themselves and maybe include a tip to gain additional priority /// in the queue. @@ -117,9 +144,9 @@ impl ChargeTransactionPayment { /// and the time it consumes. /// - (optional) _tip_: if included in the transaction, it will be added on top. Only signed /// transactions can have a tip. - fn compute_fee(len: usize, info: DispatchInfo, tip: BalanceOf) -> BalanceOf { + fn compute_fee(len: u32, info: DispatchInfo, tip: BalanceOf) -> BalanceOf { let len_fee = if info.pay_length_fee() { - let len = >::from(len as u32); + let len = >::from(len); let base = T::TransactionBaseFee::get(); let per_byte = T::TransactionByteFee::get(); base.saturating_add(per_byte.saturating_mul(len)) @@ -171,11 +198,16 @@ impl SignedExtension for ChargeTransactionPayment len: usize, ) -> TransactionValidity { // pay any fees. - let fee = Self::compute_fee(len, info, self.0); + let tip = self.0; + let fee = Self::compute_fee(len as u32, info, tip); let imbalance = match T::Currency::withdraw( who, fee, - WithdrawReason::TransactionPayment, + if tip.is_zero() { + WithdrawReason::TransactionPayment.into() + } else { + WithdrawReason::TransactionPayment | WithdrawReason::Tip + }, ExistenceRequirement::KeepAlive, ) { Ok(imbalance) => imbalance, @@ -194,17 +226,27 @@ impl SignedExtension for ChargeTransactionPayment #[cfg(test)] mod tests { use super::*; - use support::{parameter_types, impl_outer_origin}; + use codec::Encode; + use support::{parameter_types, impl_outer_origin, impl_outer_dispatch}; use primitives::H256; use sr_primitives::{ Perbill, - testing::Header, - traits::{BlakeTwo256, IdentityLookup}, - weights::DispatchClass, + testing::{Header, TestXt}, + traits::{BlakeTwo256, IdentityLookup, Extrinsic}, + weights::{DispatchClass, DispatchInfo, GetDispatchInfo}, }; + use balances::Call as BalancesCall; use rstd::cell::RefCell; + use transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; - const CALL: &::Call = &(); + const CALL: &::Call = &Call::Balances(BalancesCall::transfer(2, 69)); + + impl_outer_dispatch! { + pub enum Call for Runtime where origin: Origin { + balances::Balances, + system::System, + } + } #[derive(Clone, PartialEq, Eq, Debug)] pub struct Runtime; @@ -224,7 +266,7 @@ mod tests { type Origin = Origin; type Index = u64; type BlockNumber = u64; - type Call = (); + type Call = Call; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; @@ -289,6 +331,8 @@ mod tests { } type Balances = balances::Module; + type System = system::Module; + type TransactionPayment = Module; pub struct ExtBuilder { balance_factor: u64, @@ -452,6 +496,39 @@ mod tests { assert_eq!(Balances::free_balance(&1), 100 - 10 - (5 + 10 + 3) * 3 / 2); }) } + + #[test] + fn query_info_works() { + let call = Call::Balances(BalancesCall::transfer(2, 69)); + let origin = 111111; + let extra = (); + let xt = TestXt::new(call, Some((origin, extra))).unwrap(); + let info = xt.get_dispatch_info(); + let ext = xt.encode(); + let len = ext.len() as u32; + ExtBuilder::default() + .fees(5, 1, 2) + .build() + .execute_with(|| + { + // all fees should be x1.5 + NextFeeMultiplier::put(Fixed64::from_rational(1, 2)); + + assert_eq!( + TransactionPayment::query_info(xt, len), + RuntimeDispatchInfo { + weight: info.weight, + class: info.class, + partial_fee: ( + 5 /* base */ + + len as u64 /* len * 1 */ + + info.weight.min(MaximumBlockWeight::get()) as u64 * 2 /* weight * weight_to_fee */ + ) * 3 / 2 + }, + ); + + }); + } } diff --git a/srml/treasury/src/lib.rs b/srml/treasury/src/lib.rs index 48b56e438ed42..7c38115bfbab1 100644 --- a/srml/treasury/src/lib.rs +++ b/srml/treasury/src/lib.rs @@ -102,9 +102,6 @@ pub trait Trait: system::Trait { /// The overarching event type. type Event: From> + Into<::Event>; - /// Handler for the unbalanced increase when minting cash from the "Pot". - type MintedForSpending: OnUnbalanced>; - /// Handler for the unbalanced decrease when slashing for a rejected proposal. type ProposalRejection: OnUnbalanced>; @@ -327,7 +324,7 @@ impl Module { if let Err(problem) = T::Currency::settle( &Self::account_id(), imbalance, - WithdrawReason::Transfer, + WithdrawReason::Transfer.into(), ExistenceRequirement::KeepAlive ) { print("Inconsistent state - couldn't settle imbalance for funds spent by treasury"); @@ -441,7 +438,6 @@ mod tests { type ApproveOrigin = system::EnsureRoot; type RejectOrigin = system::EnsureRoot; type Event = (); - type MintedForSpending = (); type ProposalRejection = (); type ProposalBond = ProposalBond; type ProposalBondMinimum = ProposalBondMinimum; @@ -661,7 +657,7 @@ mod tests { >::on_finalize(4); assert_eq!(Treasury::pot(), 0); // Pot is emptied - assert_eq!(Balances::free_balance(&Treasury::account_id()), 1); // but the account is still there + assert_eq!(Balances::free_balance(&Treasury::account_id()), 1); // but the account is still there }); }