diff --git a/Cargo.lock b/Cargo.lock index 29ddf38328519..3d213b4c38845 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" dependencies = [ - "gimli 0.27.0", + "gimli 0.27.2", ] [[package]] @@ -55,6 +55,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "aead" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c192eb8f11fc081b0fe4259ba5af04217d4e0faddd02417310a927911abd7c8" +dependencies = [ + "crypto-common", + "generic-array 0.14.6", +] + [[package]] name = "aes" version = "0.6.0" @@ -79,17 +89,14 @@ dependencies = [ ] [[package]] -name = "aes-gcm" -version = "0.8.0" +name = "aes" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" +checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" dependencies = [ - "aead 0.3.2", - "aes 0.6.0", - "cipher 0.2.5", - "ctr 0.6.0", - "ghash 0.3.1", - "subtle", + "cfg-if", + "cipher 0.4.4", + "cpufeatures", ] [[package]] @@ -106,6 +113,20 @@ dependencies = [ "subtle", ] +[[package]] +name = "aes-gcm" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e1366e0c69c9f927b1fa5ce2c7bf9eafc8f9268c0b9800729e8b267612447c" +dependencies = [ + "aead 0.5.1", + "aes 0.8.2", + "cipher 0.4.4", + "ctr 0.9.2", + "ghash 0.5.0", + "subtle", +] + [[package]] name = "aes-soft" version = "0.6.4" @@ -139,9 +160,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" dependencies = [ "cfg-if", "getrandom 0.2.8", @@ -184,9 +205,27 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" +checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" + +[[package]] +name = "apk-proofs" +version = "0.1.0" +source = "git+https://github.com/w3f/apk-proofs#7d5d2198bf8fc086a5a1432dcbb8cfa2bd7175ef" +dependencies = [ + "ark-bls12-377", + "ark-bw6-761", + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "blake2 0.9.2", + "fflonk", + "merlin 3.0.0", + "rand 0.8.5", +] [[package]] name = "approx" @@ -199,9 +238,9 @@ dependencies = [ [[package]] name = "arbitrary" -version = "1.2.0" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29d47fbf90d5149a107494b15a7dc8d69b351be2db3bb9691740e88ec17fd880" +checksum = "3e90af4de65aa7b293ef2d09daff88501eb254f58edde2e1ac02c82d873eadad" [[package]] name = "arc-swap" @@ -209,6 +248,147 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" +[[package]] +name = "ark-bls12-377" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb00293ba84f51ce3bd026bd0de55899c4e68f0a39a5728cebae3a73ffdc0a4f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-bls12-381" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-bw6-761" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e0605daf0cc5aa2034b78d008aaf159f56901d92a52ee4f6ecdfdac4f426700" +dependencies = [ + "ark-bls12-377", + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c60370a92f8e1a5f053cad73a862e1b99bc642333cd676fa11c0c39f80f4ac2" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c2d42532524bee1da5a4f6f733eb4907301baa480829557adcff5dfaeee1d9a" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.6", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.0", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6873aaba7959593d89babed381d33e2329453368f1bf3c67e07686a1c1056f" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c2e7d0f2d67cc7fc925355c74d36e7eda19073639be4a0a233d4611b8c959d" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ark-poly" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6ec811462cabe265cfe1b102fcfe3df79d7d2929c2425673648ee9abfd0272" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e735959bc173ea4baf13327b19c22d452b8e9e8e8f7b7fc34e6bf0e316c33e" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.6", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd34f0920d995d2c932f38861c416f70de89a6de9875876b012557079603e6cc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "array-bytes" version = "4.2.0" @@ -246,14 +426,14 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.17", + "time 0.3.20", ] [[package]] name = "asn1-rs" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf6690c370453db30743b373a60ba498fc0d6d83b11f4abfd87a84a075db5dd4" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" dependencies = [ "asn1-rs-derive 0.4.0", "asn1-rs-impl", @@ -262,7 +442,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.17", + "time 0.3.20", ] [[package]] @@ -308,11 +488,11 @@ checksum = "e22d1f4b888c298a027c99dc9048015fac177587de20fc30232a057dfbe24a21" [[package]] name = "assert_cmd" -version = "2.0.7" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa3d466004a8b4cb1bc34044240a2fd29d17607e2e3bd613eb44fd48e8100da3" +checksum = "9834fcc22e0874394a010230586367d4a3e9f11b560f469262678547e1d2575e" dependencies = [ - "bstr 1.1.0", + "bstr", "doc-comment", "predicates", "predicates-core", @@ -348,29 +528,29 @@ dependencies = [ [[package]] name = "async-lock" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685" +checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" dependencies = [ "event-listener", - "futures-lite", ] [[package]] name = "async-stream" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" +checksum = "ad445822218ce64be7a341abfb0b1ea43b5c23aa83902542a4542e78309d8e5e" dependencies = [ "async-stream-impl", "futures-core", + "pin-project-lite 0.2.9", ] [[package]] name = "async-stream-impl" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" +checksum = "e4655ae1a7b0cdf149156f780c5bf3f1352bc53cbd9e0a361a7ef7b22947e965" dependencies = [ "proc-macro2", "quote", @@ -379,9 +559,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.60" +version = "0.1.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" +checksum = "b84f9ebcc6c1f5b8cb160f6990096a5c127f423fcb6e1ccc46c370cbdfb75dfc" dependencies = [ "proc-macro2", "quote", @@ -403,9 +583,9 @@ dependencies = [ [[package]] name = "atomic-waker" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" +checksum = "debc29dde2e69f9e47506b525f639ed42300fc014a3e007832592448fa8e4599" [[package]] name = "atty" @@ -435,7 +615,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object 0.30.0", + "object 0.30.3", "rustc-demangle", ] @@ -463,11 +643,26 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + [[package]] name = "base64ct" -version = "1.5.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "basic-toml" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c0de75129aa8d0cceaf750b89013f0e08804d6ec61416da787b35ad0d7cddf1" +dependencies = [ + "serde", +] [[package]] name = "beef" @@ -499,6 +694,7 @@ dependencies = [ "sc-network-test", "sc-utils", "serde", + "smart-default", "sp-api", "sp-application-crypto", "sp-arithmetic", @@ -547,7 +743,7 @@ name = "beefy-merkle-tree" version = "4.0.0-dev" dependencies = [ "array-bytes", - "env_logger", + "env_logger 0.9.3", "log", "sp-api", "sp-beefy", @@ -565,9 +761,9 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.60.1" +version = "0.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" +checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" dependencies = [ "bitflags", "cexpr", @@ -580,6 +776,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", + "syn", ] [[package]] @@ -600,6 +797,17 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake2" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" +dependencies = [ + "crypto-mac 0.8.0", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + [[package]] name = "blake2" version = "0.10.6" @@ -611,24 +819,24 @@ dependencies = [ [[package]] name = "blake2b_simd" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127" +checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" dependencies = [ "arrayref", "arrayvec 0.7.2", - "constant_time_eq 0.1.5", + "constant_time_eq", ] [[package]] name = "blake2s_simd" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db539cc2b5f6003621f1cd9ef92d7ded8ea5232c7de0f9faa2de251cd98730d4" +checksum = "6637f448b9e61dfadbdcbae9a885fadee1f3eaffb1f8d3c1965d3ade8bdfd44f" dependencies = [ "arrayref", "arrayvec 0.7.2", - "constant_time_eq 0.1.5", + "constant_time_eq", ] [[package]] @@ -641,7 +849,7 @@ dependencies = [ "arrayvec 0.7.2", "cc", "cfg-if", - "constant_time_eq 0.2.4", + "constant_time_eq", ] [[package]] @@ -667,9 +875,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array 0.14.6", ] @@ -699,6 +907,50 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +[[package]] +name = "bls-like" +version = "0.1.0" +source = "git+https://github.com/w3f/bls?branch=skalman-hash-to-curve-wb#79ca386894d61837cd0e76710718a658c65904b0" +dependencies = [ + "ark-bls12-377", + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-serialize-derive", + "arrayref", + "digest 0.10.6", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "sha2 0.10.6", + "sha3", + "thiserror", + "zeroize", +] + +[[package]] +name = "bls-like" +version = "0.1.0" +source = "git+https://github.com/w3f/bls#32d33cc353f1457ac562fa01d16df8757013108d" +dependencies = [ + "ark-bls12-377", + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-serialize-derive", + "arrayref", + "digest 0.10.6", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_core 0.6.4", + "sha2 0.10.6", + "sha3", + "thiserror", + "zeroize", +] + [[package]] name = "bs58" version = "0.4.0" @@ -707,18 +959,9 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "memchr", -] - -[[package]] -name = "bstr" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45ea9b00a7b3f2988e9a65ad3917e62123c38dba709b666506207be96d1790b" +checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" dependencies = [ "memchr", "once_cell", @@ -737,9 +980,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "byte-slice-cast" @@ -761,9 +1004,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "bzip2-sys" @@ -778,9 +1021,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.1" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad0e1e3e88dd237a156ab9f571021b8a158caa0ae44b1968a241efb5144c1e" +checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" dependencies = [ "serde", ] @@ -802,7 +1045,7 @@ checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" dependencies = [ "camino", "cargo-platform", - "semver 1.0.16", + "semver 1.0.17", "serde", "serde_json", ] @@ -815,9 +1058,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" dependencies = [ "jobserver", ] @@ -893,7 +1136,7 @@ name = "chain-spec-builder" version = "2.0.0" dependencies = [ "ansi_term", - "clap 4.0.32", + "clap 4.1.8", "node-cli", "rand 0.8.5", "sc-chain-spec", @@ -904,9 +1147,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.23" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" dependencies = [ "iana-time-zone", "js-sys", @@ -952,7 +1195,7 @@ checksum = "f6ed9c8b2d17acb8110c46f1da5bf4a696d745e1474a16db0cd2b49cd0249bf2" dependencies = [ "core2", "multibase", - "multihash", + "multihash 0.16.3", "serde", "unsigned-varint", ] @@ -975,6 +1218,16 @@ dependencies = [ "generic-array 0.14.6", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "ckb-merkle-mountain-range" version = "0.5.2" @@ -986,9 +1239,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.4.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" +checksum = "77ed9a53e5d4d9c573ae844bfac6872b159cb1d1585a83b29e7a64b7eef7332a" dependencies = [ "glob", "libc", @@ -1009,13 +1262,13 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.32" +version = "4.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39" +checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" dependencies = [ "bitflags", "clap_derive", - "clap_lex 0.3.0", + "clap_lex 0.3.2", "is-terminal", "once_cell", "strsim", @@ -1024,18 +1277,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.0.7" +version = "4.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b" +checksum = "501ff0a401473ea1d4c3b125ff95506b62c5bc5768d818634195fbb7c4ad5ff4" dependencies = [ - "clap 4.0.32", + "clap 4.1.8", ] [[package]] name = "clap_derive" -version = "4.0.21" +version = "4.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" +checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0" dependencies = [ "heck", "proc-macro-error", @@ -1055,9 +1308,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" dependencies = [ "os_str_bytes", ] @@ -1085,30 +1338,24 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b" +checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e" dependencies = [ "crossbeam-utils", ] [[package]] name = "const-oid" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" - -[[package]] -name = "constant_time_eq" -version = "0.1.5" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" [[package]] name = "constant_time_eq" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3ad85c1f65dc7b37604eb0e89748faf0b9653065f2a8ef69f96a687ec1e9279" +checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b" [[package]] name = "core-foundation" @@ -1153,12 +1400,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cpuid-bool" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" - [[package]] name = "cranelift-bforest" version = "0.88.2" @@ -1259,18 +1500,18 @@ dependencies = [ [[package]] name = "crc" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53757d12b596c16c78b83458d732a5d1a17ab3f53f2f7412f6fb57cc8a140ab3" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" dependencies = [ "crc-catalog", ] [[package]] name = "crc-catalog" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d0165d2900ae6778e36e80bbc4da3b5eefccee9ba939761f9c2882a5d9af3ff" +checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" [[package]] name = "crc32fast" @@ -1321,9 +1562,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" dependencies = [ "cfg-if", "crossbeam-utils", @@ -1331,9 +1572,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -1342,22 +1583,22 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset 0.7.1", + "memoffset 0.8.0", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" dependencies = [ "cfg-if", ] @@ -1387,6 +1628,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array 0.14.6", + "rand_core 0.6.4", "typenum", ] @@ -1400,16 +1642,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "crypto-mac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" -dependencies = [ - "generic-array 0.14.6", - "subtle", -] - [[package]] name = "crypto-mac" version = "0.11.1" @@ -1432,20 +1664,20 @@ dependencies = [ [[package]] name = "ctr" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" +checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" dependencies = [ - "cipher 0.2.5", + "cipher 0.3.0", ] [[package]] name = "ctr" -version = "0.8.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ - "cipher 0.3.0", + "cipher 0.4.4", ] [[package]] @@ -1476,9 +1708,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-pre.5" +version = "4.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67bc65846be335cb20f4e52d49a437b773a2c1fdb42b19fc84e79e6f6771536f" +checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" dependencies = [ "cfg-if", "fiat-crypto", @@ -1490,9 +1722,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.85" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd" +checksum = "9a140f260e6f3f79013b8bfc65e7ce630c9ab4388c6a89c71e07226f49487b72" dependencies = [ "cc", "cxxbridge-flags", @@ -1502,9 +1734,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.85" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0" +checksum = "da6383f459341ea689374bf0a42979739dc421874f112ff26f829b8040b8e613" dependencies = [ "cc", "codespan-reporting", @@ -1517,15 +1749,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.85" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59" +checksum = "90201c1a650e95ccff1c8c0bb5a343213bdd317c6e600a93075bca2eff54ec97" [[package]] name = "cxxbridge-macro" -version = "1.0.85" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" +checksum = "0b75aed41bb2e6367cae39e6326ef817a851db13c13e4f3263714ca3cfb8de56" dependencies = [ "proc-macro2", "quote", @@ -1534,9 +1766,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.14.2" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" dependencies = [ "darling_core", "darling_macro", @@ -1544,9 +1776,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.14.2" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" dependencies = [ "fnv", "ident_case", @@ -1558,9 +1790,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.14.2" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" dependencies = [ "darling_core", "quote", @@ -1620,11 +1852,11 @@ dependencies = [ [[package]] name = "der-parser" -version = "8.1.0" +version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d4bc9b0db0a0df9ae64634ac5bdefb7afcb534e182275ca0beadbe486701c1" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" dependencies = [ - "asn1-rs 0.5.1", + "asn1-rs 0.5.2", "displaydoc", "nom", "num-bigint", @@ -1632,6 +1864,17 @@ dependencies = [ "rusticata-macros", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "derive-syn-parse" version = "0.1.5" @@ -1721,7 +1964,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ - "block-buffer 0.10.3", + "block-buffer 0.10.4", "crypto-common", "subtle", ] @@ -1780,9 +2023,9 @@ dependencies = [ [[package]] name = "dissimilar" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5f0c7e4bd266b8ab2550e6238d2e74977c23c15536ac7be45e9c95e2e3fbbb" +checksum = "210ec60ae7d710bed8683e333e9d2855a8a56a3e9892b38bad3bb0d4d29b0d5e" [[package]] name = "doc-comment" @@ -1804,9 +2047,9 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "dtoa" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00704156a7de8df8da0911424e30c2049957b0a714542a44e05fe693dd85313" +checksum = "65d09067bfacaa79114679b279d7f5885b53295b1e2cfb4e79c8e4bd3d633169" [[package]] name = "dyn-clonable" @@ -1831,9 +2074,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9b0705efd4599c15a38151f4721f7bc388306f61084d3bfd50bd07fbca5cb60" +checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" [[package]] name = "ecdsa" @@ -1849,9 +2092,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ "signature", ] @@ -1886,9 +2129,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "elliptic-curve" @@ -1957,6 +2200,19 @@ dependencies = [ "termcolor", ] +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "environmental" version = "1.1.4" @@ -2013,9 +2269,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] @@ -2039,32 +2295,45 @@ dependencies = [ "subtle", ] +[[package]] +name = "fflonk" +version = "0.1.0" +source = "git+https://github.com/w3f/fflonk#cbcfc4524779872fb9883110f07890cdc46633ea" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "merlin 3.0.0", +] + [[package]] name = "fiat-crypto" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a214f5bb88731d436478f3ae1f8a277b62124089ba9fb67f4f93fb100ef73c90" +checksum = "93ace6ec7cc19c8ed33a32eaa9ea692d7faea05006b5356b9e2b668ec4bc3955" [[package]] name = "file-per-thread-logger" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e16290574b39ee41c71aeb90ae960c504ebaf1e2a1c87bd52aa56ed6e1a02f" +checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" dependencies = [ - "env_logger", + "env_logger 0.10.0", "log", ] [[package]] name = "filetime" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" +checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" dependencies = [ "cfg-if", "libc", "redox_syscall", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -2184,7 +2453,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.0.32", + "clap 4.1.8", "comfy-table", "frame-benchmarking", "frame-support", @@ -2275,7 +2544,7 @@ dependencies = [ name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.0.32", + "clap 4.1.8", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -2520,9 +2789,9 @@ dependencies = [ [[package]] name = "fs_extra" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "funty" @@ -2532,9 +2801,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.25" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549" dependencies = [ "futures-channel", "futures-core", @@ -2547,9 +2816,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac" dependencies = [ "futures-core", "futures-sink", @@ -2557,15 +2826,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd" [[package]] name = "futures-executor" -version = "0.3.25" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83" dependencies = [ "futures-core", "futures-task", @@ -2575,9 +2844,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.25" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91" [[package]] name = "futures-lite" @@ -2596,9 +2865,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.25" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6" dependencies = [ "proc-macro2", "quote", @@ -2612,21 +2881,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2411eed028cdf8c8034eaf21f9915f956b6c3abec4d4c7949ee67f0721127bd" dependencies = [ "futures-io", - "rustls 0.20.7", + "rustls 0.20.8", "webpki 0.22.0", ] [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" [[package]] name = "futures-timer" @@ -2636,9 +2905,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" dependencies = [ "futures-channel", "futures-core", @@ -2727,22 +2996,22 @@ dependencies = [ [[package]] name = "ghash" -version = "0.3.1" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" dependencies = [ "opaque-debug 0.3.0", - "polyval 0.4.5", + "polyval 0.5.3", ] [[package]] name = "ghash" -version = "0.4.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" +checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" dependencies = [ "opaque-debug 0.3.0", - "polyval 0.5.3", + "polyval 0.6.0", ] [[package]] @@ -2758,15 +3027,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "git2" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be36bc9e0546df253c0cc41fd0af34f5e92845ad8509462ec76672fac6997f5b" +checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc" dependencies = [ "bitflags", "libc", @@ -2777,18 +3046,18 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ "aho-corasick", - "bstr 0.2.17", + "bstr", "fnv", "log", "regex", @@ -2807,9 +3076,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" dependencies = [ "bytes", "fnv", @@ -2873,12 +3142,15 @@ name = "hashbrown" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.3", +] [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -2898,12 +3170,24 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + [[package]] name = "hkdf" version = "0.12.3" @@ -2923,16 +3207,6 @@ dependencies = [ "digest 0.9.0", ] -[[package]] -name = "hmac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" -dependencies = [ - "crypto-mac 0.10.1", - "digest 0.9.0", -] - [[package]] name = "hmac" version = "0.11.0" @@ -2988,9 +3262,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ "bytes", "fnv", @@ -3034,9 +3308,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.23" +version = "0.14.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" +checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" dependencies = [ "bytes", "futures-channel", @@ -3065,7 +3339,7 @@ dependencies = [ "http", "hyper", "log", - "rustls 0.20.7", + "rustls 0.20.8", "rustls-native-certs", "tokio", "tokio-rustls", @@ -3197,6 +3471,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array 0.14.6", +] + [[package]] name = "instant" version = "0.1.12" @@ -3242,12 +3525,12 @@ checksum = "59ce5ef949d49ee85593fc4d3f3f95ad61657076395cbbce23e2121fc5542074" [[package]] name = "io-lifetimes" -version = "1.0.3" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3" dependencies = [ "libc", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -3270,20 +3553,20 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" [[package]] name = "is-terminal" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" -dependencies = [ - "hermit-abi 0.2.6", - "io-lifetimes 1.0.3", - "rustix 0.36.6", - "windows-sys 0.42.0", +checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes 1.0.6", + "rustix 0.36.9", + "windows-sys 0.45.0", ] [[package]] @@ -3297,24 +3580,24 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "jobserver" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -3624,15 +3907,15 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" [[package]] name = "libgit2-sys" -version = "0.14.1+1.5.0" +version = "0.14.2+1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a07fb2692bc3593bda59de45a502bb3071659f2c515e28c71e728306b038e17" +checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4" dependencies = [ "cc", "libc", @@ -3664,16 +3947,16 @@ checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" [[package]] name = "libp2p" -version = "0.50.0" +version = "0.50.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e0a0d2f693675f49ded13c5d510c48b78069e23cbd9108d7ccd59f6dc568819" +checksum = "9c7b0104790be871edcf97db9bd2356604984e623a08d825c3f27852290266b8" dependencies = [ "bytes", "futures", "futures-timer", "getrandom 0.2.8", "instant", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-dns", "libp2p-identify", "libp2p-kad", @@ -3690,7 +3973,7 @@ dependencies = [ "libp2p-webrtc", "libp2p-websocket", "libp2p-yamux", - "multiaddr", + "multiaddr 0.16.0", "parking_lot 0.12.1", "pin-project", "smallvec", @@ -3711,8 +3994,8 @@ dependencies = [ "futures-timer", "instant", "log", - "multiaddr", - "multihash", + "multiaddr 0.16.0", + "multihash 0.16.3", "multistream-select", "once_cell", "parking_lot 0.12.1", @@ -3730,6 +4013,34 @@ dependencies = [ "zeroize", ] +[[package]] +name = "libp2p-core" +version = "0.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7f8b7d65c070a5a1b5f8f0510648189da08f787b8963f8e21219e0710733af" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "instant", + "libp2p-identity", + "log", + "multiaddr 0.17.0", + "multihash 0.17.0", + "multistream-select", + "once_cell", + "parking_lot 0.12.1", + "pin-project", + "quick-protobuf", + "rand 0.8.5", + "rw-stream-sink", + "smallvec", + "thiserror", + "unsigned-varint", + "void", +] + [[package]] name = "libp2p-dns" version = "0.38.0" @@ -3737,7 +4048,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e42a271c1b49f789b92f7fc87749fa79ce5c7bdc88cbdfacb818a4bca47fec5" dependencies = [ "futures", - "libp2p-core", + "libp2p-core 0.38.0", "log", "parking_lot 0.12.1", "smallvec", @@ -3753,7 +4064,7 @@ dependencies = [ "asynchronous-codec", "futures", "futures-timer", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-swarm", "log", "lru", @@ -3765,6 +4076,25 @@ dependencies = [ "void", ] +[[package]] +name = "libp2p-identity" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6c9cb71e2333d31f18e7556b9a5f1d0a2e013effc9325e36f436be65fe7bd2" +dependencies = [ + "bs58", + "ed25519-dalek", + "log", + "multiaddr 0.17.0", + "multihash 0.17.0", + "prost", + "prost-build", + "quick-protobuf", + "rand 0.8.5", + "thiserror", + "zeroize", +] + [[package]] name = "libp2p-kad" version = "0.42.1" @@ -3779,7 +4109,7 @@ dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-swarm", "log", "prost", @@ -3802,7 +4132,7 @@ dependencies = [ "data-encoding", "futures", "if-watch", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-swarm", "log", "rand 0.8.5", @@ -3819,7 +4149,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ad8a64f29da86005c86a4d2728b8a0719e9b192f4092b609fd8790acb9dec55" dependencies = [ - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-identify", "libp2p-kad", "libp2p-ping", @@ -3836,7 +4166,7 @@ dependencies = [ "asynchronous-codec", "bytes", "futures", - "libp2p-core", + "libp2p-core 0.38.0", "log", "nohash-hasher", "parking_lot 0.12.1", @@ -3854,7 +4184,7 @@ dependencies = [ "bytes", "curve25519-dalek 3.2.0", "futures", - "libp2p-core", + "libp2p-core 0.38.0", "log", "once_cell", "prost", @@ -3877,7 +4207,7 @@ dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-swarm", "log", "rand 0.8.5", @@ -3894,13 +4224,13 @@ dependencies = [ "futures", "futures-timer", "if-watch", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-tls", "log", "parking_lot 0.12.1", "quinn-proto", "rand 0.8.5", - "rustls 0.20.7", + "rustls 0.20.8", "thiserror", "tokio", ] @@ -3915,7 +4245,7 @@ dependencies = [ "bytes", "futures", "instant", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-swarm", "log", "rand 0.8.5", @@ -3934,7 +4264,7 @@ dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-swarm-derive", "log", "pin-project", @@ -3966,7 +4296,7 @@ dependencies = [ "futures-timer", "if-watch", "libc", - "libp2p-core", + "libp2p-core 0.38.0", "log", "socket2", "tokio", @@ -3974,16 +4304,17 @@ dependencies = [ [[package]] name = "libp2p-tls" -version = "0.1.0-alpha" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7905ce0d040576634e8a3229a7587cc8beab83f79db6023800f1792895defa8" +checksum = "ff08d13d0dc66e5e9ba6279c1de417b84fa0d0adc3b03e5732928c180ec02781" dependencies = [ "futures", "futures-rustls", - "libp2p-core", + "libp2p-core 0.39.1", + "libp2p-identity", "rcgen 0.10.0", "ring", - "rustls 0.20.7", + "rustls 0.20.8", "thiserror", "webpki 0.22.0", "x509-parser 0.14.0", @@ -3998,7 +4329,7 @@ checksum = "1bb1a35299860e0d4b3c02a3e74e3b293ad35ae0cee8a056363b0c862d082069" dependencies = [ "futures", "js-sys", - "libp2p-core", + "libp2p-core 0.38.0", "parity-send-wrapper", "wasm-bindgen", "wasm-bindgen-futures", @@ -4017,10 +4348,10 @@ dependencies = [ "futures-timer", "hex", "if-watch", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-noise", "log", - "multihash", + "multihash 0.16.3", "prost", "prost-build", "prost-codec", @@ -4044,7 +4375,7 @@ dependencies = [ "either", "futures", "futures-rustls", - "libp2p-core", + "libp2p-core 0.38.0", "log", "parking_lot 0.12.1", "quicksink", @@ -4061,7 +4392,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f63594a0aa818642d9d4915c791945053877253f08a3626f13416b5cd928a29" dependencies = [ "futures", - "libp2p-core", + "libp2p-core 0.38.0", "log", "parking_lot 0.12.1", "thiserror", @@ -4070,9 +4401,9 @@ dependencies = [ [[package]] name = "librocksdb-sys" -version = "0.8.0+7.4.4" +version = "0.8.3+7.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611804e4666a25136fcc5f8cf425ab4d26c7f74ea245ffe92ea23b85b6420b5d" +checksum = "557b255ff04123fcc176162f56ed0c9cd42d8f357cf55b3fabeb60f7413741b3" dependencies = [ "bindgen", "bzip2-sys", @@ -4090,7 +4421,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" dependencies = [ "arrayref", - "base64", + "base64 0.13.1", "digest 0.9.0", "hmac-drbg", "libsecp256k1-core", @@ -4299,9 +4630,9 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "matrixmultiply" @@ -4333,14 +4664,14 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b20a59d985586e4a5aef64564ac77299f8586d8be6cf9106a5a40207e8908efb" dependencies = [ - "rustix 0.36.6", + "rustix 0.36.9", ] [[package]] name = "memmap2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", ] @@ -4363,6 +4694,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + [[package]] name = "memory-db" version = "0.31.0" @@ -4391,6 +4731,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -4408,14 +4760,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -4494,7 +4846,25 @@ dependencies = [ "byteorder", "data-encoding", "multibase", - "multihash", + "multihash 0.16.3", + "percent-encoding", + "serde", + "static_assertions", + "unsigned-varint", + "url", +] + +[[package]] +name = "multiaddr" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b53e0cc5907a5c216ba6584bf74be8ab47d6d6289f72793b2dddbf15dc3bf8c" +dependencies = [ + "arrayref", + "byteorder", + "data-encoding", + "multibase", + "multihash 0.17.0", "percent-encoding", "serde", "static_assertions", @@ -4530,11 +4900,24 @@ dependencies = [ "unsigned-varint", ] +[[package]] +name = "multihash" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835d6ff01d610179fbce3de1694d007e500bf33a7f29689838941d6bf783ae40" +dependencies = [ + "core2", + "digest 0.10.6", + "multihash-derive", + "sha2 0.10.6", + "unsigned-varint", +] + [[package]] name = "multihash-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" +checksum = "1d6d4752e6230d8ef7adf7bd5d8c4b1f6561c1014c5ba9a37445ccefe18aa1db" dependencies = [ "proc-macro-crate", "proc-macro-error", @@ -4630,9 +5013,9 @@ dependencies = [ [[package]] name = "netlink-packet-utils" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25af9cf0dc55498b7bd94a1508af7a78706aa0ab715a73c5169273e03c84845e" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" dependencies = [ "anyhow", "byteorder", @@ -4657,9 +5040,9 @@ dependencies = [ [[package]] name = "netlink-sys" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92b654097027250401127914afb37cb1f311df6610a9891ff07a757e94199027" +checksum = "6471bf08e7ac0135876a9581bf3217ef0333c191c128d34878079f42ee150411" dependencies = [ "bytes", "futures", @@ -4682,9 +5065,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a58d1d356c6597d08cde02c2f09d785b09e28711837b1ed667dc652c08a694" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ "bitflags", "cfg-if", @@ -4699,7 +5082,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 4.0.32", + "clap 4.1.8", "derive_more", "fs_extra", "futures", @@ -4736,7 +5119,7 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.0.32", + "clap 4.1.8", "clap_complete", "criterion", "frame-benchmarking-cli", @@ -4746,7 +5129,7 @@ dependencies = [ "jsonrpsee", "kitchensink-runtime", "log", - "nix 0.26.1", + "nix 0.26.2", "node-executor", "node-inspect", "node-primitives", @@ -4855,7 +5238,7 @@ dependencies = [ name = "node-inspect" version = "0.9.0-dev" dependencies = [ - "clap 4.0.32", + "clap 4.1.8", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -4914,7 +5297,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.0.32", + "clap 4.1.8", "generate-bags", "kitchensink-runtime", ] @@ -4923,7 +5306,7 @@ dependencies = [ name = "node-template" version = "4.0.0-dev" dependencies = [ - "clap 4.0.32", + "clap 4.1.8", "frame-benchmarking", "frame-benchmarking-cli", "frame-system", @@ -5042,9 +5425,9 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "nom" -version = "7.1.2" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5507769c4919c998e69e49c839d9dc6e693ede4cc4290d6ad8b41d4f09c548c" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -5079,9 +5462,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" dependencies = [ "num-traits", ] @@ -5152,9 +5535,9 @@ dependencies = [ [[package]] name = "object" -version = "0.30.0" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "memchr", ] @@ -5174,14 +5557,14 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" dependencies = [ - "asn1-rs 0.5.1", + "asn1-rs 0.5.2", ] [[package]] name = "once_cell" -version = "1.17.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "oorandom" @@ -5577,7 +5960,7 @@ dependencies = [ "array-bytes", "assert_matches", "bitflags", - "env_logger", + "env_logger 0.9.3", "frame-benchmarking", "frame-support", "frame-system", @@ -5926,7 +6309,7 @@ name = "pallet-mmr" version = "4.0.0-dev" dependencies = [ "array-bytes", - "env_logger", + "env_logger 0.9.3", "frame-benchmarking", "frame-support", "frame-system", @@ -6701,11 +7084,11 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd684a725651d9588ef21f140a328b6b4f64e646b2e931f3e6f14f75eedf9980" +checksum = "df89dd8311063c54ae4e03d9aeb597b04212a57e82c339344130a9cad9b3e2d9" dependencies = [ - "blake2", + "blake2 0.10.6", "crc32fast", "fs2", "hex", @@ -6715,14 +7098,15 @@ dependencies = [ "memmap2", "parking_lot 0.12.1", "rand 0.8.5", + "siphasher", "snap", ] [[package]] name = "parity-scale-codec" -version = "3.2.2" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ab01d0f889e957861bc65888d5ccbe82c158d0270136ba46820d43837cdf72" +checksum = "637935964ff85a605d114591d4d2c13c5d1ba2806dae97cea6bf180238a749ac" dependencies = [ "arrayvec 0.7.2", "bitvec", @@ -6781,7 +7165,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.5", + "parking_lot_core 0.9.7", ] [[package]] @@ -6800,22 +7184,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.5" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] name = "paste" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "pbkdf2" @@ -6843,11 +7227,11 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "pem" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c64931a1a212348ec4f3b4362585eca7159d0d09cbdf4a7f74f02173596fd4" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" dependencies = [ - "base64", + "base64 0.13.1", ] [[package]] @@ -6867,9 +7251,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.5.2" +version = "2.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f6e86fb9e7026527a0d46bc308b841d73170ef8f443e1807f6ef88526a816d4" +checksum = "8cbd939b234e95d72bc393d51788aec68aeeb5d51e748ca08ff3aad58cb722f7" dependencies = [ "thiserror", "ucd-trie", @@ -6877,9 +7261,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.5.2" +version = "2.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96504449aa860c8dcde14f9fba5c58dc6658688ca1fe363589d6327b8662c603" +checksum = "a81186863f3d0a27340815be8f2078dd8050b14cd71913db9fbda795e5f707d7" dependencies = [ "pest", "pest_generator", @@ -6887,9 +7271,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.5.2" +version = "2.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "798e0220d1111ae63d66cb66a5dcb3fc2d986d520b98e49e1852bfdb11d7c5e7" +checksum = "75a1ef20bf3193c15ac345acb32e26b3dc3223aff4d77ae4fc5359567683796b" dependencies = [ "pest", "pest_meta", @@ -6900,20 +7284,20 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.5.2" +version = "2.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "984298b75898e30a843e278a9f2452c31e349a073a0ce6fd950a12a74464e065" +checksum = "5e3b284b1f13a20dc5ebc90aff59a51b8d7137c221131b52a7260c08cbc1cc80" dependencies = [ "once_cell", "pest", - "sha1", + "sha2 0.10.6", ] [[package]] name = "petgraph" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", "indexmap", @@ -7015,16 +7399,18 @@ dependencies = [ [[package]] name = "polling" -version = "2.5.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22122d5ec4f9fe1b3916419b76be1e80bcb93f618d071d2edf841b137b2a2bd6" +checksum = "7e1f879b2998099c2d69ab9605d145d5b661195627eccc680002c4918a7fb6fa" dependencies = [ "autocfg", + "bitflags", "cfg-if", + "concurrent-queue", "libc", "log", - "wepoll-ffi", - "windows-sys 0.42.0", + "pin-project-lite 0.2.9", + "windows-sys 0.45.0", ] [[package]] @@ -7035,30 +7421,31 @@ checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" dependencies = [ "cpufeatures", "opaque-debug 0.3.0", - "universal-hash", + "universal-hash 0.4.1", ] [[package]] name = "polyval" -version = "0.4.5" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" dependencies = [ - "cpuid-bool", + "cfg-if", + "cpufeatures", "opaque-debug 0.3.0", - "universal-hash", + "universal-hash 0.4.1", ] [[package]] name = "polyval" -version = "0.5.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +checksum = "7ef234e08c11dfcb2e56f79fd70f6f2eb7f025c0ce2333e82f4f0518ecad30c6" dependencies = [ "cfg-if", "cpufeatures", "opaque-debug 0.3.0", - "universal-hash", + "universal-hash 0.5.0", ] [[package]] @@ -7111,9 +7498,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8992a85d8e93a28bdf76137db888d3874e3b230dee5ed8bebac4c9f7617773" +checksum = "4ebcd279d20a4a0a2404a33056388e950504d891c855c7975b9a8fef75f3bf04" dependencies = [ "proc-macro2", "syn", @@ -7134,11 +7521,10 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.2.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" dependencies = [ - "once_cell", "thiserror", "toml", ] @@ -7169,9 +7555,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.50" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" dependencies = [ "unicode-ident", ] @@ -7215,9 +7601,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.11.5" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c01db6702aa05baa3f57dec92b8eeeeb4cb19e894e73996b32a4093289e54592" +checksum = "e48e50df39172a3e7eb17e14642445da64996989bc212b583015435d39a58537" dependencies = [ "bytes", "prost-derive", @@ -7225,9 +7611,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.11.5" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5320c680de74ba083512704acb90fe00f28f79207286a848e730c45dd73ed6" +checksum = "2c828f93f5ca4826f97fedcbd3f9a536c16b12cff3dbbb4a007f932bbad95b12" dependencies = [ "bytes", "heck", @@ -7260,9 +7646,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.5" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8842bad1a5419bca14eac663ba798f6bc19c413c2fdceb5f3ba3b0932d96720" +checksum = "4ea9b0f8cbe5e15a8a042d030bd96668db28ecb567ec37d691971ff5731d2b1b" dependencies = [ "anyhow", "itertools", @@ -7273,11 +7659,10 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.11.5" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "017f79637768cde62820bc2d4fe0e45daaa027755c323ad077767c6c5f173091" +checksum = "379119666929a1afd7a043aa6cf96fa67a6dce9af60c88095a4686dbce4c9c88" dependencies = [ - "bytes", "prost", ] @@ -7296,6 +7681,15 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quick-protobuf" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f" +dependencies = [ + "byteorder", +] + [[package]] name = "quickcheck" version = "1.0.3" @@ -7326,7 +7720,7 @@ dependencies = [ "rand 0.8.5", "ring", "rustc-hash", - "rustls 0.20.7", + "rustls 0.20.8", "slab", "thiserror", "tinyvec", @@ -7336,9 +7730,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "50686e0021c4136d1d453b2dfe059902278681512a34d4248435dc34b6b5c8ec" dependencies = [ "proc-macro2", ] @@ -7447,9 +7841,9 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ "either", "rayon-core", @@ -7457,9 +7851,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -7475,7 +7869,7 @@ checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" dependencies = [ "pem", "ring", - "time 0.3.17", + "time 0.3.20", "x509-parser 0.13.2", "yasna", ] @@ -7488,7 +7882,7 @@ checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", "ring", - "time 0.3.17", + "time 0.3.20", "yasna", ] @@ -7514,18 +7908,18 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c78fb8c9293bcd48ef6fce7b4ca950ceaf21210de6e105a883ee280c0f7b9ed" +checksum = "a9af2cf09ef80e610097515e80095b7f76660a92743c4185aff5406cd5ce3dd5" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f9c0c92af03644e4806106281fe2e068ac5bc0ae74a707266d06ea27bccee5f" +checksum = "9c501201393982e275433bc55de7d6ae6f00e7699cd5572c5b57581cd69c881b" dependencies = [ "proc-macro2", "quote", @@ -7546,9 +7940,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" dependencies = [ "aho-corasick", "memchr", @@ -7570,15 +7964,6 @@ version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - [[package]] name = "resolv-conf" version = "0.7.0" @@ -7719,7 +8104,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.16", + "semver 1.0.17", ] [[package]] @@ -7747,16 +8132,16 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.6" +version = "0.36.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549" +checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" dependencies = [ "bitflags", "errno", - "io-lifetimes 1.0.3", + "io-lifetimes 1.0.6", "libc", "linux-raw-sys 0.1.4", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -7765,7 +8150,7 @@ version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" dependencies = [ - "base64", + "base64 0.13.1", "log", "ring", "sct 0.6.1", @@ -7774,9 +8159,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.7" +version = "0.20.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", "ring", @@ -7798,18 +8183,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64", + "base64 0.21.0", ] [[package]] name = "rustversion" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" [[package]] name = "rusty-fork" @@ -7835,9 +8220,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "safe-mix" @@ -7967,7 +8352,7 @@ version = "0.10.0-dev" dependencies = [ "array-bytes", "chrono", - "clap 4.0.32", + "clap 4.1.8", "fdlimit", "futures", "futures-timer", @@ -8134,7 +8519,7 @@ dependencies = [ "fork-tree", "futures", "log", - "merlin", + "merlin 2.0.1", "num-bigint", "num-rational", "num-traits", @@ -8303,7 +8688,7 @@ dependencies = [ "array-bytes", "assert_matches", "criterion", - "env_logger", + "env_logger 0.9.3", "lru", "num_cpus", "parity-scale-codec", @@ -8385,7 +8770,7 @@ dependencies = [ name = "sc-finality-grandpa" version = "0.10.0-dev" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "array-bytes", "assert_matches", "async-trait", @@ -8585,7 +8970,7 @@ dependencies = [ name = "sc-network-gossip" version = "0.10.0-dev" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "futures", "futures-timer", "libp2p", @@ -8770,7 +9155,7 @@ name = "sc-rpc" version = "4.0.0-dev" dependencies = [ "assert_matches", - "env_logger", + "env_logger 0.9.3", "futures", "jsonrpsee", "log", @@ -8995,10 +9380,10 @@ dependencies = [ name = "sc-storage-monitor" version = "0.1.0" dependencies = [ - "clap 4.0.32", + "clap 4.1.8", "futures", "log", - "nix 0.26.1", + "nix 0.26.2", "sc-client-db", "sc-utils", "sp-core", @@ -9192,12 +9577,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" dependencies = [ - "lazy_static", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] @@ -9206,7 +9590,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "cfg-if", "hashbrown 0.13.2", ] @@ -9221,7 +9605,7 @@ dependencies = [ "arrayvec 0.5.2", "curve25519-dalek 2.1.3", "getrandom 0.1.16", - "merlin", + "merlin 2.0.1", "rand 0.7.3", "rand_core 0.5.1", "sha2 0.8.2", @@ -9237,9 +9621,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "scratch" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" +checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" [[package]] name = "sct" @@ -9289,9 +9673,9 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.24.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9512ffd81e3a3503ed401f79c33168b9148c75038956039166cd750eaa037c3" +checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" dependencies = [ "secp256k1-sys", ] @@ -9316,9 +9700,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.7.0" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ "bitflags", "core-foundation", @@ -9329,9 +9713,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.6.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" dependencies = [ "core-foundation-sys", "libc", @@ -9357,9 +9741,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" dependencies = [ "serde", ] @@ -9372,18 +9756,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.152" +version = "1.0.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "71f2b4817415c6d4210bfe1c7bfcf4801b2d904cb4d0e1a8fdb651013c9e86b8" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "d071a94a3fac4aff69d023a7f411e33f40f3483f8c5190b1953822b6b76d7630" dependencies = [ "proc-macro2", "quote", @@ -9392,9 +9776,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" dependencies = [ "itoa", "ryu", @@ -9488,9 +9872,9 @@ checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] @@ -9517,11 +9901,17 @@ dependencies = [ "paste", ] +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg", ] @@ -9538,6 +9928,17 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +[[package]] +name = "smart-default" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "snap" version = "1.1.0" @@ -9546,14 +9947,14 @@ checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snow" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774d05a3edae07ce6d68ea6984f3c05e9bba8927e3dd591e3b479e5b03213d0d" +checksum = "5ccba027ba85743e09d15c03296797cad56395089b832b48b5a5217880f57733" dependencies = [ "aes-gcm 0.9.4", - "blake2", + "blake2 0.10.6", "chacha20poly1305", - "curve25519-dalek 4.0.0-pre.5", + "curve25519-dalek 4.0.0-rc.1", "rand_core 0.6.4", "ring", "rustc_version 0.4.0", @@ -9563,9 +9964,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", @@ -9577,7 +9978,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" dependencies = [ - "base64", + "base64 0.13.1", "bytes", "flate2", "futures", @@ -9610,7 +10011,7 @@ dependencies = [ name = "sp-api-proc-macro" version = "4.0.0-dev" dependencies = [ - "blake2", + "blake2 0.10.6", "proc-macro-crate", "proc-macro2", "quote", @@ -9705,7 +10106,12 @@ dependencies = [ name = "sp-beefy" version = "4.0.0-dev" dependencies = [ + "apk-proofs", + "ark-serialize", "array-bytes", + "bls-like 0.1.0 (git+https://github.com/w3f/bls)", + "hex", + "hex-literal", "parity-scale-codec", "scale-info", "serde", @@ -9787,7 +10193,7 @@ name = "sp-consensus-babe" version = "0.10.0-dev" dependencies = [ "async-trait", - "merlin", + "merlin 2.0.1", "parity-scale-codec", "scale-info", "serde", @@ -9845,18 +10251,21 @@ dependencies = [ "array-bytes", "base58", "bitflags", - "blake2", + "blake2 0.10.6", + "bls-like 0.1.0 (git+https://github.com/w3f/bls?branch=skalman-hash-to-curve-wb)", "criterion", "dyn-clonable", "ed25519-zebra", "futures", "hash-db", "hash256-std-hasher", + "hex", + "hex-literal", "impl-serde", "lazy_static", "libsecp256k1", "log", - "merlin", + "merlin 2.0.1", "parity-scale-codec", "parking_lot 0.12.1", "primitive-types", @@ -9868,6 +10277,7 @@ dependencies = [ "secrecy", "serde", "serde_json", + "sha2 0.10.6", "sp-core-hashing", "sp-core-hashing-proc-macro", "sp-debug-derive", @@ -9887,7 +10297,7 @@ dependencies = [ name = "sp-core-hashing" version = "5.0.0" dependencies = [ - "blake2", + "blake2 0.10.6", "byteorder", "digest 0.10.6", "sha2 0.10.6", @@ -10004,7 +10414,7 @@ version = "0.13.0" dependencies = [ "async-trait", "futures", - "merlin", + "merlin 2.0.1", "parity-scale-codec", "parking_lot 0.12.1", "rand 0.7.3", @@ -10061,7 +10471,7 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.0.32", + "clap 4.1.8", "honggfuzz", "parity-scale-codec", "rand 0.8.5", @@ -10333,7 +10743,7 @@ dependencies = [ name = "sp-trie" version = "7.0.0" dependencies = [ - "ahash 0.8.2", + "ahash 0.8.3", "array-bytes", "criterion", "hash-db", @@ -10417,9 +10827,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spin" -version = "0.9.4" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" +checksum = "b5d6e0250b93c8427a177b849d144a96d5acc57006149479403d7861ab721e34" [[package]] name = "spki" @@ -10433,9 +10843,9 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.36.0" +version = "1.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d92659e7d18d82b803824a9ba5a6022cff101c3491d027c1c1d8d30e749284" +checksum = "ecf0bd63593ef78eca595a7fc25e9a443ca46fe69fd472f8f09f5245cdcd769d" dependencies = [ "Inflector", "num-format", @@ -10533,7 +10943,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7e94b1ec00bad60e6410e058b52f1c66de3dc5fe4d62d09b3e52bb7d3b73e25" dependencies = [ - "base64", + "base64 0.13.1", "crc", "lazy_static", "md-5", @@ -10550,7 +10960,7 @@ dependencies = [ name = "subkey" version = "2.0.2" dependencies = [ - "clap 4.0.32", + "clap 4.1.8", "sc-cli", ] @@ -10578,7 +10988,7 @@ dependencies = [ name = "substrate-frame-cli" version = "4.0.0-dev" dependencies = [ - "clap 4.0.32", + "clap 4.1.8", "frame-support", "frame-system", "sc-cli", @@ -10838,9 +11248,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -10888,29 +11298,28 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.5" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" +checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" [[package]] name = "tempfile" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" dependencies = [ "cfg-if", "fastrand", - "libc", "redox_syscall", - "remove_dir_all", - "winapi", + "rustix 0.36.9", + "windows-sys 0.42.0", ] [[package]] name = "termcolor" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] @@ -10929,18 +11338,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" dependencies = [ "proc-macro2", "quote", @@ -10955,10 +11364,11 @@ checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] @@ -10973,12 +11383,11 @@ dependencies = [ [[package]] name = "tikv-jemalloc-sys" -version = "0.5.2+5.3.0-patched" +version = "0.5.3+5.3.0-patched" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec45c14da997d0925c7835883e4d5c181f196fa142f8c19d7643d1e9af2592c3" +checksum = "a678df20055b43e57ef8cddde41cdfda9a3c1a060b67f4c5836dfb1d78543ba8" dependencies = [ "cc", - "fs_extra", "libc", ] @@ -10995,9 +11404,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.17" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" dependencies = [ "itoa", "serde", @@ -11013,9 +11422,9 @@ checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" [[package]] name = "time-macros" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" dependencies = [ "time-core", ] @@ -11069,15 +11478,15 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.23.0" +version = "1.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" +checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" dependencies = [ "autocfg", "bytes", @@ -11090,7 +11499,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -11110,16 +11519,16 @@ version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ - "rustls 0.20.7", + "rustls 0.20.8", "tokio", "webpki 0.22.0", ] [[package]] name = "tokio-stream" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" +checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" dependencies = [ "futures-core", "pin-project-lite 0.2.9", @@ -11142,9 +11551,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.4" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" dependencies = [ "bytes", "futures-core", @@ -11157,9 +11566,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] @@ -11407,15 +11816,15 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" dependencies = [ - "clap 4.0.32", + "clap 4.1.8", "frame-remote-externalities", "frame-try-runtime", "hex", @@ -11444,10 +11853,11 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.74" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "654bfc024d30963fce210f22f98956407fe8c8365eb85a1fa530f6f8844137ed" +checksum = "db3115bddce1b5f52dd4b5e0ec8298a66ce733e4cc6759247dc2d1c11508ec38" dependencies = [ + "basic-toml", "dissimilar", "glob", "once_cell", @@ -11455,7 +11865,6 @@ dependencies = [ "serde_derive", "serde_json", "termcolor", - "toml", ] [[package]] @@ -11471,7 +11880,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4712ee30d123ec7ae26d1e1b218395a16c87cdbaf4b3925d170d684af62ea5e8" dependencies = [ "async-trait", - "base64", + "base64 0.13.1", "futures", "log", "md-5", @@ -11521,15 +11930,15 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "524b68aca1d05e03fdf03fcdce2c6c94b6daf6d16861ddaa7e4f2b6638a9052c" [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-normalization" @@ -11562,6 +11971,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "universal-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "unsigned-varint" version = "0.7.1" @@ -11593,9 +12012,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" +checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" dependencies = [ "getrandom 0.2.8", ] @@ -11689,9 +12108,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -11699,9 +12118,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", @@ -11714,9 +12133,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" dependencies = [ "cfg-if", "js-sys", @@ -11726,9 +12145,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -11736,9 +12155,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", @@ -11749,15 +12168,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "wasm-encoder" -version = "0.20.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05632e0a66a6ed8cca593c24223aabd6262f256c3693ad9822c315285f010614" +checksum = "4eff853c4f09eec94d76af527eddad4e9de13b11d6286a1ef7134bc30135a2b7" dependencies = [ "leb128", ] @@ -11853,7 +12272,7 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01bf50edb2ea9d922aa75a7bf3c15e26a6c9e2d18c56e862b49737a582901729" dependencies = [ - "spin 0.9.4", + "spin 0.9.6", "wasmi_arena", "wasmi_core 0.5.0", "wasmparser-nostd", @@ -11960,7 +12379,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcd849399d17d2270141cfe47fa0d91ee52d5f8ea9b98cf7ddde0d53e5f79882" dependencies = [ "anyhow", - "base64", + "base64 0.13.1", "bincode", "directories-next", "file-per-thread-logger", @@ -12088,9 +12507,9 @@ dependencies = [ [[package]] name = "wast" -version = "50.0.0" +version = "55.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2cbb59d4ac799842791fe7e806fa5dbbf6b5554d538e51cc8e176db6ff0ae34" +checksum = "4984d3e1406571f4930ba5cf79bd70f75f41d0e87e17506e0bd19b0e5d085f05" dependencies = [ "leb128", "memchr", @@ -12100,18 +12519,18 @@ dependencies = [ [[package]] name = "wat" -version = "1.0.52" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "584aaf7a1ecf4d383bbe1a25eeab0cbb8ff96acc6796707ff65cde48f4632f15" +checksum = "af2b53f4da14db05d32e70e9c617abdf6620c575bd5dd972b7400037b4df2091" dependencies = [ "wast", ] [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" dependencies = [ "js-sys", "wasm-bindgen", @@ -12172,7 +12591,7 @@ dependencies = [ "sha2 0.10.6", "stun", "thiserror", - "time 0.3.17", + "time 0.3.20", "tokio", "turn", "url", @@ -12204,22 +12623,22 @@ dependencies = [ [[package]] name = "webrtc-dtls" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7021987ae0a2ed6c8cd33f68e98e49bb6e74ffe9543310267b48a1bbe3900e5f" +checksum = "942be5bd85f072c3128396f6e5a9bfb93ca8c1939ded735d177b7bcba9a13d05" dependencies = [ "aes 0.6.0", - "aes-gcm 0.8.0", + "aes-gcm 0.10.1", "async-trait", "bincode", "block-modes", "byteorder", "ccm", "curve25519-dalek 3.2.0", - "der-parser 8.1.0", + "der-parser 8.2.0", "elliptic-curve", "hkdf", - "hmac 0.10.1", + "hmac 0.12.1", "log", "oid-registry 0.6.1", "p256", @@ -12231,8 +12650,8 @@ dependencies = [ "rustls 0.19.1", "sec1", "serde", - "sha-1", - "sha2 0.9.9", + "sha1", + "sha2 0.10.6", "signature", "subtle", "thiserror", @@ -12245,9 +12664,9 @@ dependencies = [ [[package]] name = "webrtc-ice" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "494483fbb2f5492620871fdc78b084aed8807377f6e3fe88b2e49f0a9c9c41d7" +checksum = "465a03cc11e9a7d7b4f9f99870558fe37a102b65b93f8045392fef7c67b39e80" dependencies = [ "arc-swap", "async-trait", @@ -12358,20 +12777,11 @@ dependencies = [ "winapi", ] -[[package]] -name = "wepoll-ffi" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" -dependencies = [ - "cc", -] - [[package]] name = "which" -version = "4.3.0" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" dependencies = [ "either", "libc", @@ -12448,19 +12858,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.0", - "windows_i686_gnu 0.42.0", - "windows_i686_msvc 0.42.0", - "windows_x86_64_gnu 0.42.0", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.0", + "windows_x86_64_msvc 0.42.2", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_msvc" @@ -12476,9 +12910,9 @@ checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_i686_gnu" @@ -12494,9 +12928,9 @@ checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] name = "windows_i686_gnu" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_msvc" @@ -12512,9 +12946,9 @@ checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_x86_64_gnu" @@ -12530,15 +12964,15 @@ checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_msvc" @@ -12554,9 +12988,9 @@ checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "winreg" @@ -12605,7 +13039,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fb9bace5b5589ffead1afb76e43e34cff39cd0f3ce7e170ae0c29e53b88eb1c" dependencies = [ "asn1-rs 0.3.1", - "base64", + "base64 0.13.1", "data-encoding", "der-parser 7.0.0", "lazy_static", @@ -12614,7 +13048,7 @@ dependencies = [ "ring", "rusticata-macros", "thiserror", - "time 0.3.17", + "time 0.3.20", ] [[package]] @@ -12623,16 +13057,16 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" dependencies = [ - "asn1-rs 0.5.1", - "base64", + "asn1-rs 0.5.2", + "base64 0.13.1", "data-encoding", - "der-parser 8.1.0", + "der-parser 8.2.0", "lazy_static", "nom", "oid-registry 0.6.1", "rusticata-macros", "thiserror", - "time 0.3.17", + "time 0.3.20", ] [[package]] @@ -12661,7 +13095,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aed2e7a52e3744ab4d0c05c20aa065258e84c49fd4226f5191b2ed29712710b4" dependencies = [ - "time 0.3.17", + "time 0.3.20", ] [[package]] @@ -12706,10 +13140,11 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.4+zstd.1.5.2" +version = "2.0.7+zstd.1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fa202f2ef00074143e219d15b62ffc317d17cc33909feac471c044087cad7b0" +checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5" dependencies = [ "cc", "libc", + "pkg-config", ] diff --git a/Cargo.toml b/Cargo.toml index b004886e83f9a..ed12d59865ec7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -321,3 +321,5 @@ inherits = "release" lto = "fat" # https://doc.rust-lang.org/rustc/codegen-options/index.html#codegen-units codegen-units = 1 + +[patch.crates-io] diff --git a/client/beefy/Cargo.toml b/client/beefy/Cargo.toml index d81ff2587cf2c..65d173f20a08a 100644 --- a/client/beefy/Cargo.toml +++ b/client/beefy/Cargo.toml @@ -48,3 +48,4 @@ sp-finality-grandpa = { version = "4.0.0-dev", path = "../../primitives/finality sp-keyring = { version = "7.0.0", path = "../../primitives/keyring" } sp-tracing = { version = "6.0.0", path = "../../primitives/tracing" } substrate-test-runtime-client = { version = "2.0.0", path = "../../test-utils/runtime/client" } +smart-default = "0.6.0" \ No newline at end of file diff --git a/client/beefy/src/aux_schema.rs b/client/beefy/src/aux_schema.rs index fafa9948c5444..e8a5db95fdc16 100644 --- a/client/beefy/src/aux_schema.rs +++ b/client/beefy/src/aux_schema.rs @@ -24,6 +24,7 @@ use log::{info, trace}; use sc_client_api::{backend::AuxStore, Backend}; use sp_blockchain::{Error as ClientError, Result as ClientResult}; use sp_runtime::traits::Block as BlockT; +use std::fmt::Debug; const VERSION_KEY: &[u8] = b"beefy_auxschema_version"; const WORKER_STATE: &[u8] = b"beefy_voter_state"; @@ -36,15 +37,20 @@ pub(crate) fn write_current_version(backend: &B) -> ClientResult<() } /// Write voter state. -pub(crate) fn write_voter_state( +pub(crate) fn write_voter_state< + Block: BlockT, + B: AuxStore, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, +>( backend: &B, - state: &PersistedState, + state: &PersistedState, ) -> ClientResult<()> { trace!(target: LOG_TARGET, "🥩 persisting {:?}", state); backend.insert_aux(&[(WORKER_STATE, state.encode().as_slice())], &[]) } -fn load_decode(backend: &B, key: &[u8]) -> ClientResult> { +fn load_decode(backend: &BE, key: &[u8]) -> ClientResult> { match backend.get_aux(key)? { None => Ok(None), Some(t) => T::decode(&mut &t[..]) @@ -54,16 +60,21 @@ fn load_decode(backend: &B, key: &[u8]) -> ClientResult< } /// Load or initialize persistent data from backend. -pub(crate) fn load_persistent(backend: &BE) -> ClientResult>> +pub(crate) fn load_persistent( + backend: &BE, +) -> ClientResult>> where B: BlockT, BE: Backend, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, { let version: Option = load_decode(backend, VERSION_KEY)?; match version { None => (), - Some(1) => return load_decode::<_, PersistedState>(backend, WORKER_STATE), + Some(1) => + return load_decode::<_, PersistedState>(backend, WORKER_STATE), other => return Err(ClientError::Backend(format!("Unsupported BEEFY DB version: {:?}", other))), } @@ -75,22 +86,45 @@ where #[cfg(test)] pub(crate) mod tests { use super::*; - use crate::tests::BeefyTestNet; + use crate::tests::{BeefyAuthIdMaker, BeefyTestNet}; use sc_network_test::TestNetFactory; + use crate::keystore::{BeefyBLSnECDSAKeystore, BeefyECDSAKeystore, BeefyKeystore}; + + use beefy_primitives::{ + bls_crypto::{Public as BLSPublic, Signature as BLSSignature}, + ecdsa_crypto::{Public as ECDSAPublic, Signature as ECDSASignature}, + }; + // also used in tests.rs pub fn verify_persisted_version>(backend: &BE) -> bool { let version: u32 = load_decode(backend, VERSION_KEY).unwrap().unwrap(); version == CURRENT_VERSION } - #[tokio::test] - async fn should_load_persistent_sanity_checks() { - let mut net = BeefyTestNet::new(1); + //async fn should_load_persistent_sanity_checks() + async fn should_load_persistent_sanity_checks() + where + TBeefyKeystore: BeefyKeystore + 'static, + AuthId: Clone + + Encode + + Decode + + Debug + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + std::cmp::PartialEq + 'static, + { + let mut net: BeefyTestNet = + BeefyTestNet::new(1); + //let mut net: BeefyTestNet = BeefyTestNet::new(1); let backend = net.peer(0).client().as_backend(); // version not available in db -> None - assert_eq!(load_persistent(&*backend).unwrap(), None); + assert_eq!(load_persistent::<_, _, AuthId, TSignature>(&*backend).unwrap(), None); // populate version in db write_current_version(&*backend).unwrap(); @@ -98,8 +132,24 @@ pub(crate) mod tests { assert_eq!(load_decode(&*backend, VERSION_KEY).unwrap(), Some(CURRENT_VERSION)); // version is available in db but state isn't -> None - assert_eq!(load_persistent(&*backend).unwrap(), None); + assert_eq!(load_persistent::<_, _, AuthId, TSignature>(&*backend).unwrap(), None); // full `PersistedState` load is tested in `tests.rs`. } + + #[tokio::test] + async fn should_load_persistent_sanity_checks_with_ecdsa_signature() { + should_load_persistent_sanity_checks::() + .await; + } + + #[tokio::test] + async fn should_load_persistent_sanity_checks_with_ecdsa_n_bls_signature() { + should_load_persistent_sanity_checks::< + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >() + .await; + } } diff --git a/client/beefy/src/communication/gossip.rs b/client/beefy/src/communication/gossip.rs index 116a6286ed54d..ee328ff18474e 100644 --- a/client/beefy/src/communication/gossip.rs +++ b/client/beefy/src/communication/gossip.rs @@ -18,6 +18,9 @@ use std::{collections::BTreeMap, sync::Arc, time::Duration}; +use core::fmt::Debug; +use std::marker::PhantomData; + use sc_network::PeerId; use sc_network_gossip::{MessageIntent, ValidationResult, Validator, ValidatorContext}; use sp_core::hashing::twox_64; @@ -29,10 +32,7 @@ use parking_lot::{Mutex, RwLock}; use wasm_timer::Instant; use crate::{communication::peers::KnownPeers, keystore::BeefyKeystore, LOG_TARGET}; -use beefy_primitives::{ - crypto::{Public, Signature}, - VoteMessage, -}; +use beefy_primitives::VoteMessage; // Timeout for rebroadcasting messages. const REBROADCAST_AFTER: Duration = Duration::from_secs(60 * 5); @@ -95,26 +95,40 @@ impl KnownVotes { /// rejected/expired. /// ///All messaging is handled in a single BEEFY global topic. -pub(crate) struct GossipValidator +pub(crate) struct GossipValidator where B: Block, + BKS: BeefyKeystore, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, { topic: B::Hash, known_votes: RwLock>, next_rebroadcast: Mutex, known_peers: Arc>>, + _keystore: PhantomData, + _auth_id: PhantomData, + _signature: PhantomData, } -impl GossipValidator +impl GossipValidator where B: Block, + BKS: BeefyKeystore, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, { - pub fn new(known_peers: Arc>>) -> GossipValidator { + pub fn new( + known_peers: Arc>>, + ) -> GossipValidator { GossipValidator { topic: topic::(), known_votes: RwLock::new(KnownVotes::new()), next_rebroadcast: Mutex::new(Instant::now() + REBROADCAST_AFTER), known_peers, + _keystore: PhantomData, + _auth_id: PhantomData, + _signature: PhantomData, } } @@ -135,9 +149,12 @@ where } } -impl Validator for GossipValidator +impl Validator for GossipValidator where B: Block, + BKS: BeefyKeystore, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, { fn peer_disconnected(&self, _context: &mut dyn ValidatorContext, who: &PeerId) { self.known_peers.lock().remove(who); @@ -149,7 +166,7 @@ where sender: &PeerId, mut data: &[u8], ) -> ValidationResult { - if let Ok(msg) = VoteMessage::, Public, Signature>::decode(&mut data) { + if let Ok(msg) = VoteMessage::, AuthId, TSignature>::decode(&mut data) { let msg_hash = twox_64(data); let round = msg.commitment.block_number; @@ -168,7 +185,7 @@ where } } - if BeefyKeystore::verify(&msg.id, &msg.signature, &msg.commitment.encode()) { + if BKS::verify(&msg.id, &msg.signature, &msg.commitment.encode()) { self.known_votes.write().add_known(&round, msg_hash); self.known_peers.lock().note_vote_for(*sender, round); return ValidationResult::ProcessAndKeep(self.topic) @@ -187,7 +204,7 @@ where fn message_expired<'a>(&'a self) -> Box bool + 'a> { let known_votes = self.known_votes.read(); Box::new(move |_topic, mut data| { - let msg = match VoteMessage::, Public, Signature>::decode(&mut data) { + let msg = match VoteMessage::, AuthId, TSignature>::decode(&mut data) { Ok(vote) => vote, Err(_) => return true, }; @@ -221,7 +238,7 @@ where return do_rebroadcast } - let msg = match VoteMessage::, Public, Signature>::decode(&mut data) { + let msg = match VoteMessage::, AuthId, TSignature>::decode(&mut data) { Ok(vote) => vote, Err(_) => return false, }; @@ -242,9 +259,12 @@ mod tests { use sc_network_test::Block; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; - use crate::keystore::{tests::Keyring, BeefyKeystore}; + use crate::keystore::{ + tests::{GenericKeyring, Keyring}, + BeefyECDSAKeystore, BeefyKeystore, + }; use beefy_primitives::{ - crypto::Signature, known_payloads, Commitment, MmrRootHash, Payload, VoteMessage, KEY_TYPE, + ecdsa_crypto, known_payloads, Commitment, MmrRootHash, Payload, VoteMessage, KEY_TYPE, }; use super::*; @@ -279,7 +299,12 @@ mod tests { #[test] fn note_and_drop_round_works() { - let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); + let gv = GossipValidator::< + Block, + ecdsa_crypto::AuthorityId, + ecdsa_crypto::Signature, + BeefyECDSAKeystore, + >::new(Arc::new(Mutex::new(KnownPeers::new()))); gv.note_round(1u64); @@ -306,7 +331,12 @@ mod tests { #[test] fn note_same_round_twice() { - let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); + let gv = GossipValidator::< + Block, + ecdsa_crypto::AuthorityId, + ecdsa_crypto::Signature, + BeefyECDSAKeystore, + >::new(Arc::new(Mutex::new(KnownPeers::new()))); gv.note_round(3u64); gv.note_round(7u64); @@ -345,15 +375,31 @@ mod tests { } } - fn sign_commitment(who: &Keyring, commitment: &Commitment) -> Signature { + fn sign_commitment( + who: &Keyring, + commitment: &Commitment, + ) -> ecdsa_crypto::Signature { let store: SyncCryptoStorePtr = std::sync::Arc::new(LocalKeystore::in_memory()); - SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&who.to_seed())).unwrap(); - let beefy_keystore: BeefyKeystore = Some(store).into(); - - beefy_keystore.sign(&who.public(), &commitment.encode()).unwrap() + SyncCryptoStore::ecdsa_generate_new( + &*store, + KEY_TYPE, + Some(&>::to_seed(*who)), + ) + .unwrap(); + + let beefy_keystore = BeefyECDSAKeystore::new(store); + + beefy_keystore + .sign( + &>::public(*who), + &commitment.encode(), + ) + .unwrap() } - fn dummy_vote(block_number: u64) -> VoteMessage { + fn dummy_vote( + block_number: u64, + ) -> VoteMessage { let payload = Payload::from_single_entry( known_payloads::MMR_ROOT_ID, MmrRootHash::default().encode(), @@ -361,12 +407,21 @@ mod tests { let commitment = Commitment { payload, block_number, validator_set_id: 0 }; let signature = sign_commitment(&Keyring::Alice, &commitment); - VoteMessage { commitment, id: Keyring::Alice.public(), signature } + VoteMessage { + commitment, + id: >::public(Keyring::Alice), + signature, + } } #[test] fn should_avoid_verifying_signatures_twice() { - let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); + let gv = GossipValidator::< + Block, + ecdsa_crypto::AuthorityId, + ecdsa_crypto::Signature, + BeefyECDSAKeystore, + >::new(Arc::new(Mutex::new(KnownPeers::new()))); let sender = sc_network::PeerId::random(); let mut context = TestContext; @@ -402,7 +457,12 @@ mod tests { #[test] fn messages_allowed_and_expired() { - let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); + let gv = GossipValidator::< + Block, + ecdsa_crypto::AuthorityId, + ecdsa_crypto::Signature, + BeefyECDSAKeystore, + >::new(Arc::new(Mutex::new(KnownPeers::new()))); let sender = sc_network::PeerId::random(); let topic = Default::default(); let intent = MessageIntent::Broadcast; @@ -445,7 +505,12 @@ mod tests { #[test] fn messages_rebroadcast() { - let gv = GossipValidator::::new(Arc::new(Mutex::new(KnownPeers::new()))); + let gv = GossipValidator::< + Block, + ecdsa_crypto::AuthorityId, + ecdsa_crypto::Signature, + BeefyECDSAKeystore, + >::new(Arc::new(Mutex::new(KnownPeers::new()))); let sender = sc_network::PeerId::random(); let topic = Default::default(); diff --git a/client/beefy/src/communication/notification.rs b/client/beefy/src/communication/notification.rs index c673115e487f3..b94ab04f32123 100644 --- a/client/beefy/src/communication/notification.rs +++ b/client/beefy/src/communication/notification.rs @@ -32,13 +32,15 @@ pub type BeefyBestBlockStream = /// The sending half of the notifications channel(s) used to send notifications /// about versioned finality proof generated at the end of a BEEFY round. -pub type BeefyVersionedFinalityProofSender = - NotificationSender>; +pub type BeefyVersionedFinalityProofSender = + NotificationSender>; /// The receiving half of a notifications channel used to receive notifications /// about versioned finality proof generated at the end of a BEEFY round. -pub type BeefyVersionedFinalityProofStream = - NotificationStream, BeefyVersionedFinalityProofTracingKey>; +pub type BeefyVersionedFinalityProofStream = NotificationStream< + BeefyVersionedFinalityProof, + BeefyVersionedFinalityProofTracingKey, +>; /// Provides tracing key for BEEFY best block stream. #[derive(Clone)] diff --git a/client/beefy/src/communication/request_response/outgoing_requests_engine.rs b/client/beefy/src/communication/request_response/outgoing_requests_engine.rs index c7dc269b495cc..51d333585292f 100644 --- a/client/beefy/src/communication/request_response/outgoing_requests_engine.rs +++ b/client/beefy/src/communication/request_response/outgoing_requests_engine.rs @@ -17,9 +17,10 @@ // along with this program. If not, see . //! Generating request logic for request/response protocol for syncing BEEFY justifications. +use codec::{Decode, Encode}; +use std::{fmt::Debug, marker::PhantomData}; -use beefy_primitives::{crypto::AuthorityId, ValidatorSet}; -use codec::Encode; +use beefy_primitives::ValidatorSet; use futures::channel::{oneshot, oneshot::Canceled}; use log::{debug, warn}; use parking_lot::Mutex; @@ -34,6 +35,7 @@ use std::{collections::VecDeque, result::Result, sync::Arc}; use crate::{ communication::request_response::{Error, JustificationRequest, BEEFY_SYNC_LOG_TARGET}, justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof}, + keystore::BeefyKeystore, KnownPeers, }; @@ -43,27 +45,41 @@ type Response = Result, RequestFailure>; type ResponseReceiver = oneshot::Receiver; #[derive(Clone, Debug)] -struct RequestInfo { +struct RequestInfo { block: NumberFor, - active_set: ValidatorSet, + active_set: ValidatorSet, } -enum State { +enum State { Idle, - AwaitingResponse(PeerId, RequestInfo, ResponseReceiver), + AwaitingResponse(PeerId, RequestInfo, ResponseReceiver), } -pub struct OnDemandJustificationsEngine { +pub struct OnDemandJustificationsEngine< + B: Block, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + BKS: BeefyKeystore, +> { network: Arc, protocol_name: ProtocolName, live_peers: Arc>>, peers_cache: VecDeque, - state: State, + state: State, + _auth_id: PhantomData, + _signature: PhantomData, + _keystor: PhantomData, } -impl OnDemandJustificationsEngine { +impl OnDemandJustificationsEngine +where + B: Block, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + BKS: BeefyKeystore, +{ pub fn new( network: Arc, protocol_name: ProtocolName, @@ -75,6 +91,9 @@ impl OnDemandJustificationsEngine { live_peers, peers_cache: VecDeque::new(), state: State::Idle, + _auth_id: PhantomData::, + _signature: PhantomData::, + _keystor: PhantomData::, } } @@ -94,7 +113,7 @@ impl OnDemandJustificationsEngine { None } - fn request_from_peer(&mut self, peer: PeerId, req_info: RequestInfo) { + fn request_from_peer(&mut self, peer: PeerId, req_info: RequestInfo) { debug!( target: BEEFY_SYNC_LOG_TARGET, "🥩 requesting justif #{:?} from peer {:?}", req_info.block, peer, @@ -118,7 +137,7 @@ impl OnDemandJustificationsEngine { /// Start new justification request for `block`, if no other request is in progress. /// /// `active_set` will be used to verify validity of potential responses. - pub fn request(&mut self, block: NumberFor, active_set: ValidatorSet) { + pub fn request(&mut self, block: NumberFor, active_set: ValidatorSet) { // ignore new requests while there's already one pending if matches!(self.state, State::AwaitingResponse(_, _, _)) { return @@ -154,9 +173,9 @@ impl OnDemandJustificationsEngine { fn process_response( &mut self, peer: PeerId, - req_info: &RequestInfo, + req_info: &RequestInfo, response: Result, - ) -> Result, Error> { + ) -> Result, Error> { response .map_err(|e| { debug!( @@ -179,7 +198,7 @@ impl OnDemandJustificationsEngine { Error::InvalidResponse }) .and_then(|encoded| { - decode_and_verify_finality_proof::( + decode_and_verify_finality_proof::( &encoded[..], req_info.block, &req_info.active_set, @@ -195,7 +214,7 @@ impl OnDemandJustificationsEngine { }) } - pub async fn next(&mut self) -> Option> { + pub async fn next(&mut self) -> Option> { let (peer, req_info, resp) = match &mut self.state { State::Idle => { futures::pending!(); diff --git a/client/beefy/src/import.rs b/client/beefy/src/import.rs index f0fe3bfa024dc..32d0d55b6aedb 100644 --- a/client/beefy/src/import.rs +++ b/client/beefy/src/import.rs @@ -16,6 +16,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use codec::{Decode, Encode}; +use std::{fmt::Debug, marker::PhantomData}; + use beefy_primitives::{BeefyApi, BEEFY_ENGINE_ID}; use log::debug; use std::{collections::HashMap, sync::Arc}; @@ -35,6 +38,7 @@ use sc_consensus::{BlockCheckParams, BlockImport, BlockImportParams, ImportResul use crate::{ communication::notification::BeefyVersionedFinalityProofSender, justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof}, + keystore::BeefyKeystore, LOG_TARGET, }; @@ -44,49 +48,90 @@ use crate::{ /// Wraps a `inner: BlockImport` and ultimately defers to it. /// /// When using BEEFY, the block import worker should be using this block import object. -pub struct BeefyBlockImport { +pub struct BeefyBlockImport< + Block: BlockT, + Backend, + RuntimeApi, + I, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + BKS: BeefyKeystore, +> { backend: Arc, runtime: Arc, inner: I, - justification_sender: BeefyVersionedFinalityProofSender, + justification_sender: BeefyVersionedFinalityProofSender, + _auth_id: PhantomData, + _keystore: PhantomData, } -impl Clone for BeefyBlockImport { +impl< + Block: BlockT, + BE, + Runtime, + I: Clone, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + BKS: BeefyKeystore, + > Clone for BeefyBlockImport +{ fn clone(&self) -> Self { BeefyBlockImport { backend: self.backend.clone(), runtime: self.runtime.clone(), inner: self.inner.clone(), justification_sender: self.justification_sender.clone(), + _auth_id: PhantomData::, + _keystore: PhantomData::, } } } -impl BeefyBlockImport { +impl< + Block: BlockT, + BE, + Runtime, + I, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + BKS: BeefyKeystore, + > BeefyBlockImport +{ /// Create a new BeefyBlockImport. pub fn new( backend: Arc, runtime: Arc, inner: I, - justification_sender: BeefyVersionedFinalityProofSender, - ) -> BeefyBlockImport { - BeefyBlockImport { backend, runtime, inner, justification_sender } + justification_sender: BeefyVersionedFinalityProofSender, + ) -> BeefyBlockImport { + BeefyBlockImport { + backend, + runtime, + inner, + justification_sender, + _auth_id: PhantomData::, + _keystore: PhantomData::, + } } } -impl BeefyBlockImport +impl + BeefyBlockImport where Block: BlockT, BE: Backend, Runtime: ProvideRuntimeApi, - Runtime::Api: BeefyApi + Send, + Runtime::Api: BeefyApi + Send, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + BKS: BeefyKeystore, { fn decode_and_verify( &self, encoded: &EncodedJustification, number: NumberFor, hash: ::Hash, - ) -> Result, ConsensusError> { + ) -> Result, ConsensusError> { let block_id = BlockId::hash(hash); let validator_set = self .runtime @@ -95,12 +140,17 @@ where .map_err(|e| ConsensusError::ClientImport(e.to_string()))? .ok_or_else(|| ConsensusError::ClientImport("Unknown validator set".to_string()))?; - decode_and_verify_finality_proof::(&encoded[..], number, &validator_set) + decode_and_verify_finality_proof::( + &encoded[..], + number, + &validator_set, + ) } } #[async_trait::async_trait] -impl BlockImport for BeefyBlockImport +impl BlockImport + for BeefyBlockImport where Block: BlockT, BE: Backend, @@ -111,7 +161,10 @@ where > + Send + Sync, Runtime: ProvideRuntimeApi + Send + Sync, - Runtime::Api: BeefyApi, + Runtime::Api: BeefyApi, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + BKS: BeefyKeystore, { type Error = ConsensusError; type Transaction = TransactionFor; diff --git a/client/beefy/src/justification.rs b/client/beefy/src/justification.rs index 7243c692727f0..58a2a93cfe5e7 100644 --- a/client/beefy/src/justification.rs +++ b/client/beefy/src/justification.rs @@ -17,34 +17,47 @@ // along with this program. If not, see . use crate::keystore::BeefyKeystore; -use beefy_primitives::{ - crypto::{AuthorityId, Signature}, - ValidatorSet, VersionedFinalityProof, -}; +use beefy_primitives::{ValidatorSet, VersionedFinalityProof}; use codec::{Decode, Encode}; +use core::fmt::Debug; use sp_consensus::Error as ConsensusError; use sp_runtime::traits::{Block as BlockT, NumberFor}; /// A finality proof with matching BEEFY authorities' signatures. -pub type BeefyVersionedFinalityProof = - beefy_primitives::VersionedFinalityProof, Signature>; +pub type BeefyVersionedFinalityProof = + beefy_primitives::VersionedFinalityProof, TSignature>; /// Decode and verify a Beefy FinalityProof. -pub(crate) fn decode_and_verify_finality_proof( +pub(crate) fn decode_and_verify_finality_proof< + Block: BlockT, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + BKS: BeefyKeystore, +>( encoded: &[u8], target_number: NumberFor, - validator_set: &ValidatorSet, -) -> Result, ConsensusError> { - let proof = >::decode(&mut &*encoded) + validator_set: &ValidatorSet, +) -> Result, ConsensusError> { + let proof = >::decode(&mut &*encoded) .map_err(|_| ConsensusError::InvalidJustification)?; - verify_with_validator_set::(target_number, validator_set, &proof).map(|_| proof) + verify_with_validator_set::( + target_number, + validator_set, + &proof, + ) + .map(|_| proof) } /// Verify the Beefy finality proof against the validator set at the block it was generated. -fn verify_with_validator_set( +fn verify_with_validator_set< + Block: BlockT, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + BKS: BeefyKeystore, +>( target_number: NumberFor, - validator_set: &ValidatorSet, - proof: &BeefyVersionedFinalityProof, + validator_set: &ValidatorSet, + proof: &BeefyVersionedFinalityProof, ) -> Result<(), ConsensusError> { match proof { VersionedFinalityProof::V1(signed_commitment) => { @@ -65,7 +78,7 @@ fn verify_with_validator_set( .filter(|(id, signature)| { signature .as_ref() - .map(|sig| BeefyKeystore::verify(id, sig, &message[..])) + .map(|sig| BKS::verify(id, sig, &message[..])) .unwrap_or(false) }) .count(); @@ -81,52 +94,97 @@ fn verify_with_validator_set( #[cfg(test)] pub(crate) mod tests { use beefy_primitives::{ + bls_crypto::{Public as BLSPublic, Signature as BLSSignature}, + ecdsa_crypto::{Pair as ECDSAKeyPair, Public as ECDSAPublic, Signature as ECDSASignature}, known_payloads, Commitment, Payload, SignedCommitment, VersionedFinalityProof, }; use substrate_test_runtime_client::runtime::Block; use super::*; - use crate::{keystore::tests::Keyring, tests::make_beefy_ids}; + use crate::{ + keystore::{ + tests::{ECDSAnBLSPair, GenericKeyring, Keyring, SimpleKeyPair}, + BeefyBLSnECDSAKeystore, BeefyECDSAKeystore, + }, + tests::BeefyAuthIdMaker, + }; - pub(crate) fn new_finality_proof( + pub(crate) fn new_finality_proof( block_num: NumberFor, - validator_set: &ValidatorSet, + validator_set: &ValidatorSet, keys: &[Keyring], - ) -> BeefyVersionedFinalityProof { + ) -> BeefyVersionedFinalityProof + where + TKeyPair: SimpleKeyPair + SimpleKeyPair, + AuthId: Clone + Encode + Decode + Debug + Ord + Sync + Send, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + std::cmp::PartialEq + 'static, + { let commitment = Commitment { payload: Payload::from_single_entry(known_payloads::MMR_ROOT_ID, vec![]), block_number: block_num, validator_set_id: validator_set.id(), }; let message = commitment.encode(); - let signatures = keys.iter().map(|key| Some(key.sign(&message))).collect(); + let signatures = keys + .iter() + .map(|key| Some(>::sign(*key, &message))) + .collect(); VersionedFinalityProof::V1(SignedCommitment { commitment, signatures }) } - #[test] - fn should_verify_with_validator_set() { + fn should_verify_with_validator_set() + where + TKeyPair: SimpleKeyPair + SimpleKeyPair, + AuthId: Encode + + Decode + + Debug + + Clone + + Ord + + Sync + + Send + + std::hash::Hash + + BeefyAuthIdMaker, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + std::cmp::PartialEq + 'static, + BKS: BeefyKeystore, + { let keys = &[Keyring::Alice, Keyring::Bob, Keyring::Charlie]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let validator_set = + ValidatorSet::new(::make_beefy_ids(keys), 0).unwrap(); // build valid justification let block_num = 42; - let proof = new_finality_proof(block_num, &validator_set, keys); + let proof = + new_finality_proof::(block_num, &validator_set, keys); let good_proof = proof.clone().into(); // should verify successfully - verify_with_validator_set::(block_num, &validator_set, &good_proof).unwrap(); + verify_with_validator_set::( + block_num, + &validator_set, + &good_proof, + ) + .unwrap(); // wrong block number -> should fail verification let good_proof = proof.clone().into(); - match verify_with_validator_set::(block_num + 1, &validator_set, &good_proof) { + match verify_with_validator_set::( + block_num + 1, + &validator_set, + &good_proof, + ) { Err(ConsensusError::InvalidJustification) => (), _ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"), }; // wrong validator set id -> should fail verification let good_proof = proof.clone().into(); - let other = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap(); - match verify_with_validator_set::(block_num, &other, &good_proof) { + let other = + ValidatorSet::new(::make_beefy_ids(keys), 1).unwrap(); + match verify_with_validator_set::( + block_num, + &other, + &good_proof, + ) { Err(ConsensusError::InvalidJustification) => (), _ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"), }; @@ -138,7 +196,11 @@ pub(crate) mod tests { VersionedFinalityProof::V1(ref mut sc) => sc, }; bad_signed_commitment.signatures.pop().flatten().unwrap(); - match verify_with_validator_set::(block_num + 1, &validator_set, &bad_proof.into()) { + match verify_with_validator_set::( + block_num + 1, + &validator_set, + &bad_proof.into(), + ) { Err(ConsensusError::InvalidJustification) => (), _ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"), }; @@ -150,7 +212,11 @@ pub(crate) mod tests { }; // remove a signature (but same length) *bad_signed_commitment.signatures.first_mut().unwrap() = None; - match verify_with_validator_set::(block_num + 1, &validator_set, &bad_proof.into()) { + match verify_with_validator_set::( + block_num + 1, + &validator_set, + &bad_proof.into(), + ) { Err(ConsensusError::InvalidJustification) => (), _ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"), }; @@ -162,27 +228,93 @@ pub(crate) mod tests { }; // change a signature to a different key *bad_signed_commitment.signatures.first_mut().unwrap() = - Some(Keyring::Dave.sign(&bad_signed_commitment.commitment.encode())); - match verify_with_validator_set::(block_num + 1, &validator_set, &bad_proof.into()) { + Some(>::sign( + Keyring::Dave, + &bad_signed_commitment.commitment.encode(), + )); + match verify_with_validator_set::( + block_num + 1, + &validator_set, + &bad_proof.into(), + ) { Err(ConsensusError::InvalidJustification) => (), _ => assert!(false, "Expected Err(ConsensusError::InvalidJustification)"), }; } #[test] - fn should_decode_and_verify_finality_proof() { + fn should_verify_with_validator_set_with_ecdsa_keys() { + should_verify_with_validator_set::< + ECDSAKeyPair, + ECDSAPublic, + ECDSASignature, + BeefyECDSAKeystore, + >(); + } + + #[test] + fn should_verify_with_validator_set_with_ecdsa_n_bls_keys() { + should_verify_with_validator_set::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >(); + } + + fn should_decode_and_verify_finality_proof() + where + TKeyPair: SimpleKeyPair + SimpleKeyPair, + AuthId: Encode + + Decode + + Debug + + Clone + + Ord + + Sync + + Send + + std::hash::Hash + + BeefyAuthIdMaker, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + std::cmp::PartialEq + 'static, + BKS: BeefyKeystore, + { let keys = &[Keyring::Alice, Keyring::Bob]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let validator_set = + ValidatorSet::new(::make_beefy_ids(keys), 0).unwrap(); let block_num = 1; // build valid justification - let proof = new_finality_proof(block_num, &validator_set, keys); - let versioned_proof: BeefyVersionedFinalityProof = proof.into(); + let proof = + new_finality_proof::(block_num, &validator_set, keys); + let versioned_proof: BeefyVersionedFinalityProof = proof.into(); let encoded = versioned_proof.encode(); // should successfully decode and verify - let verified = - decode_and_verify_finality_proof::(&encoded, block_num, &validator_set).unwrap(); + let verified = decode_and_verify_finality_proof::( + &encoded, + block_num, + &validator_set, + ) + .unwrap(); assert_eq!(verified, versioned_proof); } + + #[test] + fn should_decode_and_verify_finality_proof_with_ecdsa_keys() { + should_decode_and_verify_finality_proof::< + ECDSAKeyPair, + ECDSAPublic, + ECDSASignature, + BeefyECDSAKeystore, + >(); + } + + #[test] + fn should_decode_and_verify_finality_proof_with_ecdsa_n_bls_keys() { + should_decode_and_verify_finality_proof::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >(); + } } diff --git a/client/beefy/src/keystore.rs b/client/beefy/src/keystore.rs index d1f5615a93701..0b2312cf9fbea 100644 --- a/client/beefy/src/keystore.rs +++ b/client/beefy/src/keystore.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use sp_application_crypto::RuntimeAppPublic; +use sp_application_crypto::{Pair, RuntimeAppPublic}; use sp_core::keccak_256; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; use sp_runtime::traits::Keccak256; @@ -24,29 +24,66 @@ use sp_runtime::traits::Keccak256; use log::warn; use beefy_primitives::{ - crypto::{Public, Signature}, + bls_crypto::{Public as BLSPublic, Signature as BLSSignature}, + ecdsa_crypto::{Public as ECDSAPublic, Signature as ECDSASignature}, BeefyAuthorityId, KEY_TYPE, }; +use codec::{Decode, Encode}; +use core::fmt::Debug; + use crate::{error, LOG_TARGET}; /// A BEEFY specific keystore implemented as a `Newtype`. This is basically a /// wrapper around [`sp_keystore::SyncCryptoStore`] and allows to customize /// common cryptographic functionality. -pub(crate) struct BeefyKeystore(Option); +pub trait BeefyKeystore: + From> + Sync + Send +where + AuthorityId: Encode + Decode + Debug + Clone + Ord + Sync + Send, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, +{ + type Public: Encode + Decode + Debug + From + Into; + + fn new(keystore: SyncCryptoStorePtr) -> Self; + + fn authority_id(&self, keys: &[AuthorityId]) -> Option; + + fn sign(&self, public: &Self::Public, message: &[u8]) -> Result; + + fn public_keys(&self) -> Result, error::Error>; + + fn authority_ids(&self) -> Result, error::Error>; + + fn verify(public: &Self::Public, sig: &TSignature, message: &[u8]) -> bool; + + fn authority_id_to_public_key(auth_id: &AuthorityId) -> Result; +} + +pub struct BeefyECDSAKeystore(Option); + +pub struct BeefyBLSKeystore(Option); + +pub struct BeefyBLSnECDSAKeystore(Option); + +impl BeefyKeystore for BeefyECDSAKeystore { + type Public = ECDSAPublic; + + fn new(keystore: SyncCryptoStorePtr) -> Self { + Self(Some(keystore)) + } -impl BeefyKeystore { /// Check if the keystore contains a private key for one of the public keys /// contained in `keys`. A public key with a matching private key is known /// as a local authority id. /// /// Return the public key for which we also do have a private key. If no /// matching private key is found, `None` will be returned. - pub fn authority_id(&self, keys: &[Public]) -> Option { + fn authority_id(&self, keys: &[ECDSAPublic]) -> Option { let store = self.0.clone()?; // we do check for multiple private keys as a key store sanity check. - let public: Vec = keys + let public: Vec = keys .iter() .filter(|k| SyncCryptoStore::has_keys(&*store, &[(k.to_raw_vec(), KEY_TYPE)])) .cloned() @@ -69,7 +106,7 @@ impl BeefyKeystore { /// Note that `message` usually will be pre-hashed before being signed. /// /// Return the message signature or an error in case of failure. - pub fn sign(&self, public: &Public, message: &[u8]) -> Result { + fn sign(&self, public: &Self::Public, message: &[u8]) -> Result { let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; let msg = keccak_256(message); @@ -87,44 +124,236 @@ impl BeefyKeystore { Ok(sig) } - /// Returns a vector of [`beefy_primitives::crypto::Public`] keys which are currently supported - /// (i.e. found in the keystore). - pub fn public_keys(&self) -> Result, error::Error> { + /// Returns a vector of [`beefy_primitives::ecdsa_crypto::Public`] keys which are currently + /// supported (i.e. found in the keystore). + fn public_keys(&self) -> Result, error::Error> { let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; - let pk: Vec = SyncCryptoStore::ecdsa_public_keys(&*store, KEY_TYPE) + let pk: Vec = SyncCryptoStore::ecdsa_public_keys(&*store, KEY_TYPE) .drain(..) - .map(Public::from) + .map(Self::Public::from) .collect(); Ok(pk) } + /// Returns a vector of [`beefy_primitives::ecdsa_crypto::Public`] keys which are currently + /// supported (i.e. found in the keystore). + fn authority_ids(&self) -> Result, error::Error> { + self.public_keys() + } + + /// Use the `public` key to verify that `sig` is a valid signature for `message`. + fn verify(public: &Self::Public, sig: &ECDSASignature, message: &[u8]) -> bool { + BeefyAuthorityId::::verify(public, sig, message) + } + + fn authority_id_to_public_key(auth_id: &ECDSAPublic) -> Result { + Ok((*auth_id).clone()) + } +} + +//Implement BLSKeyStore +impl BeefyKeystore for BeefyBLSKeystore { + type Public = BLSPublic; + + fn new(keystore: SyncCryptoStorePtr) -> Self { + Self(Some(keystore)) + } + + /// Check if the keystore contains a private key for one of the public keys + /// contained in `keys`. A public key with a matching private key is known + /// as a local authority id. + /// + /// Return the public key for which we also do have a private key. If no + /// matching private key is found, `None` will be returned. + fn authority_id(&self, keys: &[BLSPublic]) -> Option { + let store = self.0.clone()?; + + // we do check for multiple private keys as a key store sanity check. + let public: Vec = keys + .iter() + .filter(|k| SyncCryptoStore::has_keys(&*store, &[(k.to_raw_vec(), KEY_TYPE)])) + .cloned() + .collect(); + + if public.len() > 1 { + warn!(target: "beefy", "🥩 Multiple private keys found for: {:?} ({})", public, public.len()); + } + + public.get(0).cloned() + } + + /// Sign `message` with the `public` key. + /// + /// Note that `message` usually will be pre-hashed before being signed. + /// + /// Return the message signature or an error in case of failure. + fn sign(&self, public: &Self::Public, message: &[u8]) -> Result { + let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; + + let public = public.as_ref(); + + let sig = SyncCryptoStore::bls_sign(&*store, KEY_TYPE, public, &message) + .map_err(|e| error::Error::Keystore(e.to_string()))? + .ok_or_else(|| error::Error::Signature("ecdsa_sign_prehashed() failed".to_string()))?; + + // check that `sig` has the expected result type + let sig = sig.clone().try_into().map_err(|_| { + error::Error::Signature(format!("invalid signature {:?} for key {:?}", sig, public)) + })?; + + Ok(sig) + } + + /// Returns a vector of [`beefy_primitives::bls_crypto::Public`] keys which are currently + /// supported (i.e. found in the keystore). + fn public_keys(&self) -> Result, error::Error> { + let store = self.0.clone().ok_or_else(|| error::Error::Keystore("no Keystore".into()))?; + + let pk: Vec = SyncCryptoStore::bls_public_keys(&*store, KEY_TYPE) + .drain(..) + .map(Self::Public::from) + .collect(); + + Ok(pk) + } + + /// Returns a vector of [`beefy_primitives::bls_crypto::Public`] keys which are currently + /// supported (i.e. found in the keystore). + fn authority_ids(&self) -> Result, error::Error> { + self.public_keys() + } + /// Use the `public` key to verify that `sig` is a valid signature for `message`. /// /// Return `true` if the signature is authentic, `false` otherwise. - pub fn verify(public: &Public, sig: &Signature, message: &[u8]) -> bool { - BeefyAuthorityId::::verify(public, sig, message) + fn verify(public: &Self::Public, sig: &BLSSignature, message: &[u8]) -> bool { + let sig = sig.as_ref(); + let public = public.as_ref(); + + println!("{:?}: {}", message, sp_core::bls::Pair::verify(sig, &message, public)); + sp_core::bls::Pair::verify(sig, &message, public) + } + + fn authority_id_to_public_key(auth_id: &BLSPublic) -> Result { + Ok((*auth_id).clone()) } } -impl From> for BeefyKeystore { - fn from(store: Option) -> BeefyKeystore { - BeefyKeystore(store) +impl BeefyBLSnECDSAKeystore { + fn both(&self) -> (BeefyECDSAKeystore, BeefyBLSKeystore) { + (BeefyECDSAKeystore(self.0.clone()), BeefyBLSKeystore(self.0.clone())) } } +impl BeefyKeystore<(ECDSAPublic, BLSPublic), (ECDSASignature, BLSSignature)> + for BeefyBLSnECDSAKeystore +{ + fn new(keystore: SyncCryptoStorePtr) -> Self { + Self(Some(keystore)) + } + + type Public = (ECDSAPublic, BLSPublic); + /// Check if the keystore contains a private key for one of the public keys + /// contained in `keys`. A public key with a matching private key is known + /// as a local authority id. + /// + /// Return the public key for which we also do have a private key. If no + /// matching private key is found, `None` will be returned. + fn authority_id(&self, keys: &[(ECDSAPublic, BLSPublic)]) -> Option { + let (ecdsa_pubkeys, bls_pubkeys): (Vec, Vec) = + keys.iter().cloned().unzip(); + let own_ecdsa_key = self.both().0.authority_id(&ecdsa_pubkeys); + let own_bls_key = self.both().1.authority_id(&bls_pubkeys); + if own_ecdsa_key == None || own_bls_key == None { + None + } else { + Some((own_ecdsa_key.unwrap(), own_bls_key.unwrap())) + } + } + + fn sign( + &self, + public: &Self::Public, + message: &[u8], + ) -> Result<(ECDSASignature, BLSSignature), error::Error> { + let bls_n_ecdsa = self.both(); + match (bls_n_ecdsa.0.sign(&public.0, message), bls_n_ecdsa.1.sign(&public.1, message)) { + (Ok(ecdsa_sign), Ok(bls_sign)) => Ok((ecdsa_sign, bls_sign)), + _ => + Err(error::Error::Signature(format!("could not sign with both bls and ecdsa keys"))), + } + } + + fn public_keys(&self) -> Result, error::Error> { + let bls_n_ecdsa = self.both(); + let pk: Vec = bls_n_ecdsa + .0 + .public_keys()? + .into_iter() + .zip(bls_n_ecdsa.1.public_keys()?.into_iter()) + .collect(); + + Ok(pk) + } + + /// Returns a vector of [`(beefy_primitives::ecdsa_crypto::Public, + /// beefy_primitives::bls_crypto::Public)`] keys which are currently supported (i.e. found in + /// the keystore). + fn authority_ids(&self) -> Result, error::Error> { + self.public_keys() + } + + fn verify(public: &Self::Public, sig: &(ECDSASignature, BLSSignature), message: &[u8]) -> bool { + match ( + BeefyECDSAKeystore::verify(&public.0, &sig.0, message), + BeefyBLSKeystore::verify(&public.1, &sig.1, message), + ) { + (true, true) => true, + _ => false, + } + } + + fn authority_id_to_public_key( + auth_id: &(ECDSAPublic, BLSPublic), + ) -> Result { + Ok((*auth_id).clone()) + } +} + +macro_rules! impl_from_cryptostore_for_keystore { + ($keystore:tt) => { + impl From> for $keystore { + fn from(store: Option) -> $keystore { + $keystore(store) + } + } + }; +} + +impl_from_cryptostore_for_keystore!(BeefyECDSAKeystore); +impl_from_cryptostore_for_keystore!(BeefyBLSKeystore); +impl_from_cryptostore_for_keystore!(BeefyBLSnECDSAKeystore); + #[cfg(test)] pub mod tests { use std::sync::Arc; use sc_keystore::LocalKeystore; - use sp_core::{ecdsa, keccak_256, Pair}; + use sp_application_crypto::Wraps; + use sp_core::{crypto::SecretStringError, ecdsa, keccak_256, Pair}; use sp_keystore::{SyncCryptoStore, SyncCryptoStorePtr}; - use beefy_primitives::{crypto, KEY_TYPE}; + use beefy_primitives::{bls_crypto, ecdsa_crypto, KEY_TYPE}; + + use super::{ + BLSPublic, BLSSignature, BeefyBLSnECDSAKeystore, BeefyECDSAKeystore, BeefyKeystore, + ECDSAPublic, ECDSASignature, + }; + use codec::{Decode, Encode}; + use core::fmt::Debug; - use super::BeefyKeystore; use crate::error::Error; /// Set of test accounts using [`beefy_primitives::crypto`] types. @@ -141,38 +370,138 @@ pub mod tests { Two, } - impl Keyring { + pub(crate) trait SimpleKeyPair: Clone + Sized + Sync + Send { + type Public: Clone + Encode + Decode + Debug + Ord + Sync + Send; + type Signature: Clone + Encode + Decode + Debug + Clone + Sync + Send; + + fn generate_in_store(store: SyncCryptoStorePtr, owner: Keyring) -> Self::Public; + + fn add_typed_key_to_store( + store: SyncCryptoStorePtr, + key_type: sp_application_crypto::KeyTypeId, + seed: Option<&str>, + ) -> Self::Public; + + fn sign(&self, hashed_message: &[u8]) -> Self::Signature; + + fn public(&self) -> Self::Public; + + fn verify(sig: &Self::Signature, hashed_message: &[u8], pubkey: Self::Public) -> bool; + + fn from_string(s: &str, password_override: Option<&str>) + -> Result; + + /// Return a vec filled with raw data. + fn to_raw_vec(&self) -> Vec; + } + + pub(crate) trait GenericKeyring + where + TKeyPair: SimpleKeyPair, + { /// Sign `msg`. - pub fn sign(self, msg: &[u8]) -> crypto::Signature { - let msg = keccak_256(msg); - ecdsa::Pair::from(self).sign_prehashed(&msg).into() + fn sign(self, msg: &[u8]) -> TKeyPair::Signature; + + /// Return key pair. + fn pair(self) -> TKeyPair; + + /// Return public key. + fn public(self) -> TKeyPair::Public; + + /// Return seed string. + fn to_seed(self) -> String; + } + + impl GenericKeyring for Keyring + where + TKeyPair: SimpleKeyPair, + { + /// Sign `msg`. + fn sign(self, msg: &[u8]) -> TKeyPair::Signature { + let key_pair = >::pair(self); + key_pair.sign(&msg).into() } /// Return key pair. - pub fn pair(self) -> crypto::Pair { - ecdsa::Pair::from_string(self.to_seed().as_str(), None).unwrap().into() + fn pair(self) -> TKeyPair { + TKeyPair::from_string( + >::to_seed(self).as_str(), + None, + ) + .unwrap() + .into() } /// Return public key. - pub fn public(self) -> crypto::Public { - self.pair().public() + fn public(self) -> TKeyPair::Public { + >::pair(self).public() } /// Return seed string. - pub fn to_seed(self) -> String { + fn to_seed(self) -> String { format!("//{}", self) } } - impl From for crypto::Pair { - fn from(k: Keyring) -> Self { - k.pair() + // Auxiliary traits for ECDSA + impl SimpleKeyPair for ecdsa_crypto::Pair { + type Public = ecdsa_crypto::Public; + type Signature = ecdsa_crypto::Signature; + + fn generate_in_store(store: SyncCryptoStorePtr, owner: Keyring) -> Self::Public { + SyncCryptoStore::ecdsa_generate_new( + &*store, + KEY_TYPE, + Some(&>::to_seed(owner)), + ) + .ok() + .unwrap() + .into() + } + + fn add_typed_key_to_store( + store: SyncCryptoStorePtr, + key_type: sp_application_crypto::KeyTypeId, + seed: Option<&str>, + ) -> Self::Public { + SyncCryptoStore::ecdsa_generate_new(&*store, key_type, seed) + .ok() + .unwrap() + .into() + } + + fn sign(&self, message: &[u8]) -> Self::Signature { + let hashed_message = keccak_256(message); + self.as_inner_ref().sign_prehashed(&hashed_message).into() + } + + fn verify( + sig: &::Signature, + message: &[u8], + pubkey: Self::Public, + ) -> bool { + let hashed_message = keccak_256(message); + ecdsa::Pair::verify_prehashed( + sig.as_inner_ref(), + &hashed_message, + pubkey.as_inner_ref(), + ) + } + + fn public(&self) -> Self::Public { + ::public(self) + } + + fn from_string( + s: &str, + password_override: Option<&str>, + ) -> Result { + ::from_string(s, password_override) } - } - impl From for ecdsa::Pair { - fn from(k: Keyring) -> Self { - k.pair().into() + /// Return a vec filled with raw data. + fn to_raw_vec(&self) -> Vec { + ::to_raw_vec(self) } } @@ -180,201 +509,427 @@ pub mod tests { Arc::new(LocalKeystore::in_memory()) } - #[test] - fn verify_should_work() { - let msg = keccak_256(b"I am Alice!"); - let sig = Keyring::Alice.sign(b"I am Alice!"); - - assert!(ecdsa::Pair::verify_prehashed( - &sig.clone().into(), - &msg, - &Keyring::Alice.public().into(), + /// Auxiliray tairt for ECDSAnBLS + #[derive(Clone)] + pub(crate) struct ECDSAnBLSPair(pub ecdsa_crypto::Pair, pub bls_crypto::Pair); + + /// implementing ECDSAnBLSPair as a simple key pair to be used in the test key ring + impl SimpleKeyPair for ECDSAnBLSPair { + type Public = (ECDSAPublic, BLSPublic); + type Signature = (ECDSASignature, BLSSignature); + + fn generate_in_store(store: SyncCryptoStorePtr, owner: Keyring) -> Self::Public { + ( + SyncCryptoStore::ecdsa_generate_new( + &*store, + KEY_TYPE, + Some(&>::to_seed(owner)), + ) + .ok() + .unwrap() + .into(), + SyncCryptoStore::bls_generate_new( + &*store, + KEY_TYPE, + Some(&>::to_seed(owner)), + ) + .ok() + .unwrap() + .into(), + ) + } + + fn add_typed_key_to_store( + store: SyncCryptoStorePtr, + key_type: sp_application_crypto::KeyTypeId, + seed: Option<&str>, + ) -> Self::Public { + ( + SyncCryptoStore::ecdsa_generate_new(&*store, key_type, seed) + .ok() + .unwrap() + .into(), + SyncCryptoStore::bls_generate_new(&*store, key_type, seed).ok().unwrap().into(), + ) + } + + fn sign(&self, message: &[u8]) -> Self::Signature { + let hashed_message = keccak_256(message); + (self.0.as_inner_ref().sign_prehashed(&hashed_message).into(), self.1.sign(message)) + } + + fn verify(sig: &Self::Signature, message: &[u8], pubkey: Self::Public) -> bool { + let hashed_message = keccak_256(message); + ecdsa::Pair::verify_prehashed( + &sig.0.as_inner_ref(), + &hashed_message, + &pubkey.0.as_inner_ref(), + ) && bls_crypto::Pair::verify(&sig.1, &message, &pubkey.1) + } + + fn public(&self) -> Self::Public { + ( + ::public(&self.0), + ::public(&self.1), + ) + } + + fn from_string( + s: &str, + password_override: Option<&str>, + ) -> Result { + let ecdsa_pair = ::from_string( + s, + password_override, + )?; + let bls_pair = ::from_string( + s, + password_override, + )?; + Ok(ECDSAnBLSPair(ecdsa_pair, bls_pair)) + } + + /// Return a vec filled with raw data. + fn to_raw_vec(&self) -> Vec { + ::to_raw_vec(&self.0) + } + } + + fn pair_verify_should_work() { + let msg = b"I am Alice!"; + let sig = >::sign(Keyring::Alice, b"I am Alice!"); + + assert!(TKeyPair::verify( + &sig, + &msg.as_slice(), + >::public(Keyring::Alice), )); // different public key -> fail - assert!(!ecdsa::Pair::verify_prehashed( - &sig.clone().into(), - &msg, - &Keyring::Bob.public().into(), + assert!(!TKeyPair::verify( + &sig, + &msg.as_slice(), + >::public(Keyring::Bob).into(), )); - let msg = keccak_256(b"I am not Alice!"); + let msg = b"I am not Alice!"; // different msg -> fail - assert!( - !ecdsa::Pair::verify_prehashed(&sig.into(), &msg, &Keyring::Alice.public().into(),) - ); + assert!(!TKeyPair::verify( + &sig, + &msg.as_slice(), + >::public(Keyring::Alice) + )); } #[test] - fn pair_works() { - let want = crypto::Pair::from_string("//Alice", None).expect("Pair failed").to_raw_vec(); - let got = Keyring::Alice.pair().to_raw_vec(); + fn pair_verify_should_work_ecdsa() { + pair_verify_should_work::(); + } + + #[test] + fn pair_verify_should_work_ecdsa_n_bls() { + pair_verify_should_work::(); + } + + fn pair_works() + where + TKeyPair: SimpleKeyPair, + { + let want = TKeyPair::from_string("//Alice", None).expect("Pair failed").to_raw_vec(); + let got = >::pair(Keyring::Alice).to_raw_vec(); assert_eq!(want, got); - let want = crypto::Pair::from_string("//Bob", None).expect("Pair failed").to_raw_vec(); - let got = Keyring::Bob.pair().to_raw_vec(); + let want = TKeyPair::from_string("//Bob", None).expect("Pair failed").to_raw_vec(); + let got = >::pair(Keyring::Bob).to_raw_vec(); assert_eq!(want, got); - let want = crypto::Pair::from_string("//Charlie", None).expect("Pair failed").to_raw_vec(); - let got = Keyring::Charlie.pair().to_raw_vec(); + let want = TKeyPair::from_string("//Charlie", None).expect("Pair failed").to_raw_vec(); + let got = >::pair(Keyring::Charlie).to_raw_vec(); assert_eq!(want, got); - let want = crypto::Pair::from_string("//Dave", None).expect("Pair failed").to_raw_vec(); - let got = Keyring::Dave.pair().to_raw_vec(); + let want = TKeyPair::from_string("//Dave", None).expect("Pair failed").to_raw_vec(); + let got = >::pair(Keyring::Dave).to_raw_vec(); assert_eq!(want, got); - let want = crypto::Pair::from_string("//Eve", None).expect("Pair failed").to_raw_vec(); - let got = Keyring::Eve.pair().to_raw_vec(); + let want = TKeyPair::from_string("//Eve", None).expect("Pair failed").to_raw_vec(); + let got = >::pair(Keyring::Eve).to_raw_vec(); assert_eq!(want, got); - let want = crypto::Pair::from_string("//Ferdie", None).expect("Pair failed").to_raw_vec(); - let got = Keyring::Ferdie.pair().to_raw_vec(); + let want = TKeyPair::from_string("//Ferdie", None).expect("Pair failed").to_raw_vec(); + let got = >::pair(Keyring::Ferdie).to_raw_vec(); assert_eq!(want, got); - let want = crypto::Pair::from_string("//One", None).expect("Pair failed").to_raw_vec(); - let got = Keyring::One.pair().to_raw_vec(); + let want = TKeyPair::from_string("//One", None).expect("Pair failed").to_raw_vec(); + let got = >::pair(Keyring::One).to_raw_vec(); assert_eq!(want, got); - let want = crypto::Pair::from_string("//Two", None).expect("Pair failed").to_raw_vec(); - let got = Keyring::Two.pair().to_raw_vec(); + let want = TKeyPair::from_string("//Two", None).expect("Pair failed").to_raw_vec(); + let got = >::pair(Keyring::Two).to_raw_vec(); assert_eq!(want, got); } #[test] - fn authority_id_works() { + fn ecdsa_pair_works() { + pair_works::(); + } + + #[test] + fn ecdsa_n_bls_pair_works() { + pair_works::(); + } + + fn authority_id_works() + where + TKeyPair: SimpleKeyPair + SimpleKeyPair, + TBeefyKeystore: BeefyKeystore, + AuthId: Clone + Encode + Decode + Debug + Ord + Sync + Send, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + { let store = keystore(); - let alice: crypto::Public = - SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) - .ok() - .unwrap() - .into(); + TKeyPair::generate_in_store(store.clone(), Keyring::Alice); + + let alice: TKeyPair::Public = >::public(Keyring::Alice); - let bob = Keyring::Bob.public(); - let charlie = Keyring::Charlie.public(); + let bob = >::public(Keyring::Bob); + let charlie = >::public(Keyring::Charlie); - let store: BeefyKeystore = Some(store).into(); + let beefy_store: TBeefyKeystore = TBeefyKeystore::new(store); let mut keys = vec![bob, charlie]; - let id = store.authority_id(keys.as_slice()); + let id = beefy_store.authority_id(keys.as_slice()); assert!(id.is_none()); keys.push(alice.clone()); - let id = store.authority_id(keys.as_slice()).unwrap(); + let id = beefy_store.authority_id(keys.as_slice()).unwrap(); assert_eq!(id, alice); } #[test] - fn sign_works() { + fn authority_id_works_for_ecdsa() { + authority_id_works::(); + } + + #[test] + fn authority_id_works_for_ecdsa_n_bls() { + authority_id_works::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >(); + } + + fn sign_works() + where + TKeyPair: SimpleKeyPair + SimpleKeyPair, + TBeefyKeystore: BeefyKeystore, + AuthId: Clone + Encode + Decode + Debug + Ord + Sync + Send, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + { let store = keystore(); - let alice: crypto::Public = - SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) - .ok() - .unwrap() - .into(); + TKeyPair::generate_in_store(store.clone(), Keyring::Alice); - let store: BeefyKeystore = Some(store).into(); + let alice = >::public(Keyring::Alice); + + let store: TBeefyKeystore = TBeefyKeystore::new(store); let msg = b"are you involved or commited?"; let sig1 = store.sign(&alice, msg).unwrap(); - let sig2 = Keyring::Alice.sign(msg); + let sig2 = >::sign(Keyring::Alice, msg); + + assert_eq!(sig1.encode(), sig2.encode()); + } - assert_eq!(sig1, sig2); + #[test] + fn sign_works_for_ecdsa() { + sign_works::(); } #[test] - fn sign_error() { + fn sign_works_for_ecdsa_n_bls() { + sign_works::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >(); + } + + fn sign_error(expected_error_message: &str) + where + TKeyPair: SimpleKeyPair + SimpleKeyPair, + TBeefyKeystore: BeefyKeystore, + AuthId: Clone + Encode + Decode + Debug + Ord + Sync + Send, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + { let store = keystore(); - let _ = - SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Bob.to_seed())) - .ok() - .unwrap(); + TKeyPair::generate_in_store(store.clone(), Keyring::Bob); - let store: BeefyKeystore = Some(store).into(); + let store: TBeefyKeystore = TBeefyKeystore::new(store); - let alice = Keyring::Alice.public(); + let alice = >::public(Keyring::Alice); let msg = b"are you involved or commited?"; let sig = store.sign(&alice, msg).err().unwrap(); - let err = Error::Signature("ecdsa_sign_prehashed() failed".to_string()); + let err = Error::Signature(expected_error_message.to_string()); assert_eq!(sig, err); } + #[test] + fn sign_error_for_ecdsa() { + sign_error::( + "ecdsa_sign_prehashed() failed", + ); + } + + #[test] + fn sign_error_for_ecdsa_n_bls() { + sign_error::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >("could not sign with both bls and ecdsa keys"); + } + #[test] fn sign_no_keystore() { - let store: BeefyKeystore = None.into(); + //TODO: new can not generate keystore with None element + //I also don't think we need that. so this test should go away. + // let store : BeefyKeystore = None.into(); - let alice = Keyring::Alice.public(); - let msg = b"are you involved or commited"; + // let alice = Keyring::Alice.public(); + // let msg = b"are you involved or commited"; - let sig = store.sign(&alice, msg).err().unwrap(); - let err = Error::Keystore("no Keystore".to_string()); - assert_eq!(sig, err); + //let sig = store.sign(&alice, msg).err().unwrap(); + // let err = Error::Keystore("no Keystore".to_string()); + // assert_eq!(sig, err); } - #[test] - fn verify_works() { + fn verify_works() + where + TKeyPair: SimpleKeyPair + SimpleKeyPair, + TBeefyKeystore: BeefyKeystore, + AuthId: Clone + Encode + Decode + Debug + Ord + Sync + Send, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + { let store = keystore(); - let alice: crypto::Public = - SyncCryptoStore::ecdsa_generate_new(&*store, KEY_TYPE, Some(&Keyring::Alice.to_seed())) - .ok() - .unwrap() - .into(); + TKeyPair::generate_in_store(store.clone(), Keyring::Alice); + + let store: TBeefyKeystore = TBeefyKeystore::new(store); - let store: BeefyKeystore = Some(store).into(); + let alice = >::public(Keyring::Alice); // `msg` and `sig` match let msg = b"are you involved or commited?"; let sig = store.sign(&alice, msg).unwrap(); - assert!(BeefyKeystore::verify(&alice, &sig, msg)); + assert!(TBeefyKeystore::verify(&alice, &sig, msg)); // `msg and `sig` don't match let msg = b"you are just involved"; - assert!(!BeefyKeystore::verify(&alice, &sig, msg)); + assert!(!TBeefyKeystore::verify(&alice, &sig, msg)); } - // Note that we use keys with and without a seed for this test. #[test] - fn public_keys_works() { + fn verify_works_for_ecdsa() { + verify_works::(); + } + + #[test] + fn verify_works_for_ecdsa_n_bls() { + verify_works::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >(); + } + + // Note that we use keys with and without a seed for this test. + fn public_keys_works() + where + TKeyPair: SimpleKeyPair + SimpleKeyPair, + TBeefyKeystore: BeefyKeystore, + AuthId: Clone + Encode + Decode + Debug + Ord + Sync + Send, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + { const TEST_TYPE: sp_application_crypto::KeyTypeId = sp_application_crypto::KeyTypeId(*b"test"); let store = keystore(); - let add_key = |key_type, seed: Option<&str>| { - SyncCryptoStore::ecdsa_generate_new(&*store, key_type, seed).unwrap() - }; - // test keys - let _ = add_key(TEST_TYPE, Some(Keyring::Alice.to_seed().as_str())); - let _ = add_key(TEST_TYPE, Some(Keyring::Bob.to_seed().as_str())); - - let _ = add_key(TEST_TYPE, None); - let _ = add_key(TEST_TYPE, None); + let _ = TKeyPair::add_typed_key_to_store( + store.clone(), + TEST_TYPE, + Some(>::to_seed(Keyring::Alice).as_str()), + ); + let _ = TKeyPair::add_typed_key_to_store( + store.clone(), + TEST_TYPE, + Some(>::to_seed(Keyring::Bob).as_str()), + ); // BEEFY keys - let _ = add_key(KEY_TYPE, Some(Keyring::Dave.to_seed().as_str())); - let _ = add_key(KEY_TYPE, Some(Keyring::Eve.to_seed().as_str())); + let _ = TKeyPair::add_typed_key_to_store( + store.clone(), + KEY_TYPE, + Some(>::to_seed(Keyring::Dave).as_str()), + ); + let _ = TKeyPair::add_typed_key_to_store( + store.clone(), + KEY_TYPE, + Some(>::to_seed(Keyring::Eve).as_str()), + ); + + let _ = TKeyPair::add_typed_key_to_store(store.clone(), TEST_TYPE, None); + let _ = TKeyPair::add_typed_key_to_store(store.clone(), TEST_TYPE, None); - let key1: crypto::Public = add_key(KEY_TYPE, None).into(); - let key2: crypto::Public = add_key(KEY_TYPE, None).into(); + let key1: AuthId = TKeyPair::add_typed_key_to_store(store.clone(), KEY_TYPE, None); + let key2: AuthId = TKeyPair::add_typed_key_to_store(store.clone(), KEY_TYPE, None); - let store: BeefyKeystore = Some(store).into(); + let store: TBeefyKeystore = TBeefyKeystore::new(store); let keys = store.public_keys().ok().unwrap(); + println!("key len {}", keys.len()); + println!("keys {:?}", keys); + println!("dave's {:?}", >::public(Keyring::Dave)); + println!("Eve's {:?}", >::public(Keyring::Eve)); + assert!(keys.len() == 4); - assert!(keys.contains(&Keyring::Dave.public())); - assert!(keys.contains(&Keyring::Eve.public())); - assert!(keys.contains(&key1)); - assert!(keys.contains(&key2)); + + assert!(store + .authority_id(&[>::public(Keyring::Dave)]) + .is_some()); + assert!(store + .authority_id(&[>::public(Keyring::Eve)]) + .is_some()); + assert!(store.authority_id(&[key1]).is_some()); + assert!(store.authority_id(&[key2]).is_some()); + } + + #[test] + fn public_keys_works_for_ecdsa_keystore() { + public_keys_works::(); + } + + #[test] + fn public_keys_works_for_ecdsa_n_bls() { + public_keys_works::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >(); } } diff --git a/client/beefy/src/lib.rs b/client/beefy/src/lib.rs index 185f3b1ad502e..760f9123285d1 100644 --- a/client/beefy/src/lib.rs +++ b/client/beefy/src/lib.rs @@ -16,6 +16,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use codec::{Decode, Encode}; +use core::fmt::Debug; + use crate::{ communication::{ notification::{ @@ -28,12 +31,12 @@ use crate::{ }, }, import::BeefyBlockImport, + keystore::BeefyKeystore, round::Rounds, worker::PersistedState, }; use beefy_primitives::{ - crypto::AuthorityId, BeefyApi, MmrRootHash, PayloadProvider, ValidatorSet, BEEFY_ENGINE_ID, - GENESIS_AUTHORITY_SET_ID, + BeefyApi, MmrRootHash, PayloadProvider, ValidatorSet, BEEFY_ENGINE_ID, GENESIS_AUTHORITY_SET_ID, }; use futures::{stream::Fuse, StreamExt}; use log::{debug, error, info}; @@ -49,7 +52,6 @@ use sp_blockchain::{ Backend as BlockchainBackend, Error as ClientError, HeaderBackend, Result as ClientResult, }; use sp_consensus::{Error as ConsensusError, SyncOracle}; -use sp_keystore::SyncCryptoStorePtr; use sp_mmr_primitives::MmrApi; use sp_runtime::{ generic::BlockId, @@ -107,33 +109,37 @@ where /// Links between the block importer, the background voter and the RPC layer, /// to be used by the voter. #[derive(Clone)] -pub struct BeefyVoterLinks { +pub struct BeefyVoterLinks { // BlockImport -> Voter links /// Stream of BEEFY signed commitments from block import to voter. - pub from_block_import_justif_stream: BeefyVersionedFinalityProofStream, + pub from_block_import_justif_stream: BeefyVersionedFinalityProofStream, // Voter -> RPC links /// Sends BEEFY signed commitments from voter to RPC. - pub to_rpc_justif_sender: BeefyVersionedFinalityProofSender, + pub to_rpc_justif_sender: BeefyVersionedFinalityProofSender, /// Sends BEEFY best block hashes from voter to RPC. pub to_rpc_best_block_sender: BeefyBestBlockSender, } /// Links used by the BEEFY RPC layer, from the BEEFY background voter. #[derive(Clone)] -pub struct BeefyRPCLinks { +pub struct BeefyRPCLinks { /// Stream of signed commitments coming from the voter. - pub from_voter_justif_stream: BeefyVersionedFinalityProofStream, + pub from_voter_justif_stream: BeefyVersionedFinalityProofStream, /// Stream of BEEFY best block hashes coming from the voter. pub from_voter_best_beefy_stream: BeefyBestBlockStream, } /// Make block importer and link half necessary to tie the background voter to it. -pub fn beefy_block_import_and_links( +pub fn beefy_block_import_and_links( wrapped_block_import: I, backend: Arc, runtime: Arc, -) -> (BeefyBlockImport, BeefyVoterLinks, BeefyRPCLinks) +) -> ( + BeefyBlockImport, + BeefyVoterLinks, + BeefyRPCLinks, +) where B: Block, BE: Backend, @@ -141,17 +147,20 @@ where + Send + Sync, RuntimeApi: ProvideRuntimeApi + Send + Sync, - RuntimeApi::Api: BeefyApi, + RuntimeApi::Api: BeefyApi, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + BKS: BeefyKeystore, { // Voter -> RPC links let (to_rpc_justif_sender, from_voter_justif_stream) = - BeefyVersionedFinalityProofStream::::channel(); + BeefyVersionedFinalityProofStream::::channel(); let (to_rpc_best_block_sender, from_voter_best_beefy_stream) = BeefyBestBlockStream::::channel(); // BlockImport -> Voter links let (to_voter_justif_sender, from_block_import_justif_stream) = - BeefyVersionedFinalityProofStream::::channel(); + BeefyVersionedFinalityProofStream::::channel(); // BlockImport let import = @@ -181,7 +190,18 @@ pub struct BeefyNetworkParams { } /// BEEFY gadget initialization parameters. -pub struct BeefyParams { +pub struct BeefyParams +where + B: Block, + BE: Backend, + C: Client, + R: ProvideRuntimeApi, + BKS: keystore::BeefyKeystore, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + R::Api: BeefyApi + MmrApi>, + N: GossipNetwork + NetworkRequest + SyncOracle + Send + Sync + 'static, +{ /// BEEFY client pub client: Arc, /// Client Backend @@ -191,31 +211,37 @@ pub struct BeefyParams { /// Runtime Api Provider pub runtime: Arc, /// Local key store - pub key_store: Option, - /// BEEFY voter network params + pub key_store: BKS, pub network_params: BeefyNetworkParams, /// Minimal delta between blocks, BEEFY should vote for pub min_block_delta: u32, /// Prometheus metric registry pub prometheus_registry: Option, /// Links between the block importer, the background voter and the RPC layer. - pub links: BeefyVoterLinks, + pub links: BeefyVoterLinks, /// Handler for incoming BEEFY justifications requests from a remote peer. pub on_demand_justifications_handler: BeefyJustifsRequestHandler, + pub _auth_id: PhantomData, + pub _signature: PhantomData, } /// Start the BEEFY gadget. /// /// This is a thin shim around running and awaiting a BEEFY worker. -pub async fn start_beefy_gadget(beefy_params: BeefyParams) -where +pub async fn start_beefy_gadget( + beefy_params: BeefyParams, +) where B: Block, BE: Backend, C: Client + BlockBackend, P: PayloadProvider, R: ProvideRuntimeApi, - R::Api: BeefyApi + MmrApi>, + R::Api: BeefyApi + MmrApi>, N: GossipNetwork + NetworkRequest + SyncOracle + Send + Sync + 'static, + BKS: keystore::BeefyKeystore + 'static, + + AuthId: Encode + Decode + Debug + Clone + Ord + std::hash::Hash + Sync + Send + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + 'static, { let BeefyParams { client, @@ -228,6 +254,8 @@ where prometheus_registry, links, on_demand_justifications_handler, + _auth_id, + _signature, } = beefy_params; let BeefyNetworkParams { network, gossip_protocol_name, justifications_protocol_name, .. } = @@ -287,7 +315,7 @@ where backend, payload_provider, network, - key_store: key_store.into(), + key_store, gossip_engine, gossip_validator, on_demand_justifications, @@ -296,7 +324,7 @@ where persisted_state, }; - let worker = worker::BeefyWorker::<_, _, _, _>::new(worker_params); + let worker = worker::BeefyWorker::<_, _, _, _, _, _, _>::new(worker_params); futures::future::join( worker.run(block_import_justif, finality_notifications), @@ -305,17 +333,19 @@ where .await; } -fn load_or_init_voter_state( +fn load_or_init_voter_state( backend: &BE, runtime: &R, best_grandpa: ::Header, min_block_delta: u32, -) -> ClientResult> +) -> ClientResult> where B: Block, BE: Backend, R: ProvideRuntimeApi, - R::Api: BeefyApi, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + R::Api: BeefyApi, { // Initialize voter state from AUX DB or from pallet genesis. if let Some(mut state) = crate::aux_schema::load_persistent(backend)? { @@ -334,17 +364,19 @@ where // - latest BEEFY finalized block, or if none found on the way, // - BEEFY pallet genesis; // Enqueue any BEEFY mandatory blocks (session boundaries) found on the way, for voter to finalize. -fn initialize_voter_state( +fn initialize_voter_state( backend: &BE, runtime: &R, best_grandpa: ::Header, min_block_delta: u32, -) -> ClientResult> +) -> ClientResult> where B: Block, BE: Backend, R: ProvideRuntimeApi, - R::Api: BeefyApi, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + R::Api: BeefyApi, { // Walk back the imported blocks and initialize voter either, at the last block with // a BEEFY justification, or at pallet genesis block; voter will resume from there. @@ -396,7 +428,7 @@ where .ok_or_else(|| ClientError::Backend("Invalid BEEFY chain".into()))? } - if let Some(active) = worker::find_authorities_change::(&header) { + if let Some(active) = worker::find_authorities_change::(&header) { info!( target: LOG_TARGET, "🥩 Marking block {:?} as BEEFY Mandatory.", @@ -429,7 +461,7 @@ where /// Wait for BEEFY runtime pallet to be available, return active validator set. /// Should be called only once during worker initialization. -async fn wait_for_runtime_pallet( +async fn wait_for_runtime_pallet( runtime: &R, mut gossip_engine: &mut GossipEngine, finality: &mut Fuse>, @@ -437,7 +469,8 @@ async fn wait_for_runtime_pallet( where B: Block, R: ProvideRuntimeApi, - R::Api: BeefyApi, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + R::Api: BeefyApi, { info!(target: LOG_TARGET, "🥩 BEEFY gadget waiting for BEEFY pallet to become available..."); loop { @@ -467,9 +500,11 @@ where Err(ClientError::Backend(err_msg)) } -fn genesis_set_sanity_check( - active: ValidatorSet, -) -> ClientResult> { +fn genesis_set_sanity_check< + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, +>( + active: ValidatorSet, +) -> ClientResult> { if active.id() == GENESIS_AUTHORITY_SET_ID { Ok(active) } else { @@ -478,14 +513,15 @@ fn genesis_set_sanity_check( } } -fn expect_validator_set( +fn expect_validator_set( runtime: &R, at: BlockId, -) -> ClientResult> +) -> ClientResult> where B: Block, R: ProvideRuntimeApi, - R::Api: BeefyApi, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + R::Api: BeefyApi, { runtime .runtime_api() diff --git a/client/beefy/src/round.rs b/client/beefy/src/round.rs index 647d42110e926..6c6bcd70530e8 100644 --- a/client/beefy/src/round.rs +++ b/client/beefy/src/round.rs @@ -16,29 +16,48 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use std::{collections::BTreeMap, hash::Hash}; + use crate::LOG_TARGET; +use core::fmt::Debug; -use beefy_primitives::{ - crypto::{Public, Signature}, - ValidatorSet, ValidatorSetId, -}; +use beefy_primitives::{ValidatorSet, ValidatorSetId}; use codec::{Decode, Encode}; use log::{debug, trace}; use sp_runtime::traits::{Block, NumberFor}; -use std::{collections::BTreeMap, hash::Hash}; /// Tracks for each round which validators have voted/signed and /// whether the local `self` validator has voted/signed. /// /// Does not do any validation on votes or signatures, layers above need to handle that (gossip). -#[derive(Debug, Decode, Default, Encode, PartialEq)] -struct RoundTracker { +#[derive(Debug, Decode, Encode, PartialEq)] +struct RoundTracker< + AuthId: Encode + Decode + Debug + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, +> { self_vote: bool, - votes: BTreeMap, + votes: BTreeMap, +} + +impl< + AuthId: Encode + Decode + Debug + Ord + Sync + Send + core::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + > Default for RoundTracker +{ + fn default() -> Self { + RoundTracker::<_, _> { + self_vote: false, + votes: as Default>::default(), + } + } } -impl RoundTracker { - fn add_vote(&mut self, vote: (Public, Signature), self_vote: bool) -> bool { +impl< + AuthId: Encode + Decode + Debug + Ord + Sync + Send + core::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + > RoundTracker +{ + fn add_vote(&mut self, vote: (AuthId, TSignature), self_vote: bool) -> bool { if self.votes.contains_key(&vote.0) { return false } @@ -68,20 +87,27 @@ pub fn threshold(authorities: usize) -> usize { /// /// Does not do any validation on votes or signatures, layers above need to handle that (gossip). #[derive(Debug, Decode, Encode, PartialEq)] -pub(crate) struct Rounds { - rounds: BTreeMap<(Payload, NumberFor), RoundTracker>, +pub(crate) struct Rounds< + Payload, + B: Block, + AuthId: Encode + Decode + Debug + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, +> { + rounds: BTreeMap<(Payload, NumberFor), RoundTracker>, session_start: NumberFor, - validator_set: ValidatorSet, + validator_set: ValidatorSet, mandatory_done: bool, best_done: Option>, } -impl Rounds +impl Rounds where P: Ord + Hash + Clone, B: Block, + AuthId: Encode + Decode + Debug + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, { - pub(crate) fn new(session_start: NumberFor, validator_set: ValidatorSet) -> Self { + pub(crate) fn new(session_start: NumberFor, validator_set: ValidatorSet) -> Self { Rounds { rounds: BTreeMap::new(), session_start, @@ -91,7 +117,7 @@ where } } - pub(crate) fn validator_set(&self) -> &ValidatorSet { + pub(crate) fn validator_set(&self) -> &ValidatorSet { &self.validator_set } @@ -99,7 +125,7 @@ where self.validator_set.id() } - pub(crate) fn validators(&self) -> &[Public] { + pub(crate) fn validators(&self) -> &[AuthId] { self.validator_set.validators() } @@ -119,7 +145,7 @@ where pub(crate) fn add_vote( &mut self, round: &(P, NumberFor), - vote: (Public, Signature), + vote: (AuthId, TSignature), self_vote: bool, ) -> bool { let num = round.1; @@ -134,6 +160,7 @@ where ); false } else { + //self.rounds.entry(round.clone()).or_default().add_vote(vote, self_vote) self.rounds.entry(round.clone()).or_default().add_vote(vote, self_vote) } } @@ -141,7 +168,7 @@ where pub(crate) fn should_conclude( &mut self, round: &(P, NumberFor), - ) -> Option>> { + ) -> Option>> { let done = self .rounds .get(round) @@ -173,28 +200,43 @@ where #[cfg(test)] mod tests { + use core::fmt::Debug; use sc_network_test::Block; use sp_core::H256; - use beefy_primitives::{crypto::Public, ValidatorSet}; + use beefy_primitives::{ + bls_crypto::{Public as BLSPublic, Signature as BLSSignature}, + ecdsa_crypto::{self, Public as ECDSAPublic, Signature as ECDSASignature}, + ValidatorSet, + }; + use codec::{Decode, Encode}; use super::{threshold, Block as BlockT, Hash, RoundTracker, Rounds}; - use crate::keystore::tests::Keyring; + use crate::keystore::tests::{ECDSAnBLSPair, GenericKeyring, Keyring, SimpleKeyPair}; - impl Rounds + impl Rounds where P: Ord + Hash + Clone, B: BlockT, + AuthId: Encode + Decode + Debug + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, { pub(crate) fn test_set_mandatory_done(&mut self, done: bool) { self.mandatory_done = done; } } - #[test] - fn round_tracker() { + fn round_tracker() + where + TKeyPair: SimpleKeyPair, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + { let mut rt = RoundTracker::default(); - let bob_vote = (Keyring::Bob.public(), Keyring::Bob.sign(b"I am committed")); + let bob_vote = ( + >::public(Keyring::Bob), + >::sign(Keyring::Bob, b"I am committed"), + ); let threshold = 2; // self vote not added yet @@ -211,7 +253,10 @@ mod tests { // vote is not done assert!(!rt.is_done(threshold)); - let alice_vote = (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")); + let alice_vote = ( + >::public(Keyring::Alice), + >::sign(Keyring::Alice, b"I am committed"), + ); // adding new vote (self vote this time) allowed assert!(rt.add_vote(alice_vote, true)); @@ -221,6 +266,16 @@ mod tests { assert!(rt.is_done(threshold)); } + #[test] + fn round_tracker_with_ecdsa_keys() { + round_tracker::(); + } + + #[test] + fn round_tracker_with_ecdsa_n_bls_keys() { + round_tracker::(); + } + #[test] fn vote_threshold() { assert_eq!(threshold(1), 1); @@ -231,45 +286,71 @@ mod tests { assert_eq!(threshold(300), 201); } - #[test] - fn new_rounds() { + fn new_rounds() + where + TKeyPair: SimpleKeyPair, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + { sp_tracing::try_init_simple(); - - let validators = ValidatorSet::::new( - vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], + let validators = ValidatorSet::new( + vec![ + >::public(Keyring::Alice), + >::public(Keyring::Bob), + >::public(Keyring::Charlie), + ], 42, ) .unwrap(); let session_start = 1u64.into(); - let rounds = Rounds::::new(session_start, validators); + let rounds = Rounds::::new(session_start, validators); assert_eq!(42, rounds.validator_set_id()); assert_eq!(1, rounds.session_start()); assert_eq!( - &vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], + &vec![ + >::public(Keyring::Alice), + >::public(Keyring::Bob), + >::public(Keyring::Charlie) + ], rounds.validators() ); } #[test] - fn add_and_conclude_votes() { + fn new_rounds_with_ecdsa_keys() { + new_rounds::(); + } + + #[test] + fn new_rounds_with_ecdsa_n_bls_keys() { + new_rounds::(); + } + + fn add_and_conclude_votes() + where + TKeyPair: SimpleKeyPair, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + { sp_tracing::try_init_simple(); - let validators = ValidatorSet::::new( + let validators = ValidatorSet::new( vec![ - Keyring::Alice.public(), - Keyring::Bob.public(), - Keyring::Charlie.public(), - Keyring::Eve.public(), + >::public(Keyring::Alice), + >::public(Keyring::Bob), + >::public(Keyring::Charlie), + >::public(Keyring::Eve), ], Default::default(), ) .unwrap(); + let round = (H256::from_low_u64_le(1), 1); let session_start = 1u64.into(); - let mut rounds = Rounds::::new(session_start, validators); + let mut rounds = Rounds::::new(session_start, validators); // no self vote yet, should self vote assert!(rounds.should_self_vote(&round)); @@ -277,7 +358,10 @@ mod tests { // add 1st good vote assert!(rounds.add_vote( &round, - (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")), + ( + >::public(Keyring::Alice), + >::sign(Keyring::Alice, b"I am committed") + ), true )); // round not concluded @@ -288,14 +372,20 @@ mod tests { // double voting not allowed assert!(!rounds.add_vote( &round, - (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")), + ( + >::public(Keyring::Alice), + >::sign(Keyring::Alice, b"I am committed") + ), true )); // invalid vote (Dave is not a validator) assert!(!rounds.add_vote( &round, - (Keyring::Dave.public(), Keyring::Dave.sign(b"I am committed")), + ( + >::public(Keyring::Dave), + >::sign(Keyring::Dave, b"I am committed") + ), false )); assert!(rounds.should_conclude(&round).is_none()); @@ -303,7 +393,10 @@ mod tests { // add 2nd good vote assert!(rounds.add_vote( &round, - (Keyring::Bob.public(), Keyring::Bob.sign(b"I am committed")), + ( + >::public(Keyring::Bob), + >::sign(Keyring::Bob, b"I am committed") + ), false )); // round not concluded @@ -312,7 +405,10 @@ mod tests { // add 3rd good vote assert!(rounds.add_vote( &round, - (Keyring::Charlie.public(), Keyring::Charlie.sign(b"I am committed")), + ( + >::public(Keyring::Charlie), + >::sign(Keyring::Charlie, b"I am committed") + ), false )); // round concluded @@ -322,24 +418,52 @@ mod tests { // Eve is a validator, but round was concluded, adding vote disallowed assert!(!rounds.add_vote( &round, - (Keyring::Eve.public(), Keyring::Eve.sign(b"I am committed")), + ( + >::public(Keyring::Eve), + >::sign(Keyring::Eve, b"I am committed") + ), false )); } #[test] - fn old_rounds_not_accepted() { + fn add_and_conclude_votes_with_ecdsa_keys() { + add_and_conclude_votes::(); + } + + #[test] + fn add_and_conclude_votes_with_ecdsa_n_bls_keys() { + add_and_conclude_votes::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + >(); + } + + fn old_rounds_not_accepted() + where + TKeyPair: SimpleKeyPair, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + { sp_tracing::try_init_simple(); - let validators = ValidatorSet::::new( - vec![Keyring::Alice.public(), Keyring::Bob.public(), Keyring::Charlie.public()], + let validators = ValidatorSet::new( + vec![ + >::public(Keyring::Alice), + >::public(Keyring::Bob), + >::public(Keyring::Charlie), + ], 42, ) .unwrap(); - let alice = (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")); + let alice = ( + >::public(Keyring::Alice), + >::sign(Keyring::Alice, b"I am committed"), + ); let session_start = 10u64.into(); - let mut rounds = Rounds::::new(session_start, validators); + let mut rounds = Rounds::::new(session_start, validators); let mut vote = (H256::from_low_u64_le(1), 9); // add vote for previous session, should fail @@ -365,71 +489,128 @@ mod tests { } #[test] - fn multiple_rounds() { + fn old_rounds_not_accepted_with_ecdsa_keys() { + old_rounds_not_accepted::(); + } + + #[test] + fn old_rounds_not_accepted_with_ecdsa_n_bls_keys() { + old_rounds_not_accepted::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + >(); + } + + fn multiple_rounds() + where + TKeyPair: SimpleKeyPair, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + std::cmp::PartialEq, + { sp_tracing::try_init_simple(); - let validators = ValidatorSet::::new( + let validators = ValidatorSet::new( vec![ - Keyring::Alice.public(), - Keyring::Bob.public(), - Keyring::Charlie.public(), - Keyring::Dave.public(), + >::public(Keyring::Alice), + >::public(Keyring::Bob), + >::public(Keyring::Charlie), + >::public(Keyring::Dave), ], Default::default(), ) .unwrap(); let session_start = 1u64.into(); - let mut rounds = Rounds::::new(session_start, validators); + let mut rounds = Rounds::::new(session_start, validators); // round 1 assert!(rounds.add_vote( &(H256::from_low_u64_le(1), 1), - (Keyring::Alice.public(), Keyring::Alice.sign(b"I am committed")), + ( + >::public(Keyring::Alice), + >::sign(Keyring::Alice, b"I am committed") + ), true, )); assert!(rounds.add_vote( &(H256::from_low_u64_le(1), 1), - (Keyring::Bob.public(), Keyring::Bob.sign(b"I am committed")), + ( + >::public(Keyring::Bob), + >::sign(Keyring::Bob, b"I am committed") + ), false, )); assert!(rounds.add_vote( &(H256::from_low_u64_le(1), 1), - (Keyring::Charlie.public(), Keyring::Charlie.sign(b"I am committed")), + ( + >::public(Keyring::Charlie), + >::sign(Keyring::Charlie, b"I am committed") + ), false, )); // round 2 assert!(rounds.add_vote( &(H256::from_low_u64_le(2), 2), - (Keyring::Alice.public(), Keyring::Alice.sign(b"I am again committed")), + ( + >::public(Keyring::Alice), + >::sign( + Keyring::Alice, + b"I am again committed" + ) + ), true, )); assert!(rounds.add_vote( &(H256::from_low_u64_le(2), 2), - (Keyring::Bob.public(), Keyring::Bob.sign(b"I am again committed")), + ( + >::public(Keyring::Bob), + >::sign(Keyring::Bob, b"I am again committed") + ), false, )); assert!(rounds.add_vote( &(H256::from_low_u64_le(2), 2), - (Keyring::Charlie.public(), Keyring::Charlie.sign(b"I am again committed")), + ( + >::public(Keyring::Charlie), + >::sign( + Keyring::Charlie, + b"I am again committed" + ) + ), false, )); // round 3 assert!(rounds.add_vote( &(H256::from_low_u64_le(3), 3), - (Keyring::Alice.public(), Keyring::Alice.sign(b"I am still committed")), + ( + >::public(Keyring::Alice), + >::sign( + Keyring::Alice, + b"I am still committed" + ) + ), true, )); assert!(rounds.add_vote( &(H256::from_low_u64_le(3), 3), - (Keyring::Bob.public(), Keyring::Bob.sign(b"I am still committed")), + ( + >::public(Keyring::Bob), + >::sign(Keyring::Bob, b"I am still committed") + ), false, )); assert!(rounds.add_vote( &(H256::from_low_u64_le(3), 3), - (Keyring::Charlie.public(), Keyring::Charlie.sign(b"I am still committed")), + ( + >::public(Keyring::Charlie), + >::sign( + Keyring::Charlie, + b"I am still committed" + ) + ), false, )); assert_eq!(3, rounds.rounds.len()); @@ -446,11 +627,31 @@ mod tests { assert_eq!( signatures, vec![ - Some(Keyring::Alice.sign(b"I am again committed")), - Some(Keyring::Bob.sign(b"I am again committed")), - Some(Keyring::Charlie.sign(b"I am again committed")), + Some(>::sign( + Keyring::Alice, + b"I am again committed" + )), + Some(>::sign( + Keyring::Bob, + b"I am again committed" + )), + Some(>::sign( + Keyring::Charlie, + b"I am again committed" + )), None ] ); } + + #[test] + fn multiple_rounds_with_ecdsa_keys() { + multiple_rounds::(); + } + + #[test] + fn multiple_rounds_with_ecdsa_n_bls_keys() { + multiple_rounds::( + ); + } } diff --git a/client/beefy/src/tests.rs b/client/beefy/src/tests.rs index 2642035ba5dd5..cf07b8c61fb4b 100644 --- a/client/beefy/src/tests.rs +++ b/client/beefy/src/tests.rs @@ -26,17 +26,25 @@ use crate::{ }, gossip_protocol_name, justification::*, - keystore::tests::Keyring as BeefyKeyring, + keystore::{ + tests::{ECDSAnBLSPair, GenericKeyring, Keyring, SimpleKeyPair}, + BeefyBLSnECDSAKeystore, BeefyECDSAKeystore, + }, load_or_init_voter_state, wait_for_runtime_pallet, BeefyRPCLinks, BeefyVoterLinks, KnownPeers, PersistedState, }; use beefy_primitives::{ - crypto::{AuthorityId, Signature}, + bls_crypto::{AuthorityId as BLSAuthorityId, Public as BLSPublic, Signature as BLSSignature}, + ecdsa_crypto::{ + AuthorityId as ECDSAAuthorityId, Pair as ECDSAKeyPair, Public as ECDSAPublic, + Signature as ECDSASignature, + }, known_payloads, mmr::MmrRootProvider, BeefyApi, Commitment, ConsensusLog, MmrRootHash, Payload, SignedCommitment, ValidatorSet, - VersionedFinalityProof, BEEFY_ENGINE_ID, KEY_TYPE as BeefyKeyType, + VersionedFinalityProof, BEEFY_ENGINE_ID, }; +use core::fmt::Debug; use futures::{future, stream::FuturesUnordered, Future, StreamExt}; use parking_lot::Mutex; use sc_client_api::{Backend as BackendT, BlockchainEvents, FinalityNotifications, HeaderBackend}; @@ -44,6 +52,7 @@ use sc_consensus::{ BlockImport, BlockImportParams, BoxJustificationImport, ForkChoiceStrategy, ImportResult, ImportedAux, }; +use sc_keystore::LocalKeystore; use sc_network::{config::RequestResponseConfig, ProtocolName}; use sc_network_test::{ Block, BlockImportAdapter, FullPeerConfig, PassThroughVerifier, Peer, PeersClient, @@ -54,10 +63,10 @@ use serde::{Deserialize, Serialize}; use sp_api::{ApiRef, ProvideRuntimeApi}; use sp_consensus::BlockOrigin; use sp_core::H256; -use sp_keystore::{testing::KeyStore as TestKeystore, SyncCryptoStore, SyncCryptoStorePtr}; +use sp_keystore::SyncCryptoStorePtr; use sp_mmr_primitives::{EncodableOpaqueLeaf, Error as MmrError, MmrApi, Proof}; use sp_runtime::{ - codec::Encode, + codec::{Decode, Encode}, generic::BlockId, traits::{Header as HeaderT, NumberFor}, BuildStorage, DigestItem, Justifications, Storage, @@ -66,6 +75,8 @@ use std::{collections::HashMap, marker::PhantomData, sync::Arc, task::Poll}; use substrate_test_runtime_client::{runtime::Header, ClientExt}; use tokio::time::Duration; +use smart_default::SmartDefault; + const GENESIS_HASH: H256 = H256::zero(); fn beefy_gossip_proto_name() -> ProtocolName { gossip_protocol_name(GENESIS_HASH, None) @@ -74,15 +85,19 @@ fn beefy_gossip_proto_name() -> ProtocolName { const GOOD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0xbf); const BAD_MMR_ROOT: MmrRootHash = MmrRootHash::repeat_byte(0x42); -type BeefyBlockImport = crate::BeefyBlockImport< +type BeefyBlockImport = crate::BeefyBlockImport< Block, substrate_test_runtime_client::Backend, two_validators::TestApi, BlockImportAdapter>, + AuthId, + TSignature, + TBeefyKeystore, >; -pub(crate) type BeefyValidatorSet = ValidatorSet; -pub(crate) type BeefyPeer = Peer; +pub(crate) type BeefyValidatorSet = ValidatorSet; +pub(crate) type BeefyPeer = + Peer, BeefyBlockImport>; #[derive(Debug, Serialize, Deserialize)] struct Genesis(std::collections::BTreeMap); @@ -95,20 +110,44 @@ impl BuildStorage for Genesis { } } -#[derive(Default)] -pub(crate) struct PeerData { - pub(crate) beefy_rpc_links: Mutex>>, - pub(crate) beefy_voter_links: Mutex>>, +//#[derive(Default)] can not derive due to generic +#[derive(SmartDefault)] +pub(crate) struct PeerData +where + TSignature: Encode + Decode + Debug + Clone + Sync + Send, +{ + pub(crate) beefy_rpc_links: Mutex>>, + pub(crate) beefy_voter_links: Mutex>>, pub(crate) beefy_justif_req_handler: Mutex>>, } -#[derive(Default)] -pub(crate) struct BeefyTestNet { - peers: Vec, +// #[derive(Default)] can not derive due to generic +#[derive(SmartDefault)] +pub(crate) struct BeefyTestNet +where + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + TBeefyKeystore: BeefyKeystore, +{ + peers: Vec>, } -impl BeefyTestNet { +impl BeefyTestNet +where + AuthId: Clone + + Encode + + Decode + + Debug + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + 'static, + TBeefyKeystore: BeefyKeystore + 'static, +{ pub(crate) fn new(n_authority: usize) -> Self { let mut net = BeefyTestNet { peers: Vec::with_capacity(n_authority) }; @@ -146,7 +185,7 @@ impl BeefyTestNet { &mut self, count: usize, session_length: u64, - validator_set: &BeefyValidatorSet, + validator_set: &BeefyValidatorSet, include_mmr_digest: bool, ) -> Vec { let mut all_hashes = Vec::with_capacity(count + 1); @@ -181,12 +220,27 @@ impl BeefyTestNet { } } -impl TestNetFactory for BeefyTestNet { +impl TestNetFactory + for BeefyTestNet +where + AuthId: Clone + + Encode + + Decode + + Debug + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + 'static, + TBeefyKeystore: BeefyKeystore + 'static, +{ type Verifier = PassThroughVerifier; - type BlockImport = BeefyBlockImport; - type PeerData = PeerData; + type BlockImport = BeefyBlockImport; + type PeerData = PeerData; - fn make_verifier(&self, _client: PeersClient, _: &PeerData) -> Self::Verifier { + fn make_verifier(&self, _client: PeersClient, _: &PeerData) -> Self::Verifier { PassThroughVerifier::new(false) // use non-instant finality. } @@ -204,23 +258,27 @@ impl TestNetFactory for BeefyTestNet { client.as_backend(), Arc::new(two_validators::TestApi {}), ); - let peer_data = PeerData { + let peer_data = PeerData:: { beefy_rpc_links: Mutex::new(Some(rpc_links)), beefy_voter_links: Mutex::new(Some(voter_links)), - ..Default::default() + beefy_justif_req_handler: Mutex::new(None), + //..Default::default() }; (BlockImportAdapter::new(block_import), None, peer_data) } - fn peer(&mut self, i: usize) -> &mut BeefyPeer { + fn peer(&mut self, i: usize) -> &mut BeefyPeer { &mut self.peers[i] } - fn peers(&self) -> &Vec { + fn peers(&self) -> &Vec> { &self.peers } - fn mut_peers)>(&mut self, closure: F) { + fn mut_peers>)>( + &mut self, + closure: F, + ) { closure(&mut self.peers); } @@ -251,9 +309,11 @@ macro_rules! create_test_api { } } sp_api::mock_impl_runtime_apis! { - impl BeefyApi for RuntimeApi { - fn validator_set() -> Option { - BeefyValidatorSet::new(make_beefy_ids(&[$($inits),+]), 0) + impl BeefyApi for RuntimeApi + where + { + fn validator_set() -> Option> { + BeefyValidatorSet::new(::make_beefy_ids(&[$($inits),+]), 0) } } @@ -286,86 +346,143 @@ macro_rules! create_test_api { }; } -create_test_api!(two_validators, mmr_root: GOOD_MMR_ROOT, BeefyKeyring::Alice, BeefyKeyring::Bob); +create_test_api!(two_validators, mmr_root: GOOD_MMR_ROOT, Keyring::Alice, Keyring::Bob); create_test_api!( four_validators, mmr_root: GOOD_MMR_ROOT, - BeefyKeyring::Alice, - BeefyKeyring::Bob, - BeefyKeyring::Charlie, - BeefyKeyring::Dave + Keyring::Alice, + Keyring::Bob, + Keyring::Charlie, + Keyring::Dave ); create_test_api!( bad_four_validators, mmr_root: BAD_MMR_ROOT, - BeefyKeyring::Alice, - BeefyKeyring::Bob, - BeefyKeyring::Charlie, - BeefyKeyring::Dave + Keyring::Alice, + Keyring::Bob, + Keyring::Charlie, + Keyring::Dave ); fn add_mmr_digest(header: &mut Header, mmr_hash: MmrRootHash) { header.digest_mut().push(DigestItem::Consensus( BEEFY_ENGINE_ID, - ConsensusLog::::MmrRoot(mmr_hash).encode(), + ConsensusLog::::MmrRoot(mmr_hash).encode(), )); } -fn add_auth_change_digest(header: &mut Header, new_auth_set: BeefyValidatorSet) { +fn add_auth_change_digest(header: &mut Header, new_auth_set: BeefyValidatorSet) +where + AuthId: Clone + Encode + Decode + Debug + Ord + Sync + Send, +{ header.digest_mut().push(DigestItem::Consensus( BEEFY_ENGINE_ID, - ConsensusLog::::AuthoritiesChange(new_auth_set).encode(), + ConsensusLog::::AuthoritiesChange(new_auth_set).encode(), )); } -pub(crate) fn make_beefy_ids(keys: &[BeefyKeyring]) -> Vec { - keys.iter().map(|&key| key.public().into()).collect() +pub(crate) trait BeefyAuthIdMaker: + Clone + Encode + Decode + Debug + Ord + Sync + Send +{ + fn make_beefy_ids(keys: &[Keyring]) -> Vec; +} + +impl BeefyAuthIdMaker for ECDSAAuthorityId { + fn make_beefy_ids(keys: &[Keyring]) -> Vec { + keys.iter() + .map(|&key| >::public(key).into()) + .collect() + } +} + +impl BeefyAuthIdMaker for (ECDSAAuthorityId, BLSAuthorityId) { + fn make_beefy_ids(keys: &[Keyring]) -> Vec { + keys.iter() + .map(|&key| >::public(key).into()) + .collect() + } } -pub(crate) fn create_beefy_keystore(authority: BeefyKeyring) -> SyncCryptoStorePtr { - let keystore = Arc::new(TestKeystore::new()); - SyncCryptoStore::ecdsa_generate_new(&*keystore, BeefyKeyType, Some(&authority.to_seed())) - .expect("Creates authority key"); +pub(crate) fn create_beefy_keystore( + authority: Keyring, +) -> SyncCryptoStorePtr { + let keystore = Arc::new(LocalKeystore::in_memory()); + TKeyPair::generate_in_store(keystore.clone(), authority); keystore } -fn voter_init_setup( - net: &mut BeefyTestNet, +fn voter_init_setup( + net: &mut BeefyTestNet, finality: &mut futures::stream::Fuse>, -) -> sp_blockchain::Result> { +) -> sp_blockchain::Result> +where + AuthId: Clone + + Encode + + Decode + + Debug + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + 'static, + TBeefyKeystore: BeefyKeystore + 'static, +{ let backend = net.peer(0).client().as_backend(); let api = Arc::new(crate::tests::two_validators::TestApi {}); let known_peers = Arc::new(Mutex::new(KnownPeers::new())); - let gossip_validator = - Arc::new(crate::communication::gossip::GossipValidator::new(known_peers)); + let gossip_validator = Arc::new(crate::communication::gossip::GossipValidator::< + Block, + AuthId, + TSignature, + TBeefyKeystore, + >::new(known_peers)); let mut gossip_engine = sc_network_gossip::GossipEngine::new( net.peer(0).network_service().clone(), "/beefy/whatever", gossip_validator, None, ); - let best_grandpa = - futures::executor::block_on(wait_for_runtime_pallet(&*api, &mut gossip_engine, finality)) - .unwrap(); + let best_grandpa = futures::executor::block_on(wait_for_runtime_pallet::<_, _, AuthId>( + &*api, + &mut gossip_engine, + finality, + )) + .unwrap(); load_or_init_voter_state(&*backend, &*api, best_grandpa, 1) } +use crate::keystore::BeefyKeystore; // Spawns beefy voters. Returns a future to spawn on the runtime. -fn initialize_beefy( - net: &mut BeefyTestNet, - peers: Vec<(usize, &BeefyKeyring, Arc)>, +fn initialize_beefy( + net: &mut BeefyTestNet, + peers: Vec<(usize, &Keyring, Arc)>, min_block_delta: u32, ) -> impl Future where API: ProvideRuntimeApi + Default + Sync + Send, - API::Api: BeefyApi + MmrApi>, + API::Api: BeefyApi + MmrApi>, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + 'static, + TKeyPair: Sync + Send + SimpleKeyPair, + AuthId: Clone + + Encode + + Decode + + Debug + + Ord + + BeefyAuthIdMaker + + std::hash::Hash + + Sync + + Send + + 'static, + BKS: BeefyKeystore + 'static, { let tasks = FuturesUnordered::new(); for (peer_id, key, api) in peers.into_iter() { let peer = &net.peers[peer_id]; - let keystore = create_beefy_keystore(*key); + let keystore = create_beefy_keystore::(key.clone()); let (_, _, peer_data) = net.make_block_import(peer.client().clone()); let PeerData { beefy_rpc_links, beefy_voter_links, .. } = peer_data; @@ -389,14 +506,16 @@ where backend: peer.client().as_backend(), payload_provider, runtime: api.clone(), - key_store: Some(keystore), + key_store: BKS::new(keystore), network_params, links: beefy_voter_links.unwrap(), min_block_delta, prometheus_registry: None, on_demand_justifications_handler: on_demand_justif_handler, + _auth_id: PhantomData, + _signature: PhantomData, }; - let task = crate::start_beefy_gadget::<_, _, _, _, _, _>(beefy_params); + let task = crate::start_beefy_gadget::<_, _, _, _, _, _, _, _, _>(beefy_params); fn assert_send(_: &T) {} assert_send(&task); @@ -406,7 +525,23 @@ where tasks.for_each(|_| async move {}) } -async fn run_until(future: impl Future + Unpin, net: &Arc>) { +async fn run_until( + future: impl Future + Unpin, + net: &Arc>>, +) where + AuthId: Encode + + Decode + + Debug + + Clone + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + 'static, + BKS: BeefyKeystore + 'static, +{ let drive_to_completion = futures::future::poll_fn(|cx| { net.lock().poll(cx); Poll::<()>::Pending @@ -414,15 +549,47 @@ async fn run_until(future: impl Future + Unpin, net: &Arc>) let _ = future::select(future, drive_to_completion).await; } -async fn run_for(duration: Duration, net: &Arc>) { +async fn run_for( + duration: Duration, + net: &Arc>>, +) where + AuthId: Encode + + Decode + + Debug + + Clone + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + 'static, + BKS: BeefyKeystore + 'static, +{ run_until(Box::pin(tokio::time::sleep(duration)), net).await; } -pub(crate) fn get_beefy_streams( - net: &mut BeefyTestNet, +pub(crate) fn get_beefy_streams( + net: &mut BeefyTestNet, // peer index and key - peers: impl Iterator, -) -> (Vec>, Vec>>) + peers: impl Iterator, +) -> ( + Vec>, + Vec>>, +) +where + AuthId: Encode + + Decode + + Debug + + Clone + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + 'static, + BKS: BeefyKeystore + 'static, { let mut best_block_streams = Vec::new(); let mut versioned_finality_proof_streams = Vec::new(); @@ -436,11 +603,24 @@ pub(crate) fn get_beefy_streams( (best_block_streams, versioned_finality_proof_streams) } -async fn wait_for_best_beefy_blocks( +async fn wait_for_best_beefy_blocks( streams: Vec>, - net: &Arc>, + net: &Arc>>, expected_beefy_blocks: &[u64], -) { +) where + AuthId: Encode + + Decode + + Debug + + Clone + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + 'static, + BKS: BeefyKeystore + 'static, +{ let mut wait_for = Vec::new(); let len = expected_beefy_blocks.len(); streams.into_iter().enumerate().for_each(|(i, stream)| { @@ -460,11 +640,24 @@ async fn wait_for_best_beefy_blocks( run_until(wait_for, net).await; } -async fn wait_for_beefy_signed_commitments( - streams: Vec>>, - net: &Arc>, +async fn wait_for_beefy_signed_commitments( + streams: Vec>>, + net: &Arc>>, expected_commitment_block_nums: &[u64], -) { +) where + AuthId: Encode + + Decode + + Debug + + Clone + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + 'static, + BKS: BeefyKeystore + 'static, +{ let mut wait_for = Vec::new(); let len = expected_commitment_block_nums.len(); streams.into_iter().for_each(|stream| { @@ -485,13 +678,25 @@ async fn wait_for_beefy_signed_commitments( run_until(wait_for, net).await; } -async fn streams_empty_after_timeout( +async fn streams_empty_after_timeout( streams: Vec>, - net: &Arc>, + net: &Arc>>, timeout: Option, ) where T: std::fmt::Debug, T: std::cmp::PartialEq, + AuthId: Encode + + Decode + + Debug + + Clone + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + 'static, + BKS: BeefyKeystore + 'static, { if let Some(timeout) = timeout { run_for(timeout, net).await; @@ -505,13 +710,26 @@ async fn streams_empty_after_timeout( } } -async fn finalize_block_and_wait_for_beefy( - net: &Arc>, +async fn finalize_block_and_wait_for_beefy( + net: &Arc>>, // peer index and key - peers: impl Iterator + Clone, + peers: impl Iterator + Clone, finalize_targets: &[H256], expected_beefy: &[u64], -) { +) where + AuthId: Encode + + Decode + + Debug + + Clone + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + std::cmp::PartialEq + 'static, + BKS: BeefyKeystore + 'static, +{ let (best_blocks, versioned_finality_proof) = get_beefy_streams(&mut net.lock(), peers.clone()); for block in finalize_targets { @@ -533,20 +751,41 @@ async fn finalize_block_and_wait_for_beefy( } } -#[tokio::test] -async fn beefy_finalizing_blocks() { +async fn beefy_finalizing_blocks() +where + TKeyPair: SimpleKeyPair + SimpleKeyPair + 'static, + TBeefyKeystore: BeefyKeystore + 'static, + AuthId: Clone + + Encode + + Decode + + Debug + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + std::cmp::PartialEq + 'static, +{ sp_tracing::try_init_simple(); - let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob]; - let validator_set = ValidatorSet::new(make_beefy_ids(&peers), 0).unwrap(); + let peers = [Keyring::Alice, Keyring::Bob]; + let validator_set = + ValidatorSet::new(::make_beefy_ids(&peers), 0).unwrap(); let session_len = 10; let min_block_delta = 4; - let mut net = BeefyTestNet::new(2); + let mut net: BeefyTestNet = BeefyTestNet::new(2); let api = Arc::new(two_validators::TestApi {}); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); - tokio::spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); + tokio::spawn(initialize_beefy::< + two_validators::TestApi, + AuthId, + TSignature, + TBeefyKeystore, + TKeyPair, + >(&mut net, beefy_peers, min_block_delta)); // push 42 blocks including `AuthorityChange` digests every 10 blocks. let hashes = net.generate_blocks_and_sync(42, session_len, &validator_set, true).await; @@ -573,18 +812,56 @@ async fn beefy_finalizing_blocks() { } #[tokio::test] -async fn lagging_validators() { +async fn beefy_finalizing_blocks_using_ecdsa_signature() { + beefy_finalizing_blocks::() + .await; +} + +#[tokio::test] +async fn beefy_finalizing_blocks_using_ecdsa_n_bls_signature() { + beefy_finalizing_blocks::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >() + .await; +} + +async fn lagging_validators() +where + TKeyPair: SimpleKeyPair + SimpleKeyPair + 'static, + TBeefyKeystore: BeefyKeystore + 'static, + AuthId: Clone + + Encode + + Decode + + Debug + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + std::cmp::PartialEq + 'static, +{ sp_tracing::try_init_simple(); - let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob]; - let validator_set = ValidatorSet::new(make_beefy_ids(&peers), 0).unwrap(); + let peers = [Keyring::Alice, Keyring::Bob]; + let validator_set = + ValidatorSet::new(::make_beefy_ids(&peers), 0).unwrap(); let session_len = 30; let min_block_delta = 1; - let mut net = BeefyTestNet::new(2); + let mut net: BeefyTestNet = BeefyTestNet::new(2); let api = Arc::new(two_validators::TestApi {}); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); - tokio::spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); + tokio::spawn(initialize_beefy::< + two_validators::TestApi, + AuthId, + TSignature, + TBeefyKeystore, + TKeyPair, + >(&mut net, beefy_peers, min_block_delta)); // push 62 blocks including `AuthorityChange` digests every 30 blocks. let hashes = net.generate_blocks_and_sync(62, session_len, &validator_set, true).await; @@ -649,29 +926,72 @@ async fn lagging_validators() { } #[tokio::test] -async fn correct_beefy_payload() { +async fn lagging_validators_with_ecdsa_crypto() { + lagging_validators::().await; +} + +#[tokio::test] +async fn lagging_validators_with_ecdsa_n_bls_crypto() { + lagging_validators::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >() + .await; +} + +async fn correct_beefy_payload() +where + TKeyPair: SimpleKeyPair + SimpleKeyPair + 'static, + TBeefyKeystore: BeefyKeystore + 'static, + AuthId: Clone + + Encode + + Decode + + Debug + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + std::cmp::PartialEq + 'static, +{ sp_tracing::try_init_simple(); - let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie, BeefyKeyring::Dave]; - let validator_set = ValidatorSet::new(make_beefy_ids(&peers), 0).unwrap(); + let peers = [Keyring::Alice, Keyring::Bob, Keyring::Charlie, Keyring::Dave]; + let validator_set = + ValidatorSet::new(::make_beefy_ids(&peers), 0).unwrap(); let session_len = 20; let min_block_delta = 2; - let mut net = BeefyTestNet::new(4); + let mut net: BeefyTestNet = BeefyTestNet::new(4); // Alice, Bob, Charlie will vote on good payloads let good_api = Arc::new(four_validators::TestApi {}); - let good_peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie] + let good_peers = [Keyring::Alice, Keyring::Bob, Keyring::Charlie] .iter() .enumerate() .map(|(id, key)| (id, key, good_api.clone())) .collect(); - tokio::spawn(initialize_beefy(&mut net, good_peers, min_block_delta)); + tokio::spawn(initialize_beefy::< + four_validators::TestApi, + AuthId, + TSignature, + TBeefyKeystore, + TKeyPair, + >(&mut net, good_peers, min_block_delta)); // Dave will vote on bad mmr roots let bad_api = Arc::new(bad_four_validators::TestApi {}); - let bad_peers = vec![(3, &BeefyKeyring::Dave, bad_api)]; - tokio::spawn(initialize_beefy(&mut net, bad_peers, min_block_delta)); + let bad_peers = vec![(3, &Keyring::Dave, bad_api)]; + tokio::spawn(initialize_beefy::< + bad_four_validators::TestApi, + AuthId, + TSignature, + TBeefyKeystore, + TKeyPair, + >(&mut net, bad_peers, min_block_delta)); // push 12 blocks let hashes = net.generate_blocks_and_sync(12, session_len, &validator_set, false).await; @@ -682,7 +1002,7 @@ async fn correct_beefy_payload() { finalize_block_and_wait_for_beefy(&net, peers, &[hashes[1], hashes[10]], &[1, 9]).await; let (best_blocks, versioned_finality_proof) = - get_beefy_streams(&mut net.lock(), [(0, BeefyKeyring::Alice)].into_iter()); + get_beefy_streams(&mut net.lock(), [(0, Keyring::Alice)].into_iter()); // now 2 good validators and 1 bad one are voting let hashof11 = hashes[11]; @@ -697,7 +1017,7 @@ async fn correct_beefy_payload() { // 3rd good validator catches up and votes as well let (best_blocks, versioned_finality_proof) = - get_beefy_streams(&mut net.lock(), [(0, BeefyKeyring::Alice)].into_iter()); + get_beefy_streams(&mut net.lock(), [(0, Keyring::Alice)].into_iter()); net.lock().peer(2).client().as_client().finalize_block(hashof11, None).unwrap(); // verify consensus is reached @@ -706,14 +1026,44 @@ async fn correct_beefy_payload() { } #[tokio::test] -async fn beefy_importing_blocks() { - use futures::{future::poll_fn, task::Poll}; +async fn correct_beefy_payload_with_ecdsa_signature() { + correct_beefy_payload::().await; +} + +#[tokio::test] +async fn correct_beefy_payload_with_ecdsa_n_bls_signature() { + correct_beefy_payload::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >() + .await; +} + +async fn beefy_importing_blocks() +where + TKeyPair: SimpleKeyPair + SimpleKeyPair + 'static, + TBeefyKeystore: BeefyKeystore + 'static, + AuthId: Clone + + Encode + + Decode + + Debug + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + std::cmp::PartialEq + 'static, +{ + use futures::future::poll_fn; use sc_block_builder::BlockBuilderProvider; use sc_client_api::BlockBackend; sp_tracing::try_init_simple(); - let mut net = BeefyTestNet::new(2); + let mut net: BeefyTestNet = BeefyTestNet::new(2); let client = net.peer(0).client().clone(); let (mut block_import, _, peer_data) = net.make_block_import(client.clone()); @@ -769,10 +1119,15 @@ async fn beefy_importing_blocks() { // Import with valid justification. let parent_id = BlockId::Number(1); let block_num = 2; - let keys = &[BeefyKeyring::Alice, BeefyKeyring::Bob]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let proof = crate::justification::tests::new_finality_proof(block_num, &validator_set, keys); - let versioned_proof: VersionedFinalityProof, Signature> = proof.into(); + let keys = &[Keyring::Alice, Keyring::Bob]; + let validator_set = + ValidatorSet::new(::make_beefy_ids(keys), 0).unwrap(); + let proof = crate::justification::tests::new_finality_proof::( + block_num, + &validator_set, + keys, + ); + let versioned_proof: VersionedFinalityProof, TSignature> = proof.into(); let encoded = versioned_proof.encode(); let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded))); @@ -813,10 +1168,15 @@ async fn beefy_importing_blocks() { // Import with invalid justification (incorrect validator set). let parent_id = BlockId::Number(2); let block_num = 3; - let keys = &[BeefyKeyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap(); - let proof = crate::justification::tests::new_finality_proof(block_num, &validator_set, keys); - let versioned_proof: VersionedFinalityProof, Signature> = proof.into(); + let keys = &[Keyring::Alice]; + let validator_set = + ValidatorSet::new(::make_beefy_ids(keys), 1).unwrap(); + let proof = crate::justification::tests::new_finality_proof::( + block_num, + &validator_set, + keys, + ); + let versioned_proof: VersionedFinalityProof, TSignature> = proof.into(); let encoded = versioned_proof.encode(); let justif = Some(Justifications::from((BEEFY_ENGINE_ID, encoded))); @@ -853,21 +1213,58 @@ async fn beefy_importing_blocks() { } #[tokio::test] -async fn voter_initialization() { +async fn beefy_importing_blocks_with_ecdsa_signature() { + beefy_importing_blocks::().await; +} + +#[tokio::test] +async fn beefy_importing_blocks_with_ecdsa_n_bls_signature() { + beefy_importing_blocks::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >() + .await; +} + +async fn voter_initialization() +where + TKeyPair: SimpleKeyPair + SimpleKeyPair + 'static, + TBeefyKeystore: BeefyKeystore + 'static, + AuthId: Clone + + Encode + + Decode + + Debug + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + std::cmp::PartialEq + 'static, +{ sp_tracing::try_init_simple(); // Regression test for voter initialization where finality notifications were dropped // after waiting for BEEFY pallet availability. - let peers = [BeefyKeyring::Alice, BeefyKeyring::Bob]; - let validator_set = ValidatorSet::new(make_beefy_ids(&peers), 0).unwrap(); + let peers = [Keyring::Alice, Keyring::Bob]; + let validator_set = + ValidatorSet::new(::make_beefy_ids(&peers), 0).unwrap(); let session_len = 5; // Should vote on all mandatory blocks no matter the `min_block_delta`. let min_block_delta = 10; - let mut net = BeefyTestNet::new(2); + let mut net: BeefyTestNet = BeefyTestNet::new(2); let api = Arc::new(two_validators::TestApi {}); let beefy_peers = peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); - tokio::spawn(initialize_beefy(&mut net, beefy_peers, min_block_delta)); + tokio::spawn(initialize_beefy::< + two_validators::TestApi, + AuthId, + TSignature, + TBeefyKeystore, + TKeyPair, + >(&mut net, beefy_peers, min_block_delta)); // push 26 blocks let hashes = net.generate_blocks_and_sync(26, session_len, &validator_set, false).await; @@ -886,29 +1283,70 @@ async fn voter_initialization() { } #[tokio::test] -async fn on_demand_beefy_justification_sync() { +async fn voter_initialization_with_ecdsa_crypto() { + voter_initialization::().await; +} + +#[tokio::test] +async fn voter_initialization_with_ecdsa_n_bls_crypto() { + voter_initialization::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >() + .await; +} + +async fn on_demand_beefy_justification_sync() +where + TKeyPair: SimpleKeyPair + SimpleKeyPair + 'static, + TBeefyKeystore: BeefyKeystore + 'static, + AuthId: Clone + + Encode + + Decode + + Debug + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + std::cmp::PartialEq + 'static, +{ sp_tracing::try_init_simple(); - let all_peers = - [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie, BeefyKeyring::Dave]; - let validator_set = ValidatorSet::new(make_beefy_ids(&all_peers), 0).unwrap(); + let all_peers = [Keyring::Alice, Keyring::Bob, Keyring::Charlie, Keyring::Dave]; + let validator_set = + ValidatorSet::new(::make_beefy_ids(&all_peers), 0).unwrap(); let session_len = 5; let min_block_delta = 5; - let mut net = BeefyTestNet::new(4); + let mut net: BeefyTestNet = BeefyTestNet::new(4); // Alice, Bob, Charlie start first and make progress through voting. let api = Arc::new(four_validators::TestApi {}); - let fast_peers = [BeefyKeyring::Alice, BeefyKeyring::Bob, BeefyKeyring::Charlie]; + let fast_peers = [Keyring::Alice, Keyring::Bob, Keyring::Charlie]; let voting_peers = fast_peers.iter().enumerate().map(|(id, key)| (id, key, api.clone())).collect(); - tokio::spawn(initialize_beefy(&mut net, voting_peers, min_block_delta)); + tokio::spawn(initialize_beefy::< + four_validators::TestApi, + AuthId, + TSignature, + TBeefyKeystore, + TKeyPair, + >(&mut net, voting_peers, min_block_delta)); // Dave will start late and have to catch up using on-demand justification requests (since // in this test there is no block import queue to automatically import justifications). - let dave = vec![(3, &BeefyKeyring::Dave, api)]; + let dave = vec![(3, &Keyring::Dave, api)]; // Instantiate but don't run Dave, yet. - let dave_task = initialize_beefy(&mut net, dave, min_block_delta); + let dave_task = + initialize_beefy::( + &mut net, + dave, + min_block_delta, + ); let dave_index = 3; // push 30 blocks @@ -933,7 +1371,7 @@ async fn on_demand_beefy_justification_sync() { run_for(Duration::from_millis(400), &net).await; let (dave_best_blocks, _) = - get_beefy_streams(&mut net.lock(), [(dave_index, BeefyKeyring::Dave)].into_iter()); + get_beefy_streams(&mut net.lock(), [(dave_index, Keyring::Dave)].into_iter()); let client = net.lock().peer(dave_index).client().as_client(); client.finalize_block(hashes[1], None).unwrap(); // Give Dave task some cpu cycles to process the finality notification, @@ -951,7 +1389,7 @@ async fn on_demand_beefy_justification_sync() { // then verify Dave catches up through on-demand justification requests. finalize_block_and_wait_for_beefy( &net, - [(dave_index, BeefyKeyring::Dave)].into_iter(), + [(dave_index, Keyring::Dave)].into_iter(), &[hashes[6], hashes[10], hashes[17], hashes[24], hashes[26]], &[5, 10, 15, 20, 25], ) @@ -963,10 +1401,47 @@ async fn on_demand_beefy_justification_sync() { } #[tokio::test] -async fn should_initialize_voter_at_genesis() { - let keys = &[BeefyKeyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); +async fn on_demand_beefy_justification_sync_with_ecdsa_signature() { + on_demand_beefy_justification_sync::< + ECDSAKeyPair, + ECDSAPublic, + ECDSASignature, + BeefyECDSAKeystore, + >() + .await; +} + +#[tokio::test] +async fn on_demand_beefy_justification_sync_with_ecdsa_n_bls_signature() { + on_demand_beefy_justification_sync::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >() + .await; +} + +async fn should_initialize_voter_at_genesis() +where + TKeyPair: SimpleKeyPair + SimpleKeyPair + 'static, + TBeefyKeystore: BeefyKeystore + 'static, + AuthId: Clone + + Encode + + Decode + + Debug + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + std::cmp::PartialEq + 'static, +{ + let keys = &[Keyring::Alice]; + let validator_set = + ValidatorSet::new(::make_beefy_ids(keys), 0).unwrap(); + let mut net: BeefyTestNet = BeefyTestNet::new(1); let backend = net.peer(0).client().as_backend(); // push 15 blocks with `AuthorityChange` digests every 10 blocks @@ -1007,10 +1482,52 @@ async fn should_initialize_voter_at_genesis() { } #[tokio::test] -async fn should_initialize_voter_when_last_final_is_session_boundary() { - let keys = &[BeefyKeyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); +async fn should_initialize_voter_at_genesis_with_ecdsa_signature() { + should_initialize_voter_at_genesis::< + ECDSAKeyPair, + ECDSAPublic, + ECDSASignature, + BeefyECDSAKeystore, + >() + .await; +} + +#[tokio::test] +async fn should_initialize_voter_at_genesis_with_ecdsa_n_bls_signature() { + should_initialize_voter_at_genesis::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >() + .await; +} + +async fn should_initialize_voter_when_last_final_is_session_boundary< + TKeyPair, + AuthId, + TSignature, + TBeefyKeystore, +>() +where + TKeyPair: SimpleKeyPair + SimpleKeyPair + 'static, + TBeefyKeystore: BeefyKeystore + 'static, + AuthId: Clone + + Encode + + Decode + + Debug + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + std::cmp::PartialEq + 'static, +{ + let keys = &[Keyring::Alice]; + let validator_set = + ValidatorSet::new(::make_beefy_ids(keys), 0).unwrap(); + let mut net: BeefyTestNet = BeefyTestNet::new(1); let backend = net.peer(0).client().as_backend(); // push 15 blocks with `AuthorityChange` digests every 10 blocks @@ -1027,7 +1544,7 @@ async fn should_initialize_voter_when_last_final_is_session_boundary() { block_number: 10, validator_set_id: validator_set.id(), }; - let justif = VersionedFinalityProof::<_, Signature>::V1(SignedCommitment { + let justif = VersionedFinalityProof::<_, TSignature>::V1(SignedCommitment { commitment, signatures: vec![None], }); @@ -1065,10 +1582,47 @@ async fn should_initialize_voter_when_last_final_is_session_boundary() { } #[tokio::test] -async fn should_initialize_voter_at_latest_finalized() { - let keys = &[BeefyKeyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); +async fn should_initialize_voter_when_last_final_is_session_boundary_with_ecdsa_signature() { + should_initialize_voter_when_last_final_is_session_boundary::< + ECDSAKeyPair, + ECDSAPublic, + ECDSASignature, + BeefyECDSAKeystore, + >() + .await; +} + +#[tokio::test] +async fn should_initialize_voter_when_last_final_is_session_boundary_with_ecdsa_n_bls_signature() { + should_initialize_voter_when_last_final_is_session_boundary::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >() + .await; +} + +async fn should_initialize_voter_at_latest_finalized() +where + TKeyPair: SimpleKeyPair + SimpleKeyPair + 'static, + TBeefyKeystore: BeefyKeystore + 'static, + AuthId: Clone + + Encode + + Decode + + Debug + + Ord + + Sync + + Send + + BeefyAuthIdMaker + + std::hash::Hash + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + std::cmp::PartialEq + 'static, +{ + let keys = &[Keyring::Alice]; + let validator_set = + ValidatorSet::new(::make_beefy_ids(keys), 0).unwrap(); + let mut net: BeefyTestNet = BeefyTestNet::new(1); let backend = net.peer(0).client().as_backend(); // push 15 blocks with `AuthorityChange` digests every 10 blocks @@ -1085,7 +1639,7 @@ async fn should_initialize_voter_at_latest_finalized() { block_number: 12, validator_set_id: validator_set.id(), }; - let justif = VersionedFinalityProof::<_, Signature>::V1(SignedCommitment { + let justif = VersionedFinalityProof::<_, TSignature>::V1(SignedCommitment { commitment, signatures: vec![None], }); @@ -1119,3 +1673,25 @@ async fn should_initialize_voter_at_latest_finalized() { let state = load_persistent(&*backend).unwrap().unwrap(); assert_eq!(state, persisted_state); } + +#[tokio::test] +async fn should_initialize_voter_at_latest_finalized_with_ecdsa_signature() { + should_initialize_voter_at_latest_finalized::< + ECDSAKeyPair, + ECDSAPublic, + ECDSASignature, + BeefyECDSAKeystore, + >() + .await; +} + +#[tokio::test] +async fn should_initialize_voter_at_latest_finalized_with_ecdsa_n_bls_signature() { + should_initialize_voter_at_latest_finalized::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >() + .await; +} diff --git a/client/beefy/src/worker.rs b/client/beefy/src/worker.rs index 19ab52f520225..335aff64ff817 100644 --- a/client/beefy/src/worker.rs +++ b/client/beefy/src/worker.rs @@ -16,24 +16,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{ - communication::{ - gossip::{topic, GossipValidator}, - request_response::outgoing_requests_engine::OnDemandJustificationsEngine, - }, - error::Error, - justification::BeefyVersionedFinalityProof, - keystore::BeefyKeystore, - metric_inc, metric_set, - metrics::Metrics, - round::Rounds, - BeefyVoterLinks, LOG_TARGET, -}; -use beefy_primitives::{ - crypto::{AuthorityId, Signature}, - Commitment, ConsensusLog, Payload, PayloadProvider, SignedCommitment, ValidatorSet, - VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, +use std::{ + collections::{BTreeMap, VecDeque}, + fmt::Debug, + marker::PhantomData, + sync::Arc, }; + use codec::{Codec, Decode, Encode}; use futures::{stream::Fuse, FutureExt, StreamExt}; use log::{debug, error, info, log_enabled, trace, warn}; @@ -49,12 +38,26 @@ use sp_runtime::{ traits::{Block, ConstU32, Header, NumberFor, Zero}, BoundedVec, SaturatedConversion, }; -use std::{ - collections::{BTreeMap, BTreeSet, VecDeque}, - fmt::Debug, - marker::PhantomData, - sync::Arc, + +use beefy_primitives::{ + Commitment, ConsensusLog, Payload, PayloadProvider, SignedCommitment, ValidatorSet, + VersionedFinalityProof, VoteMessage, BEEFY_ENGINE_ID, +}; + +use crate::{ + communication::{ + gossip::{topic, GossipValidator}, + request_response::outgoing_requests_engine::OnDemandJustificationsEngine, + }, + error::Error, + justification::BeefyVersionedFinalityProof, + keystore::BeefyKeystore, + metric_inc, metric_set, + metrics::Metrics, + round::Rounds, + BeefyVoterLinks, LOG_TARGET, }; + /// Bound for the number of buffered future voting rounds. const MAX_BUFFERED_VOTE_ROUNDS: usize = 600; /// Bound for the number of buffered votes per round number. @@ -73,7 +76,11 @@ pub(crate) enum RoundAction { /// It chooses which incoming votes to accept and which votes to generate. /// Keeps track of voting seen for current and future rounds. #[derive(Debug, Decode, Encode, PartialEq)] -pub(crate) struct VoterOracle { +pub(crate) struct VoterOracle< + B: Block, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, +> { /// Queue of known sessions. Keeps track of voting rounds (block numbers) within each session. /// /// There are three voter states coresponding to three queue states: @@ -83,15 +90,20 @@ pub(crate) struct VoterOracle { /// 3. lagging behind GRANDPA: queue has [1, N] elements, where all `mandatory_done == false`. /// In this state, everytime a session gets its mandatory block BEEFY finalized, it's /// popped off the queue, eventually getting to state `2. up-to-date`. - sessions: VecDeque>, + sessions: VecDeque>, /// Min delta in block numbers between two blocks, BEEFY should vote on. min_block_delta: u32, } -impl VoterOracle { +impl< + B: Block, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + > VoterOracle +{ /// Verify provided `sessions` satisfies requirements, then build `VoterOracle`. pub fn checked_new( - sessions: VecDeque>, + sessions: VecDeque>, min_block_delta: u32, ) -> Option { let mut prev_start = Zero::zero(); @@ -136,13 +148,13 @@ impl VoterOracle { // Return reference to rounds pertaining to first session in the queue. // Voting will always happen at the head of the queue. - fn active_rounds(&self) -> Option<&Rounds> { + fn active_rounds(&self) -> Option<&Rounds> { self.sessions.front() } // Return mutable reference to rounds pertaining to first session in the queue. // Voting will always happen at the head of the queue. - fn active_rounds_mut(&mut self) -> Option<&mut Rounds> { + fn active_rounds_mut(&mut self) -> Option<&mut Rounds> { self.sessions.front_mut() } @@ -157,7 +169,7 @@ impl VoterOracle { } /// Add new observed session to the Oracle. - pub fn add_session(&mut self, rounds: Rounds) { + pub fn add_session(&mut self, rounds: Rounds) { self.sessions.push_back(rounds); // Once we add a new session we can drop/prune previous session if it's been finalized. self.try_prune(); @@ -173,7 +185,7 @@ impl VoterOracle { } /// Return current pending mandatory block, if any, plus its active validator set. - pub fn mandatory_pending(&self) -> Option<(NumberFor, ValidatorSet)> { + pub fn mandatory_pending(&self) -> Option<(NumberFor, ValidatorSet)> { self.sessions.front().and_then(|round| { if round.mandatory_done() { None @@ -245,35 +257,52 @@ impl VoterOracle { } } -pub(crate) struct WorkerParams { +pub(crate) struct WorkerParams< + B: Block, + BE, + P, + N, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + BKS: BeefyKeystore, +> { pub backend: Arc, pub payload_provider: P, pub network: N, - pub key_store: BeefyKeystore, + pub key_store: BKS, pub gossip_engine: GossipEngine, - pub gossip_validator: Arc>, - pub on_demand_justifications: OnDemandJustificationsEngine, - pub links: BeefyVoterLinks, + pub gossip_validator: Arc>, + pub on_demand_justifications: OnDemandJustificationsEngine, + pub links: BeefyVoterLinks, pub metrics: Option, - pub persisted_state: PersistedState, + pub persisted_state: PersistedState, } #[derive(Debug, Decode, Encode, PartialEq)] -pub(crate) struct PersistedState { +pub(crate) struct PersistedState< + B: Block, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, +> { /// Best block we received a GRANDPA finality for. best_grandpa_block_header: ::Header, /// Best block a BEEFY voting round has been concluded for. best_beefy_block: NumberFor, /// Chooses which incoming votes to accept and which votes to generate. /// Keeps track of voting seen for current and future rounds. - voting_oracle: VoterOracle, + voting_oracle: VoterOracle, } -impl PersistedState { +impl< + B: Block, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + > PersistedState +{ pub fn checked_new( grandpa_header: ::Header, best_beefy: NumberFor, - sessions: VecDeque>, + sessions: VecDeque>, min_block_delta: u32, ) -> Option { VoterOracle::checked_new(sessions, min_block_delta).map(|voting_oracle| PersistedState { @@ -293,21 +322,29 @@ impl PersistedState { } /// A BEEFY worker plays the BEEFY protocol -pub(crate) struct BeefyWorker { +pub(crate) struct BeefyWorker< + B: Block, + BE, + P, + N, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + BKS: BeefyKeystore, +> { // utilities backend: Arc, payload_provider: P, network: N, - key_store: BeefyKeystore, + key_store: BKS, // communication gossip_engine: GossipEngine, - gossip_validator: Arc>, - on_demand_justifications: OnDemandJustificationsEngine, + gossip_validator: Arc>, + on_demand_justifications: OnDemandJustificationsEngine, // channels /// Links between the block importer, the background voter and the RPC layer. - links: BeefyVoterLinks, + links: BeefyVoterLinks, // voter state /// BEEFY client metrics. @@ -316,22 +353,25 @@ pub(crate) struct BeefyWorker { pending_votes: BTreeMap< NumberFor, BoundedVec< - VoteMessage, AuthorityId, Signature>, + VoteMessage, AuthId, TSignature>, ConstU32, >, >, /// Buffer holding justifications for future processing. - pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, + pending_justifications: BTreeMap, BeefyVersionedFinalityProof>, /// Persisted voter state. - persisted_state: PersistedState, + persisted_state: PersistedState, } -impl BeefyWorker +impl BeefyWorker where B: Block + Codec, BE: Backend, P: PayloadProvider, N: NetworkEventStream + NetworkRequest + SyncOracle + Send + Sync + Clone + 'static, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + BKS: BeefyKeystore, { /// Return a new BEEFY worker instance. /// @@ -339,7 +379,7 @@ where /// BEEFY pallet has been deployed on-chain. /// /// The BEEFY pallet is needed in order to keep track of the BEEFY authority set. - pub(crate) fn new(worker_params: WorkerParams) -> Self { + pub(crate) fn new(worker_params: WorkerParams) -> Self { let WorkerParams { backend, payload_provider, @@ -377,11 +417,11 @@ where self.persisted_state.best_beefy_block } - fn voting_oracle(&self) -> &VoterOracle { + fn voting_oracle(&self) -> &VoterOracle { &self.persisted_state.voting_oracle } - fn active_rounds(&mut self) -> Option<&Rounds> { + fn active_rounds(&mut self) -> Option<&Rounds> { self.persisted_state.voting_oracle.active_rounds() } @@ -396,26 +436,22 @@ where fn verify_validator_set( &self, block: &NumberFor, - active: &ValidatorSet, + active: &ValidatorSet, ) -> Result<(), Error> { - let active: BTreeSet<&AuthorityId> = active.validators().iter().collect(); - - let public_keys = self.key_store.public_keys()?; - let store: BTreeSet<&AuthorityId> = public_keys.iter().collect(); - - if store.intersection(&active).count() == 0 { - let msg = "no authority public key found in store".to_string(); - debug!(target: LOG_TARGET, "🥩 for block {:?} {}", block, msg); - Err(Error::Keystore(msg)) - } else { - Ok(()) + match self.key_store.authority_id(active.validators()) { + None => { + let msg = "no authority public key found in store".to_string(); + debug!(target: LOG_TARGET, "🥩 for block {:?} {}", block, msg); + Err(Error::Keystore(msg)) + }, + Some(_auth_id) => Ok(()), } } /// Handle session changes by starting new voting round for mandatory blocks. fn init_session_at( &mut self, - validator_set: ValidatorSet, + validator_set: ValidatorSet, new_session_start: NumberFor, ) { debug!(target: LOG_TARGET, "🥩 New active validator set: {:?}", validator_set); @@ -472,7 +508,7 @@ where }) .chain(std::iter::once(header.clone())) { - if let Some(new_validator_set) = find_authorities_change::(&header) { + if let Some(new_validator_set) = find_authorities_change::(&header) { self.init_session_at(new_validator_set, *header.number()); } } @@ -482,7 +518,7 @@ where /// Based on [VoterOracle] this vote is either processed here or enqueued for later. fn triage_incoming_vote( &mut self, - vote: VoteMessage, AuthorityId, Signature>, + vote: VoteMessage, AuthId, TSignature>, ) -> Result<(), Error> { let block_num = vote.commitment.block_number; let best_grandpa = self.best_grandpa_block(); @@ -516,7 +552,7 @@ where /// Expects `justification` to be valid. fn triage_incoming_justif( &mut self, - justification: BeefyVersionedFinalityProof, + justification: BeefyVersionedFinalityProof, ) -> Result<(), Error> { let signed_commitment = match justification { VersionedFinalityProof::V1(ref sc) => sc, @@ -547,7 +583,7 @@ where fn handle_vote( &mut self, round: (Payload, NumberFor), - vote: (AuthorityId, Signature), + vote: (AuthId, TSignature), self_vote: bool, ) -> Result<(), Error> { self.gossip_validator.note_round(round.1); @@ -607,7 +643,10 @@ where /// 4. Send best block hash and `finality_proof` to RPC worker. /// /// Expects `finality proof` to be valid. - fn finalize(&mut self, finality_proof: BeefyVersionedFinalityProof) -> Result<(), Error> { + fn finalize( + &mut self, + finality_proof: BeefyVersionedFinalityProof, + ) -> Result<(), Error> { let block_num = match finality_proof { VersionedFinalityProof::V1(ref sc) => sc.commitment.block_number, }; @@ -801,7 +840,7 @@ where target: LOG_TARGET, "🥩 Produced signature using {:?}, is_valid: {:?}", authority_id, - BeefyKeystore::verify(&authority_id, &signature, &encoded_commitment) + BKS::verify(&authority_id, &signature, &encoded_commitment) ); let message = VoteMessage { commitment, id: authority_id, signature }; @@ -852,7 +891,9 @@ where /// which is driven by finality notifications and gossiped votes. pub(crate) async fn run( mut self, - mut block_import_justif: Fuse>>, + mut block_import_justif: Fuse< + NotificationReceiver>, + >, mut finality_notifications: Fuse>, ) { info!( @@ -867,7 +908,7 @@ where .filter_map(|notification| async move { trace!(target: LOG_TARGET, "🥩 Got vote message: {:?}", notification); - VoteMessage::, AuthorityId, Signature>::decode( + VoteMessage::, AuthId, TSignature>::decode( &mut ¬ification.message[..], ) .ok() @@ -938,13 +979,14 @@ where /// Scan the `header` digest log for a BEEFY validator set change. Return either the new /// validator set or `None` in case no validator set change has been signaled. -pub(crate) fn find_authorities_change(header: &B::Header) -> Option> +pub(crate) fn find_authorities_change(header: &B::Header) -> Option> where B: Block, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, { let id = OpaqueDigestItemId::Consensus(&BEEFY_ENGINE_ID); - let filter = |log: ConsensusLog| match log { + let filter = |log: ConsensusLog| match log { ConsensusLog::AuthoritiesChange(validator_set) => Some(validator_set), _ => None, }; @@ -992,14 +1034,23 @@ pub(crate) mod tests { use super::*; use crate::{ communication::notification::{BeefyBestBlockStream, BeefyVersionedFinalityProofStream}, - keystore::tests::Keyring, + keystore::{ + tests::{ECDSAnBLSPair, GenericKeyring, Keyring, SimpleKeyPair}, + BeefyBLSnECDSAKeystore, BeefyECDSAKeystore, + }, tests::{ - create_beefy_keystore, get_beefy_streams, make_beefy_ids, two_validators::TestApi, + create_beefy_keystore, get_beefy_streams, two_validators::TestApi, BeefyAuthIdMaker, BeefyPeer, BeefyTestNet, }, BeefyRPCLinks, KnownPeers, }; - use beefy_primitives::{known_payloads, mmr::MmrRootProvider}; + + use beefy_primitives::{ + bls_crypto::{Public as BLSPublic, Signature as BLSSignature}, + ecdsa_crypto::{Pair as ECDSAKeyPair, Public as ECDSAPublic, Signature as ECDSASignature}, + known_payloads, + mmr::MmrRootProvider, + }; use futures::{future::poll_fn, task::Poll}; use parking_lot::Mutex; use sc_client_api::{Backend as BackendT, HeaderBackend}; @@ -1013,12 +1064,17 @@ pub(crate) mod tests { Backend, }; - impl PersistedState { - pub fn voting_oracle(&self) -> &VoterOracle { + impl PersistedState + where + B: super::Block, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + { + pub fn voting_oracle(&self) -> &VoterOracle { &self.voting_oracle } - pub fn active_round(&self) -> Option<&Rounds> { + pub fn active_round(&self) -> Option<&Rounds> { self.voting_oracle.active_rounds() } @@ -1031,32 +1087,54 @@ pub(crate) mod tests { } } - impl VoterOracle { - pub fn sessions(&self) -> &VecDeque> { + impl< + B: super::Block, + AuthId: Encode + Decode + Debug + Clone + Ord + Sync + Send + std::hash::Hash, + TSignature: Encode + Decode + Debug + Clone + Sync + Send, + > VoterOracle + { + pub fn sessions(&self) -> &VecDeque> { &self.sessions } } - fn create_beefy_worker( - peer: &BeefyPeer, + fn create_beefy_worker( + peer: &BeefyPeer, key: &Keyring, min_block_delta: u32, - genesis_validator_set: ValidatorSet, + genesis_validator_set: ValidatorSet, ) -> BeefyWorker< Block, Backend, MmrRootProvider, Arc>, - > { - let keystore = create_beefy_keystore(*key); + AuthId, + TSignature, + BKS, + > + where + TKeyPair: Sync + Send + SimpleKeyPair, + AuthId: Encode + + Decode + + Debug + + Clone + + Ord + + Sync + + Send + + std::hash::Hash + + BeefyAuthIdMaker + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + 'static, + BKS: BeefyKeystore + 'static, + { + let keystore = create_beefy_keystore::(*key); let (to_rpc_justif_sender, from_voter_justif_stream) = - BeefyVersionedFinalityProofStream::::channel(); + BeefyVersionedFinalityProofStream::::channel(); let (to_rpc_best_block_sender, from_voter_best_beefy_stream) = BeefyBestBlockStream::::channel(); let (_, from_block_import_justif_stream) = - BeefyVersionedFinalityProofStream::::channel(); - + BeefyVersionedFinalityProofStream::::channel(); let beefy_rpc_links = BeefyRPCLinks { from_voter_justif_stream, from_voter_best_beefy_stream }; *peer.data.beefy_rpc_links.lock() = Some(beefy_rpc_links); @@ -1103,7 +1181,7 @@ pub(crate) mod tests { on_demand_justifications, persisted_state, }; - BeefyWorker::<_, _, _, _>::new(worker_params) + BeefyWorker::<_, _, _, _, _, _, _>::new(worker_params) } #[test] @@ -1198,15 +1276,31 @@ pub(crate) mod tests { assert_eq!(Some(1072), t); } - #[test] - fn should_vote_target() { - let mut oracle = VoterOracle:: { min_block_delta: 1, sessions: VecDeque::new() }; + fn should_vote_target() + where + AuthId: Encode + + Decode + + Debug + + Clone + + Ord + + Sync + + Send + + std::hash::Hash + + BeefyAuthIdMaker + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + 'static, + { + let mut oracle = VoterOracle:: { + min_block_delta: 1, + sessions: VecDeque::new(), + }; // rounds not initialized -> should vote: `None` assert_eq!(oracle.voting_target(0, 1), None); let keys = &[Keyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let validator_set = + ValidatorSet::new(::make_beefy_ids(keys), 0).unwrap(); oracle.add_session(Rounds::new(1, validator_set.clone())); @@ -1238,11 +1332,37 @@ pub(crate) mod tests { } #[test] - fn test_oracle_accepted_interval() { + fn should_vote_target_with_ecdsa_keys() { + should_vote_target::(); + } + + #[test] + fn should_vote_target_with_ecdsa_n_bls_keys() { + should_vote_target::<(ECDSAPublic, BLSPublic), (ECDSASignature, BLSSignature)>(); + } + + fn test_oracle_accepted_interval() + where + AuthId: Encode + + Decode + + Debug + + Clone + + Ord + + Sync + + Send + + std::hash::Hash + + BeefyAuthIdMaker + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + 'static, + { let keys = &[Keyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let validator_set = + ValidatorSet::new(::make_beefy_ids(keys), 0).unwrap(); - let mut oracle = VoterOracle:: { min_block_delta: 1, sessions: VecDeque::new() }; + let mut oracle = VoterOracle:: { + min_block_delta: 1, + sessions: VecDeque::new(), + }; // rounds not initialized -> should accept votes: `None` assert!(oracle.accepted_interval(1).is_err()); @@ -1300,7 +1420,28 @@ pub(crate) mod tests { } #[test] - fn extract_authorities_change_digest() { + fn test_oracle_accepted_interval_with_ecdsa_keys() { + test_oracle_accepted_interval::(); + } + + #[test] + fn test_oracle_accepted_interval_with_ecdsa_n_bls_keys() { + test_oracle_accepted_interval::<(ECDSAPublic, BLSPublic), (ECDSASignature, BLSSignature)>(); + } + + fn extract_authorities_change_digest() + where + AuthId: Encode + + Decode + + Debug + + Clone + + Ord + + Sync + + Send + + std::hash::Hash + + BeefyAuthIdMaker + + 'static, + { let mut header = Header::new( 1u32.into(), Default::default(), @@ -1310,51 +1451,121 @@ pub(crate) mod tests { ); // verify empty digest shows nothing - assert!(find_authorities_change::(&header).is_none()); + assert!(find_authorities_change::(&header).is_none()); let peers = &[Keyring::One, Keyring::Two]; let id = 42; - let validator_set = ValidatorSet::new(make_beefy_ids(peers), id).unwrap(); + let validator_set = + ValidatorSet::new(::make_beefy_ids(peers), id).unwrap(); header.digest_mut().push(DigestItem::Consensus( BEEFY_ENGINE_ID, - ConsensusLog::::AuthoritiesChange(validator_set.clone()).encode(), + ConsensusLog::::AuthoritiesChange(validator_set.clone()).encode(), )); // verify validator set is correctly extracted from digest - let extracted = find_authorities_change::(&header); + let extracted = find_authorities_change::(&header); assert_eq!(extracted, Some(validator_set)); } - #[tokio::test] - async fn keystore_vs_validator_set() { + #[test] + fn extract_authorities_change_digest_with_ecdsa_keys() { + extract_authorities_change_digest::(); + } + + #[test] + fn extract_authorities_change_digest_with_ecdsa_n_bls_keys() { + extract_authorities_change_digest::<(ECDSAPublic, BLSPublic)>(); + } + + fn keystore_vs_validator_set() + where + TKeyPair: Sync + Send + SimpleKeyPair, + AuthId: Encode + + Decode + + Debug + + Clone + + Ord + + Sync + + Send + + std::hash::Hash + + BeefyAuthIdMaker + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + 'static, + BKS: BeefyKeystore + 'static, + { let keys = &[Keyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let validator_set = + ValidatorSet::new(::make_beefy_ids(keys), 0).unwrap(); let mut net = BeefyTestNet::new(1); - let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1, validator_set.clone()); + let mut worker = create_beefy_worker::( + &net.peer(0), + &keys[0], + 1, + validator_set.clone(), + ); // keystore doesn't contain other keys than validators' assert_eq!(worker.verify_validator_set(&1, &validator_set), Ok(())); // unknown `Bob` key let keys = &[Keyring::Bob]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let validator_set = + ValidatorSet::new(::make_beefy_ids(keys), 0).unwrap(); let err_msg = "no authority public key found in store".to_string(); let expected = Err(Error::Keystore(err_msg)); assert_eq!(worker.verify_validator_set(&1, &validator_set), expected); // worker has no keystore worker.key_store = None.into(); - let expected_err = Err(Error::Keystore("no Keystore".into())); + //let expected_err = Err(Error::Keystore("no Keystore".into())); + let expected_err = + Err(Error::Keystore("no authority public key found in store".to_string())); assert_eq!(worker.verify_validator_set(&1, &validator_set), expected_err); } #[tokio::test] - async fn should_finalize_correctly() { + async fn keystore_vs_validator_set_with_ecdsa_keys() { + keystore_vs_validator_set::( + ); + } + + #[tokio::test] + async fn keystore_vs_validator_set_with_ecdsa_n_bls_keys() { + keystore_vs_validator_set::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >(); + } + + async fn should_finalize_correctly() + where + TKeyPair: Sync + Send + SimpleKeyPair, + AuthId: Encode + + Decode + + Debug + + Clone + + Ord + + Sync + + Send + + std::hash::Hash + + BeefyAuthIdMaker + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + std::cmp::PartialEq + 'static, + BKS: BeefyKeystore + 'static, + { let keys = [Keyring::Alice]; - let validator_set = ValidatorSet::new(make_beefy_ids(&keys), 0).unwrap(); + let validator_set = + ValidatorSet::new(::make_beefy_ids(&keys), 0).unwrap(); let mut net = BeefyTestNet::new(1); let backend = net.peer(0).client().as_backend(); - let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1, validator_set.clone()); + let mut worker = create_beefy_worker::( + &net.peer(0), + &keys[0], + 1, + validator_set.clone(), + ); // remove default session, will manually add custom one. worker.persisted_state.voting_oracle.sessions.clear(); @@ -1449,11 +1660,49 @@ pub(crate) mod tests { } #[tokio::test] - async fn should_init_session() { + async fn should_finalize_correctly_with_ecdsa_keys() { + should_finalize_correctly::( + ) + .await; + } + + #[tokio::test] + async fn should_finalize_correctly_with_ecdsa_n_bls_keys() { + should_finalize_correctly::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >() + .await; + } + + async fn should_init_session() + where + TKeyPair: Sync + Send + SimpleKeyPair, + AuthId: Encode + + Decode + + Debug + + Clone + + Ord + + Sync + + Send + + std::hash::Hash + + BeefyAuthIdMaker + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + 'static, + BKS: BeefyKeystore + 'static, + { let keys = &[Keyring::Alice, Keyring::Bob]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); + let validator_set = + ValidatorSet::new(::make_beefy_ids(keys), 0).unwrap(); let mut net = BeefyTestNet::new(1); - let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1, validator_set.clone()); + let mut worker = create_beefy_worker::( + &net.peer(0), + &keys[0], + 1, + validator_set.clone(), + ); let worker_rounds = worker.active_rounds().unwrap(); assert_eq!(worker_rounds.session_start(), 1); @@ -1462,7 +1711,8 @@ pub(crate) mod tests { // new validator set let keys = &[Keyring::Bob]; - let new_validator_set = ValidatorSet::new(make_beefy_ids(keys), 1).unwrap(); + let new_validator_set = + ValidatorSet::new(::make_beefy_ids(keys), 1).unwrap(); worker.init_session_at(new_validator_set.clone(), 11); // Since mandatory is not done for old rounds, we still get those. @@ -1480,17 +1730,57 @@ pub(crate) mod tests { } #[tokio::test] - async fn should_triage_votes_and_process_later() { + async fn should_init_session_with_ecdsa_keys() { + should_init_session::() + .await; + } + + #[tokio::test] + async fn should_init_session_with_ecdsa_n_bls_keys() { + should_init_session::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >() + .await; + } + + async fn should_triage_votes_and_process_later() + where + TKeyPair: Sync + Send + SimpleKeyPair, + AuthId: Encode + + Decode + + Debug + + Clone + + Ord + + Sync + + Send + + std::hash::Hash + + BeefyAuthIdMaker + + 'static, + TSignature: Encode + Decode + Debug + Clone + Sync + Send + 'static, + BKS: BeefyKeystore + 'static, + { let keys = &[Keyring::Alice, Keyring::Bob]; - let validator_set = ValidatorSet::new(make_beefy_ids(keys), 0).unwrap(); - let mut net = BeefyTestNet::new(1); - let mut worker = create_beefy_worker(&net.peer(0), &keys[0], 1, validator_set.clone()); + let validator_set = + ValidatorSet::new(::make_beefy_ids(keys), 0).unwrap(); + let mut net: BeefyTestNet = BeefyTestNet::new(1); + let mut worker = create_beefy_worker::( + &net.peer(0), + &keys[0], + 1, + validator_set.clone(), + ); // remove default session, will manually add custom one. worker.persisted_state.voting_oracle.sessions.clear(); - fn new_vote( + fn new_vote( block_number: NumberFor, - ) -> VoteMessage, AuthorityId, Signature> { + ) -> VoteMessage, AuthId, TSignature> + where + TKeyPair: Sync + Send + SimpleKeyPair, + { let commitment = Commitment { payload: Payload::from_single_entry(*b"BF", vec![]), block_number, @@ -1498,8 +1788,11 @@ pub(crate) mod tests { }; VoteMessage { commitment, - id: Keyring::Alice.public(), - signature: Keyring::Alice.sign(b"I am committed"), + id: >::public(Keyring::Alice), + signature: >::sign( + Keyring::Alice, + b"I am committed", + ), } } @@ -1519,13 +1812,25 @@ pub(crate) mod tests { worker.persisted_state.best_grandpa_block_header = best_grandpa_header; // triage votes for blocks 10..13 - worker.triage_incoming_vote(new_vote(10)).unwrap(); - worker.triage_incoming_vote(new_vote(11)).unwrap(); - worker.triage_incoming_vote(new_vote(12)).unwrap(); + worker + .triage_incoming_vote(new_vote::(10)) + .unwrap(); + worker + .triage_incoming_vote(new_vote::(11)) + .unwrap(); + worker + .triage_incoming_vote(new_vote::(12)) + .unwrap(); // triage votes for blocks 20..23 - worker.triage_incoming_vote(new_vote(20)).unwrap(); - worker.triage_incoming_vote(new_vote(21)).unwrap(); - worker.triage_incoming_vote(new_vote(22)).unwrap(); + worker + .triage_incoming_vote(new_vote::(20)) + .unwrap(); + worker + .triage_incoming_vote(new_vote::(21)) + .unwrap(); + worker + .triage_incoming_vote(new_vote::(22)) + .unwrap(); // vote for 10 should have been handled, while the rest buffered for later processing let mut votes = worker.pending_votes.values(); @@ -1549,4 +1854,26 @@ pub(crate) mod tests { assert_eq!(votes.next().unwrap().first().unwrap().commitment.block_number, 21); assert_eq!(votes.next().unwrap().first().unwrap().commitment.block_number, 22); } + + #[tokio::test] + async fn should_triage_votes_and_process_later_with_ecdsa_keys() { + should_triage_votes_and_process_later::< + ECDSAKeyPair, + ECDSAPublic, + ECDSASignature, + BeefyECDSAKeystore, + >() + .await; + } + + #[tokio::test] + async fn should_triage_votes_and_process_later_with_ecdsa_n_bls_keys() { + should_triage_votes_and_process_later::< + ECDSAnBLSPair, + (ECDSAPublic, BLSPublic), + (ECDSASignature, BLSSignature), + BeefyBLSnECDSAKeystore, + >() + .await; + } } diff --git a/client/keystore/src/local.rs b/client/keystore/src/local.rs index 54ff6a5b164a8..26561f0347e5c 100644 --- a/client/keystore/src/local.rs +++ b/client/keystore/src/local.rs @@ -19,7 +19,7 @@ use async_trait::async_trait; use parking_lot::RwLock; -use sp_application_crypto::{ecdsa, ed25519, sr25519, AppKey, AppPair, IsWrappedBy}; +use sp_application_crypto::{bls, ecdsa, ed25519, sr25519, AppKey, AppPair, IsWrappedBy}; use sp_core::{ crypto::{ ByteArray, CryptoTypePublicPair, ExposeSecret, KeyTypeId, Pair as PairT, SecretString, @@ -114,6 +114,18 @@ impl CryptoStore for LocalKeystore { SyncCryptoStore::ecdsa_generate_new(self, id, seed) } + async fn bls_public_keys(&self, id: KeyTypeId) -> Vec { + SyncCryptoStore::bls_public_keys(self, id) + } + + async fn bls_generate_new( + &self, + id: KeyTypeId, + seed: Option<&str>, + ) -> std::result::Result { + SyncCryptoStore::bls_generate_new(self, id, seed) + } + async fn insert_unknown( &self, id: KeyTypeId, @@ -308,6 +320,32 @@ impl SyncCryptoStore for LocalKeystore { Ok(pair.public()) } + fn bls_public_keys(&self, key_type: KeyTypeId) -> Vec { + self.0 + .read() + .raw_public_keys(key_type) + .map(|v| { + v.into_iter() + .filter_map(|k| bls::Public::from_slice(k.as_slice()).ok()) + .collect() + }) + .unwrap_or_default() + } + + fn bls_generate_new( + &self, + id: KeyTypeId, + seed: Option<&str>, + ) -> std::result::Result { + let pair = match seed { + Some(seed) => self.0.write().insert_ephemeral_from_seed_by_type::(seed, id), + None => self.0.write().generate_by_type::(id), + } + .map_err(|e| -> TraitError { e.into() })?; + + Ok(pair.public()) + } + fn insert_unknown( &self, key_type: KeyTypeId, @@ -350,6 +388,16 @@ impl SyncCryptoStore for LocalKeystore { pair.map(|k| k.sign_prehashed(msg)).map(Ok).transpose() } + + fn bls_sign( + &self, + id: KeyTypeId, + public: &bls::Public, + msg: &[u8], + ) -> std::result::Result, TraitError> { + let pair = self.0.read().key_pair_by_type::(public, id)?; + pair.map(|k| k.sign(msg)).map(Ok).transpose() + } } impl Into for LocalKeystore { diff --git a/primitives/application-crypto/src/bls.rs b/primitives/application-crypto/src/bls.rs new file mode 100644 index 0000000000000..6c5db04f7c0a4 --- /dev/null +++ b/primitives/application-crypto/src/bls.rs @@ -0,0 +1,62 @@ +// This file is part of Substrate. + +// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! bls crypto types. + +use crate::{KeyTypeId, RuntimePublic}; + +use sp_std::vec::Vec; + +pub use sp_core::bls::*; + +mod app { + use sp_core::testing::BLS; + + crate::app_crypto!(super, BLS); + + impl crate::traits::BoundToRuntimeAppPublic for Public { + type Public = Self; + } +} + +#[cfg(feature = "full_crypto")] +pub use app::Pair as AppPair; +pub use app::{Public as AppPublic, Signature as AppSignature}; + +impl RuntimePublic for Public { + type Signature = Signature; + + fn all(key_type: KeyTypeId) -> crate::Vec { + sp_io::crypto::bls_public_keys(key_type) + } + + fn generate_pair(key_type: KeyTypeId, seed: Option>) -> Self { + sp_io::crypto::bls_generate(key_type, seed) + } + + fn sign>(&self, key_type: KeyTypeId, msg: &M) -> Option { + sp_io::crypto::bls_sign(key_type, self, msg.as_ref()) + } + + fn verify>(&self, msg: &M, signature: &Self::Signature) -> bool { + sp_io::crypto::bls_verify(&signature, msg.as_ref(), self) + } + + fn to_raw_vec(&self) -> Vec { + sp_core::crypto::ByteArray::to_raw_vec(self) + } +} diff --git a/primitives/application-crypto/src/lib.rs b/primitives/application-crypto/src/lib.rs index 05f89c40ef99f..0592f464be967 100644 --- a/primitives/application-crypto/src/lib.rs +++ b/primitives/application-crypto/src/lib.rs @@ -44,6 +44,7 @@ pub use serde; #[doc(hidden)] pub use sp_std::{ops::Deref, vec::Vec}; +pub mod bls; pub mod ecdsa; pub mod ed25519; pub mod sr25519; diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index 6a22f0383a3d0..8c5fb831ec80b 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/Cargo.toml @@ -22,10 +22,16 @@ sp-io = { version = "7.0.0", default-features = false, path = "../io" } sp-mmr-primitives = { version = "4.0.0-dev", default-features = false, path = "../merkle-mountain-range" } sp-runtime = { version = "7.0.0", default-features = false, path = "../runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../std" } +bls-like = {git = "https://github.com/w3f/bls", default-features = false} +apk-proofs = {git = "https://github.com/w3f/apk-proofs", default-features = false} +ark-serialize = { version = "0.4.0", default-features = false, features = [ "derive" ] } [dev-dependencies] array-bytes = "4.1" sp-keystore = { version = "0.13.0", path = "../keystore" } +bls-like = {git = "https://github.com/w3f/bls", features = ["std"] } +hex = { version = "0.4", default-features = false} +hex-literal = "0.3.4" [features] default = ["std"] diff --git a/primitives/beefy/src/commitment.rs b/primitives/beefy/src/commitment.rs index 5765ff3609dbb..62ccc490dd40e 100644 --- a/primitives/beefy/src/commitment.rs +++ b/primitives/beefy/src/commitment.rs @@ -248,20 +248,40 @@ impl From> for VersionedFinalityProof { #[cfg(test)] mod tests { - use super::*; - use crate::{crypto, known_payloads, KEY_TYPE}; - use codec::Decode; + use hex::ToHex; use sp_core::{keccak_256, Pair}; use sp_keystore::{testing::KeyStore, SyncCryptoStore, SyncCryptoStorePtr}; + use super::*; + use codec::Decode; + + use crate::{bls_crypto::Signature as BLSSignature, ecdsa_crypto, known_payloads, KEY_TYPE}; + use bls_like::{ + pop::SignatureAggregatorAssumingPoP, Keypair, SerializableToBytes, Signed, + SignedMessage as BLSSignedMessage, BLS377, + }; + type TestCommitment = Commitment; - type TestSignedCommitment = SignedCommitment; - type TestVersionedFinalityProof = VersionedFinalityProof; const LARGE_RAW_COMMITMENT: &[u8] = include_bytes!("../test-res/large-raw-commitment"); + ///types for bls-less commitment + + type TestSignedCommitment = SignedCommitment; + type TestVersionedFinalityProof = VersionedFinalityProof; + + ///types for commitment supporting aggregatable bls signature + #[derive(Clone, Debug, PartialEq, codec::Encode, codec::Decode)] + struct BLSAggregatableSignature(BLSSignature); + + #[derive(Clone, Debug, PartialEq, codec::Encode, codec::Decode)] + struct ECDSABLSSignaturePair(ecdsa_crypto::Signature, BLSSignature); + + type TestBLSSignedCommitment = SignedCommitment; + type TestVersionedBLSFinalityProof = VersionedFinalityProof; + // The mock signatures are equivalent to the ones produced by the BEEFY keystore - fn mock_signatures() -> (crypto::Signature, crypto::Signature) { + fn mock_ecdsa_signatures() -> (ecdsa_crypto::Signature, ecdsa_crypto::Signature) { let store: SyncCryptoStorePtr = KeyStore::new().into(); let alice = sp_core::ecdsa::Pair::from_string("//Alice", None).unwrap(); @@ -282,6 +302,25 @@ mod tests { (sig1.into(), sig2.into()) } + ///generates mock aggregatable bls signature for generating test commitment + ///BLS signatures + fn mock_bls_signatures() -> (BLSSignature, BLSSignature) { + let store: SyncCryptoStorePtr = KeyStore::new().into(); + + let mut alice = sp_core::bls::Pair::from_string("//Alice", None).unwrap(); + let _ = + SyncCryptoStore::insert_unknown(&*store, KEY_TYPE, "//Alice", alice.public().as_ref()) + .unwrap(); + + let msg = b"This is the first message"; + let sig1 = alice.sign(msg); + + let msg = b"This is the second message"; + let sig2 = alice.sign(msg); + + (sig1.into(), sig2.into()) + } + #[test] fn commitment_encode_decode() { // given @@ -289,7 +328,6 @@ mod tests { Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".encode()); let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; - // when let encoded = codec::Encode::encode(&commitment); let decoded = TestCommitment::decode(&mut &*encoded); @@ -312,19 +350,19 @@ mod tests { let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; - let sigs = mock_signatures(); + let ecdsa_sigs = mock_ecdsa_signatures(); - let signed = SignedCommitment { - commitment, - signatures: vec![None, None, Some(sigs.0), Some(sigs.1)], + let ecdsa_signed = SignedCommitment { + commitment: commitment.clone(), + signatures: vec![None, None, Some(ecdsa_sigs.0.clone()), Some(ecdsa_sigs.1.clone())], }; // when - let encoded = codec::Encode::encode(&signed); + let encoded = codec::Encode::encode(&ecdsa_signed); let decoded = TestSignedCommitment::decode(&mut &*encoded); // then - assert_eq!(decoded, Ok(signed)); + assert_eq!(decoded, Ok(ecdsa_signed)); assert_eq!( encoded, array_bytes::hex2bytes_unchecked( @@ -337,6 +375,34 @@ mod tests { " ) ); + + //including bls signature + let bls_signed_msgs = mock_bls_signatures(); + + let ecdsa_and_bls_signed = SignedCommitment { + commitment, + signatures: vec![ + None, + None, + Some(ECDSABLSSignaturePair(ecdsa_sigs.0, bls_signed_msgs.0)), + Some(ECDSABLSSignaturePair(ecdsa_sigs.1, bls_signed_msgs.1)), + ], + }; + + //when + let encoded = codec::Encode::encode(&ecdsa_and_bls_signed); + let decoded = TestBLSSignedCommitment::decode(&mut &*encoded); + + println!("encoded is {}", encoded.encode_hex::()); + + // then + assert_eq!(decoded, Ok(ecdsa_and_bls_signed)); + assert_eq!( + encoded, + hex_literal::hex!( + "046d68343048656c6c6f20576f726c642105000000000000000000000000000000000000000000000004300400000008558455ad81279df0795cc985580e4fb75d72d948d1107b2ac80a09abed4da8480c746cc321f2319a5e99a830e314d10dd3cd68ce3dc0c33c86e99bcb7816f9ba01c7dc77fb482be09d1abf060059bfb33452184946af97417d5acab792b03d92f4d6ef8a053667a1463cf638526f163c01cd47c820a5fba1fc31a412369ea6de7c354374fb39fc0acc6490fcb27b8bf452d0d0e9328b4f7fe778473868148c86802d6e1f8105c337a86cdd9aaacdc496577f3db8c55ef9e6fd48f2c5c05a2274707491635d8ba3df64f324575b7b2a34487bca2324b6a0046395a71681be3d0c2a000d0d8346712c6f2441d8cf824e0540daef1ec40b5462cbab5c41ca430cde51a074ddc82e02f47abfa5f6c66d29b1b400937d98744780735c75fce188e1183e7d936f101af6d4a96a94098935921a366b0e381ee3e6bc846ddb36256491483a81" + ) + ); } #[test] @@ -347,7 +413,7 @@ mod tests { let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; - let sigs = mock_signatures(); + let sigs = mock_ecdsa_signatures(); let mut signed = SignedCommitment { commitment, @@ -394,7 +460,7 @@ mod tests { let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; - let sigs = mock_signatures(); + let sigs = mock_ecdsa_signatures(); let signed = SignedCommitment { commitment, @@ -421,7 +487,7 @@ mod tests { let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; - let sigs = mock_signatures(); + let sigs = mock_ecdsa_signatures(); let signatures: Vec> = (0..1024) .into_iter() diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs index eb7b8db89b214..dec84da370002 100644 --- a/primitives/beefy/src/lib.rs +++ b/primitives/beefy/src/lib.rs @@ -42,6 +42,7 @@ pub use payload::{known_payloads, BeefyPayloadId, Payload, PayloadProvider}; use codec::{Codec, Decode, Encode}; use scale_info::TypeInfo; use sp_application_crypto::RuntimeAppPublic; + use sp_core::H256; use sp_runtime::traits::Hash; use sp_std::prelude::*; @@ -59,19 +60,16 @@ pub trait BeefyAuthorityId: RuntimeAppPublic { fn verify(&self, signature: &::Signature, msg: &[u8]) -> bool; } -/// BEEFY cryptographic types +/// BEEFY cryptographic types for ECDSA crypto /// /// This module basically introduces three crypto types: -/// - `crypto::Pair` -/// - `crypto::Public` -/// - `crypto::Signature` +/// - `ecdsa_crypto::Pair` +/// - `ecdsa_crypto::Public` +/// - `ecdsa_crypto::Signature` /// /// Your code should use the above types as concrete types for all crypto related /// functionality. -/// -/// The current underlying crypto scheme used is ECDSA. This can be changed, -/// without affecting code restricted against the above listed crypto types. -pub mod crypto { +pub mod ecdsa_crypto { use super::{BeefyAuthorityId, Hash, RuntimeAppPublic}; use sp_application_crypto::{app_crypto, ecdsa}; use sp_core::crypto::Wraps; @@ -100,6 +98,26 @@ pub mod crypto { } } +/// BEEFY cryptographic types for BLS crypto +/// +/// This module basically introduces three crypto types: +/// - `bls_crypto::Pair` +/// - `bls_crypto::Public` +/// - `bls_crypto::Signature` +/// +/// Your code should use the above types as concrete types for all crypto related +/// functionality. +pub mod bls_crypto { + use sp_application_crypto::{app_crypto, bls}; + app_crypto!(bls, crate::KEY_TYPE); + + /// Identity of a BEEFY authority using BLS as its crypto. + pub type AuthorityId = Public; + + /// Signature for a BEEFY authority using BLS as its crypto. + pub type AuthoritySignature = Signature; +} + /// The `ConsensusEngineId` of BEEFY. pub const BEEFY_ENGINE_ID: sp_runtime::ConsensusEngineId = *b"BEEF"; @@ -198,12 +216,13 @@ impl OnNewValidatorSet for () { } sp_api::decl_runtime_apis! { - /// API necessary for BEEFY voters. - pub trait BeefyApi + /// API necessary for BEEFY voters with only ECDSA key. + pub trait BeefyApi where AuthorityId : Encode + Decode { /// Return the current active BEEFY validator set - fn validator_set() -> Option>; + fn validator_set() -> Option>; } + } #[cfg(test)] @@ -229,12 +248,12 @@ mod tests { #[test] fn beefy_verify_works() { let msg = &b"test-message"[..]; - let (pair, _) = crypto::Pair::generate(); + let (pair, _) = ecdsa_crypto::Pair::generate(); - let keccak_256_signature: crypto::Signature = + let keccak_256_signature: ecdsa_crypto::Signature = pair.as_inner_ref().sign_prehashed(&keccak_256(msg)).into(); - let blake2_256_signature: crypto::Signature = + let blake2_256_signature: ecdsa_crypto::Signature = pair.as_inner_ref().sign_prehashed(&blake2_256(msg)).into(); // Verification works if same hashing function is used when signing and verifying. @@ -253,7 +272,7 @@ mod tests { )); // Other public key doesn't work - let (other_pair, _) = crypto::Pair::generate(); + let (other_pair, _) = ecdsa_crypto::Pair::generate(); assert!(!BeefyAuthorityId::::verify( &other_pair.public(), &keccak_256_signature, diff --git a/primitives/beefy/src/mmr.rs b/primitives/beefy/src/mmr.rs index 549d2edbdf287..48e2d0149d5a9 100644 --- a/primitives/beefy/src/mmr.rs +++ b/primitives/beefy/src/mmr.rs @@ -26,14 +26,89 @@ //! but we imagine they will be useful for other chains that either want to bridge with Polkadot //! or are completely standalone, but heavily inspired by Polkadot. -use crate::{crypto::AuthorityId, ConsensusLog, MmrRootHash, Vec, BEEFY_ENGINE_ID}; -use codec::{Decode, Encode, MaxEncodedLen}; -use scale_info::TypeInfo; +use crate::{ecdsa_crypto::AuthorityId, ConsensusLog, MmrRootHash, Vec, BEEFY_ENGINE_ID}; +use codec::{Decode, Encode, Error as CodecError, Input, MaxEncodedLen, Output}; +use scale_info::{build::Fields, Path, Type, TypeInfo}; use sp_runtime::{ generic::OpaqueDigestItemId, traits::{Block, Header}, }; +use apk_proofs::KeysetCommitment; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +#[cfg(feature = "std")] +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; + +/// Wrapper around keyset commitment to provide scale codec for the commitment +//#[cfg_attr(feature = "std", derive(Deserialize))] +#[derive(Debug, Default, Clone, PartialEq, Eq)] +pub struct AuthoritySetCommitment(pub KeysetCommitment); + +impl Encode for AuthoritySetCommitment { + fn encode_to(&self, dest: &mut W) { + let mut serialized_representation: Vec = Vec::new(); + self.0.serialize_compressed(&mut serialized_representation[..]).unwrap(); + as Encode>::encode_to(&serialized_representation, dest); + } +} + +impl Decode for AuthoritySetCommitment { + fn decode(input: &mut I) -> Result { + let mut descaled_bytes: Vec = Vec::with_capacity(input.remaining_len()?.unwrap()); + input.read(descaled_bytes.as_mut_slice())?; + match ::deserialize_compressed( + descaled_bytes.as_slice(), + ) { + Ok(keyset_commitment) => Ok(AuthoritySetCommitment(keyset_commitment)), + _ => Err("unable to deserialze compressed commitment".into()), + } + } +} + +//TODO: This is a place holder as I didn't know if there isn't +// a better way to derive this +impl TypeInfo for AuthoritySetCommitment { + type Identity = Self; + + fn type_info() -> Type { + Type::builder() + .path(Path::new("AuthoritySetCommitment", module_path!())) + .composite(Fields::unnamed().field(|f| f.ty::().type_name("u32"))) + } +} + +impl MaxEncodedLen for AuthoritySetCommitment { + fn max_encoded_len() -> usize { + //Two G1 points on BW6_761 and a u32 + return 96 * 2 + 4 + } +} + +#[cfg(feature = "std")] +impl Serialize for AuthoritySetCommitment { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_bytes(self.encode().as_slice()) + } +} + +#[cfg(feature = "std")] +impl<'de> Deserialize<'de> for AuthoritySetCommitment { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let encoded_auth_set = Vec::::deserialize(deserializer)?; + // let encoded_auth_set = deserializer.deserialize_bytes(encoded_auth_set)?; + match AuthoritySetCommitment::decode(&mut &encoded_auth_set[..]) { + Ok(authority_set_commtment) => Ok(authority_set_commtment), + _ => Err(de::Error::custom("i32 out of range: {}")), + } + } +} + /// A provider for extra data that gets added to the Mmr leaf pub trait BeefyDataProvider { /// Return a vector of bytes, ideally should be a merkle root hash @@ -121,6 +196,11 @@ pub struct BeefyAuthoritySet { /// validator set. Light Clients using interactive protocol, might verify only subset of /// signatures, hence don't require the full list here (will receive inclusion proofs). pub root: MerkleRoot, + + /// polynomial commitment to the polynomial interpolating AuthorityIds + /// This is used by APK proof based light clients to verify the validity + /// of aggregated BLS keys using APK proofs. + pub keyset_commitment: AuthoritySetCommitment, } /// Details of the next BEEFY authority set. diff --git a/primitives/beefy/src/witness.rs b/primitives/beefy/src/witness.rs index 2c45e0ade90c4..1192e09405fbe 100644 --- a/primitives/beefy/src/witness.rs +++ b/primitives/beefy/src/witness.rs @@ -37,18 +37,21 @@ use crate::commitment::{Commitment, SignedCommitment}; /// Ethereum Mainnet), in a commit-reveal like scheme, where first we submit only the signed /// commitment witness and later on, the client picks only some signatures to verify at random. #[derive(Debug, PartialEq, Eq, codec::Encode, codec::Decode)] -pub struct SignedCommitmentWitness { +pub struct SignedCommitmentWitness { /// The full content of the commitment. pub commitment: Commitment, /// The bit vector of validators who signed the commitment. pub signed_by: Vec, // TODO [ToDr] Consider replacing with bitvec crate - /// A merkle root of signatures in the original signed commitment. - pub signatures_merkle_root: TMerkleRoot, + /// Either a merkle root of signatures in the original signed commitment or a single aggregated + /// BLS signature aggregating all original signatures. + pub signature_accumulator: TSignatureAccumulator, } -impl SignedCommitmentWitness { +impl + SignedCommitmentWitness +{ /// Convert [SignedCommitment] into [SignedCommitmentWitness]. /// /// This takes a [SignedCommitment], which contains full signatures @@ -57,18 +60,18 @@ impl SignedCommitmentWitness( + pub fn from_signed( signed: SignedCommitment, - merkelize: TMerkelize, + aggregator: TSignatureAggregator, ) -> (Self, Vec>) where - TMerkelize: FnOnce(&[Option]) -> TMerkleRoot, + TSignatureAggregator: FnOnce(&[Option]) -> TSignatureAccumulator, { let SignedCommitment { commitment, signatures } = signed; let signed_by = signatures.iter().map(|s| s.is_some()).collect(); - let signatures_merkle_root = merkelize(&signatures); + let signature_accumulator = aggregator(&signatures); - (Self { commitment, signed_by, signatures_merkle_root }, signatures) + (Self { commitment, signed_by, signature_accumulator }, signatures) } } @@ -81,15 +84,30 @@ mod tests { use super::*; use codec::Decode; - use crate::{crypto, known_payloads, Payload, KEY_TYPE}; + use crate::{ + bls_crypto::Signature as BLSSignature, ecdsa_crypto, known_payloads, Payload, KEY_TYPE, + }; + use bls_like::{ + pop::SignatureAggregatorAssumingPoP, EngineBLS, SerializableToBytes, Signed, BLS377, + }; type TestCommitment = Commitment; - type TestSignedCommitment = SignedCommitment; + + ///types for ecdsa signed commitment + type TestSignedCommitment = SignedCommitment; type TestSignedCommitmentWitness = - SignedCommitmentWitness>>; + SignedCommitmentWitness>>; + + #[derive(Clone, Debug, PartialEq, codec::Encode, codec::Decode)] + struct ECDSABLSSignaturePair(ecdsa_crypto::Signature, BLSSignature); + + ///types for commitment containing bls signature along side ecdsa signature + type TestBLSSignedCommitment = SignedCommitment; + type TestBLSSignedCommitmentWitness = + SignedCommitmentWitness; // The mock signatures are equivalent to the ones produced by the BEEFY keystore - fn mock_signatures() -> (crypto::Signature, crypto::Signature) { + fn mock_ecdsa_signatures() -> (ecdsa_crypto::Signature, ecdsa_crypto::Signature) { let store: SyncCryptoStorePtr = KeyStore::new().into(); let alice = sp_core::ecdsa::Pair::from_string("//Alice", None).unwrap(); @@ -110,7 +128,26 @@ mod tests { (sig1.into(), sig2.into()) } - fn signed_commitment() -> TestSignedCommitment { + ///generates mock aggregatable bls signature for generating test commitment + ///BLS signatures + fn mock_bls_signatures() -> (BLSSignature, BLSSignature) { + let store: SyncCryptoStorePtr = KeyStore::new().into(); + + let mut alice = sp_core::bls::Pair::from_string("//Alice", None).unwrap(); + let _ = + SyncCryptoStore::insert_unknown(&*store, KEY_TYPE, "//Alice", alice.public().as_ref()) + .unwrap(); + + let msg = b"This is the first message"; + let sig1 = alice.sign(msg); + + let msg = b"This is the second message"; + let sig2 = alice.sign(msg); + + (sig1.into(), sig2.into()) + } + + fn ecdsa_signed_commitment() -> TestSignedCommitment { let payload = Payload::from_single_entry( known_payloads::MMR_ROOT_ID, "Hello World!".as_bytes().to_vec(), @@ -118,29 +155,85 @@ mod tests { let commitment: TestCommitment = Commitment { payload, block_number: 5, validator_set_id: 0 }; - let sigs = mock_signatures(); + let sigs = mock_ecdsa_signatures(); SignedCommitment { commitment, signatures: vec![None, None, Some(sigs.0), Some(sigs.1)] } } + fn ecdsa_and_bls_signed_commitment() -> TestBLSSignedCommitment { + let payload = Payload::from_single_entry(known_payloads::MMR_ROOT_ID, "Hello World!".as_bytes().to_vec()); + let commitment: TestCommitment = + Commitment { payload, block_number: 5, validator_set_id: 0 }; + + let ecdsa_sigs = mock_ecdsa_signatures(); + let bls_sigs = mock_bls_signatures(); + + SignedCommitment { + commitment, + signatures: vec![ + None, + None, + Some(ECDSABLSSignaturePair(ecdsa_sigs.0, bls_sigs.0)), + Some(ECDSABLSSignaturePair(ecdsa_sigs.1, bls_sigs.1)), + ], + } + } + #[test] fn should_convert_signed_commitment_to_witness() { // given - let signed = signed_commitment(); + let signed = ecdsa_signed_commitment(); // when - let (witness, signatures) = - TestSignedCommitmentWitness::from_signed(signed, |sigs| sigs.to_vec()); + let (witness, signatures) = TestSignedCommitmentWitness::from_signed::< + _, + _, + >(signed, |sigs| sigs.to_vec()); // then - assert_eq!(witness.signatures_merkle_root, signatures); + assert_eq!(witness.signature_accumulator, signatures); + } + + #[test] + fn should_convert_dually_signed_commitment_to_witness() { + // given + let signed = ecdsa_and_bls_signed_commitment(); + + // when + let (witness, signatures) = TestBLSSignedCommitmentWitness::from_signed::< + _, + _, + >(signed, |sigs| { + //we are going to aggregate the signatures here + let mut aggregatedsigs: SignatureAggregatorAssumingPoP = + SignatureAggregatorAssumingPoP::new(); + sigs.iter().filter_map(|sig| { + sig.clone().map(|sig| { + aggregatedsigs.add_signature( + &(bls_like::Signature::from_bytes( + >::as_ref(&sig.1.clone()) + .try_into() + .unwrap(), + )) + .unwrap(), + ) + }) + }); + (&aggregatedsigs).signature().to_bytes() + }); + + BLSSignature::try_from(witness.signature_accumulator.as_slice()).unwrap(); } #[test] fn should_encode_and_decode_witness() { // given - let signed = signed_commitment(); - let (witness, _) = TestSignedCommitmentWitness::from_signed(signed, |sigs| sigs.to_vec()); + let signed = ecdsa_signed_commitment(); + let (witness, _) = + TestSignedCommitmentWitness::from_signed::<_, _, >( + signed, + |sigs: &[std::option::Option]| sigs.to_vec(), + ); // when let encoded = codec::Encode::encode(&witness); diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index 5fd838de3538d..4459ae9091129 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -50,6 +50,10 @@ schnorrkel = { version = "0.9.1", features = [ "preaudit_deprecated", "u64_backend", ], default-features = false, optional = true } +bls-like = {git = "https://github.com/w3f/bls", branch = "skalman-hash-to-curve-wb", default-features = false} +#bls-like = {version="*", default-features = false } +sha2 = { version = "0.10.0", default-features = false, optional = true } +hex = { version = "0.4", default-features = false, optional = true} libsecp256k1 = { version = "0.7", default-features = false, features = ["static-context"], optional = true } merlin = { version = "2.0", default-features = false, optional = true } secp256k1 = { version = "0.24.0", default-features = false, features = ["recovery", "alloc"], optional = true } @@ -63,6 +67,7 @@ rand = "0.8.5" criterion = "0.4.0" serde_json = "1.0" sp-core-hashing-proc-macro = { version = "5.0.0", path = "./hashing/proc-macro" } +hex-literal = "0.3.4" [[bench]] name = "bench" @@ -114,6 +119,7 @@ std = [ "futures/thread-pool", "libsecp256k1/std", "dyn-clonable", + "hex", ] # This feature enables all crypto primitives for `no_std` builds like microcontrollers @@ -130,3 +136,4 @@ full_crypto = [ "sp-runtime-interface/disable_target_static_assertions", "merlin", ] + diff --git a/primitives/core/src/bls.rs b/primitives/core/src/bls.rs new file mode 100644 index 0000000000000..0710fb3e2bc2e --- /dev/null +++ b/primitives/core/src/bls.rs @@ -0,0 +1,730 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// tag::description[] +//! Simple BLS (Boneh–Lynn–Shacham) Signature API. +// end::description[] + +#[cfg(feature = "full_crypto")] +use sp_std::vec::Vec; + +use crate::{ + crypto::ByteArray, + hash::{H384, H768}, +}; +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; + +#[cfg(feature = "std")] +use crate::crypto::Ss58Codec; +use crate::crypto::{ + CryptoType, CryptoTypeId, CryptoTypePublicPair, Derive, Public as TraitPublic, UncheckedFrom, +}; +#[cfg(feature = "full_crypto")] +use crate::crypto::{DeriveJunction, Pair as TraitPair, SecretStringError}; +#[cfg(feature = "std")] +use bip39::{Language, Mnemonic, MnemonicType}; +use bls_like::{EngineBLS, Keypair, Message, SerializableToBytes, BLS377}; +#[cfg(feature = "full_crypto")] +use core::convert::TryFrom; +#[cfg(feature = "std")] +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; +use sp_runtime_interface::pass_by::PassByInner; +use sp_std::ops::Deref; +#[cfg(feature = "std")] +use substrate_bip39::seed_from_entropy; + +#[cfg(feature = "std")] +use hex; + +/// An identifier used to match public keys against bls377 keys +pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"bls7"); + +/// A secret seed. It's not called a "secret key" because ring doesn't expose the secret keys +/// of the key pair (yeah, dumb); as such we're forced to remember the seed manually if we +/// will need it later (such as for HDKD). +#[cfg(feature = "full_crypto")] +type Seed = [u8; BLS377::SECRET_KEY_SIZE]; + +/// A public key. +#[cfg_attr(feature = "full_crypto", derive(Hash))] +#[derive( + PartialEq, + Eq, + PartialOrd, + Ord, + Clone, + Copy, + Encode, + Decode, + PassByInner, + MaxEncodedLen, + TypeInfo, +)] +pub struct Public(pub [u8; BLS377::PUBLICKEY_SERIALIZED_SIZE]); + +/// A key pair. +#[cfg(feature = "full_crypto")] +pub struct Pair(Keypair); + +#[cfg(feature = "full_crypto")] +impl Clone for Pair { + fn clone(&self) -> Self { + Pair(self.0.clone()) + } +} + +impl AsRef<[u8; BLS377::PUBLICKEY_SERIALIZED_SIZE]> for Public { + fn as_ref(&self) -> &[u8; BLS377::PUBLICKEY_SERIALIZED_SIZE] { + &self.0 + } +} + +impl AsRef<[u8]> for Public { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl AsMut<[u8]> for Public { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0[..] + } +} + +impl Deref for Public { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl sp_std::convert::TryFrom<&[u8]> for Public { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() != Self::LEN { + return Err(()) + } + let mut r = [0u8; Self::LEN]; + r.copy_from_slice(data); + Ok(Self::unchecked_from(r)) + } +} + +impl From for [u8; BLS377::PUBLICKEY_SERIALIZED_SIZE] { + fn from(x: Public) -> Self { + x.0 + } +} + +#[cfg(feature = "full_crypto")] +impl From for Public { + fn from(x: Pair) -> Self { + x.public() + } +} + +impl From for H384 { + fn from(x: Public) -> Self { + x.0.into() + } +} + +#[cfg(feature = "std")] +impl std::str::FromStr for Public { + type Err = crate::crypto::PublicError; + + fn from_str(s: &str) -> Result { + Self::from_ss58check(s) + } +} + +impl UncheckedFrom<[u8; BLS377::PUBLICKEY_SERIALIZED_SIZE]> for Public { + fn unchecked_from(x: [u8; BLS377::PUBLICKEY_SERIALIZED_SIZE]) -> Self { + Public::from_raw(x) + } +} + +impl UncheckedFrom for Public { + fn unchecked_from(x: H384) -> Self { + Public::from_h384(x) + } +} + +#[cfg(feature = "std")] +impl std::fmt::Display for Public { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.to_ss58check()) + } +} + +impl sp_std::fmt::Debug for Public { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + let s = self.to_ss58check(); + write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + Ok(()) + } +} + +#[cfg(feature = "std")] +impl Serialize for Public { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&self.to_ss58check()) + } +} + +#[cfg(feature = "std")] +impl<'de> Deserialize<'de> for Public { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Public::from_ss58check(&String::deserialize(deserializer)?) + .map_err(|e| de::Error::custom(format!("{:?}", e))) + } +} + +/// A signature (a 512-bit value). +#[cfg_attr(feature = "full_crypto", derive(Hash))] +#[derive(Encode, Decode, MaxEncodedLen, PassByInner, TypeInfo, PartialEq, Eq)] +pub struct Signature(pub [u8; BLS377::SIGNATURE_SERIALIZED_SIZE]); + +impl sp_std::convert::TryFrom<&[u8]> for Signature { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() == BLS377::SIGNATURE_SERIALIZED_SIZE { + let mut inner = [0u8; BLS377::SIGNATURE_SERIALIZED_SIZE]; + inner.copy_from_slice(data); + Ok(Signature(inner)) + } else { + Err(()) + } + } +} + +#[cfg(feature = "std")] +impl Serialize for Signature { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&hex::encode(self)) + } +} + +#[cfg(feature = "std")] +impl<'de> Deserialize<'de> for Signature { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let signature_hex = hex::decode(&String::deserialize(deserializer)?) + .map_err(|e| de::Error::custom(format!("{:?}", e)))?; + Signature::try_from(signature_hex.as_ref()) + .map_err(|e| de::Error::custom(format!("{:?}", e))) + } +} + +impl Clone for Signature { + fn clone(&self) -> Self { + let mut r = [0u8; BLS377::SIGNATURE_SERIALIZED_SIZE]; + r.copy_from_slice(&self.0[..]); + Signature(r) + } +} + +impl From for H768 { + fn from(v: Signature) -> H768 { + H768::from(v.0) + } +} + +impl From for [u8; BLS377::SIGNATURE_SERIALIZED_SIZE] { + fn from(v: Signature) -> [u8; BLS377::SIGNATURE_SERIALIZED_SIZE] { + v.0 + } +} + +impl AsRef<[u8; BLS377::SIGNATURE_SERIALIZED_SIZE]> for Signature { + fn as_ref(&self) -> &[u8; BLS377::SIGNATURE_SERIALIZED_SIZE] { + &self.0 + } +} + +impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl AsMut<[u8]> for Signature { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0[..] + } +} + +impl sp_std::fmt::Debug for Signature { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0)) + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + Ok(()) + } +} + +impl UncheckedFrom<[u8; BLS377::SIGNATURE_SERIALIZED_SIZE]> for Signature { + fn unchecked_from(data: [u8; BLS377::SIGNATURE_SERIALIZED_SIZE]) -> Signature { + Signature(data) + } +} + +impl Signature { + /// A new instance from the given BLS377::SIGNATURE_SERIALIZED_SIZE-byte `data`. + /// + /// NOTE: No checking goes on to ensure this is a real signature. Only use it if + /// you are certain that the array actually is a signature. GIGO! + pub fn from_raw(data: [u8; BLS377::SIGNATURE_SERIALIZED_SIZE]) -> Signature { + Signature(data) + } + + /// A new instance from the given slice that should be 64 bytes long. + /// + /// NOTE: No checking goes on to ensure this is a real signature. Only use it if + /// you are certain that the array actually is a signature. GIGO! + pub fn from_slice(data: &[u8]) -> Option { + let mut r = [0u8; BLS377::SIGNATURE_SERIALIZED_SIZE]; + r.copy_from_slice(data); + Some(Signature(r)) + } + + /// A new instance from an H512. + /// + /// NOTE: No checking goes on to ensure this is a real signature. Only use it if + /// you are certain that the array actually is a signature. GIGO! + pub fn from_h512(v: H768) -> Signature { + Signature(v.into()) + } +} + +/// A localized signature also contains sender information. +#[cfg(feature = "std")] +#[derive(PartialEq, Eq, Clone, Debug, Encode, Decode)] +pub struct LocalizedSignature { + /// The signer of the signature. + pub signer: Public, + /// The signature itself. + pub signature: Signature, +} + +impl Public { + /// A new instance from the given BLS377::PUBLICKEY_SERIALIZED_SIZE-byte `data`. + /// + /// NOTE: No checking goes on to ensure this is a real public key. Only use it if + /// you are certain that the array actually is a pubkey. GIGO! + pub fn from_raw(data: [u8; BLS377::PUBLICKEY_SERIALIZED_SIZE]) -> Self { + Public(data) + } + + /// A new instance from an H384. + /// + /// NOTE: No checking goes on to ensure this is a real public key. Only use it if + /// you are certain that the array actually is a pubkey. GIGO! + pub fn from_h384(x: H384) -> Self { + Public(x.into()) + } + + /// Return a slice filled with raw data. + pub fn as_array_ref(&self) -> &[u8; BLS377::PUBLICKEY_SERIALIZED_SIZE] { + self.as_ref() + } +} + +impl ByteArray for Public { + const LEN: usize = BLS377::PUBLICKEY_SERIALIZED_SIZE; +} + +impl TraitPublic for Public { + fn to_public_crypto_pair(&self) -> CryptoTypePublicPair { + CryptoTypePublicPair(CRYPTO_ID, self.to_raw_vec()) + } +} + +impl Derive for Public {} + +impl From for CryptoTypePublicPair { + fn from(key: Public) -> Self { + (&key).into() + } +} + +impl From<&Public> for CryptoTypePublicPair { + fn from(key: &Public) -> Self { + CryptoTypePublicPair(CRYPTO_ID, key.to_raw_vec()) + } +} + +///??? +///What is HDKD? What is hard junction? should seed be 48bytes +/// Derive a single hard junction. +#[cfg(feature = "full_crypto")] +fn derive_hard_junction(secret_seed: &Seed, cc: &[u8; 32]) -> Seed { + ("BLS12377HDKD", secret_seed, cc).using_encoded(sp_core_hashing::blake2_256) + // using_encoded(|data| { + // let mut res = [0u8; BLS377::SECRET_KEY_SIZE]; + // res.copy_from_slice(blake2::Blake2b::blake2b(BLS377::SECRET_KEY_SIZE, &[], data).as_bytes()); + // res + // }) +} + +/// An error when deriving a key. +#[cfg(feature = "full_crypto")] +pub enum DeriveError { + /// A soft key was found in the path (and is unsupported). + SoftKeyInPath, +} + +#[cfg(feature = "full_crypto")] +impl TraitPair for Pair { + type Public = Public; + type Seed = Seed; + type Signature = Signature; + type DeriveError = DeriveError; + + /// Generate new secure (random) key pair and provide the recovery phrase. + /// + /// You can recover the same key later with `from_phrase`. + #[cfg(feature = "std")] + fn generate_with_phrase(password: Option<&str>) -> (Pair, String, Seed) { + let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English); + let phrase = mnemonic.phrase(); + let (pair, seed) = Self::from_phrase(phrase, password) + .expect("All phrases generated by Mnemonic are valid; qed"); + (pair, phrase.to_owned(), seed) + } + + /// Generate key pair from given recovery phrase and password. + #[cfg(feature = "std")] + fn from_phrase( + phrase: &str, + password: Option<&str>, + ) -> Result<(Pair, Seed), SecretStringError> { + let big_seed = seed_from_entropy( + Mnemonic::from_phrase(phrase, Language::English) + .map_err(|_| SecretStringError::InvalidPhrase)? + .entropy(), + password.unwrap_or(""), + ) + .map_err(|_| SecretStringError::InvalidSeed)?; + let mut seed = Seed::default(); + seed.copy_from_slice(&big_seed[0..32]); + Self::from_seed_slice(&big_seed[0..32]).map(|x| (x, seed)) + } + + /// Make a new key pair from secret seed material. + /// + /// You should never need to use this; generate(), generate_with_phrase + fn from_seed(seed: &Seed) -> Pair { + Self::from_seed_slice(&seed[..]).expect("seed has valid length; qed") + } + + /// Make a new key pair from secret seed material. The slice must be 32 bytes long or it + /// will return `None`. + /// + /// You should never need to use this; generate(), generate_with_phrase + fn from_seed_slice(seed_slice: &[u8]) -> Result { + if seed_slice.len() != BLS377::SECRET_KEY_SIZE { + return Err(SecretStringError::InvalidSeedLength) + } + let secret = bls_like::SecretKey::from_seed(seed_slice); + let public = secret.into_public(); + Ok(Pair(bls_like::Keypair { secret, public })) + } + + /// Derive a child key from a series of given junctions. + fn derive>( + &self, + path: Iter, + _seed: Option, + ) -> Result<(Pair, Option), DeriveError> { + let mut acc = self.0.secret.to_bytes(); + for j in path { + match j { + DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath), + DeriveJunction::Hard(cc) => acc = derive_hard_junction(&acc, &cc), + } + } + Ok((Self::from_seed(&acc), Some(acc))) + } + + /// Get the public key. + fn public(&self) -> Public { + let mut r = [0u8; BLS377::PUBLICKEY_SERIALIZED_SIZE]; + let pk = self.0.public.to_bytes(); + r.copy_from_slice(pk.as_slice()); + Public(r) + } + + /// Sign a message. + fn sign(&self, message: &[u8]) -> Signature { + let mut mutable_self = self.clone(); + let r = mutable_self.0.sign(Message::new(b"", message)).to_bytes(); + Signature::from_raw(r) + } + + /// Verify a signature on a message. Returns true if the signature is good. + fn verify>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool { + Self::verify_weak(&sig.0[..], message.as_ref(), pubkey) + } + + /// Verify a signature on a message. Returns true if the signature is good. + /// + /// This doesn't use the type system to ensure that `sig` and `pubkey` are the correct + /// size. Use it only if you're coming from byte buffers and need the speed. + fn verify_weak, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool { + let pubkey_array: [u8; BLS377::PUBLICKEY_SERIALIZED_SIZE] = match pubkey.as_ref().try_into() + { + Ok(pk) => pk, + Err(_) => return false, + }; + let public_key = match bls_like::PublicKey::::from_bytes(&pubkey_array) { + Ok(pk) => pk, + Err(_) => return false, + }; + + let sig_array = match sig.try_into() { + Ok(s) => s, + Err(_) => return false, + }; + let sig = match bls_like::Signature::from_bytes(sig_array) { + Ok(s) => s, + Err(_) => return false, + }; + + sig.verify(Message::new(b"", message.as_ref()), &public_key) + } + + /// Return a vec filled with raw data. + fn to_raw_vec(&self) -> Vec { + self.seed().to_vec() + } +} + +#[cfg(feature = "full_crypto")] +impl Pair { + /// Get the seed for this key. + pub fn seed(&self) -> Seed { + self.0.secret.to_bytes() + } + + /// Exactly as `from_string` except that if no matches are found then, the the first 32 + /// characters are taken (padded with spaces as necessary) and used as the MiniSecretKey. + #[cfg(feature = "std")] + pub fn from_legacy_string(s: &str, password_override: Option<&str>) -> Pair { + Self::from_string(s, password_override).unwrap_or_else(|_| { + let mut padded_seed: Seed = [b' '; 32]; + let len = s.len().min(32); + padded_seed[..len].copy_from_slice(&s.as_bytes()[..len]); + Self::from_seed(&padded_seed) + }) + } +} +impl CryptoType for Public { + #[cfg(feature = "full_crypto")] + type Pair = Pair; +} + +impl CryptoType for Signature { + #[cfg(feature = "full_crypto")] + type Pair = Pair; +} + +#[cfg(feature = "full_crypto")] +impl CryptoType for Pair { + type Pair = Pair; +} + +#[cfg(test)] +mod test { + use super::*; + use crate::crypto::DEV_PHRASE; + use hex_literal::hex; + use serde_json; + + #[test] + fn default_phrase_should_be_used() { + assert_eq!( + Pair::from_string("//Alice///password", None).unwrap().public(), + Pair::from_string(&format!("{}//Alice", DEV_PHRASE), Some("password")) + .unwrap() + .public(), + ); + } + + //only passes if the seed = seed (mod ScalarField) + #[test] + fn seed_and_derive_should_work() { + let seed = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f00"); + let pair = Pair::from_seed(&seed); + // we are using hash to field so this is not going to work + // assert_eq!(pair.seed(), seed); + let path = vec![DeriveJunction::Hard([0u8; 32])]; + let derived = pair.derive(path.into_iter(), None).ok().unwrap().0; + assert_eq!( + derived.seed(), + hex!("a4f2269333b3e87c577aa00c4a2cd650b3b30b2e8c286a47c251279ff3a26e0d") + ); + } + + #[test] + fn test_vector_should_work() { + let pair = Pair::from_seed(&hex!( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60" + )); + let public = pair.public(); + assert_eq!( + public, + Public::from_raw(hex!( + "7a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb80" + )) + ); + let message = b""; + let signature = hex!("0e5854002b249175764e463165aec0e38a46ddd44c2db29d6fec3022a3993b3390b001b53a04d155a4d216dd361df90087281be27c58ae22c7f1333820259ff5ae1b321126d1a001bf91ee088fb56ca9d4aa484d129ede7e701ced08df631581"); + let signature = Signature::from_raw(signature); + assert!(pair.sign(&message[..]) == signature); + assert!(Pair::verify(&signature, &message[..], &public)); + } + + #[test] + fn test_vector_by_string_should_work() { + let pair = Pair::from_string( + "0x9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + None, + ) + .unwrap(); + let public = pair.public(); + assert_eq!( + public, + Public::from_raw(hex!( + "6dc6be608fab3c6bd894a606be86db346cc170db85c733853a371f3db54ae1b12052c0888d472760c81b537572a26f00" + )) + ); + let message = b""; + let signature = hex!("9f7d07e0fdd6aa342f6defaade946b59bfeba8af45c243f86b208cd339b2c713421844e3007e0acafd0a529542ee050047b739fe5bfd311d884451542204e173d784e648eb55f4bd32da747f006120fadf4801c2b1c88f9745c50c2141b1d380"); + let signature = Signature::from_raw(signature); + assert!(pair.sign(&message[..]) == signature); + assert!(Pair::verify(&signature, &message[..], &public)); + } + + #[test] + fn generated_pair_should_work() { + let (pair, _) = Pair::generate(); + let public = pair.public(); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + assert!(Pair::verify(&signature, &message[..], &public)); + assert!(!Pair::verify(&signature, b"Something else", &public)); + } + + #[test] + fn seeded_pair_should_work() { + let pair = Pair::from_seed(b"12345678901234567890123456789012"); + let public = pair.public(); + assert_eq!( + public, + Public::from_raw( + hex!( + "754d2f2bbfa67df54d7e0e951979a18a1e0f45948857752cc2bac6bbb0b1d05e8e48bcc453920bf0c4bbd59932124801") + ) + ); + let message = hex!("2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"); + let signature = pair.sign(&message[..]); + println!("Correct signature: {:?}", signature); + assert!(Pair::verify(&signature, &message[..], &public)); + assert!(!Pair::verify(&signature, "Other message", &public)); + } + + #[test] + fn generate_with_phrase_recovery_possible() { + let (pair1, phrase, _) = Pair::generate_with_phrase(None); + let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); + + assert_eq!(pair1.public(), pair2.public()); + } + + #[test] + fn generate_with_password_phrase_recovery_possible() { + let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); + let (pair2, _) = Pair::from_phrase(&phrase, Some("password")).unwrap(); + + assert_eq!(pair1.public(), pair2.public()); + } + + #[test] + fn password_does_something() { + let (pair1, phrase, _) = Pair::generate_with_phrase(Some("password")); + let (pair2, _) = Pair::from_phrase(&phrase, None).unwrap(); + + assert_ne!(pair1.public(), pair2.public()); + } + + #[test] + fn ss58check_roundtrip_works() { + let pair = Pair::from_seed(b"12345678901234567890123456789012"); + let public = pair.public(); + let s = public.to_ss58check(); + println!("Correct: {}", s); + let cmp = Public::from_ss58check(&s).unwrap(); + assert_eq!(cmp, public); + } + + #[test] + fn signature_serialization_works() { + let pair = Pair::from_seed(b"12345678901234567890123456789012"); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + let serialized_signature = serde_json::to_string(&signature).unwrap(); + // Signature is 96 bytes, so 192 chars + 2 quote chars + assert_eq!(serialized_signature.len(), 194); + let signature = serde_json::from_str(&serialized_signature).unwrap(); + assert!(Pair::verify(&signature, &message[..], &pair.public())); + } + + #[test] + fn signature_serialization_doesnt_panic() { + fn deserialize_signature(text: &str) -> Result { + serde_json::from_str(text) + } + assert!(deserialize_signature("Not valid json.").is_err()); + assert!(deserialize_signature("\"Not an actual signature.\"").is_err()); + // Poorly-sized + assert!(deserialize_signature("\"abc123\"").is_err()); + } +} diff --git a/primitives/core/src/hash.rs b/primitives/core/src/hash.rs index f2974e9372ad5..5222bf8ec3158 100644 --- a/primitives/core/src/hash.rs +++ b/primitives/core/src/hash.rs @@ -17,7 +17,7 @@ //! A fixed hash type. -pub use primitive_types::{H160, H256, H512}; +pub use primitive_types::{H160, H256, H384, H512, H768}; /// Hash conversion. Used to convert between unbound associated hash types in traits, /// implemented by the same hash type. diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index 30d0cc199b74d..0689009123d63 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -55,6 +55,7 @@ pub mod bounded; pub mod crypto; pub mod hexdisplay; +pub mod bls; pub mod defer; pub mod ecdsa; pub mod ed25519; diff --git a/primitives/core/src/testing.rs b/primitives/core/src/testing.rs index d3fa3fc86fce5..900cd869aee6e 100644 --- a/primitives/core/src/testing.rs +++ b/primitives/core/src/testing.rs @@ -25,6 +25,8 @@ pub const ED25519: KeyTypeId = KeyTypeId(*b"ed25"); pub const SR25519: KeyTypeId = KeyTypeId(*b"sr25"); /// Key type for generic ECDSA key. pub const ECDSA: KeyTypeId = KeyTypeId(*b"ecds"); +/// Key type for generic BLS12-377 key. +pub const BLS: KeyTypeId = KeyTypeId(*b"bls7"); /// Macro for exporting functions from wasm in with the expected signature for using it with the /// wasm executor. This is useful for tests where you need to call a function in wasm. diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index bb06c00ee2c6f..620bface6a9ca 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -46,6 +46,7 @@ use sp_core::{ use sp_keystore::{KeystoreExt, SyncCryptoStore}; use sp_core::{ + bls, crypto::KeyTypeId, ecdsa, ed25519, offchain::{ @@ -1120,6 +1121,56 @@ pub trait Crypto { .map_err(|_| EcdsaVerifyError::BadSignature)?; Ok(pubkey.serialize()) } + + /// Returns all `bls` public keys for the given key id from the keystore. + /// This is needed for beefy keystore. + fn bls_public_keys(&mut self, id: KeyTypeId) -> Vec { + let keystore = &***self + .extension::() + .expect("No `keystore` associated for the current context!"); + SyncCryptoStore::bls_public_keys(keystore, id) + } + + /// Generate an `bls12-377` key for the given key type using an optional seed and + /// store it in the keystore. + /// + /// The `seed` needs to be a valid utf8. + /// + /// Returns the public key. + fn bls_generate(&mut self, id: KeyTypeId, seed: Option>) -> bls::Public { + let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + let keystore = &***self + .extension::() + .expect("No `keystore` associated for the current context!"); + SyncCryptoStore::bls_generate_new(keystore, id, seed).expect("`bls_generate` failed") + } + + /// Sign the given `msg` with the `bls12-377` key that corresponds to the given public key and + /// key type in the keystore. + /// + /// Returns the signature. + fn bls_sign( + &mut self, + id: KeyTypeId, + pub_key: &bls::Public, + msg: &[u8], + ) -> Option { + let keystore = &***self + .extension::() + .expect("No `keystore` associated for the current context!"); + SyncCryptoStore::sign_with(keystore, id, &pub_key.into(), msg) + .ok() + .flatten() + .and_then(|sig| bls::Signature::from_slice(&sig)) + } + + /// Verify an `bls12-377` signature. + /// + /// Returns `true` when the verification in successful regardless of + /// signature version. + fn bls_verify(sig: &bls::Signature, msg: &[u8], pubkey: &bls::Public) -> bool { + bls::Pair::verify(sig, msg, pubkey) + } } /// Interface that provides functions for hashing with different algorithms. diff --git a/primitives/keystore/src/lib.rs b/primitives/keystore/src/lib.rs index 6540e71bc3fe0..c618dfed288e2 100644 --- a/primitives/keystore/src/lib.rs +++ b/primitives/keystore/src/lib.rs @@ -23,6 +23,7 @@ use crate::vrf::{VRFSignature, VRFTranscriptData}; use async_trait::async_trait; use futures::{executor::block_on, future::join_all}; use sp_core::{ + bls, crypto::{CryptoTypePublicPair, KeyTypeId}, ecdsa, ed25519, sr25519, }; @@ -85,6 +86,22 @@ pub trait CryptoStore: Send + Sync { seed: Option<&str>, ) -> Result; + /// Returns all bls12-377 public keys for the given key type. + async fn bls_public_keys(&self, id: KeyTypeId) -> Vec; + + /// Generate a new bls12-377 key pair for the given key type and an optional seed. + /// + /// If the given seed is `Some(_)`, the key pair will only be stored in memory. + /// + /// Returns the public key of the generated key pair. + async fn bls_generate_new( + &self, + id: KeyTypeId, + seed: Option<&str>, + ) -> Result; + + /// Returns all ed25519 public keys for the given key type. + /// Insert a new key. This doesn't require any known of the crypto; but a public key must be /// manually provided. /// @@ -257,6 +274,16 @@ pub trait SyncCryptoStore: CryptoStore + Send + Sync { fn ecdsa_generate_new(&self, id: KeyTypeId, seed: Option<&str>) -> Result; + /// Returns all bls12-377 public keys for the given key type. + fn bls_public_keys(&self, id: KeyTypeId) -> Vec; + + /// Generate a new bls12-377 key pair for the given key type and an optional seed. + /// + /// If the given seed is `Some(_)`, the key pair will only be stored in memory. + /// + /// Returns the public key of the generated key pair. + fn bls_generate_new(&self, id: KeyTypeId, seed: Option<&str>) -> Result; + /// Insert a new key. This doesn't require any known of the crypto; but a public key must be /// manually provided. /// @@ -382,6 +409,25 @@ pub trait SyncCryptoStore: CryptoStore + Send + Sync { public: &ecdsa::Public, msg: &[u8; 32], ) -> Result, Error>; + + /// Generate an BLS12-377 signature for a given message. + /// + /// Receives [`KeyTypeId`] and an [`bls::Public`] key to be able to map + /// them to a private key that exists in the keystore. This private key is, + /// in turn, used for signing the provided message. + /// + /// The `msg` argument provided should be a message for which an + /// BLS12-377 signature should be generated. + /// + /// Returns an [`bls::Signature`] or `None` in case the given `id` and + /// `public` combination doesn't exist in the keystore. An `Err` will be + /// returned if generating the signature itself failed. + fn bls_sign( + &self, + id: KeyTypeId, + public: &bls::Public, + msg: &[u8], + ) -> Result, Error>; } /// A pointer to a keystore. diff --git a/primitives/keystore/src/testing.rs b/primitives/keystore/src/testing.rs index a9ec6709d912a..b5eacfedeec4b 100644 --- a/primitives/keystore/src/testing.rs +++ b/primitives/keystore/src/testing.rs @@ -18,6 +18,7 @@ //! Types that should only be used for testing! use sp_core::{ + bls, crypto::{ByteArray, CryptoTypePublicPair, KeyTypeId, Pair}, ecdsa, ed25519, sr25519, }; @@ -69,6 +70,14 @@ impl KeyStore { .map(|s| ecdsa::Pair::from_string(s, None).expect("`ecdsa` seed slice is valid")) }) } + + fn bls_key_pair(&self, id: KeyTypeId, pub_key: &bls::Public) -> Option { + self.keys.read().get(&id).and_then(|inner| { + inner + .get(pub_key.as_slice()) + .map(|s| bls::Pair::from_string(s, None).expect("`bls` seed slice is valid")) + }) + } } #[async_trait] @@ -105,6 +114,18 @@ impl CryptoStore for KeyStore { SyncCryptoStore::ecdsa_public_keys(self, id) } + async fn bls_public_keys(&self, id: KeyTypeId) -> Vec { + SyncCryptoStore::bls_public_keys(self, id) + } + + async fn bls_generate_new( + &self, + id: KeyTypeId, + seed: Option<&str>, + ) -> Result { + SyncCryptoStore::bls_generate_new(self, id, seed) + } + async fn ecdsa_generate_new( &self, id: KeyTypeId, @@ -304,6 +325,43 @@ impl SyncCryptoStore for KeyStore { } } + fn bls_public_keys(&self, id: KeyTypeId) -> Vec { + self.keys + .read() + .get(&id) + .map(|keys| { + keys.values() + .map(|s| bls::Pair::from_string(s, None).expect("`bls` seed slice is valid")) + .map(|p| p.public()) + .collect() + }) + .unwrap_or_default() + } + + fn bls_generate_new(&self, id: KeyTypeId, seed: Option<&str>) -> Result { + match seed { + Some(seed) => { + let pair = bls::Pair::from_string(seed, None) + .map_err(|_| Error::ValidationError("Generates an `bls` pair.".to_owned()))?; + self.keys + .write() + .entry(id) + .or_default() + .insert(pair.public().to_raw_vec(), seed.into()); + Ok(pair.public()) + }, + None => { + let (pair, phrase, _) = bls::Pair::generate_with_phrase(None); + self.keys + .write() + .entry(id) + .or_default() + .insert(pair.public().to_raw_vec(), phrase); + Ok(pair.public()) + }, + } + } + fn insert_unknown(&self, id: KeyTypeId, suri: &str, public: &[u8]) -> Result<(), ()> { self.keys .write() @@ -384,6 +442,16 @@ impl SyncCryptoStore for KeyStore { let pair = self.ecdsa_key_pair(id, public); pair.map(|k| k.sign_prehashed(msg)).map(Ok).transpose() } + + fn bls_sign( + &self, + id: KeyTypeId, + public: &bls::Public, + msg: &[u8], + ) -> Result, Error> { + let pair = self.bls_key_pair(id, public); + pair.map(|k| k.sign(msg)).map(Ok).transpose() + } } impl Into for KeyStore { diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 8b64528e243bd..616518f03d49b 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -972,8 +972,8 @@ cfg_if! { } } - impl beefy_primitives::BeefyApi for Runtime { - fn validator_set() -> Option> { + impl beefy_primitives::BeefyApi for Runtime { + fn validator_set() -> Option> { None } }