diff --git a/Cargo.lock b/Cargo.lock index f20bc4b8..3cf167d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,9 +136,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.5" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" dependencies = [ "anstyle", "anstyle-parse", @@ -482,9 +482,9 @@ dependencies = [ [[package]] name = "async-io" -version = "2.2.2" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6afaa937395a620e33dc6a742c593c01aced20aa376ffb0f628121198578ccc7" +checksum = "fb41eb19024a91746eba0773aa5e16036045bbf45733766661099e182ea6a744" dependencies = [ "async-lock", "cfg-if", @@ -493,7 +493,7 @@ dependencies = [ "futures-lite", "parking", "polling", - "rustix 0.38.28", + "rustix 0.38.30", "slab", "tracing", "windows-sys 0.52.0", @@ -638,9 +638,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.6" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c79fed4cdb43e993fcdadc7e58a09fd0e3e649c4436fa11da71c9f1f3ee7feb9" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64ct" @@ -1228,9 +1228,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "bitvec" @@ -1591,16 +1591,16 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "41daef31d7a747c5c847246f36de49ced6f7403b4cdabc807a97b5cc184cda7a" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.48.5", + "windows-targets 0.52.0", ] [[package]] @@ -1649,9 +1649,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.14" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e92c5c1a78c62968ec57dbc2440366a2d6e5a23faf829970ff1585dc6b18e2" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" dependencies = [ "clap_builder", "clap_derive", @@ -1659,9 +1659,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.14" +version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4323769dc8a61e2c39ad7dc26f6f2800524691a44d74fe3d1071a5c24db6370" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" dependencies = [ "anstream", "anstyle", @@ -2559,9 +2559,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" dependencies = [ "humantime", "is-terminal", @@ -3946,7 +3946,7 @@ dependencies = [ "aho-corasick", "bstr 1.9.0", "log", - "regex-automata 0.4.3", + "regex-automata 0.4.4", "regex-syntax 0.8.2", ] @@ -3963,9 +3963,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.22" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" dependencies = [ "bytes", "fnv", @@ -4072,9 +4072,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" [[package]] name = "hex" @@ -4430,7 +4430,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.3", + "hermit-abi 0.3.4", "libc", "windows-sys 0.48.0", ] @@ -4465,8 +4465,8 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" dependencies = [ - "hermit-abi 0.3.3", - "rustix 0.38.28", + "hermit-abi 0.3.4", + "rustix 0.38.30", "windows-sys 0.52.0", ] @@ -4505,9 +4505,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.66" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" dependencies = [ "wasm-bindgen", ] @@ -4615,9 +4615,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures", ] @@ -5097,7 +5097,7 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "libc", "redox_syscall 0.4.1", ] @@ -5228,9 +5228,9 @@ checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" [[package]] name = "linux-raw-sys" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lioness" @@ -5398,7 +5398,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix 0.38.28", + "rustix 0.38.30", ] [[package]] @@ -5748,7 +5748,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "cfg-if", "libc", ] @@ -5868,7 +5868,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.3", + "hermit-abi 0.3.4", "libc", ] @@ -5943,11 +5943,11 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.62" +version = "0.10.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" +checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "cfg-if", "foreign-types", "libc", @@ -5975,9 +5975,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.98" +version = "0.9.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" +checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae" dependencies = [ "cc", "libc", @@ -6798,9 +6798,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" [[package]] name = "platforms" @@ -6810,14 +6810,14 @@ checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c" [[package]] name = "polling" -version = "3.3.1" +version = "3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf63fa624ab313c11656b4cda960bfc46c410187ad493c41f6ba2d8c1e991c9e" +checksum = "545c980a3880efd47b2e262f6a4bb6daad6555cf3367aa9c4e52895f69537a41" dependencies = [ "cfg-if", "concurrent-queue", "pin-project-lite 0.2.13", - "rustix 0.38.28", + "rustix 0.38.30", "tracing", "windows-sys 0.52.0", ] @@ -7168,9 +7168,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.76" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -7445,9 +7445,9 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" dependencies = [ "either", "rayon-core", @@ -7455,9 +7455,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -7538,13 +7538,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.3", + "regex-automata 0.4.4", "regex-syntax 0.8.2", ] @@ -7559,9 +7559,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" dependencies = [ "aho-corasick", "memchr", @@ -7774,14 +7774,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.28" +version = "0.38.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "errno", "libc", - "linux-raw-sys 0.4.12", + "linux-raw-sys 0.4.13", "windows-sys 0.52.0", ] @@ -7827,7 +7827,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.6", + "base64 0.21.7", ] [[package]] @@ -9186,9 +9186,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" @@ -9265,9 +9265,9 @@ checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" [[package]] name = "smallvec" -version = "1.11.2" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "snap" @@ -10158,9 +10158,9 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.45.0" +version = "1.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c0c74081753a8ce1c8eb10b9f262ab6f7017e5ad3317c17a54c7ab65fcb3c6e" +checksum = "b1114ee5900b8569bbc8b1a014a942f937b752af4b44f4607430b5f86cedaac0" dependencies = [ "Inflector", "num-format", @@ -10452,15 +10452,15 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.4.1", - "rustix 0.38.28", + "rustix 0.38.30", "windows-sys 0.52.0", ] [[package]] name = "termcolor" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] @@ -10750,7 +10750,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "bytes", "futures-core", "futures-util", @@ -10989,9 +10989,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -11170,9 +11170,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -11180,9 +11180,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" dependencies = [ "bumpalo", "log", @@ -11195,9 +11195,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.39" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" dependencies = [ "cfg-if", "js-sys", @@ -11207,9 +11207,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -11217,9 +11217,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" dependencies = [ "proc-macro2", "quote", @@ -11230,9 +11230,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" [[package]] name = "wasm-instrument" @@ -11352,7 +11352,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c86437fa68626fe896e5afc69234bb2b5894949083586535f200385adfd71213" dependencies = [ "anyhow", - "base64 0.21.6", + "base64 0.21.7", "bincode", "directories-next", "file-per-thread-logger", @@ -11505,9 +11505,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.66" +version = "0.3.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" dependencies = [ "js-sys", "wasm-bindgen", @@ -11541,14 +11541,14 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.28", + "rustix 0.38.30", ] [[package]] name = "wide" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68938b57b33da363195412cfc5fc37c9ed49aa9cfe2156fde64b8d2c9498242" +checksum = "b31891d644eba1789fb6715f27fbc322e4bdf2ecdc412ede1993246159271613" dependencies = [ "bytemuck", "safe_arch", @@ -11819,9 +11819,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.33" +version = "0.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7520bbdec7211caa7c4e682eb1fbe07abe20cee6756b6e00f537c82c11816aa" +checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" dependencies = [ "memchr", ] diff --git a/pallets/bfc-staking/src/pallet/impls.rs b/pallets/bfc-staking/src/pallet/impls.rs index cb0844bb..333e51b4 100644 --- a/pallets/bfc-staking/src/pallet/impls.rs +++ b/pallets/bfc-staking/src/pallet/impls.rs @@ -61,13 +61,10 @@ impl Pallet { } /// Verifies if the given account has already requested for controller account update - pub fn is_controller_set_requested(controller: T::AccountId) -> bool { + pub fn is_controller_set_requested(controller: &T::AccountId) -> bool { let round = Self::round(); let controller_sets = Self::delayed_controller_sets(round.current_round_index); - if controller_sets.is_empty() { - return false; - } - return controller_sets.into_iter().any(|c| c.old == controller); + controller_sets.into_iter().any(|c| c.old == *controller) } /// Verifies if the given account has already requested for commission rate update @@ -426,48 +423,46 @@ impl Pallet { pub fn handle_delayed_controller_sets(now: RoundIndex) { let delayed_round = now - 1; let controller_sets = >::take(delayed_round); - if !controller_sets.is_empty() { - controller_sets.into_iter().for_each(|c| { - if let Some(candidate) = Self::candidate_info(&c.old) { - // replace `CandidateInfo` - >::remove(&c.old); - >::insert(&c.new, candidate.clone()); - // replace `BondedStash` - >::insert(&c.stash, c.new.clone()); - // replace `CandidatePool` - Self::replace_from_candidate_pool(&c.old, &c.new); - // replace `SelectedCandidates` - if candidate.is_selected { - Self::replace_from_selected_candidates(&c.old, &c.new, candidate.tier); - T::RelayManager::replace_bonded_controller(c.old.clone(), c.new.clone()); - } - // replace `TopNominations` - if let Some(top_nominations) = >::take(&c.old) { - Self::replace_nominator_nominations( - &top_nominations.nominators(), - &c.old, - &c.new, - ); - >::insert(&c.new, top_nominations); - } - // replace `BottomNominations` - if let Some(bottom_nominations) = >::take(&c.old) { - Self::replace_nominator_nominations( - &bottom_nominations.nominators(), - &c.old, - &c.new, - ); - >::insert(&c.new, bottom_nominations); - } - // replace `AwardedPts` - let points = >::take(now, &c.old); - >::insert(now, &c.new, points); - // replace `AtStake` - let at_stake = >::take(now, &c.old); - >::insert(now, &c.new, at_stake); + controller_sets.into_iter().for_each(|c| { + if let Some(candidate) = Self::candidate_info(&c.old) { + // replace `CandidateInfo` + >::remove(&c.old); + >::insert(&c.new, candidate.clone()); + // replace `BondedStash` + >::insert(&c.stash, c.new.clone()); + // replace `CandidatePool` + Self::replace_from_candidate_pool(&c.old, &c.new); + // replace `SelectedCandidates` + if candidate.is_selected { + Self::replace_from_selected_candidates(&c.old, &c.new, candidate.tier); + T::RelayManager::replace_bonded_controller(c.old.clone(), c.new.clone()); } - }); - } + // replace `TopNominations` + if let Some(top_nominations) = >::take(&c.old) { + Self::replace_nominator_nominations( + &top_nominations.nominators(), + &c.old, + &c.new, + ); + >::insert(&c.new, top_nominations); + } + // replace `BottomNominations` + if let Some(bottom_nominations) = >::take(&c.old) { + Self::replace_nominator_nominations( + &bottom_nominations.nominators(), + &c.old, + &c.new, + ); + >::insert(&c.new, bottom_nominations); + } + // replace `AwardedPts` + let points = >::take(now, &c.old); + >::insert(now, &c.new, points); + // replace `AtStake` + let at_stake = >::take(now, &c.old); + >::insert(now, &c.new, at_stake); + } + }); } /// Mints exactly `amount` native tokens to the `to` account. @@ -924,30 +919,35 @@ impl Pallet { // update round let mut round = Self::round(); round.update_round::(now); - let current_round = round.current_round_index; + let now = round.current_round_index; + // handle delayed relayer update requests + // this must be executed in advance, bc initial and current state should be matched at this moment + T::RelayManager::refresh_round(now); + T::RelayManager::handle_delayed_relayer_sets(now); // reset candidate states Pallet::::reset_candidate_states(); // pay all stakers for T::RewardPaymentDelay rounds ago - Self::prepare_staking_payouts(current_round); + Self::prepare_staking_payouts(now); // select top validator candidates for the next round let (validator_count, _, total_staked) = - Self::update_top_candidates(current_round, full_validators, basic_validators); + Self::update_top_candidates(now, full_validators, basic_validators); // start next round >::put(round); // refresh majority - Self::refresh_majority(current_round); - T::RelayManager::refresh_majority(current_round); + Self::refresh_majority(now); + T::RelayManager::refresh_majority(now); // refresh productivity rate per block Self::refresh_productivity_per_block(validator_count, round.round_length); // snapshot total stake and storage state - >::insert(current_round, Self::total()); - >::remove(current_round - 1); - // handle delayed set requests - Self::handle_delayed_controller_sets(current_round); - Self::handle_delayed_commission_sets(current_round); + >::insert(now, Self::total()); + >::remove(now - 1); + // handle delayed controller update requests + Self::handle_delayed_controller_sets(now); + Self::handle_delayed_commission_sets(now); + Self::deposit_event(Event::NewRound { starting_block: round.first_round_block, - round: current_round, + round: now, selected_validators_number: validator_count, total_balance: total_staked, }); diff --git a/pallets/bfc-staking/src/pallet/mod.rs b/pallets/bfc-staking/src/pallet/mod.rs index f4e15443..547a50a2 100644 --- a/pallets/bfc-staking/src/pallet/mod.rs +++ b/pallets/bfc-staking/src/pallet/mod.rs @@ -187,6 +187,10 @@ pub mod pallet { CannotGoOnlineIfLeaving, /// The given candidate cannot leave due to its offline state. CannotLeaveIfOffline, + /// The given candidate cannot leave if controller set requested. It must be cancelled. + CannotLeaveIfControllerSetRequested, + /// The given candidate cannot leave if commission set requested. It must be cancelled. + CannotLeaveIfCommissionSetRequested, /// The given nominator exceeds the maximum limit of nominations. ExceedMaxNominationsPerNominator, /// The given nominator already nominated the candidate. @@ -817,6 +821,7 @@ pub mod pallet { T::DefaultBlocksPerSession::get(), ); >::put(round); + T::RelayManager::refresh_round(1u32); // Set productivity rate per block let blocks_per_validator = { if v_count == 0 { @@ -1056,6 +1061,7 @@ pub mod pallet { !Self::is_commission_set_requested(&controller), Error::::AlreadyCommissionSetRequested, ); + ensure!(!state.is_leaving(), Error::::CandidateAlreadyLeaving); Self::add_to_commission_sets(&controller, old, new)?; Self::deposit_event(Event::ValidatorCommissionSet { candidate: controller, old, new }); Ok(().into()) @@ -1247,7 +1253,14 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let controller = ensure_signed(origin)?; let mut state = >::get(&controller).ok_or(Error::::CandidateDNE)?; - let (now, when) = state.schedule_leave::()?; + ensure!( + !Self::is_controller_set_requested(&controller), + Error::::CannotLeaveIfControllerSetRequested, + ); + ensure!( + !Self::is_commission_set_requested(&controller), + Error::::CannotLeaveIfCommissionSetRequested, + ); let candidates = >::get(); ensure!( candidate_count >= candidates.len() as u32, @@ -1257,6 +1270,7 @@ pub mod pallet { Self::remove_from_candidate_pool(&controller), Error::::CannotLeaveIfOffline, ); + let (now, when) = state.schedule_leave::()?; >::insert(&controller, state); Self::deposit_event(Event::CandidateScheduledExit { exit_allowed_round: now, @@ -1379,10 +1393,12 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let stash = ensure_signed(origin)?; let old = Self::bonded_stash(&stash).ok_or(Error::::StashDNE)?; + let state = >::get(&old).ok_or(Error::::CandidateDNE)?; ensure!(new != old, Error::::NoWritingSameValue); ensure!(!Self::is_candidate(&new, TierType::All), Error::::AlreadyPaired); + ensure!(!state.is_leaving(), Error::::CandidateAlreadyLeaving); ensure!( - !Self::is_controller_set_requested(old.clone()), + !Self::is_controller_set_requested(&old), Error::::AlreadyControllerSetRequested ); Self::add_to_controller_sets(stash, old.clone(), new.clone())?; @@ -1397,10 +1413,7 @@ pub mod pallet { pub fn cancel_controller_set(origin: OriginFor) -> DispatchResultWithPostInfo { let controller = ensure_signed(origin)?; ensure!(Self::is_candidate(&controller, TierType::All), Error::::CandidateDNE); - ensure!( - Self::is_controller_set_requested(controller.clone()), - Error::::ControllerSetDNE - ); + ensure!(Self::is_controller_set_requested(&controller), Error::::ControllerSetDNE); Self::remove_controller_set(&controller)?; Self::deposit_event(Event::ControllerSetCancelled { candidate: controller }); Ok(().into()) diff --git a/pallets/relay-manager/src/lib.rs b/pallets/relay-manager/src/lib.rs index 5e3566b0..2ed1cd77 100644 --- a/pallets/relay-manager/src/lib.rs +++ b/pallets/relay-manager/src/lib.rs @@ -180,3 +180,18 @@ impl Offence >::get() } } + +#[derive(Default, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)] +/// Information of the single-round delayed relayer address update request +pub struct DelayedRelayerSet { + /// The current relayer address. + pub old: AccountId, + /// The requested relayer address. + pub new: AccountId, +} + +impl DelayedRelayerSet { + pub fn new(old: AccountId, new: AccountId) -> Self { + DelayedRelayerSet { old, new } + } +} diff --git a/pallets/relay-manager/src/pallet/impls.rs b/pallets/relay-manager/src/pallet/impls.rs index 80ef8805..530dd5c7 100644 --- a/pallets/relay-manager/src/pallet/impls.rs +++ b/pallets/relay-manager/src/pallet/impls.rs @@ -29,6 +29,10 @@ where Ok(()) } + fn refresh_round(now: RoundIndex) { + >::put(now); + } + fn refresh_relayer_pool() { let pool = Self::relayer_pool(); pool.iter().for_each(|r| { @@ -59,7 +63,6 @@ where }); } } - >::put(round); >::put(selected_relayers.clone()); >::put(selected_relayers.clone()); Self::refresh_cached_selected_relayers(round, selected_relayers); @@ -187,6 +190,14 @@ where Self::deposit_event(Event::::SomeOffline { offline: offenders.clone() }); } } + + fn handle_delayed_relayer_sets(now: RoundIndex) { + let delayed_round = now - 1; + let relayer_sets = >::take(delayed_round); + relayer_sets.into_iter().for_each(|r| { + Self::replace_bonded_relayer(&r.old, &r.new).expect("Replacement must success"); + }); + } } impl Pallet { @@ -208,6 +219,13 @@ impl Pallet { } } + /// Verifies if the given account has already requested for relayer account update + pub fn is_relayer_set_requested(relayer: T::AccountId) -> bool { + let round = Self::round(); + let relayer_sets = Self::delayed_relayer_sets(round); + relayer_sets.into_iter().any(|r| r.old == relayer) + } + /// Compute majority based on the current selected relayers fn compute_majority() -> u32 { ((Self::selected_relayers().len() as u32) / 2) + 1 @@ -256,6 +274,25 @@ impl Pallet { }) } + /// Adds a new relayer address update request. The state reflection will be applied in the next round. + pub fn add_to_relayer_sets(old: T::AccountId, new: T::AccountId) -> DispatchResult { + let round = Self::round(); + >::try_mutate(round, |relayer_sets| -> DispatchResult { + Ok(relayer_sets + .try_push(DelayedRelayerSet::new(old, new)) + .map_err(|_| >::TooManyDelayedRelayers)?) + }) + } + + /// Remove the given `who` from the `DelayedRelayerSets` of the current round. + pub fn remove_relayer_set(who: &T::AccountId) -> DispatchResult { + let round = Self::round(); + >::mutate(round, |relayer_set| { + relayer_set.retain(|r| r.old != *who); + }); + Ok(()) + } + /// Refresh the latest rounds cached selected relayers to the current state fn refresh_latest_cached_relayers() { let round = Self::round(); diff --git a/pallets/relay-manager/src/pallet/mod.rs b/pallets/relay-manager/src/pallet/mod.rs index 95fd02b6..4507a4db 100644 --- a/pallets/relay-manager/src/pallet/mod.rs +++ b/pallets/relay-manager/src/pallet/mod.rs @@ -1,7 +1,8 @@ mod impls; use crate::{ - migrations, IdentificationTuple, Relayer, RelayerMetadata, UnresponsivenessOffence, WeightInfo, + migrations, DelayedRelayerSet, IdentificationTuple, Relayer, RelayerMetadata, + UnresponsivenessOffence, WeightInfo, }; use frame_support::{ @@ -67,6 +68,8 @@ pub mod pallet { RelayerDNE, /// The controller does not exist ControllerDNE, + /// A relayer set request does not exist with the target account. + RelayerSetDNE, /// Cannot set the value as identical to the previous value NoWritingSameValue, /// Cannot set the value below one @@ -75,6 +78,10 @@ pub mod pallet { TooManyRelayers, /// SelectedRelayers out of bound TooManySelectedRelayers, + /// The given account has already requested a relayer set. + AlreadyRelayerSetRequested, + /// DelayedRelayerSets out of bound. + TooManyDelayedRelayers, } #[pallet::event] @@ -98,6 +105,8 @@ pub mod pallet { HeartbeatOffenceActivationSet { is_active: bool }, /// Set the slash fraction for heartbeat offences HeartbeatSlashFractionSet { old: Perbill, new: Perbill }, + /// Cancel the relayer set. + RelayerSetCancelled { relayer: T::AccountId }, } #[pallet::storage] @@ -142,6 +151,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn initial_selected_relayers)] /// The active relayer set selected at the beginning of the current round. This storage is sorted by address. + /// This is used to differentiate with kicked out relayers. pub type InitialSelectedRelayers = StorageValue<_, BoundedBTreeSet>, ValueQuery>; @@ -159,6 +169,7 @@ pub mod pallet { #[pallet::unbounded] #[pallet::getter(fn cached_initial_selected_relayers)] /// The cached active relayer set selected from the beginning of each previous rounds. This storage is sorted by address. + /// This is used to differentiate with kicked out relayers. pub type CachedInitialSelectedRelayers = StorageValue< _, BTreeMap>>, @@ -172,7 +183,8 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn initial_majority)] - /// The majority of the current active relayer set at the beginning of the current round + /// The majority of the current active relayer set at the beginning of the current round. + /// This is used to differentiate with kicked out relayers. pub type InitialMajority = StorageValue<_, u32, ValueQuery>; #[pallet::storage] @@ -184,8 +196,8 @@ pub mod pallet { #[pallet::storage] #[pallet::unbounded] #[pallet::getter(fn cached_initial_majority)] - /// The cached majority based on the active relayer set selected from the beginning of each - /// previous rounds + /// The cached majority based on the active relayer set selected from the beginning of each previous rounds. + /// This is used to differentiate with kicked out relayers. pub type CachedInitialMajority = StorageValue<_, BTreeMap, ValueQuery>; @@ -212,6 +224,17 @@ pub mod pallet { /// The slash fraction for heartbeat offences pub type HeartbeatSlashFraction = StorageValue<_, Perbill, ValueQuery>; + #[pallet::storage] + #[pallet::getter(fn delayed_relayer_sets)] + /// Delayed relayer address update requests + pub type DelayedRelayerSets = StorageMap< + _, + Twox64Concat, + RoundIndex, + BoundedVec, ConstU32>, + ValueQuery, + >; + #[pallet::hooks] impl Hooks> for Pallet { fn on_runtime_upgrade() -> Weight { @@ -301,19 +324,37 @@ pub mod pallet { #[pallet::call_index(3)] #[pallet::weight(::WeightInfo::set_relayer())] /// (Re-)set the bonded relayer account. The origin must be the bonded controller account. - /// The state reflection will be immediately applied. + /// The state reflection will be applied on the next round update. + /// - origin should be the controller account pub fn set_relayer(origin: OriginFor, new: T::AccountId) -> DispatchResultWithPostInfo { let controller = ensure_signed(origin)?; let old = Self::bonded_controller(&controller).ok_or(Error::::ControllerDNE)?; ensure!(old != new, Error::::NoWritingSameValue); ensure!(Self::is_relayer(&old), Error::::RelayerDNE); ensure!(!Self::is_relayer(&new), Error::::RelayerAlreadyJoined); - ensure!(Self::replace_bonded_relayer(&old, &new)?, Error::::RelayerDNE); + ensure!( + !Self::is_relayer_set_requested(old.clone()), + Error::::AlreadyRelayerSetRequested + ); + Self::add_to_relayer_sets(old.clone(), new.clone())?; Self::deposit_event(Event::RelayerSet { old, new }); Ok(().into()) } #[pallet::call_index(4)] + #[pallet::weight(::WeightInfo::cancel_relayer_set())] + /// Cancel the request for (re-)setting the bonded relayer account. + /// - origin should be the controller account. + pub fn cancel_relayer_set(origin: OriginFor) -> DispatchResultWithPostInfo { + let controller = ensure_signed(origin)?; + let relayer = Self::bonded_controller(&controller).ok_or(Error::::ControllerDNE)?; + ensure!(Self::is_relayer_set_requested(controller.clone()), Error::::RelayerSetDNE); + Self::remove_relayer_set(&relayer)?; + Self::deposit_event(Event::RelayerSetCancelled { relayer }); + Ok(().into()) + } + + #[pallet::call_index(5)] #[pallet::weight(::WeightInfo::heartbeat())] /// DEPRECATED, this extrinsic will be removed later on. Please use `heartbeat_v2()` /// instead. Sends a new heartbeat to manage relayer liveness for the current session. The @@ -334,7 +375,7 @@ pub mod pallet { Ok(().into()) } - #[pallet::call_index(5)] + #[pallet::call_index(6)] #[pallet::weight(::WeightInfo::heartbeat_v2())] /// Sends a new heartbeat to manage relayer liveness for the current session. The origin /// must be the registered relayer account, and only the selected relayers can request. diff --git a/pallets/relay-manager/src/weights.rs b/pallets/relay-manager/src/weights.rs index edfc659d..91cebe4a 100644 --- a/pallets/relay-manager/src/weights.rs +++ b/pallets/relay-manager/src/weights.rs @@ -13,6 +13,7 @@ pub trait WeightInfo { fn set_heartbeat_offence_activation() -> Weight; fn set_heartbeat_slash_fraction() -> Weight; fn set_relayer() -> Weight; + fn cancel_relayer_set() -> Weight; fn heartbeat() -> Weight; fn heartbeat_v2() -> Weight; } @@ -40,6 +41,11 @@ impl WeightInfo for SubstrateWeight { .saturating_add(T::DbWeight::get().reads(6 as u64)) .saturating_add(T::DbWeight::get().writes(4 as u64)) } + fn cancel_relayer_set() -> Weight { + Weight::from_parts(18_178_000, 0) + .saturating_add(T::DbWeight::get().reads(6 as u64)) + .saturating_add(T::DbWeight::get().writes(4 as u64)) + } fn heartbeat() -> Weight { Weight::from_parts(18_178_000, 0) .saturating_add(T::DbWeight::get().reads(6 as u64)) @@ -74,6 +80,11 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(6 as u64)) .saturating_add(RocksDbWeight::get().writes(4 as u64)) } + fn cancel_relayer_set() -> Weight { + Weight::from_parts(18_178_000, 0) + .saturating_add(RocksDbWeight::get().reads(6 as u64)) + .saturating_add(RocksDbWeight::get().writes(4 as u64)) + } fn heartbeat() -> Weight { Weight::from_parts(18_178_000, 0) .saturating_add(RocksDbWeight::get().reads(6 as u64)) diff --git a/primitives/bfc-staking/src/traits.rs b/primitives/bfc-staking/src/traits.rs index ba4e9eaf..002b7d9e 100644 --- a/primitives/bfc-staking/src/traits.rs +++ b/primitives/bfc-staking/src/traits.rs @@ -11,6 +11,9 @@ pub trait RelayManager { /// Add the given `relayer` to the `RelayerPool` and bond to the given `controller` account fn join_relayers(relayer: AccountId, controller: AccountId) -> Result<(), DispatchError>; + /// Refresh the current round + fn refresh_round(now: RoundIndex); + /// Refresh the relayers status to default. fn refresh_relayer_pool(); @@ -39,6 +42,9 @@ pub trait RelayManager { /// relayer has pulsed a heartbeat. If not, it will report an offence. This method will be /// requested at every block before the session ends. fn collect_heartbeats(); + + /// Apply the delayed relayer set requests. Replaces the entire bonded storage values from the old to new. + fn handle_delayed_relayer_sets(now: RoundIndex); } /// The trait used for `pallet_bfc_offences` diff --git a/tests/tests/pallets/test_bfc_staking.ts b/tests/tests/pallets/test_bfc_staking.ts index e6d043b6..9f68d773 100644 --- a/tests/tests/pallets/test_bfc_staking.ts +++ b/tests/tests/pallets/test_bfc_staking.ts @@ -24,12 +24,31 @@ describeDevNode('pallet_bfc_staking - set controller', (context) => { const charleth = keyring.addFromUri(TEST_CONTROLLERS[2].private); const alithStash = keyring.addFromUri(TEST_STASHES[0].private); - it('should successfully replace controller account', async function () { + it('should successfully request controller address update', async function () { await context.polkadotApi.tx.bfcStaking .setController(newAlith.address) .signAndSend(alithStash); await context.createBlock(); + const rawCurrentRound: any = await context.polkadotApi.query.bfcStaking.round(); + const currentRound = rawCurrentRound.currentRoundIndex.toNumber(); + + const rawControllerSets: any = await context.polkadotApi.query.bfcStaking.delayedControllerSets(currentRound); + const controllerSets = rawControllerSets.toJSON(); + expect(controllerSets.length).equals(1); + }); + + it('should fail due to multiple requests', async function () { + await context.polkadotApi.tx.bfcStaking + .setController(newAlith.address) + .signAndSend(alithStash); + await context.createBlock(); + + const extrinsicResult = await getExtrinsicResult(context, 'bfcStaking', 'setController'); + expect(extrinsicResult).equal('AlreadyControllerSetRequested'); + }); + + it('should successfully replace controller account', async function () { const stake = new BigNumber(MIN_NOMINATOR_STAKING_AMOUNT); await context.polkadotApi.tx.bfcStaking @@ -45,10 +64,6 @@ describeDevNode('pallet_bfc_staking - set controller', (context) => { const rawCurrentRound: any = await context.polkadotApi.query.bfcStaking.round(); const currentRound = rawCurrentRound.currentRoundIndex.toNumber(); - const rawControllerSets: any = await context.polkadotApi.query.bfcStaking.delayedControllerSets(currentRound); - const controllerSets = rawControllerSets.toJSON(); - expect(controllerSets.length).equals(1); - await jumpToRound(context, currentRound + 1); const rawPrevCandidateState: any = await context.polkadotApi.query.bfcStaking.candidateInfo(alith.address); @@ -1514,6 +1529,54 @@ describeDevNode('pallet_bfc_staking - candidate leave', (context) => { expect(extrinsicResult).equal('CandidateDNE'); }); + it('should fail due to existing controller address update request', async function () { + await context.polkadotApi.tx.bfcStaking + .setController(charleth.address) + .signAndSend(baltatharStash, { nonce: -1 }); + await context.createBlock(); + await context.createBlock(); + + const candidates: any = await context.polkadotApi.query.bfcStaking.candidatePool(); + + await context.polkadotApi.tx.bfcStaking + .scheduleLeaveCandidates(candidates.length) + .signAndSend(baltathar, { nonce: -1 }); + await context.createBlock(); + + const extrinsicResult = await getExtrinsicResult(context, 'bfcStaking', 'scheduleLeaveCandidates'); + expect(extrinsicResult).equal('CannotLeaveIfControllerSetRequested'); + + // cancel request for continueing tests + await context.polkadotApi.tx.bfcStaking + .cancelControllerSet() + .signAndSend(baltathar, { nonce: -1 }); + await context.createBlock(); + }); + + it('should fail due to existing commission update request', async function () { + const commission = new BigNumber(70).multipliedBy(10 ** 7); + await context.polkadotApi.tx.bfcStaking + .setValidatorCommission(commission.toFixed()) + .signAndSend(baltathar, { nonce: -1 }); + await context.createBlock(); + + const candidates: any = await context.polkadotApi.query.bfcStaking.candidatePool(); + + await context.polkadotApi.tx.bfcStaking + .scheduleLeaveCandidates(candidates.length) + .signAndSend(baltathar, { nonce: -1 }); + await context.createBlock(); + + const extrinsicResult = await getExtrinsicResult(context, 'bfcStaking', 'scheduleLeaveCandidates'); + expect(extrinsicResult).equal('CannotLeaveIfCommissionSetRequested'); + + // cancel request for continueing tests + await context.polkadotApi.tx.bfcStaking + .cancelValidatorCommissionSet() + .signAndSend(baltathar, { nonce: -1 }); + await context.createBlock(); + }); + it('should fail due to invalid candidate', async function () { const candidates: any = await context.polkadotApi.query.bfcStaking.candidatePool(); diff --git a/tests/tests/pallets/test_relay_manager.ts b/tests/tests/pallets/test_relay_manager.ts index 32897b2c..ef6bc6b3 100644 --- a/tests/tests/pallets/test_relay_manager.ts +++ b/tests/tests/pallets/test_relay_manager.ts @@ -94,6 +94,15 @@ describeDevNode('pallet_relay_manager - set relayer', (context) => { .signAndSend(alith); await context.createBlock(); + const rawCurrentRound: any = await context.polkadotApi.query.bfcStaking.round(); + const currentRound = rawCurrentRound.currentRoundIndex.toNumber(); + + const rawRelayerSets: any = await context.polkadotApi.query.relayManager.delayedRelayerSets(currentRound); + const relayerSets = rawRelayerSets.toJSON(); + expect(relayerSets.length).equals(1); + + await jumpToRound(context, currentRound + 1); + // check `BondedController` const rawBondedController: any = await context.polkadotApi.query.relayManager.bondedController(alith.address); const bondedController = rawBondedController.toJSON(); @@ -127,28 +136,37 @@ describeDevNode('pallet_relay_manager - set relayer', (context) => { const rawInitialRelayers: any = await context.polkadotApi.query.relayManager.initialSelectedRelayers(); const initialRelayers = rawInitialRelayers.toJSON(); expect(initialRelayers.length).equal(1); - expect(initialRelayers[0]).equal(alithRelayer.address); + expect(initialRelayers[0]).equal(newRelayer.address); - const rawCurrentRound: any = await context.polkadotApi.query.bfcStaking.round(); - const currentRound = rawCurrentRound.currentRoundIndex.toNumber(); + const rawCurrentRoundV2: any = await context.polkadotApi.query.bfcStaking.round(); + const currentRoundV2 = rawCurrentRoundV2.currentRoundIndex.toNumber(); // check `CachedSelectedRelayers` const rawCachedRelayers: any = await context.polkadotApi.query.relayManager.cachedSelectedRelayers(); const cachedRelayers = rawCachedRelayers.toJSON(); - expect(cachedRelayers[currentRound].length).equal(1); - expect(cachedRelayers[currentRound]).include(newRelayer.address); + expect(cachedRelayers[currentRoundV2].length).equal(1); + expect(cachedRelayers[currentRoundV2]).include(newRelayer.address); // check `CachedInitialSelectedRelayers` const rawCachedInitialRelayers: any = await context.polkadotApi.query.relayManager.cachedInitialSelectedRelayers(); const cachedInitialRelayers = rawCachedInitialRelayers.toJSON(); - expect(cachedInitialRelayers[currentRound].length).equal(1); - expect(cachedInitialRelayers[currentRound]).include(alithRelayer.address); + expect(cachedInitialRelayers[currentRoundV2].length).equal(1); + expect(cachedInitialRelayers[currentRoundV2]).include(newRelayer.address); // check `ReceivedHeartbeats` - const currentSession = rawCurrentRound.currentSessionIndex.toNumber(); + await context.polkadotApi.tx.relayManager.heartbeat() + .signAndSend(newRelayer); + await context.createBlock(); + + const currentSession = rawCurrentRoundV2.currentSessionIndex.toNumber(); + const rawHeartbeat: any = await context.polkadotApi.query.relayManager.receivedHeartbeats(currentSession, newRelayer.address); const heartbeat = rawHeartbeat.toJSON(); expect(heartbeat).equal(true); + + const rawRelayerStateV2: any = await context.polkadotApi.query.relayManager.relayerState(newRelayer.address); + const relayerStateV2 = rawRelayerStateV2.unwrap().toJSON(); + expect(relayerStateV2.status).equal('Active'); }); }); @@ -627,3 +645,251 @@ describeDevNode('pallet_relay_manager - leave request cancelled', (context) => { } }); }, true); + +describeDevNode('pallet_relay_manager - set kicked out relayer address', (context) => { + const keyring = new Keyring({ type: 'ethereum' }); + + const alith = keyring.addFromUri(TEST_CONTROLLERS[0].private); + const alithRelayer = keyring.addFromUri(TEST_RELAYERS[0].private); + + const baltathar = keyring.addFromUri(TEST_CONTROLLERS[1].private); + const baltatharStash = keyring.addFromUri(TEST_STASHES[1].private); + const baltatharRelayer = keyring.addFromUri(TEST_RELAYERS[1].private); + + const newRelayer = keyring.addFromUri(TEST_RELAYERS[2].private); + + let baltatharAura = ''; + let baltatharGran = ''; + let baltatharImOnline = ''; + + before('should successfully join candidate pool and set session keys', async function () { + const stake = new BigNumber(MIN_FULL_VALIDATOR_STAKING_AMOUNT); + + await context.polkadotApi.tx.bfcStaking + .joinCandidates(baltathar.address, baltatharRelayer.address, stake.toFixed(), 1) + .signAndSend(baltatharStash, { nonce: -1 }); + await context.createBlock(); + + const response = await axios.post( + 'http://localhost:9934', + { + 'jsonrpc': '2.0', + 'method': 'author_rotateKeys', + 'id': 1, + }, + ); + const sessionKey = response.data.result.slice(2); + const auraSessionKey = `0x${sessionKey.slice(0, 64)}`; + const granSessionKey = `0x${sessionKey.slice(64, 128)}`; + const imonlineSessionKey = `0x${sessionKey.slice(128)}`; + + baltatharAura = auraSessionKey; + baltatharGran = granSessionKey; + baltatharImOnline = imonlineSessionKey; + + const keys: any = { + aura: auraSessionKey, + grandpa: granSessionKey, + imOnline: imonlineSessionKey, + }; + await context.polkadotApi.tx.session.setKeys(keys, '0x00').signAndSend(baltathar, { nonce: -1 }); + await context.createBlock(); + }); + + before('should successfully set auto-compound to account', async function () { + await context.polkadotApi.tx.bfcStaking + .setCandidateRewardDst('Account') + .signAndSend(baltathar, { nonce: -1 }); + await context.createBlock(); + }); + + it('should be added to queued keys on the next round - baltathar', async function () { + this.timeout(20000); + + const rawCurrentRound: any = await context.polkadotApi.query.bfcStaking.round(); + const currentRound = rawCurrentRound.currentRoundIndex.toNumber(); + + await jumpToRound(context, currentRound + 1); + + const rawQueuedKeys: any = await context.polkadotApi.query.session.queuedKeys(); + const queuedKeys = rawQueuedKeys.toJSON(); + let isKeyFound = false; + for (const key of queuedKeys) { + if (key[0] === baltathar.address) { + isKeyFound = true; + expect(key[1].aura).equal(baltatharAura); + expect(key[1].grandpa).equal(baltatharGran); + expect(key[1].imOnline).equal(baltatharImOnline); + break; + } + } + expect(isKeyFound).equal(true); + + const rawValidators: any = await context.polkadotApi.query.session.validators(); + const validators = rawValidators.toJSON(); + expect(validators).includes(alith.address); + expect(validators).not.includes(baltathar.address); + }); + + it('should be added to session validators after one session - baltathar', async function () { + this.timeout(20000); + + const rawCurrentRound: any = await context.polkadotApi.query.bfcStaking.round(); + const currentSession = rawCurrentRound.currentSessionIndex.toNumber(); + + const blockHash: any = await jumpToSession(context, currentSession + 1); + const success = await isEventTriggered( + context, + blockHash, + [ + { method: 'AllGood', section: 'imOnline' }, + { method: 'NewSession', section: 'session' }, + ], + ); + expect(success).equal(true); + + const rawValidators: any = await context.polkadotApi.query.session.validators(); + const validators = rawValidators.toJSON(); + expect(validators).includes(alith.address); + expect(validators).includes(baltathar.address); + }); + + it('should successfully activate heartbeat offences', async function () { + await context.polkadotApi.tx.sudo.sudo( + context.polkadotApi.tx.relayManager.setHeartbeatOffenceActivation(true), + ).signAndSend(alith); + await context.createBlock(); + + const isActive = await context.polkadotApi.query.relayManager.isHeartbeatOffenceActive(); + expect(isActive.toJSON()).equal(true); + }); + + it('should be kicked out and apply relayer address update on next round', async function () { + const rawMaximumOffenceCount: any = await context.polkadotApi.query.bfcOffences.fullMaximumOffenceCount(); + for (let idx = 0; idx < rawMaximumOffenceCount.toNumber(); idx++) { + const rawCurrentRound: any = await context.polkadotApi.query.bfcStaking.round(); + const currentSession = rawCurrentRound.currentSessionIndex.toNumber(); + + await context.polkadotApi.tx.relayManager.heartbeat() + .signAndSend(alithRelayer); + await context.createBlock(); + + const rawHeartbeat: any = await context.polkadotApi.query.relayManager.receivedHeartbeats(currentSession, alithRelayer.address); + const heartbeat = rawHeartbeat.toJSON(); + expect(heartbeat).equal(true); + + const blockHash: any = await jumpToSession(context, currentSession + 1); + + const success = await isEventTriggered( + context, + blockHash, + [ + { method: 'SomeOffline', section: 'relayManager' }, + { method: 'Offence', section: 'offences' }, + { method: 'Slashed', section: 'bfcOffences' }, + { method: 'Slashed', section: 'balances' }, + { method: 'KickedOut', section: 'bfcStaking' }, + ], + ); + if (success) { + await context.polkadotApi.tx.relayManager + .setRelayer(newRelayer.address) + .signAndSend(baltathar); + await context.createBlock(); + + const rawCurrentRound: any = await context.polkadotApi.query.bfcStaking.round(); + const currentRound = rawCurrentRound.currentRoundIndex.toNumber(); + + const rawRelayerSets: any = await context.polkadotApi.query.relayManager.delayedRelayerSets(currentRound); + const relayerSets = rawRelayerSets.toJSON(); + expect(relayerSets.length).equals(1); + + const rawRelayerState: any = await context.polkadotApi.query.relayManager.relayerState(alithRelayer.address); + const relayerState = rawRelayerState.unwrap().toJSON(); + expect(relayerState.status).equal('Active'); + + const rawRelayerStateB: any = await context.polkadotApi.query.relayManager.relayerState(baltatharRelayer.address); + const relayerStateB = rawRelayerStateB.unwrap().toJSON(); + expect(relayerStateB.status).equal('KickedOut'); + + const rawCandidateState: any = await context.polkadotApi.query.bfcStaking.candidateInfo(baltathar.address); + const candidateState = rawCandidateState.unwrap().toJSON(); + expect(candidateState.status).has.key('kickedOut'); + } + } + + const rawCurrentRound: any = await context.polkadotApi.query.bfcStaking.round(); + const currentRound = rawCurrentRound.currentRoundIndex.toNumber(); + await jumpToRound(context, currentRound + 1); + + const rawRelayerSets: any = await context.polkadotApi.query.relayManager.delayedRelayerSets(currentRound); + const relayerSets = rawRelayerSets.toJSON(); + expect(relayerSets.length).equals(0); + + const rawRelayerStateB: any = await context.polkadotApi.query.relayManager.relayerState(newRelayer.address); + const relayerStateB = rawRelayerStateB.unwrap().toJSON(); + + const rawCandidateState: any = await context.polkadotApi.query.bfcStaking.candidateInfo(relayerStateB.controller); + const candidateState = rawCandidateState.unwrap().toJSON(); + expect(candidateState.status).has.key('kickedOut'); + }); +}, true); + +describeDevNode('pallet_relay_manager - controller and relayer address update', (context) => { + const keyring = new Keyring({ type: 'ethereum' }); + const alith = keyring.addFromUri(TEST_CONTROLLERS[0].private); + const alithStash = keyring.addFromUri(TEST_STASHES[0].private); + const newController = keyring.addFromUri(TEST_CONTROLLERS[1].private); + const newRelayer = keyring.addFromUri(TEST_RELAYERS[1].private); + + before('should successfully request controller address update', async function () { + await context.polkadotApi.tx.bfcStaking + .setController(newController.address) + .signAndSend(alithStash); + await context.createBlock(); + + const rawCurrentRound: any = await context.polkadotApi.query.bfcStaking.round(); + const currentRound = rawCurrentRound.currentRoundIndex.toNumber(); + + const rawControllerSets: any = await context.polkadotApi.query.bfcStaking.delayedControllerSets(currentRound); + const controllerSets = rawControllerSets.toJSON(); + expect(controllerSets.length).equals(1); + }); + + before('should successfully request relayer address update', async function () { + await context.polkadotApi.tx.relayManager + .setRelayer(newRelayer.address) + .signAndSend(alith); + await context.createBlock(); + + const rawCurrentRound: any = await context.polkadotApi.query.bfcStaking.round(); + const currentRound = rawCurrentRound.currentRoundIndex.toNumber(); + + const rawRelayerSets: any = await context.polkadotApi.query.relayManager.delayedRelayerSets(currentRound); + const relayerSets = rawRelayerSets.toJSON(); + expect(relayerSets.length).equals(1); + }); + + it('should successfully update both controller and relayer address on same round', async function () { + const rawCurrentRound: any = await context.polkadotApi.query.bfcStaking.round(); + const currentRound = rawCurrentRound.currentRoundIndex.toNumber(); + + await jumpToRound(context, currentRound + 1); + + const rawCandidateState: any = await context.polkadotApi.query.bfcStaking.candidateInfo(newController.address); + const candidateState = rawCandidateState.unwrap().toJSON(); + expect(candidateState.stash).equal(alithStash.address); + + const rawBondedStash: any = await context.polkadotApi.query.bfcStaking.bondedStash(alithStash.address); + const bondedStash = rawBondedStash.unwrap().toJSON(); + expect(bondedStash).equal(newController.address); + + const rawBondedController: any = await context.polkadotApi.query.relayManager.bondedController(newController.address); + const bondedController = rawBondedController.toJSON(); + expect(bondedController).equal(newRelayer.address); + + const rawRelayerState: any = await context.polkadotApi.query.relayManager.relayerState(newRelayer.address); + const relayerState = rawRelayerState.unwrap().toJSON(); + expect(relayerState.controller).equal(newController.address); + }); +});